diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..94b88276b82 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,29 @@ +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +*.jpg binary +*.png binary +*.gif binary + +*.cs text eol=crlf diff=csharp +*.aspx text eol=crlf +*.asax text eol=crlf +*.config text=auto +*.html text eol=crlf +*.htm text eol=crlf +*.css text=auto +*.js text=auto + +*.csproj text=auto merge=union +*.vbproj text=auto merge=union +*.fsproj text=auto merge=union +*.dbproj text=auto merge=union +*.sln text=auto eol=crlf merge=union \ No newline at end of file diff --git a/.gitignore b/.gitignore index d7201700de3..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 @@ -36,14 +39,32 @@ _ReSharper*/ App_Data/ build/*.dll *.user +*.userprefs +packages/ +.vs/ +.vscode/ +*.lock.json +*.nuget.props +*.nuget.targets release/latest/ *.nupkg release/* - -src/ServiceStack.MonoTouch/.DS_Store +requestlogs/ + +*.DS_Store + NuGet/ -build/ -*.DS_Store + +build/ *.dotCover + +*.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 8de494a57ea..5e9b96594eb 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,95 +1,309 @@ -# Contributors - - - [mythz](https://github.com/mythz) (Demis Bellot) - - [arxisos](https://github.com/arxisos) (Steffen M) - - [desunit](https://github.com/desunit) (Sergey Bogdanov) - - [bman654](https://github.com/bman654) (Brandon Wallace) - - [Iristyle](https://github.com/Iristyle) (Ethan Brown) - - [superlogical](https://github.com/superlogical) (Jake Scott) - - [itamar82](https://github.com/itamar82) - - [chadwackerman](https://github.com/chadwackerman) - - [derfsplat](https://github.com/derfsplat) - - [JohnACarruthers](https://github.com/JohnACarruthers) (John Carruthers) - - [mvitorino](https://github.com/mvitorino) (Miguel Vitorino) - - [bsiegel](https://github.com/bsiegel) (Brandon Siegel) - - [mdavid](https://github.com/mdavid) (M. David Peterson) - - [lhaussknecht](https://github.com/lhaussknecht) (Louis Haussknecht) - - [grendello](https://github.com/grendello) (Marek Habersack) - - [SteveDunn](https://github.com/SteveDunn) (Steve Dunn) - - [kcherenkov](https://github.com/kcherenkov) (Konstantin Cherenkov) - - [timryan](https://github.com/timryan) (Tim Ryan) - - [letssellsomebananas](https://github.com/letssellsomebananas) (Tymek Majewski) - - [danbarua](https://github.com/danbarua) (Dan Barua) - - [JonCanning](https://github.com/JonCanning) (Jon Canning) - - [paegun](https://github.com/paegun) (James Gorlick) - - [pvasek](https://github.com/pvasek) (pvasek) - - [derfsplat](https://github.com/derfsplat) (derfsplat) - - [justinrolston](https://github.com/justinrolston) (Justin Rolston) - - [danmiser](https://github.com/danmiser) (Dan Miser) - - [danatkinson](https://github.com/danatkinson) (Dan Atkinson) - - [brainless83](https://github.com/brainless83) (Thomas Grassauer) - - [angelcolmenares](https://github.com/angelcolmenares) (angel colmenares) - - [dbeattie71](https://github.com/dbeattie71) (Derek Beattie) - - [danielwertheim](https://github.com/danielwertheim) (Daniel Wertheim) - - [greghroberts](https://github.com/greghroberts) (Gregh Roberts) - - [int03](https://github.com/int03) (Selim Selçuk) - - [andidog](https://github.com/AndiDog) (AndiDog) - - [chuckb](https://github.com/chuckb) (chuckb) - - [niemyjski](https://github.com/niemyjski) (Blake Niemyjski) - - [mj1856](https://github.com/mj1856) (Matt Johnson) - - [matthieugd](https://github.com/matthieugd) (Matthieu) - - [tomaszkubacki](https://github.com/tomaszkubacki) (Tomasz Kubacki) - - [e11137](https://github.com/e11137) (Rogelio Canedo) - - [davrot](https://github.com/davrot) (David Roth) - - [meebey](https://github.com/meebey) (Mirco Bauer) - - [codedemonuk](https://github.com/codedemonuk) (Pervez Choudhury) - - [jrosskopf](https://github.com/jrosskopf) (Joachim Rosskopf) - - [friism](https://github.com/friism) (Michael Friis) - - [mp3125](https://github.com/mp3125) - - [aurimas86](https://github.com/aurimas86) - - [parnham](https://github.com/parnham) (Dan Parnham) - - [yeurch](https://github.com/yeurch) (Richard Fawcett) - - [damianh](https://github.com/damianh) (Damian Hickey) - - [freeman](https://github.com/freeman) (Michel Rasschaert) - - [kvervo](https://github.com/kvervo) (Kvervo) - - [pauldbau](https://github.com/pauldbau) (Paul Du Bois) - - [justinpihony](https://github.com/JustinPihony) (Justin Pihony) - - [bokmadsen](https://github.com/bokmadsen) (Bo Kingo Damgaard) - - [dragan](https://github.com/dragan) (Dale Ragan) - - [sneal](https://github.com/sneal) (Shawn Neal) - - [johnsheehan](https://github.com/johnsheehan) (John Sheehan) - - [jschlicht](https://github.com/jschlicht) (Jared Schlicht) - - [kumarnitin](https://github.com/kumarnitin) (Nitin Kumar) - - [DavidChristiansen](https://github.com/DavidChristiansen) (David Christiansen) - - [PaulECoyote](https://github.com/PaulECoyote) (Paul Evans) - - [kongo2002](https://github.com/kongo2002) (Gregor Uhlenheuer) - - [BrannonKing](https://github.com/BrannonKing) (Brannon King) - - [alexandrerocco](https://github.com/alexandrerocco) (Alexandre Rocco) - - [cbarbara](https://github.com/cbarbara) - - [assaframan](https://github.com/assaframan) (Assaf Raman) - - [csakshaug](https://github.com/csakshaug) (Christian Sakshaug) - - [johnman](https://github.com/johnman) - - [jarroda](https://github.com/jarroda) - - [ssboisen](https://github.com/ssboisen) (Simon Skov Boisen) - - [paulduran](https://github.com/paulduran) (Paul Duran) - - [pruiz](https://github.com/pruiz) (Pablo Ruiz García) - - [fantasticjamieburns](https://github.com/fantasticjamieburns) - - [pseabury](https://github.com/pseabury) - - [kevingessner](https://github.com/kevingessner) (Kevin Gessner) - - [iskomorokh](https://github.com/iskomorokh) (Igor Skomorokh) - - [royjacobs](https://github.com/royjacobs) (Roy Jacobs) - - [robertmircea](https://github.com/robertmircea) (Robert Mircea) - - [markswiatek](https://github.com/markswiatek) (Mark Swiatek) - - [flq](https://github.com/flq) (Frank Quednau) - - [ashd](https://github.com/ashd) (Ash D) - - [thanhhh](https://github.com/thanhhh) - - [algra](https://github.com/algra) (Alexey Gravanov) - - [jimschubert](https://github.com/jimschubert) (Jim Schubert) - - [gkathire](https://github.com/gkathire) - - [mikaelwaltersson](https://github.com/mikaelwaltersson) (Mikael Waltersson) - - [asunar](https://github.com/asunar) (Alper) - - [chucksavage](https://github.com/chucksavage) (Chuck Savage) - - [sashagit](https://github.com/sashagit) (Sasha) - - [froyke](https://github.com/froyke) (Froyke) - - [dbhobbs](https://github.com/dbhobbs) (Daniel Hobbs) - - [bculberson](https://github.com/bculberson) (Brad Culberson) +# Contributors + + - [mythz](https://github.com/mythz) (Demis Bellot) + - [arxisos](https://github.com/arxisos) (Steffen Müller) + - [desunit](https://github.com/desunit) (Sergey Bogdanov) + - [bman654](https://github.com/bman654) (Brandon Wallace) + - [iristyle](https://github.com/iristyle) (Ethan Brown) + - [superlogical](https://github.com/superlogical) (Jake Scott) + - [itamar82](https://github.com/itamar82) + - [chadwackerman](https://github.com/chadwackerman) + - [derfsplat](https://github.com/derfsplat) + - [johnacarruthers](https://github.com/johnacarruthers) (John Carruthers) + - [mvitorino](https://github.com/mvitorino) (Miguel Vitorino) + - [bsiegel](https://github.com/bsiegel) (Brandon Siegel) + - [mdavid](https://github.com/mdavid) (M. David Peterson) + - [lhaussknecht](https://github.com/lhaussknecht) (Louis Haussknecht) + - [grendello](https://github.com/grendello) (Marek Habersack) + - [SteveDunn](https://github.com/SteveDunn) (Steve Dunn) + - [kcherenkov](https://github.com/kcherenkov) (Konstantin Cherenkov) + - [timryan](https://github.com/timryan) (Tim Ryan) + - [letssellsomebananas](https://github.com/letssellsomebananas) (Tymek Majewski) + - [danbarua](https://github.com/danbarua) (Dan Barua) + - [JonCanning](https://github.com/JonCanning) (Jon Canning) + - [paegun](https://github.com/paegun) (James Gorlick) + - [pvasek](https://github.com/pvasek) (pvasek) + - [derfsplat](https://github.com/derfsplat) (derfsplat) + - [justinrolston](https://github.com/justinrolston) (Justin Rolston) + - [danmiser](https://github.com/danmiser) (Dan Miser) + - [danatkinson](https://github.com/danatkinson) (Dan Atkinson) + - [brainless83](https://github.com/brainless83) (Thomas Grassauer) + - [angelcolmenares](https://github.com/angelcolmenares) (angel colmenares) + - [dbeattie71](https://github.com/dbeattie71) (Derek Beattie) + - [danielwertheim](https://github.com/danielwertheim) (Daniel Wertheim) + - [greghroberts](https://github.com/greghroberts) (Gregh Roberts) + - [int03](https://github.com/int03) (Selim Selçuk) + - [andidog](https://github.com/AndiDog) (AndiDog) + - [chuckb](https://github.com/chuckb) (chuckb) + - [niemyjski](https://github.com/niemyjski) (Blake Niemyjski) + - [mj1856](https://github.com/mj1856) (Matt Johnson) + - [matthieugd](https://github.com/matthieugd) (Matthieu) + - [tomaszkubacki](https://github.com/tomaszkubacki) (Tomasz Kubacki) + - [e11137](https://github.com/e11137) (Rogelio Canedo) + - [davrot](https://github.com/davrot) (David Roth) + - [meebey](https://github.com/meebey) (Mirco Bauer) + - [codedemonuk](https://github.com/codedemonuk) (Pervez Choudhury) + - [jrosskopf](https://github.com/jrosskopf) (Joachim Rosskopf) + - [friism](https://github.com/friism) (Michael Friis) + - [mp3125](https://github.com/mp3125) + - [aurimas86](https://github.com/aurimas86) + - [parnham](https://github.com/parnham) (Dan Parnham) + - [yeurch](https://github.com/yeurch) (Richard Fawcett) + - [damianh](https://github.com/damianh) (Damian Hickey) + - [freeman](https://github.com/freeman) (Michel Rasschaert) + - [kvervo](https://github.com/kvervo) (Kvervo) + - [pauldbau](https://github.com/pauldbau) (Paul Du Bois) + - [justinpihony](https://github.com/JustinPihony) (Justin Pihony) + - [bokmadsen](https://github.com/bokmadsen) (Bo Kingo Damgaard) + - [dragan](https://github.com/dragan) (Dale Ragan) + - [sneal](https://github.com/sneal) (Shawn Neal) + - [johnsheehan](https://github.com/johnsheehan) (John Sheehan) + - [jschlicht](https://github.com/jschlicht) (Jared Schlicht) + - [kumarnitin](https://github.com/kumarnitin) (Nitin Kumar) + - [davidchristiansen](https://github.com/davidchristiansen) (David Christiansen) + - [paulecoyote](https://github.com/paulecoyote) (Paul Evans) + - [kongo2002](https://github.com/kongo2002) (Gregor Uhlenheuer) + - [brannonking](https://github.com/brannonking) (Brannon King) + - [alexandrerocco](https://github.com/alexandrerocco) (Alexandre Rocco) + - [cbarbara](https://github.com/cbarbara) + - [assaframan](https://github.com/assaframan) (Assaf Raman) + - [csakshaug](https://github.com/csakshaug) (Christian Sakshaug) + - [johnman](https://github.com/johnman) + - [jarroda](https://github.com/jarroda) + - [ssboisen](https://github.com/ssboisen) (Simon Skov Boisen) + - [paulduran](https://github.com/paulduran) (Paul Duran) + - [pruiz](https://github.com/pruiz) (Pablo Ruiz García) + - [fantasticjamieburns](https://github.com/fantasticjamieburns) + - [pseabury](https://github.com/pseabury) + - [kevingessner](https://github.com/kevingessner) (Kevin Gessner) + - [iskomorokh](https://github.com/iskomorokh) (Igor Skomorokh) + - [royjacobs](https://github.com/royjacobs) (Roy Jacobs) + - [robertmircea](https://github.com/robertmircea) (Robert Mircea) + - [markswiatek](https://github.com/markswiatek) (Mark Swiatek) + - [flq](https://github.com/flq) (Frank Quednau) + - [ashd](https://github.com/ashd) (Ash D) + - [thanhhh](https://github.com/thanhhh) + - [algra](https://github.com/algra) (Alexey Gravanov) + - [jimschubert](https://github.com/jimschubert) (Jim Schubert) + - [gkathire](https://github.com/gkathire) + - [mikaelwaltersson](https://github.com/mikaelwaltersson) (Mikael Waltersson) + - [asunar](https://github.com/asunar) (Alper) + - [chucksavage](https://github.com/chucksavage) (Chuck Savage) + - [sashagit](https://github.com/sashagit) (Sasha) + - [froyke](https://github.com/froyke) (Froyke) + - [dbhobbs](https://github.com/dbhobbs) (Daniel Hobbs) + - [bculberson](https://github.com/bculberson) (Brad Culberson) + - [awr](https://github.com/awr) (Andrew) + - [pingvinen](https://github.com/pingvinen) (Patrick) + - [citndev](https://github.com/CITnDev) (Sebastien Curutchet) + - [cyberprune](https://github.com/cyberprune) + - [jorbor](https://github.com/jorbor) (Jordan Hayashi) + - [bojanv55](https://github.com/bojanv55) + - [i-e-b](https://github.com/i-e-b) (Iain Ballard) + - [pietervp](https://github.com/pietervp) (Pieter Van Parys) + - [franklinwise](https://github.com/franklinwise) + - [ckasabula](https://github.com/ckasabula) (Chuck Kasabula) + - [dortzur](https://github.com/dortzur) (Dor Tzur) + - [allenarthurgay](https://github.com/allenarthurgay) (Allen Gay) + - [viceberg](https://github.com/vIceBerg) + - [vansha](https://github.com/vansha) (Ivan Korneliuk) + - [aaronlerch](https://github.com/aaronlerch) (Aaron Lerch) + - [glikoz](https://github.com/glikoz) + - [danielcrenna](https://github.com/danielcrenna) (Daniel Crenna) + - [stevegraygh](https://github.com/stevegraygh) (Steve Graygh) + - [jrmitch120](https://github.com/jrmitch120) (Jeff Mitchell) + - [manuelnelson](https://github.com/manuelnelson) (Manuel Nelson) + - [babcca](https://github.com/babcca) (Petr Babicka) + - [jgeurts](https://github.com/jgeurts) (Jim Geurts) + - [driis](https://github.com/driis) (Dennis Riis) + - [gshackles](https://github.com/gshackles) (Greg Shackles) + - [jsonmez](https://github.com/jsonmez) (John Sonmez) + - [dchurchland](https://github.com/dchurchland) (David Churchland) + - [softwx](https://github.com/softwx) (Steve Hatchett) + - [ggeurts](https://github.com/ggeurts) (Gerke Geurts) + - [andrewrissing](https://github.com/AndrewRissing) (Andrew Rissing) + - [jjavery](https://github.com/jjavery) (James Javery) + - [suremaker](https://github.com/suremaker) (Wojtek) + - [cheesebaron](https://github.com/cheesebaron) (Tomasz Cielecki) + - [mikkelfish](https://github.com/mikkelfish) (Mikkel Fishman) + - [johngibb](https://github.com/johngibb) (John Gibb) + - [gixug](https://github.com/gixug) (David Stone) + - [mikepugh](https://github.com/mikepugh) (Mike Pugh) + - [permalmberg](https://github.com/permalmberg) (Per Malmberg) + - [adamralph](https://github.com/adamralph) (Adam Ralph) + - [shamsulamry](https://github.com/shamsulamry) (Shamsul Amry) + - [peterlazzarino](https://github.com/peterlazzarino) (Peter Lazzarino) + - [kevin-montrose](https://github.com/kevin-montrose) (Kevin Montrose) + - [msarchet](https://github.com/msarchet) (Michael Sarchet) + - [jeffgabhart](https://github.com/jeffgabhart) (Jeff Gabhart) + - [pkudinov](https://github.com/pkudinov) (Pavel Kudinov) + - [permalmberg](https://github.com/permalmberg) (Per Malmberg) + - [namman](https://github.com/namman) (Nick Miller) + - [leon-andria](https://github.com/leon-andria) (Leon Andria) + - [kkolstad](https://github.com/kkolstad) (Kenneth Kolstad) + - [electricshaman](https://github.com/electricshaman) (Jeff Smith) + - [ecgan](https://github.com/ecgan) (Gan Eng Chin) + - [its-tyson](https://github.com/its-tyson) (Tyson Stolarski) + - [tischlda](https://github.com/tischlda) (David Tischler) + - [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) + - [cliffstill](https://github.com/cliffstill) + - [somya](https://github.com/somya) (Somya Jain) + - [thinkbeforecoding](https://github.com/thinkbeforecoding) (Jérémie Chassaing) + - [paksys](https://github.com/paksys) (Khalil Ahmad) + - [mcguinness](https://github.com/mcguinness) (Karl McGuinness) + - [jpasichnyk](https://github.com/jpasichnyk) (Jesse Pasichnyk) + - [waynebrantley](https://github.com/waynebrantley) (Wayne Brantley) + - [dcartoon](https://github.com/dcartoon) (Dan Cartoon) + - [alexvodovoz](https://github.com/alexvodovoz) (Alex Vodovoz) + - [jluchiji](https://github.com/jluchiji) (Denis Luchkin-Zhou) + - [grexican](https://github.com/grexican) + - [akoslukacs](https://github.com/akoslukacs) (Ákos Lukács) + - [medianick](https://github.com/medianick) (Nick Jones) + - [arhoads76](https://github.com/arhoads76) + - [dylanvdmerwe](https://github.com/dylanvdmerwe) (Dylan v.d Merwe) + - [mattiasw2](https://github.com/mattiasw2) (Mattias) + - [paultyng](https://github.com/paultyng) (Paul Tyng) + - [h2oman](https://github.com/h2oman) (Jason Waterman) + - [anewton](https://github.com/anewton) (Allen Newton) + - [sami1971](https://github.com/sami1971) + - [russellchadwick](https://github.com/russellchadwick) (Russell Chadwick) + - [cyberzed](https://github.com/cyberzed) (Stefan Daugaard Poulsen) + - [filipw](https://github.com/filipw) (Filip Wojcieszyn) + - [ghuntley](https://github.com/ghuntley) (Geoffrey Huntley) + - [baramuse](https://github.com/baramuse) + - [captncraig](https://github.com/captncraig) (Craig Peterson) + - [pdegenhardt](https://github.com/pdegenhardt) (Phil Degenhardt) + - [abattery](https://github.com/abattery) (Jae sung Chung) + - [biliktamas79](https://github.com/biliktamas79) + - [garuma](https://github.com/garuma) (Jérémie Laval) + - [dsimunic](https://github.com/dsimunic) + - [adamfowleruk](https://github.com/adamfowleruk) (Adam Fowler) + - [bfriesen](https://github.com/bfriesen) (Brian Friesen) + - [roryf](https://github.com/roryf) (Rory Fitzpatrick) + - [stefandevo](https://github.com/stefandevo) + - [gdassac](https://github.com/gdassac) + - [metal10k](https://github.com/metal10k) + - [cmelgarejo](https://github.com/cmelgarejo) + - [skaman](https://github.com/skaman) + - [rossipedia](https://github.com/rossipedia) (Bryan J. Ross) + - [wimatihomer](https://github.com/wimatihomer) (Wim Pool) + - [sword-breaker](https://github.com/sword-breaker) + - [adebisi-fa](https://github.com/adebisi-fa) (Adebisi Foluso A.) + - [mbischoff](https://github.com/mbischoff) (M. Bischoff) + - [ivanfioravanti](https://github.com/ivanfioravanti) (Ivan Fioravanti) + - [inhibition](https://github.com/inhibition) (Keith Hassen) + - [joshearl](https://github.com/joshearl) (Josh Earl) + - [friism](https://github.com/friism) (Michael Friis) + - [corkupine](https://github.com/corkupine) + - [bchavez](https://github.com/bchavez) (Brian Chavez) + - [nhhagen](https://github.com/nhhagen) (Niels Henrik Hagen) + - [daggmano](https://github.com/daggmano) (Darren Oster) + - [chappoo](https://github.com/chappoo) (Steve Chapman) + - [julrichkieffer](https://github.com/julrichkieffer) (Julrich Kieffer) + - [adamclarsen](https://github.com/adamclarsen) (Adam Larsen) + - [joero74](https://github.com/joero74) (Joerg Rosenkranz) + - [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) (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) + - [aleshi](https://github.com/aleshi) (Alexander Shiryaev) + - [alexandryz](https://github.com/alexandryz) (Alexandr Zaozerskiy) + - [mistobaan](https://github.com/mistobaan) (Fabrizio Milo) + - [niemyjski](https://github.com/niemyjski) (Blake Niemyjski) + - [alexandernyquist](https://github.com/alexandernyquist) (Alexander Nyquist) + - [mcduck76](https://github.com/mcduck76) + - [kojoru](https://github.com/kojoru) + - [jeremy-bridges](https://github.com/jeremy-bridges) (Jeremy Bridges) + - [andreabalducci](https://github.com/andreabalducci) (Andrea Balducci) + - [robertthegrey](https://github.com/RobertTheGrey) (Robert Greyling) + - [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 c5e98c937d6..00000000000 --- a/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2007-2011, 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. \ No newline at end of file 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 2082ac60a4f..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 6dda2465d62..00000000000 --- a/NuGet/NuGetPack.cmd +++ /dev/null @@ -1,9 +0,0 @@ -nuget pack ServiceStack\servicestack.nuspec -nuget pack ServiceStack.Common\servicestack.common.nuspec -nuget pack ServiceStack.Mvc\servicestack.mvc.nuspec -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.Host.Mvc\servicestack.host.mvc.nuspec -nuget pack ServiceStack.Plugins.ProtoBuf\servicestack.plugins.protobuf.nuspec - diff --git a/NuGet/ServiceStack.Client.Silverlight/servicestack.client.silverlight.nuspec b/NuGet/ServiceStack.Client.Silverlight/servicestack.client.silverlight.nuspec deleted file mode 100644 index 84cafa0d474..00000000000 --- a/NuGet/ServiceStack.Client.Silverlight/servicestack.client.silverlight.nuspec +++ /dev/null @@ -1,24 +0,0 @@ - - - - ServiceStack.Client.Silverlight - 3.9.0 - Silverlight Clients for ServiceStack webservices - Demis Bellot - Demis Bellot - Silverlight JSON, XML, JSV ServiceClients for ServiceStack web services - - ServiceStack client binaries for Silverlight. Provides generic JSON, XML and JSV Service Clients allowing you to call ServiceStack web services from a Silverlight client. - This is now a stub that points to ServiceStack.Common NuGet package which now contains the Silverlight client builds. - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - Silverlight Fast JSON XML JSV REST Web Services - en-US - servicestack.net 2012 and contributors - - - - - \ No newline at end of file diff --git a/NuGet/ServiceStack.Common/lib/sl4/README.txt b/NuGet/ServiceStack.Common/lib/sl4/README.txt deleted file mode 100644 index 6e4324a1416..00000000000 --- a/NuGet/ServiceStack.Common/lib/sl4/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -ServiceStack Client builds for Silverlight. - -Due to restrictions in Silverlight only the Async operations are supported. \ No newline at end of file diff --git a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Common.dll b/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Common.dll deleted file mode 100644 index 2d28618e4f1..00000000000 Binary files a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Common.dll and /dev/null differ diff --git a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Common.xml b/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Common.xml deleted file mode 100644 index 68425b9eb77..00000000000 --- a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Common.xml +++ /dev/null @@ -1,475 +0,0 @@ - - - - ServiceStack.Common - - - - - The exception which is thrown when a validation error occured. - This validation is serialized in a extra clean and human-readable way by ServiceStack. - - - - - Used if we need to serialize this exception to XML - - - - - - Returns the first error code - - The error code. - - - Need to provide async request options - http://msdn.microsoft.com/en-us/library/86wf6409(VS.71).aspx - - - - Sets the username and the password for basic authentication. - - - - - Specifies if cookies should be stored - - - - - The request filter is called before any request. - This request filter is executed globally. - - - - - The user name for basic authentication - - - - - The password for basic authentication - - - - - Gets or sets authentication information for the request. - Warning: It's recommened to use and for basic auth. - This property is only used for IIS level authentication. - - - - - Determines if the basic auth header should be sent with every request. - By default, the basic auth header is only sent when "401 Unauthorized" is returned. - - - - - The request filter is called before any request. - This request filter only works with the instance where it was set (not global). - - - - - Encapsulates creating a new message handler - - - - - Useful IPAddressExtensions from: - http://blogs.msdn.com/knom/archive/2008/12/31/ip-address-calculations-with-c-subnetmasks-networks.aspx - - - - - - Gets the ipv4 addresses from all Network Interfaces that have Subnet masks. - - - - - - Gets the ipv6 addresses from all Network Interfaces. - - - - - - These extensions have a potential to conflict with the LINQ extensions methods so - leaving the implmentation in the 'Extensions' sub-namespace to force explicit opt-in - - - - - - Invokes the action provided and returns true if no excpetion was thrown. - Otherwise logs the exception and returns false if an exception was thrown. - - The action. - - - - - Contains methods required for encoding and decoding rcon packets. - - - - - Decodes a packet. - - The packet. - A packet object. - - - - Decodes the packet header. - - - - - - - Decodes words in a packet. - - - - - - - Encodes a packet for transmission to the server. - - - - - - - - - - Encodes a packet header. - - - - - - - - - Encodes words. - - - - - - - Maps the path of a file in the context of a VS project - - the relative path - the absolute path - Assumes static content is two directories above the /bin/ directory, - eg. in a unit test scenario the assembly would be in /bin/Debug/. - - - - Maps the path of a file in a self-hosted scenario - - the relative path - the absolute path - Assumes static content is copied to /bin/ folder with the assemblies - - - - Maps the path of a file in an Asp.Net hosted scenario - - the relative path - the absolute path - Assumes static content is in the parent folder of the /bin/ directory - - - - Encapsulates a validation result. - - - - - Constructs a new ValidationResult - - - - - Constructs a new ValidationResult - - A list of validation results - - - - Initializes a new instance of the class. - - The errors. - The success code. - The error code. - - - - Gets or sets the success code. - - The success code. - - - - Gets or sets the error code. - - The error code. - - - - Gets or sets the success message. - - The success message. - - - - Gets or sets the error message. - - The error message. - - - - The errors generated by the validation. - - - - - Returns True if the validation was successful (errors list is empty). - - - - - Populate an object with Example data. - - - - - - - Populates the object with example data. - - - Tracks how deeply nested we are - - - - - Processes all messages in a Normal and Priority Queue. - Expects to be called in 1 thread. i.e. Non Thread-Safe. - - - - - - Single threaded message handler that can process all messages - of a particular message type. - - - - - Process all messages pending - - - - - - Get Current Stats for this Message Handler - - - - - - The type of the message this handler processes - - - - - Gets the textual description of the enum if it has one. e.g. - - - enum UserColors - { - [Description("Bright Red")] - BrightRed - } - UserColors.BrightRed.ToDescription(); - - - - - - - - True if the packet originated on the server. - - - - - True if the packet is a response from a sent packet. - - - - - Sequence identifier. Unique to the connection. - - - - - Words. - - - - - Creates a Unified Resource Name (URN) with the following formats: - - - urn:{TypeName}:{IdFieldValue} e.g. urn:UserSession:1 - - urn:{TypeName}:{IdFieldName}:{IdFieldValue} e.g. urn:UserSession:UserId:1 - - - - - - Common functionality when creating adapters - - - - - Executes the specified expression. - - - The action. - - - - - Executes the specified action (for void methods). - - The action. - - - Need to provide async request options - http://msdn.microsoft.com/en-us/library/86wf6409(VS.71).aspx - - - - Default MaxStringContentLength is 8k, and throws an exception when reached - - - - - Func to get the Strongly-typed field - - - - - Required to cast the return ValueType to an object for caching - - - - - Func to set the Strongly-typed field - - - - - Required to cast the ValueType to an object for caching - - - - - Required to cast the ValueType to an object for caching - - - - - Executes the specified action. - - - The action. - - - - - Gets the current context (or null if none). - - - - - Checks if the current context is set to "initialize only". - - - - - Determines whether this context is initialise only or not - - - - - Constructs a new InitialiseOnlyContext - - - - - Call to remove this current context and reveal the previous context (if any). - - - - - Gets or sets the object that has been initialized only. - - - - - Serializer cache of delegates required to create a type from a string map (e.g. for REST urls) - - - - - Provide the an option for the callee to block until all commands are executed - - - - - - - Note: InMemoryLog keeps all logs in memory, so don't use it long running exceptions - - Returns a thread-safe InMemoryLog which you can use while *TESTING* - to provide a detailed analysis of your logs. - - - - - Func to get the Strongly-typed field - - - - - Required to cast the return ValueType to an object for caching - - - - - Func to set the Strongly-typed field - - - - - Required to cast the ValueType to an object for caching - - - - - Required to cast the ValueType to an object for caching - - - - diff --git a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Interfaces.dll b/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Interfaces.dll deleted file mode 100644 index 0840a35772a..00000000000 Binary files a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Interfaces.dll and /dev/null differ diff --git a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Interfaces.xml b/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Interfaces.xml deleted file mode 100644 index 47c34dfd40b..00000000000 --- a/NuGet/ServiceStack.Common/lib/sl4/ServiceStack.Interfaces.xml +++ /dev/null @@ -1,1343 +0,0 @@ - - - - ServiceStack.Interfaces - - - - - This instructs the generator tool to generate translator methods for the types supplied. - A {TypeName}.generated.cs partial class will be generated that contains the methods required - to generate to and from that type. - - - - - Error information pertaining to a particular named field. - Used for returning multiple field validation errors.s - - - - - If the Service also implements this interface, - IRestPutService.Put() will be used instead of IService.Execute() for - EndpointAttributes.HttpPut requests - - - - - - A thin wrapper around ASP.NET or HttpListener's HttpResponse - - - - - Signal that this response has been handled and no more processing should be done. - When used in a request or response filter, no more filters or processing is done on this request. - - - - - Calls Response.End() on ASP.NET HttpResponse otherwise is an alias for Close(). - Useful when you want to prevent ASP.NET to provide it's own custom error page. - - - - - Response.Flush() and OutputStream.Flush() seem to have different behaviour in ASP.NET - - - - - The underlying ASP.NET or HttpListener HttpResponse - - - - - Gets a value indicating whether this instance is closed. - - - - - Subscribe to channels by name - - - - - - Subscribe to channels matching the supplied patterns - - - - - - The number of active subscriptions this client has - - - - - Registered handler called after client *Subscribes* to each new channel - - - - - Registered handler called when each message is received - - - - - Registered handler called when each channel is unsubscribed - - - - - Wrap the common redis list operations under a IList[string] interface. - - - - - Creates a Debug Logger, that logs all messages to: System.Diagnostics.Debug - - Made public so its testable - - - - - Factory to create ILog instances - - - - - Gets the logger. - - The type. - - - - - Gets the logger. - - Name of the type. - - - - - Contract indication that the Response DTO has a ResponseStatus - - - - - interface to operation that can queue commands - - - - - For messaging exceptions that should by-pass the messaging service's configured - retry attempts and store the message straight into the DLQ - - - - - Base Exception for all ServiceStack.Messaging exceptions - - - - - Default logger is to Console.WriteLine - - Made public so its testable - - - - - Logs a message in a running application - - - - - Logs a Debug message. - - The message. - - - - Logs a Debug message and exception. - - The message. - The exception. - - - - Logs a Debug format message. - - The format. - The args. - - - - Logs a Error message. - - The message. - - - - Logs a Error message and exception. - - The message. - The exception. - - - - Logs a Error format message. - - The format. - The args. - - - - Logs a Fatal message. - - The message. - - - - Logs a Fatal message and exception. - - The message. - The exception. - - - - Logs a Error format message. - - The format. - The args. - - - - Logs an Info message and exception. - - The message. - - - - Logs an Info message and exception. - - The message. - The exception. - - - - Logs an Info format message. - - The format. - The args. - - - - Logs a Warning message. - - The message. - - - - Logs a Warning message and exception. - - The message. - The exception. - - - - Logs a Warning format message. - - The format. - The args. - - - - Gets or sets a value indicating whether this instance is debug enabled. - - - true if this instance is debug enabled; otherwise, false. - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - Base interface all webservices need to implement. - For simplicity this is the only interface you need to implement - - - - - - The HTTP Response Status Code - - - - - The HTTP Status Description - - - - - The HTTP Response ContentType - - - - - Additional HTTP Headers - - - - - Response DTO - - - - - A specific template, if not the default (for HTML, Markdown, etc. ContentTypes) - - - - - if not provided, get's injected by ServiceStack - - - - - Holds the request call context - - - - - Resolve a dependency from the AppHost's IOC - - - - - - - Pipeline interface shared by typed and non-typed pipelines - - - - - Interface to operations that allow queued commands to be completed - - - - - The same functionality is on IServiceResolver - - - - - Creates a Debug Logger, that logs all messages to: System.Diagnostics.Debug - - Made public so its testable - - - - - This instructs the generator tool to generate translator extension methods for the types supplied. - A {TypeName}.generated.cs static class will be generated that contains the extension methods required - to generate to and from that type. - - The source type is what the type the attribute is decorated on which can only be resolved at runtime. - - - - - Utility interface that implements all Rest operations - - - - - - If the Service also implements this interface, - IRestGetService.Get() will be used instead of IService.Execute() for - EndpointAttributes.HttpGet requests - - - - - - If the Service also implements this interface, - IRestPostService.Post() will be used instead of IService.Execute() for - EndpointAttributes.HttpPost requests - - - - - - If the Service also implements this interface, - IRestDeleteService.Delete() will be used instead of IService.Execute() for - EndpointAttributes.HttpDelete requests - - - - - - If the Service also implements this interface, - IRestPutService.Patch() will be used instead of IService.Execute() for - EndpointAttributes.HttpPatch requests - - - - - - Interface to redis typed pipeline - - - - - interface to queueable operation using typed redis client - - - - - - Publish the specified message into the durable queue @queueName - - - - - - - Publish the specified message into the transient queue @queueName - - - - - - - Synchronous blocking get. - - - - - - - - Non blocking get message - - - - - - - Blocking wait for notifications on any of the supplied channels - - - - - - - Logging API for this library. You can inject your own implementation otherwise - will use the DebugLogFactory to write to System.Diagnostics.Debug - - - - - Gets the logger. - - The type. - - - - - Gets the logger. - - Name of the type. - - - - - Gets or sets the log factory. - Use this to override the factory that is used to create loggers - - The log factory. - - - - Sends the specified request. - - The request. - - - - - Common ResponseStatus class that should be present on all response DTO's - - - - - Initializes a new instance of the class. - - A response status without an errorcode == success - - - - - Initializes a new instance of the class. - - A response status with an errorcode == failure - - - - - Initializes a new instance of the class. - - A response status with an errorcode == failure - - - - - Holds the custom ErrorCode enum if provided in ValidationException - otherwise will hold the name of the Exception type, e.g. typeof(Exception).Name - - A value of non-null means the service encountered an error while processing the request. - - - - - A human friendly error message - - - - - - - - - - For multiple detailed validation errors. - Can hold a specific error message for each named field. - - - - - Log every service request - - - - - Log a request - - - - - - - Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. - - - - - - Returns a Read/Write ICacheClient (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly ICacheClient using the hosts defined in ReadOnlyHosts. - - - - - - Basic implementation of IMessage[T] - - - - - - Tests logger which stores all log messages in a member list which can be examined later - - Made public so its testable - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - Allow the registration of user-defined routes for services - - - - - Maps the specified REST path to the specified request DTO. - - The type of request DTO to map - the path to. - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - The same instance; - never . - - - - Maps the specified REST path to the specified request DTO, and - specifies the HTTP verbs supported by the path. - - The type of request DTO to map - the path to. - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - - The comma-delimited list of HTTP verbs supported by the path, - such as "GET,PUT,DELETE". Specify empty or - to indicate that all verbs are supported. - - The same instance; - never . - - - - Maps the specified REST path to the specified request DTO, - specifies the HTTP verbs supported by the path, and indicates - the default MIME type of the returned response. - - The type of request DTO to map - the path to. - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - - The comma-delimited list of HTTP verbs supported by the path, - such as "GET,PUT,DELETE". - - - The default MIME type in which the response object returned to the client - is formatted, if formatting hints are not provided by the client. - Specify or empty to require formatting hints from - the client. - - The same instance; - never . - - - - Maps the specified REST path to the specified request DTO, - specifies the HTTP verbs supported by the path, and indicates - the default MIME type of the returned response. - - - The type of request DTO to map the path to. - - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - - The comma-delimited list of HTTP verbs supported by the path, - such as "GET,PUT,DELETE". - - - The default MIME type in which the response object returned to the client - is formatted, if formatting hints are not provided by the client. - Specify or empty to require formatting hints from - the client. - - The same instance; - never . - - - - A light interface over a cache client. - This interface was inspired by Enyim.Caching.MemcachedClient - - Only the methods that are intended to be used are required, if you require - extra functionality you can uncomment the unused methods below as they have been - implemented in DdnMemcachedClient - - - - - Removes the specified item from the cache. - - The identifier for the item to delete. - - true if the item was successfully removed from the cache; false otherwise. - - - - - Removes the cache for all the keys provided. - - The keys. - - - - Retrieves the specified item from the cache. - - The identifier for the item to retrieve. - - The retrieved item, or null if the key was not found. - - - - - Increments the value of the specified key by the given amount. The operation is atomic and happens on the server. - - The identifier for the item to increment. - The amount by which the client wants to increase the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Increments the value of the specified key by the given amount. The operation is atomic and happens on the server. - - The identifier for the item to increment. - The amount by which the client wants to decrease the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Inserts an item into the cache with a cache key to reference its location. - - The key used to reference the item. - The object to be inserted into the cache. - - true if the item was successfully stored in the cache; false otherwise. - - The item does not expire unless it is removed due memory pressure. - - - - Inserts an item into the cache with a cache key to reference its location. - - The key used to reference the item. - The object to be inserted into the cache. - The time when the item is invalidated in the cache. - true if the item was successfully stored in the cache; false otherwise. - - - - Removes all data from the cache. - - - - - Retrieves multiple items from the cache. - - The list of identifiers for the items to retrieve. - - a Dictionary holding all items indexed by their key. - - - - - Base transaction interface, shared by typed and non-typed transactions - - - - - Redis transaction for typed client - - - - - - Default logger is to System.Diagnostics.Debug.WriteLine - - Made public so its testable - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - For providers that want a cleaner API with a little more perf - - - - - - Allow delegation of dependencies to other IOC's - - - - - Resolve Property Dependency - - - - - - - Resolve Constructor Dependency - - - - - - - An Error Message Type that can be easily serialized - - - - - Simple definition of an MQ Host - - - - - Register DTOs and hanlders the MQ Host will process - - - - - - - Register DTOs and hanlders the MQ Host will process - - - - - - - - Get Total Current Stats for all Message Handlers - - - - - - Get a Stats dump - - - - - - Start the MQ Host if not already started. - - - - - Stop the MQ Host if not already stopped. - - - - - Factory to create consumers and producers that work with this service - - - - - Default logger is to System.Diagnostics.Debug.Print - - Made public so its testable - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - Manages a connection to a persistance provider - - - - - This changes the default behaviour for the - - - - - Used to decorate Request DTO's to associate a RESTful request - path mapping with a service. Multiple attributes can be applied to - each request DTO, to map multiple paths to the service. - - - - - Initializes an instance of the class. - - - The path template to map to the request. See - RestServiceAttribute.Path - for details on the correct format. - - - - - Initializes an instance of the class. - - - The path template to map to the request. See - RestServiceAttribute.Path - for details on the correct format. - - A comma-delimited list of HTTP verbs supported by the - service. If unspecified, all verbs are assumed to be supported. - - - - Initializes an instance of the class. - - - The path template to map to the request. See - RestServiceAttribute.Path - for details on the correct format. - - A comma-delimited list of HTTP verbs supported by the - service. If unspecified, all verbs are assumed to be supported. - The default MIME type in which the response - object returned to the client is formatted, if formatting hints are unspecified - in the URL. Specify or empty to require formatting - hints from the client. - - - - Gets or sets the path template to be mapped to the request. - - - A value providing the path mapped to - the request. Never . - - - Some examples of valid paths are: - - - "/Inventory" - "/Inventory/{Category}/{ItemId}" - "/Inventory/{ItemPath*}" - - - Variables are specified within "{}" - brackets. Each variable in the path is mapped to the same-named property - on the request DTO. At runtime, ServiceStack will parse the - request URL, extract the variable values, instantiate the request DTO, - and assign the variable values into the corresponding request properties, - prior to passing the request DTO to the service object for processing. - - It is not necessary to specify all request properties as - variables in the path. For unspecified properties, callers may provide - values in the query string. For example: the URL - "http://services/Inventory?Category=Books&ItemId=12345" causes the same - request DTO to be processed as "http://services/Inventory/Books/12345", - provided that the paths "/Inventory" (which supports the first URL) and - "/Inventory/{Category}/{ItemId}" (which supports the second URL) - are both mapped to the request DTO. - - Please note that while it is possible to specify property values - in the query string, it is generally considered to be less RESTful and - less desirable than to specify them as variables in the path. Using the - query string to specify property values may also interfere with HTTP - caching. - - The final variable in the path may contain a "*" suffix - to grab all remaining segments in the path portion of the request URL and assign - them to a single property on the request DTO. - For example, if the path "/Inventory/{ItemPath*}" is mapped to the request DTO, - then the request URL "http://services/Inventory/Books/12345" will result - in a request DTO whose ItemPath property contains "Books/12345". - You may only specify one such variable in the path, and it must be positioned at - the end of the path. - - - - - Gets or sets a comma-delimited list of HTTP verbs supported by the service, such as - "GET,PUT,POST,DELETE". - - - A providing a comma-delimited list of HTTP verbs supported - by the service, or empty if all verbs are supported. - - - - - Gets or sets the default MIME type in which the response - object returned to the client is formatted, when format hints - are not provided in the URI. Some valid examples are such as - "application/json", or "application/xml". - - - A providing the default MIME type of the response; - or empty if formatting hints are required - from the client. - - - - - Interface to redis transaction - - - - - A common interface implementation that is implemeneted by most cache providers - - - - - Removes the specified item from the cache. - - The identifier for the item to delete. - - true if the item was successfully removed from the cache; false otherwise. - - - - - Removes the cache for all the keys provided. - - The keys. - - - - Retrieves the specified item from the cache. - - - The identifier for the item to retrieve. - - The retrieved item, or null if the key was not found. - - - - - Increments the value of the specified key by the given amount. - The operation is atomic and happens on the server. - A non existent value at key starts at 0 - - The identifier for the item to increment. - The amount by which the client wants to increase the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Increments the value of the specified key by the given amount. - The operation is atomic and happens on the server. - A non existent value at key starts at 0 - - The identifier for the item to increment. - The amount by which the client wants to decrease the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Adds a new item into the cache at the specified cache key only if the cache is empty. - - The key used to reference the item. - The object to be inserted into the cache. - - true if the item was successfully stored in the cache; false otherwise. - - The item does not expire unless it is removed due memory pressure. - - - - Sets an item into the cache at the cache key specified regardless if it already exists or not. - - - - - Replaces the item at the cachekey specified only if an items exists at the location already. - - - - - Invalidates all data on the cache. - - - - - - Sets multiple items to the cache. - - - The values. - - - - Used to decorate Request DTO's to alter the behaviour of a service. - - - - - Sets a single access restriction - - The restrict access to. - - - - Set multiple access scenarios - - The restrict access to scenarios. - - - - If the Service also implements this interface, - IAsyncService.ExecuteAsync() will be used instead of IService.Execute() for - EndpointAttributes.AsyncOneWay requests - - - - - - Interface to redis pipeline - - - - - Creates a Debug Logger, that logs all messages to: System.Diagnostics.Debug - - Made public so its testable - - - - - Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. - - - - - - Returns a Read/Write ICacheClient (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly ICacheClient using the hosts defined in ReadOnlyHosts. - - - - - - Util static generic class to create unique queue names for types - - - - - - Util class to create unique queue names for runtime types - - - - - Responsible for executing the operation within the specified context. - - The operation types. - - - - Returns the first matching RestPath - - - - - - - - Executes the DTO request under the supplied requestContext. - - - - - - - - Returns a list of operation types available in this service - - The operation types. - - - - Returns a list of ALL operation types available in this service - - The operation types. - - - - Allow the registration of custom routes - - - - - Implement on services that need access to the RequestContext - - - - - Creates a test Logger, that stores all log messages in a member list - - - - - A Users Session - - - - - Set a typed value at key - - - - - - - - Get a typed value at key - - - - - - - - Store any object at key - - - - - - diff --git a/NuGet/ServiceStack.Common/lib/sl5/README.txt b/NuGet/ServiceStack.Common/lib/sl5/README.txt deleted file mode 100644 index 6e4324a1416..00000000000 --- a/NuGet/ServiceStack.Common/lib/sl5/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -ServiceStack Client builds for Silverlight. - -Due to restrictions in Silverlight only the Async operations are supported. \ No newline at end of file diff --git a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Common.dll b/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Common.dll deleted file mode 100644 index f55c1b7e405..00000000000 Binary files a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Common.dll and /dev/null differ diff --git a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Common.xml b/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Common.xml deleted file mode 100644 index 68425b9eb77..00000000000 --- a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Common.xml +++ /dev/null @@ -1,475 +0,0 @@ - - - - ServiceStack.Common - - - - - The exception which is thrown when a validation error occured. - This validation is serialized in a extra clean and human-readable way by ServiceStack. - - - - - Used if we need to serialize this exception to XML - - - - - - Returns the first error code - - The error code. - - - Need to provide async request options - http://msdn.microsoft.com/en-us/library/86wf6409(VS.71).aspx - - - - Sets the username and the password for basic authentication. - - - - - Specifies if cookies should be stored - - - - - The request filter is called before any request. - This request filter is executed globally. - - - - - The user name for basic authentication - - - - - The password for basic authentication - - - - - Gets or sets authentication information for the request. - Warning: It's recommened to use and for basic auth. - This property is only used for IIS level authentication. - - - - - Determines if the basic auth header should be sent with every request. - By default, the basic auth header is only sent when "401 Unauthorized" is returned. - - - - - The request filter is called before any request. - This request filter only works with the instance where it was set (not global). - - - - - Encapsulates creating a new message handler - - - - - Useful IPAddressExtensions from: - http://blogs.msdn.com/knom/archive/2008/12/31/ip-address-calculations-with-c-subnetmasks-networks.aspx - - - - - - Gets the ipv4 addresses from all Network Interfaces that have Subnet masks. - - - - - - Gets the ipv6 addresses from all Network Interfaces. - - - - - - These extensions have a potential to conflict with the LINQ extensions methods so - leaving the implmentation in the 'Extensions' sub-namespace to force explicit opt-in - - - - - - Invokes the action provided and returns true if no excpetion was thrown. - Otherwise logs the exception and returns false if an exception was thrown. - - The action. - - - - - Contains methods required for encoding and decoding rcon packets. - - - - - Decodes a packet. - - The packet. - A packet object. - - - - Decodes the packet header. - - - - - - - Decodes words in a packet. - - - - - - - Encodes a packet for transmission to the server. - - - - - - - - - - Encodes a packet header. - - - - - - - - - Encodes words. - - - - - - - Maps the path of a file in the context of a VS project - - the relative path - the absolute path - Assumes static content is two directories above the /bin/ directory, - eg. in a unit test scenario the assembly would be in /bin/Debug/. - - - - Maps the path of a file in a self-hosted scenario - - the relative path - the absolute path - Assumes static content is copied to /bin/ folder with the assemblies - - - - Maps the path of a file in an Asp.Net hosted scenario - - the relative path - the absolute path - Assumes static content is in the parent folder of the /bin/ directory - - - - Encapsulates a validation result. - - - - - Constructs a new ValidationResult - - - - - Constructs a new ValidationResult - - A list of validation results - - - - Initializes a new instance of the class. - - The errors. - The success code. - The error code. - - - - Gets or sets the success code. - - The success code. - - - - Gets or sets the error code. - - The error code. - - - - Gets or sets the success message. - - The success message. - - - - Gets or sets the error message. - - The error message. - - - - The errors generated by the validation. - - - - - Returns True if the validation was successful (errors list is empty). - - - - - Populate an object with Example data. - - - - - - - Populates the object with example data. - - - Tracks how deeply nested we are - - - - - Processes all messages in a Normal and Priority Queue. - Expects to be called in 1 thread. i.e. Non Thread-Safe. - - - - - - Single threaded message handler that can process all messages - of a particular message type. - - - - - Process all messages pending - - - - - - Get Current Stats for this Message Handler - - - - - - The type of the message this handler processes - - - - - Gets the textual description of the enum if it has one. e.g. - - - enum UserColors - { - [Description("Bright Red")] - BrightRed - } - UserColors.BrightRed.ToDescription(); - - - - - - - - True if the packet originated on the server. - - - - - True if the packet is a response from a sent packet. - - - - - Sequence identifier. Unique to the connection. - - - - - Words. - - - - - Creates a Unified Resource Name (URN) with the following formats: - - - urn:{TypeName}:{IdFieldValue} e.g. urn:UserSession:1 - - urn:{TypeName}:{IdFieldName}:{IdFieldValue} e.g. urn:UserSession:UserId:1 - - - - - - Common functionality when creating adapters - - - - - Executes the specified expression. - - - The action. - - - - - Executes the specified action (for void methods). - - The action. - - - Need to provide async request options - http://msdn.microsoft.com/en-us/library/86wf6409(VS.71).aspx - - - - Default MaxStringContentLength is 8k, and throws an exception when reached - - - - - Func to get the Strongly-typed field - - - - - Required to cast the return ValueType to an object for caching - - - - - Func to set the Strongly-typed field - - - - - Required to cast the ValueType to an object for caching - - - - - Required to cast the ValueType to an object for caching - - - - - Executes the specified action. - - - The action. - - - - - Gets the current context (or null if none). - - - - - Checks if the current context is set to "initialize only". - - - - - Determines whether this context is initialise only or not - - - - - Constructs a new InitialiseOnlyContext - - - - - Call to remove this current context and reveal the previous context (if any). - - - - - Gets or sets the object that has been initialized only. - - - - - Serializer cache of delegates required to create a type from a string map (e.g. for REST urls) - - - - - Provide the an option for the callee to block until all commands are executed - - - - - - - Note: InMemoryLog keeps all logs in memory, so don't use it long running exceptions - - Returns a thread-safe InMemoryLog which you can use while *TESTING* - to provide a detailed analysis of your logs. - - - - - Func to get the Strongly-typed field - - - - - Required to cast the return ValueType to an object for caching - - - - - Func to set the Strongly-typed field - - - - - Required to cast the ValueType to an object for caching - - - - - Required to cast the ValueType to an object for caching - - - - diff --git a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Interfaces.dll b/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Interfaces.dll deleted file mode 100644 index d0027388cf5..00000000000 Binary files a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Interfaces.dll and /dev/null differ diff --git a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Interfaces.xml b/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Interfaces.xml deleted file mode 100644 index 47c34dfd40b..00000000000 --- a/NuGet/ServiceStack.Common/lib/sl5/ServiceStack.Interfaces.xml +++ /dev/null @@ -1,1343 +0,0 @@ - - - - ServiceStack.Interfaces - - - - - This instructs the generator tool to generate translator methods for the types supplied. - A {TypeName}.generated.cs partial class will be generated that contains the methods required - to generate to and from that type. - - - - - Error information pertaining to a particular named field. - Used for returning multiple field validation errors.s - - - - - If the Service also implements this interface, - IRestPutService.Put() will be used instead of IService.Execute() for - EndpointAttributes.HttpPut requests - - - - - - A thin wrapper around ASP.NET or HttpListener's HttpResponse - - - - - Signal that this response has been handled and no more processing should be done. - When used in a request or response filter, no more filters or processing is done on this request. - - - - - Calls Response.End() on ASP.NET HttpResponse otherwise is an alias for Close(). - Useful when you want to prevent ASP.NET to provide it's own custom error page. - - - - - Response.Flush() and OutputStream.Flush() seem to have different behaviour in ASP.NET - - - - - The underlying ASP.NET or HttpListener HttpResponse - - - - - Gets a value indicating whether this instance is closed. - - - - - Subscribe to channels by name - - - - - - Subscribe to channels matching the supplied patterns - - - - - - The number of active subscriptions this client has - - - - - Registered handler called after client *Subscribes* to each new channel - - - - - Registered handler called when each message is received - - - - - Registered handler called when each channel is unsubscribed - - - - - Wrap the common redis list operations under a IList[string] interface. - - - - - Creates a Debug Logger, that logs all messages to: System.Diagnostics.Debug - - Made public so its testable - - - - - Factory to create ILog instances - - - - - Gets the logger. - - The type. - - - - - Gets the logger. - - Name of the type. - - - - - Contract indication that the Response DTO has a ResponseStatus - - - - - interface to operation that can queue commands - - - - - For messaging exceptions that should by-pass the messaging service's configured - retry attempts and store the message straight into the DLQ - - - - - Base Exception for all ServiceStack.Messaging exceptions - - - - - Default logger is to Console.WriteLine - - Made public so its testable - - - - - Logs a message in a running application - - - - - Logs a Debug message. - - The message. - - - - Logs a Debug message and exception. - - The message. - The exception. - - - - Logs a Debug format message. - - The format. - The args. - - - - Logs a Error message. - - The message. - - - - Logs a Error message and exception. - - The message. - The exception. - - - - Logs a Error format message. - - The format. - The args. - - - - Logs a Fatal message. - - The message. - - - - Logs a Fatal message and exception. - - The message. - The exception. - - - - Logs a Error format message. - - The format. - The args. - - - - Logs an Info message and exception. - - The message. - - - - Logs an Info message and exception. - - The message. - The exception. - - - - Logs an Info format message. - - The format. - The args. - - - - Logs a Warning message. - - The message. - - - - Logs a Warning message and exception. - - The message. - The exception. - - - - Logs a Warning format message. - - The format. - The args. - - - - Gets or sets a value indicating whether this instance is debug enabled. - - - true if this instance is debug enabled; otherwise, false. - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - Base interface all webservices need to implement. - For simplicity this is the only interface you need to implement - - - - - - The HTTP Response Status Code - - - - - The HTTP Status Description - - - - - The HTTP Response ContentType - - - - - Additional HTTP Headers - - - - - Response DTO - - - - - A specific template, if not the default (for HTML, Markdown, etc. ContentTypes) - - - - - if not provided, get's injected by ServiceStack - - - - - Holds the request call context - - - - - Resolve a dependency from the AppHost's IOC - - - - - - - Pipeline interface shared by typed and non-typed pipelines - - - - - Interface to operations that allow queued commands to be completed - - - - - The same functionality is on IServiceResolver - - - - - Creates a Debug Logger, that logs all messages to: System.Diagnostics.Debug - - Made public so its testable - - - - - This instructs the generator tool to generate translator extension methods for the types supplied. - A {TypeName}.generated.cs static class will be generated that contains the extension methods required - to generate to and from that type. - - The source type is what the type the attribute is decorated on which can only be resolved at runtime. - - - - - Utility interface that implements all Rest operations - - - - - - If the Service also implements this interface, - IRestGetService.Get() will be used instead of IService.Execute() for - EndpointAttributes.HttpGet requests - - - - - - If the Service also implements this interface, - IRestPostService.Post() will be used instead of IService.Execute() for - EndpointAttributes.HttpPost requests - - - - - - If the Service also implements this interface, - IRestDeleteService.Delete() will be used instead of IService.Execute() for - EndpointAttributes.HttpDelete requests - - - - - - If the Service also implements this interface, - IRestPutService.Patch() will be used instead of IService.Execute() for - EndpointAttributes.HttpPatch requests - - - - - - Interface to redis typed pipeline - - - - - interface to queueable operation using typed redis client - - - - - - Publish the specified message into the durable queue @queueName - - - - - - - Publish the specified message into the transient queue @queueName - - - - - - - Synchronous blocking get. - - - - - - - - Non blocking get message - - - - - - - Blocking wait for notifications on any of the supplied channels - - - - - - - Logging API for this library. You can inject your own implementation otherwise - will use the DebugLogFactory to write to System.Diagnostics.Debug - - - - - Gets the logger. - - The type. - - - - - Gets the logger. - - Name of the type. - - - - - Gets or sets the log factory. - Use this to override the factory that is used to create loggers - - The log factory. - - - - Sends the specified request. - - The request. - - - - - Common ResponseStatus class that should be present on all response DTO's - - - - - Initializes a new instance of the class. - - A response status without an errorcode == success - - - - - Initializes a new instance of the class. - - A response status with an errorcode == failure - - - - - Initializes a new instance of the class. - - A response status with an errorcode == failure - - - - - Holds the custom ErrorCode enum if provided in ValidationException - otherwise will hold the name of the Exception type, e.g. typeof(Exception).Name - - A value of non-null means the service encountered an error while processing the request. - - - - - A human friendly error message - - - - - - - - - - For multiple detailed validation errors. - Can hold a specific error message for each named field. - - - - - Log every service request - - - - - Log a request - - - - - - - Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. - - - - - - Returns a Read/Write ICacheClient (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly ICacheClient using the hosts defined in ReadOnlyHosts. - - - - - - Basic implementation of IMessage[T] - - - - - - Tests logger which stores all log messages in a member list which can be examined later - - Made public so its testable - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - Allow the registration of user-defined routes for services - - - - - Maps the specified REST path to the specified request DTO. - - The type of request DTO to map - the path to. - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - The same instance; - never . - - - - Maps the specified REST path to the specified request DTO, and - specifies the HTTP verbs supported by the path. - - The type of request DTO to map - the path to. - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - - The comma-delimited list of HTTP verbs supported by the path, - such as "GET,PUT,DELETE". Specify empty or - to indicate that all verbs are supported. - - The same instance; - never . - - - - Maps the specified REST path to the specified request DTO, - specifies the HTTP verbs supported by the path, and indicates - the default MIME type of the returned response. - - The type of request DTO to map - the path to. - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - - The comma-delimited list of HTTP verbs supported by the path, - such as "GET,PUT,DELETE". - - - The default MIME type in which the response object returned to the client - is formatted, if formatting hints are not provided by the client. - Specify or empty to require formatting hints from - the client. - - The same instance; - never . - - - - Maps the specified REST path to the specified request DTO, - specifies the HTTP verbs supported by the path, and indicates - the default MIME type of the returned response. - - - The type of request DTO to map the path to. - - The path to map the request DTO to. - See RestServiceAttribute.Path - for details on the correct format. - - The comma-delimited list of HTTP verbs supported by the path, - such as "GET,PUT,DELETE". - - - The default MIME type in which the response object returned to the client - is formatted, if formatting hints are not provided by the client. - Specify or empty to require formatting hints from - the client. - - The same instance; - never . - - - - A light interface over a cache client. - This interface was inspired by Enyim.Caching.MemcachedClient - - Only the methods that are intended to be used are required, if you require - extra functionality you can uncomment the unused methods below as they have been - implemented in DdnMemcachedClient - - - - - Removes the specified item from the cache. - - The identifier for the item to delete. - - true if the item was successfully removed from the cache; false otherwise. - - - - - Removes the cache for all the keys provided. - - The keys. - - - - Retrieves the specified item from the cache. - - The identifier for the item to retrieve. - - The retrieved item, or null if the key was not found. - - - - - Increments the value of the specified key by the given amount. The operation is atomic and happens on the server. - - The identifier for the item to increment. - The amount by which the client wants to increase the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Increments the value of the specified key by the given amount. The operation is atomic and happens on the server. - - The identifier for the item to increment. - The amount by which the client wants to decrease the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Inserts an item into the cache with a cache key to reference its location. - - The key used to reference the item. - The object to be inserted into the cache. - - true if the item was successfully stored in the cache; false otherwise. - - The item does not expire unless it is removed due memory pressure. - - - - Inserts an item into the cache with a cache key to reference its location. - - The key used to reference the item. - The object to be inserted into the cache. - The time when the item is invalidated in the cache. - true if the item was successfully stored in the cache; false otherwise. - - - - Removes all data from the cache. - - - - - Retrieves multiple items from the cache. - - The list of identifiers for the items to retrieve. - - a Dictionary holding all items indexed by their key. - - - - - Base transaction interface, shared by typed and non-typed transactions - - - - - Redis transaction for typed client - - - - - - Default logger is to System.Diagnostics.Debug.WriteLine - - Made public so its testable - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - For providers that want a cleaner API with a little more perf - - - - - - Allow delegation of dependencies to other IOC's - - - - - Resolve Property Dependency - - - - - - - Resolve Constructor Dependency - - - - - - - An Error Message Type that can be easily serialized - - - - - Simple definition of an MQ Host - - - - - Register DTOs and hanlders the MQ Host will process - - - - - - - Register DTOs and hanlders the MQ Host will process - - - - - - - - Get Total Current Stats for all Message Handlers - - - - - - Get a Stats dump - - - - - - Start the MQ Host if not already started. - - - - - Stop the MQ Host if not already stopped. - - - - - Factory to create consumers and producers that work with this service - - - - - Default logger is to System.Diagnostics.Debug.Print - - Made public so its testable - - - - - Initializes a new instance of the class. - - The type. - - - - Initializes a new instance of the class. - - The type. - - - - Logs the specified message. - - The message. - The exception. - - - - Logs the format. - - The message. - The args. - - - - Logs the specified message. - - The message. - - - - Manages a connection to a persistance provider - - - - - This changes the default behaviour for the - - - - - Used to decorate Request DTO's to associate a RESTful request - path mapping with a service. Multiple attributes can be applied to - each request DTO, to map multiple paths to the service. - - - - - Initializes an instance of the class. - - - The path template to map to the request. See - RestServiceAttribute.Path - for details on the correct format. - - - - - Initializes an instance of the class. - - - The path template to map to the request. See - RestServiceAttribute.Path - for details on the correct format. - - A comma-delimited list of HTTP verbs supported by the - service. If unspecified, all verbs are assumed to be supported. - - - - Initializes an instance of the class. - - - The path template to map to the request. See - RestServiceAttribute.Path - for details on the correct format. - - A comma-delimited list of HTTP verbs supported by the - service. If unspecified, all verbs are assumed to be supported. - The default MIME type in which the response - object returned to the client is formatted, if formatting hints are unspecified - in the URL. Specify or empty to require formatting - hints from the client. - - - - Gets or sets the path template to be mapped to the request. - - - A value providing the path mapped to - the request. Never . - - - Some examples of valid paths are: - - - "/Inventory" - "/Inventory/{Category}/{ItemId}" - "/Inventory/{ItemPath*}" - - - Variables are specified within "{}" - brackets. Each variable in the path is mapped to the same-named property - on the request DTO. At runtime, ServiceStack will parse the - request URL, extract the variable values, instantiate the request DTO, - and assign the variable values into the corresponding request properties, - prior to passing the request DTO to the service object for processing. - - It is not necessary to specify all request properties as - variables in the path. For unspecified properties, callers may provide - values in the query string. For example: the URL - "http://services/Inventory?Category=Books&ItemId=12345" causes the same - request DTO to be processed as "http://services/Inventory/Books/12345", - provided that the paths "/Inventory" (which supports the first URL) and - "/Inventory/{Category}/{ItemId}" (which supports the second URL) - are both mapped to the request DTO. - - Please note that while it is possible to specify property values - in the query string, it is generally considered to be less RESTful and - less desirable than to specify them as variables in the path. Using the - query string to specify property values may also interfere with HTTP - caching. - - The final variable in the path may contain a "*" suffix - to grab all remaining segments in the path portion of the request URL and assign - them to a single property on the request DTO. - For example, if the path "/Inventory/{ItemPath*}" is mapped to the request DTO, - then the request URL "http://services/Inventory/Books/12345" will result - in a request DTO whose ItemPath property contains "Books/12345". - You may only specify one such variable in the path, and it must be positioned at - the end of the path. - - - - - Gets or sets a comma-delimited list of HTTP verbs supported by the service, such as - "GET,PUT,POST,DELETE". - - - A providing a comma-delimited list of HTTP verbs supported - by the service, or empty if all verbs are supported. - - - - - Gets or sets the default MIME type in which the response - object returned to the client is formatted, when format hints - are not provided in the URI. Some valid examples are such as - "application/json", or "application/xml". - - - A providing the default MIME type of the response; - or empty if formatting hints are required - from the client. - - - - - Interface to redis transaction - - - - - A common interface implementation that is implemeneted by most cache providers - - - - - Removes the specified item from the cache. - - The identifier for the item to delete. - - true if the item was successfully removed from the cache; false otherwise. - - - - - Removes the cache for all the keys provided. - - The keys. - - - - Retrieves the specified item from the cache. - - - The identifier for the item to retrieve. - - The retrieved item, or null if the key was not found. - - - - - Increments the value of the specified key by the given amount. - The operation is atomic and happens on the server. - A non existent value at key starts at 0 - - The identifier for the item to increment. - The amount by which the client wants to increase the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Increments the value of the specified key by the given amount. - The operation is atomic and happens on the server. - A non existent value at key starts at 0 - - The identifier for the item to increment. - The amount by which the client wants to decrease the item. - - The new value of the item or -1 if not found. - - The item must be inserted into the cache before it can be changed. The item must be inserted as a . The operation only works with values, so -1 always indicates that the item was not found. - - - - Adds a new item into the cache at the specified cache key only if the cache is empty. - - The key used to reference the item. - The object to be inserted into the cache. - - true if the item was successfully stored in the cache; false otherwise. - - The item does not expire unless it is removed due memory pressure. - - - - Sets an item into the cache at the cache key specified regardless if it already exists or not. - - - - - Replaces the item at the cachekey specified only if an items exists at the location already. - - - - - Invalidates all data on the cache. - - - - - - Sets multiple items to the cache. - - - The values. - - - - Used to decorate Request DTO's to alter the behaviour of a service. - - - - - Sets a single access restriction - - The restrict access to. - - - - Set multiple access scenarios - - The restrict access to scenarios. - - - - If the Service also implements this interface, - IAsyncService.ExecuteAsync() will be used instead of IService.Execute() for - EndpointAttributes.AsyncOneWay requests - - - - - - Interface to redis pipeline - - - - - Creates a Debug Logger, that logs all messages to: System.Diagnostics.Debug - - Made public so its testable - - - - - Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. - - - - - - Returns a Read/Write ICacheClient (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly ICacheClient using the hosts defined in ReadOnlyHosts. - - - - - - Util static generic class to create unique queue names for types - - - - - - Util class to create unique queue names for runtime types - - - - - Responsible for executing the operation within the specified context. - - The operation types. - - - - Returns the first matching RestPath - - - - - - - - Executes the DTO request under the supplied requestContext. - - - - - - - - Returns a list of operation types available in this service - - The operation types. - - - - Returns a list of ALL operation types available in this service - - The operation types. - - - - Allow the registration of custom routes - - - - - Implement on services that need access to the RequestContext - - - - - Creates a test Logger, that stores all log messages in a member list - - - - - A Users Session - - - - - Set a typed value at key - - - - - - - - Get a typed value at key - - - - - - - - Store any object at key - - - - - - diff --git a/NuGet/ServiceStack.Common/servicestack.common.nuspec b/NuGet/ServiceStack.Common/servicestack.common.nuspec deleted file mode 100644 index 36b8878fb90..00000000000 --- a/NuGet/ServiceStack.Common/servicestack.common.nuspec +++ /dev/null @@ -1,29 +0,0 @@ - - - - ServiceStack.Common - Service Clients and Common libs for ServiceStack projects - 3.9.7 - Demis Bellot - Demis Bellot - Opensource .NET and Mono REST Web Services framework - - Common library dependency for other ServiceStack projects. - Includes JSON, XML, JSV and SOAP Generic Service Clients. - Contains: - - ServiceStack.Interfaces - - ServiceStack.Common - Dependenies: - - ServiceStack.Text - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - ServiceStack Common Framework - en-US - servicestack.net 2012 and contributors - - - - - \ No newline at end of file diff --git a/NuGet/ServiceStack.Host.AspNet/content/App_Start/AppHost.cs.pp b/NuGet/ServiceStack.Host.AspNet/content/App_Start/AppHost.cs.pp deleted file mode 100644 index edbf3489e3b..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/App_Start/AppHost.cs.pp +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Linq; -using System.Configuration; -using System.Collections.Generic; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints; - -[assembly: WebActivator.PreApplicationStartMethod(typeof($rootnamespace$.App_Start.AppHost), "Start")] - - -/** - * Entire ServiceStack Starter Template configured with a 'Hello' Web Service and a 'Todo' Rest Service. - * - * Auto-Generated Metadata API page at: /metadata - * See other complete web service examples at: https://github.com/ServiceStack/ServiceStack.Examples - */ - -namespace $rootnamespace$.App_Start -{ - public class AppHost - : AppHostBase - { - public AppHost() //Tell ServiceStack the name and where to find your web services - : base("StarterTemplate ASP.NET Host", typeof(HelloService).Assembly) { } - - public override void Configure(Funq.Container container) - { - //Set JSON web services to return idiomatic JSON camelCase properties - ServiceStack.Text.JsConfig.EmitCamelCaseNames = true; - - //Configure User Defined REST Paths - Routes - .Add("/hello") - .Add("/hello/{Name*}") - .Add("/todos") - .Add("/todos/{Id}"); - - //Uncomment to change the default ServiceStack configuration - //SetConfig(new EndpointHostConfig { - // DebugMode = true, //Show StackTraces when developing - //}); - - //Enable Authentication - //ConfigureAuth(container); - - //Register all your dependencies - container.Register(new TodoRepository()); - } - - /* Uncomment to enable ServiceStack Authentication and CustomUserSession - private void ConfigureAuth(Funq.Container container) - { - var appSettings = new AppSettings(); - - //Default route: /auth/{provider} - Plugins.Add(new AuthFeature(this, () => new CustomUserSession(), - new IAuthProvider[] { - new CredentialsAuthProvider(appSettings), - new FacebookAuthProvider(appSettings), - new TwitterAuthProvider(appSettings), - new BasicAuthProvider(appSettings), - })); - - //Default route: /register - Plugins.Add(new RegistrationFeature()); - - //Requires ConnectionString configured in Web.Config - var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString; - container.Register(c => - new OrmLiteConnectionFactory(connectionString, SqlServerOrmLiteDialectProvider.Instance)); - - container.Register(c => - new OrmLiteAuthRepository(c.Resolve())); - - var authRepo = (OrmLiteAuthRepository)container.Resolve(); - authRepo.CreateMissingTables(); - } - */ - - public static void Start() - { - new AppHost().Init(); - } - } -} diff --git a/NuGet/ServiceStack.Host.AspNet/content/App_Start/PageBase.cs.pp b/NuGet/ServiceStack.Host.AspNet/content/App_Start/PageBase.cs.pp deleted file mode 100644 index 1d25db52d84..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/App_Start/PageBase.cs.pp +++ /dev/null @@ -1,79 +0,0 @@ -using System.Web.UI; -using Funq; -using ServiceStack.CacheAccess; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.WebHost.Endpoints; - - -/** - * Base ASP.NET WebForms page using ServiceStack's Compontents, see: http://www.servicestack.net/mvc-powerpack/ - */ - -namespace $rootnamespace$.App_Start -{ - //A customizeable typed UserSession that can be extended with your own properties - public class CustomUserSession : AuthUserSession - { - public string CustomProperty { get; set; } - } - - public class PageBase : Page - { - private Container container; - public Container Container - { - get { return container ?? (container = AppHostBase.Instance.Container); } - } - - protected string SessionKey - { - get - { - var sessionId = SessionFeature.GetSessionId(); - return sessionId == null ? null : SessionFeature.GetSessionKey(sessionId); - } - } - - private CustomUserSession userSession; - protected CustomUserSession UserSession - { - get - { - if (userSession != null) return userSession; - if (SessionKey != null) - userSession = this.Cache.Get(SessionKey); - else - SessionFeature.CreateSessionIds(); - - var unAuthorizedSession = new CustomUserSession(); - return userSession ?? (userSession = unAuthorizedSession); - } - } - - public void ClearSession() - { - userSession = null; - this.Cache.Remove(SessionKey); - } - - public new ICacheClient Cache - { - get { return Container.Resolve(); } - } - - public ISessionFactory SessionFactory - { - get { return Container.Resolve(); } - } - - private ISession session; - public new ISession Session - { - get - { - return session ?? (session = SessionFactory.GetOrCreateSession()); - } - } - } -} \ No newline at end of file diff --git a/NuGet/ServiceStack.Host.AspNet/content/App_Start/WebServiceExamples.cs.pp b/NuGet/ServiceStack.Host.AspNet/content/App_Start/WebServiceExamples.cs.pp deleted file mode 100644 index 037b053fee9..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/App_Start/WebServiceExamples.cs.pp +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Linq; -using System.Configuration; -using System.Collections.Generic; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints; - -namespace $rootnamespace$ -{ - //Request DTO - public class Hello - { - public string Name { get; set; } - } - - //Response DTO - public class HelloResponse : IHasResponseStatus - { - public string Result { get; set; } - public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized - } - - //Can be called via any endpoint or format, see: http://servicestack.net/ServiceStack.Hello/ - public class HelloService : ServiceBase - { - protected override object Run(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } - } - - - //REST DTO - public class Todo - { - public long Id { get; set; } - public string Content { get; set; } - public int Order { get; set; } - public bool Done { get; set; } - } - - //Todo REST Service implementation - public class TodoService : RestServiceBase - { - public TodoRepository Repository { get; set; } //Injected by IOC - - public override object OnGet(Todo request) - { - if (request.Id == default(long)) - return Repository.GetAll(); - - return Repository.GetById(request.Id); - } - - public override object OnPost(Todo todo) - { - return Repository.Store(todo); - } - - public override object OnPut(Todo todo) - { - return Repository.Store(todo); - } - - public override object OnDelete(Todo request) - { - Repository.DeleteById(request.Id); - return null; - } - } - - - /// - /// In-memory repository, so we can run the TODO app without any external dependencies - /// Registered in Funq as a singleton, auto injected on every request - /// - public class TodoRepository - { - private readonly List todos = new List(); - - public List GetAll() - { - return todos; - } - - public Todo GetById(long id) - { - return todos.FirstOrDefault(x => x.Id == id); - } - - public Todo Store(Todo todo) - { - if (todo.Id == default(long)) - { - todo.Id = todos.Count == 0 ? 1 : todos.Max(x => x.Id) + 1; - } - else - { - for (var i = 0; i < todos.Count; i++) - { - if (todos[i].Id != todo.Id) continue; - - todos[i] = todo; - return todo; - } - } - - todos.Add(todo); - return todo; - } - - public void DeleteById(long id) - { - todos.RemoveAll(x => x.Id == id); - } - } -} diff --git a/NuGet/ServiceStack.Host.AspNet/content/Content/js/ss-validation.js b/NuGet/ServiceStack.Host.AspNet/content/Content/js/ss-validation.js deleted file mode 100644 index 4ecf52fe092..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/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") - ); - } - 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/NuGet/ServiceStack.Host.AspNet/content/README.txt b/NuGet/ServiceStack.Host.AspNet/content/README.txt deleted file mode 100644 index a75aa9feab6..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/README.txt +++ /dev/null @@ -1,36 +0,0 @@ -To enable the Mini Profiler add the following lines in to Global class in Global.asax.cs: - - - protected void Application_BeginRequest(object src, EventArgs e) - { - if (Request.IsLocal) - ServiceStack.MiniProfiler.Profiler.Start(); - } - - protected void Application_EndRequest(object src, EventArgs e) - { - ServiceStack.MiniProfiler.Profiler.Stop(); - } - - -For more info on the MiniProfiler see v3.09 of the https://github.com/ServiceStack/ServiceStack/wiki/Release-Notes - - -The Urls for metadata page and included Services: - - * /metadata - Auto generated metadata pages - * /hello - Simple Hello World Service. see: http://www.servicestack.net/ServiceStack.Hello/ - * /todos - Simple REST Service. see: http://www.servicestack.net/Backbone.Todos/ - - * /default.htm - Backbone.js TODO application talking to the TODO REST service at /todos - - -For more info about ServiceStack please visit: http://www.servicestack.net - -Feel free to ask questions about ServiceStack on: -http://stackoverflow.com/ - -or on the mailing Group at: -http://groups.google.com/group/servicestack - -Enjoy! \ No newline at end of file diff --git a/NuGet/ServiceStack.Host.AspNet/content/default.htm b/NuGet/ServiceStack.Host.AspNet/content/default.htm deleted file mode 100644 index 78c2a89314c..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/default.htm +++ /dev/null @@ -1,685 +0,0 @@ - - - - - Backbone Demo: Todos - - - - - - - - - - - - -
- -
-

Todos

-
- -
- -
- - -
- -
-
    -
    - -
    - -
    - -
    - - - -
    - Created by -
    - Jérôme Gravel-Niquet -
    -
    - Powered By Open Source -
    - servicestack.net - | redis - | mono -
    - - - - - - - - - - - - - - diff --git a/NuGet/ServiceStack.Host.AspNet/content/jqunback-1.51.min.js b/NuGet/ServiceStack.Host.AspNet/content/jqunback-1.51.min.js deleted file mode 100644 index 97da2a076f8..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/jqunback-1.51.min.js +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * jQuery JavaScript Library v1.5.1 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Wed Feb 23 13:55:29 2011 -0500 - */ -(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,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=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.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 e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(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(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,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"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="
    a";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.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?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){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,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.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(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.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]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),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]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.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!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},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=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([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.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":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=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=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(q){p=function(a,b){var c=0,d=b||[];if(f.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)&&(l.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:[]}},l.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&&(l.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")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(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;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},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 P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div
    ","
    "]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(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 d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(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(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(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=d(arguments[0]);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,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.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 d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.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?d("
    ").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[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","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.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(!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 bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
    ";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.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):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window);// Underscore.js 1.1.5 -// (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 q=this,D=q._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,E=k.unshift,F=o.toString,m=o.hasOwnProperty,s=k.forEach,t=k.map,u=k.reduce,v=k.reduceRight,w=k.filter,x=k.every,y=k.some,p=k.indexOf,z=k.lastIndexOf;o=Array.isArray;var G=Object.keys,A=Function.prototype.bind,c=function(a){return new l(a)};if(typeof module!=="undefined"&&module.exports){module.exports=c;c._=c}else q._=c;c.VERSION="1.1.5";var j=c.each=c.forEach=function(a,b,d){if(a!=null)if(s&&a.forEach===s)a.forEach(b, -d);else if(c.isNumber(a.length))for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};j(a,function(f,g,h){g=b?b.call(d,f,g,h):f;gh?1:0}),"value")};c.sortedIndex= -function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=G||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)if(m.call(a, -d))b[b.length]=d;return b};c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};c.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)if(a[d]==null)a[d]=b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a, -b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a._chain)a=a._wrapped;if(b._chain)b=b._wrapped;if(a.isEqual)return a.isEqual(b);if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false; -d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===0;for(var b in a)if(m.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=o||function(a){return F.call(a)==="[object Array]"};c.isArguments=function(a){return!!(a&&m.call(a,"callee"))};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&& -a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return a!==a};c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){q._= -D;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate, -function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.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 b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},I=function(a,b){l.prototype[a]=function(){var d=i.call(arguments);E.call(d,this._wrapped);return r(b.apply(c, -d),this._chain)}};c.mixin(c);j(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=k[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})(); -// Backbone.js 0.3.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 e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.3";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery||this.Zepto;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);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,g=c.length;d/g,">").replace(/"/g, -""")},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 false;if("id"in a)this.id=a.id;for(var g in a){var i=a[g];if(!f.isEqual(c[g],i)){c[g]=i;delete d[g];if(!b.silent){this._changed=true;this.trigger("change:"+g,this,i,b)}}}!b.silent&&this._changed&&this.change(b);return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&& -!this._performValidation(c,b))return false;delete this.attributes[a];delete this._escapedAttributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this,void 0,b);this.change(b)}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};this._escapedAttributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this,void 0,a);this.change(a)}return this}, -fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=j(b.error,c,b),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("delete", -this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=k(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=false},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=false,d;for(d in a)if(!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){b.error?b.error(this,c):this.trigger("error",this,c,b);return false}return true}}); -e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};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; -"onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment= -this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(l,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize(a)};var q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events, -{tagName:"div",$:function(a){return h(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({}, -this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend= -m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:k(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override", -g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url},j=function(a,b,c){return function(d){a?a(b,d):b.trigger("error",b,d,c)}}})(); diff --git a/NuGet/ServiceStack.Host.AspNet/content/web.config.transform b/NuGet/ServiceStack.Host.AspNet/content/web.config.transform deleted file mode 100644 index d52f5e0a9e8..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/content/web.config.transform +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/NuGet/ServiceStack.Host.AspNet/servicestack.host.aspnet.nuspec b/NuGet/ServiceStack.Host.AspNet/servicestack.host.aspnet.nuspec deleted file mode 100644 index 90d1a313389..00000000000 --- a/NuGet/ServiceStack.Host.AspNet/servicestack.host.aspnet.nuspec +++ /dev/null @@ -1,25 +0,0 @@ - - - - ServiceStack.Host.AspNet - Starter ASP.NET Website Template - ServiceStack at / - 3.9.0 - Demis Bellot - Demis Bellot - Opensource .NET and Mono REST Web Services framework - -Host ServiceStack in an existing ASP.NET web application at the root path '/'. -ServiceStack is a modern, high-performance, code-first web service framework promoting code and web services best practices. Simple, Fast, Elegant. Website: http://www.servicestack.net - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - Fast JSON XML CSV HTML SOAP JSV REST Web Service Framework MONO - en-US - servicestack.net 2012 and contributors - - - - - - \ No newline at end of file diff --git a/NuGet/ServiceStack.Host.Mvc/content/App_Start/AppHost.cs.pp b/NuGet/ServiceStack.Host.Mvc/content/App_Start/AppHost.cs.pp deleted file mode 100644 index 55de1a82492..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/App_Start/AppHost.cs.pp +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Linq; -using System.Configuration; -using System.Collections.Generic; -using System.Web.Mvc; -using ServiceStack.Configuration; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.Mvc; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints; - -[assembly: WebActivator.PreApplicationStartMethod(typeof($rootnamespace$.App_Start.AppHost), "Start")] - -//IMPORTANT: Add the line below to MvcApplication.RegisterRoutes(RouteCollection) in the Global.asax: -//routes.IgnoreRoute("api/{*pathInfo}"); - -/** - * Entire ServiceStack Starter Template configured with a 'Hello' Web Service and a 'Todo' Rest Service. - * - * Auto-Generated Metadata API page at: /metadata - * See other complete web service examples at: https://github.com/ServiceStack/ServiceStack.Examples - */ - -namespace $rootnamespace$.App_Start -{ - //A customizeable typed UserSession that can be extended with your own properties - //To access ServiceStack's Session, Cache, etc from MVC Controllers inherit from ControllerBase - public class CustomUserSession : AuthUserSession - { - public string CustomProperty { get; set; } - } - - public class AppHost - : AppHostBase - { - public AppHost() //Tell ServiceStack the name and where to find your web services - : base("StarterTemplate ASP.NET Host", typeof(HelloService).Assembly) { } - - public override void Configure(Funq.Container container) - { - //Set JSON web services to return idiomatic JSON camelCase properties - ServiceStack.Text.JsConfig.EmitCamelCaseNames = true; - - //Configure User Defined REST Paths - Routes - .Add("/hello") - .Add("/hello/{Name*}") - .Add("/todos") - .Add("/todos/{Id}"); - - //Change the default ServiceStack configuration - //SetConfig(new EndpointHostConfig { - // DebugMode = true, //Show StackTraces in responses in development - //}); - - //Enable Authentication - //ConfigureAuth(container); - - //Register all your dependencies - container.Register(new TodoRepository()); - - //Register In-Memory Cache provider. - //For Distributed Cache Providers Use: PooledRedisClientManager, BasicRedisClientManager or see: https://github.com/ServiceStack/ServiceStack/wiki/Caching - container.Register(new MemoryCacheClient()); - container.Register(c => - new SessionFactory(c.Resolve())); - - //Set MVC to use the same Funq IOC as ServiceStack - ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container)); - } - - /* Uncomment to enable ServiceStack Authentication and CustomUserSession - private void ConfigureAuth(Funq.Container container) - { - var appSettings = new AppSettings(); - - //Default route: /auth/{provider} - Plugins.Add(new AuthFeature(this, () => new CustomUserSession(), - new IAuthProvider[] { - new CredentialsAuthProvider(appSettings), - new FacebookAuthProvider(appSettings), - new TwitterAuthProvider(appSettings), - new BasicAuthProvider(appSettings), - })); - - //Default route: /register - Plugins.Add(new RegistrationFeature()); - - //Requires ConnectionString configured in Web.Config - var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString; - container.Register(c => - new OrmLiteConnectionFactory(connectionString, SqlServerOrmLiteDialectProvider.Instance)); - - container.Register(c => - new OrmLiteAuthRepository(c.Resolve())); - - var authRepo = (OrmLiteAuthRepository)container.Resolve(); - authRepo.CreateMissingTables(); - } - */ - - public static void Start() - { - new AppHost().Init(); - } - } -} \ No newline at end of file diff --git a/NuGet/ServiceStack.Host.Mvc/content/App_Start/WebServiceExamples.cs.pp b/NuGet/ServiceStack.Host.Mvc/content/App_Start/WebServiceExamples.cs.pp deleted file mode 100644 index 3ca35e3a131..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/App_Start/WebServiceExamples.cs.pp +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Linq; -using System.Configuration; -using System.Collections.Generic; -using System.Web.Mvc; -using ServiceStack.Configuration; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints; - -namespace $rootnamespace$ -{ - /* - * ServiceStack's Hello World Web Service. - */ - - //Request DTO - public class Hello - { - public string Name { get; set; } - } - - //Response DTO - public class HelloResponse : IHasResponseStatus - { - public string Result { get; set; } - public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized - } - - //Implementation. Can be called via any endpoint or format, see: http://servicestack.net/ServiceStack.Hello/ - public class HelloService : ServiceBase - { - protected override object Run(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } - } - - /* - * A Simple REST Web Service example - */ - - //REST DTO - public class Todo - { - public long Id { get; set; } - public string Content { get; set; } - public int Order { get; set; } - public bool Done { get; set; } - } - - //Todo REST Service implementation - public class TodoService : RestServiceBase - { - public TodoRepository Repository { get; set; } //Injected by IOC - - public override object OnGet(Todo request) - { - if (request.Id == default(long)) - return Repository.GetAll(); - - return Repository.GetById(request.Id); - } - - public override object OnPost(Todo todo) - { - return Repository.Store(todo); - } - - public override object OnPut(Todo todo) - { - return Repository.Store(todo); - } - - public override object OnDelete(Todo request) - { - Repository.DeleteById(request.Id); - return null; - } - } - - - /// - /// In-memory repository, so we can run the TODO app without any external dependencies - /// Registered in Funq as a singleton, auto injected on every request - /// - public class TodoRepository - { - private readonly List todos = new List(); - - public List GetAll() - { - return todos; - } - - public Todo GetById(long id) - { - return todos.FirstOrDefault(x => x.Id == id); - } - - public Todo Store(Todo todo) - { - if (todo.Id == default(long)) - { - todo.Id = todos.Count == 0 ? 1 : todos.Max(x => x.Id) + 1; - } - else - { - for (var i = 0; i < todos.Count; i++) - { - if (todos[i].Id != todo.Id) continue; - - todos[i] = todo; - return todo; - } - } - - todos.Add(todo); - return todo; - } - - public void DeleteById(long id) - { - todos.RemoveAll(x => x.Id == id); - } - } -} diff --git a/NuGet/ServiceStack.Host.Mvc/content/Content/js/ss-validation.js b/NuGet/ServiceStack.Host.Mvc/content/Content/js/ss-validation.js deleted file mode 100644 index 4ecf52fe092..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/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") - ); - } - 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/NuGet/ServiceStack.Host.Mvc/content/README.txt b/NuGet/ServiceStack.Host.Mvc/content/README.txt deleted file mode 100644 index 922460f217f..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/README.txt +++ /dev/null @@ -1,43 +0,0 @@ -You *MUST* register ServiceStacks '/api' path by adding the line below to MvcApplication.RegisterRoutes(RouteCollection) in the Global.asax: - - routes.IgnoreRoute("api/{*pathInfo}"); - routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" }); //Prevent exceptions for favicon - - -To enable the Mini Profiler add the following lines in to MvcApplication in Global.asax.cs: - - - protected void Application_BeginRequest(object src, EventArgs e) - { - if (Request.IsLocal) - ServiceStack.MiniProfiler.Profiler.Start(); - } - - protected void Application_EndRequest(object src, EventArgs e) - { - ServiceStack.MiniProfiler.Profiler.Stop(); - } - - -For more info on the MiniProfiler see v3.09 of the https://github.com/ServiceStack/ServiceStack/wiki/Release-Notes - - -The Urls for metadata page and included Services: - - * /api/metadata - Auto generated metadata pages - * /api/hello - Simple Hello World Service see: http://www.servicestack.net/ServiceStack.Hello/ - * /api/todos - Simple REST Service see: http://www.servicestack.net/Backbone.Todos/ - - * /default.htm - Backbone.js TODO application talking to the TODO REST service at /api/todos - - - -For more info about ServiceStack please visit: http://www.servicestack.net - -Feel free to ask questions about ServiceStack on: -http://stackoverflow.com/ - -or on the mailing Group at: -http://groups.google.com/group/servicestack - -Enjoy! \ No newline at end of file diff --git a/NuGet/ServiceStack.Host.Mvc/content/default.htm b/NuGet/ServiceStack.Host.Mvc/content/default.htm deleted file mode 100644 index a451c4f026a..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/default.htm +++ /dev/null @@ -1,685 +0,0 @@ - - - - - Backbone Demo: Todos - - - - - - - - - - - - -
    - -
    -

    Todos

    -
    - -
    - -
    - - -
    - -
    -
      -
      - -
      - -
      - -
      - - - -
      - Created by -
      - Jérôme Gravel-Niquet -
      -
      - Powered By Open Source -
      - servicestack.net - | redis - | mono -
      - - - - - - - - - - - - - - diff --git a/NuGet/ServiceStack.Host.Mvc/content/jqunback-1.51.min.js b/NuGet/ServiceStack.Host.Mvc/content/jqunback-1.51.min.js deleted file mode 100644 index 97da2a076f8..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/jqunback-1.51.min.js +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * jQuery JavaScript Library v1.5.1 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Wed Feb 23 13:55:29 2011 -0500 - */ -(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,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=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.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 e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(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(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,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"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="
      a";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
      ",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
      t
      ";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.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?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){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,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.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(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.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]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),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]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.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!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},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=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([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.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":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=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=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(q){p=function(a,b){var c=0,d=b||[];if(f.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)&&(l.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:[]}},l.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&&(l.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")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

      ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(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;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},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 P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/",""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div
      ","
      "]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(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 d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(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(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(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=d(arguments[0]);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,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.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 d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.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?d("
      ").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[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","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.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(!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 bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
      ";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.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):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window);// Underscore.js 1.1.5 -// (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 q=this,D=q._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,E=k.unshift,F=o.toString,m=o.hasOwnProperty,s=k.forEach,t=k.map,u=k.reduce,v=k.reduceRight,w=k.filter,x=k.every,y=k.some,p=k.indexOf,z=k.lastIndexOf;o=Array.isArray;var G=Object.keys,A=Function.prototype.bind,c=function(a){return new l(a)};if(typeof module!=="undefined"&&module.exports){module.exports=c;c._=c}else q._=c;c.VERSION="1.1.5";var j=c.each=c.forEach=function(a,b,d){if(a!=null)if(s&&a.forEach===s)a.forEach(b, -d);else if(c.isNumber(a.length))for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};j(a,function(f,g,h){g=b?b.call(d,f,g,h):f;gh?1:0}),"value")};c.sortedIndex= -function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=G||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)if(m.call(a, -d))b[b.length]=d;return b};c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};c.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)if(a[d]==null)a[d]=b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a, -b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a._chain)a=a._wrapped;if(b._chain)b=b._wrapped;if(a.isEqual)return a.isEqual(b);if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false; -d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===0;for(var b in a)if(m.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=o||function(a){return F.call(a)==="[object Array]"};c.isArguments=function(a){return!!(a&&m.call(a,"callee"))};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&& -a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return a!==a};c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){q._= -D;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate, -function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.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 b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},I=function(a,b){l.prototype[a]=function(){var d=i.call(arguments);E.call(d,this._wrapped);return r(b.apply(c, -d),this._chain)}};c.mixin(c);j(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=k[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})(); -// Backbone.js 0.3.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 e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.3";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery||this.Zepto;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);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,g=c.length;d/g,">").replace(/"/g, -""")},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 false;if("id"in a)this.id=a.id;for(var g in a){var i=a[g];if(!f.isEqual(c[g],i)){c[g]=i;delete d[g];if(!b.silent){this._changed=true;this.trigger("change:"+g,this,i,b)}}}!b.silent&&this._changed&&this.change(b);return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&& -!this._performValidation(c,b))return false;delete this.attributes[a];delete this._escapedAttributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this,void 0,b);this.change(b)}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};this._escapedAttributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this,void 0,a);this.change(a)}return this}, -fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=j(b.error,c,b),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("delete", -this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=k(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=false},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=false,d;for(d in a)if(!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){b.error?b.error(this,c):this.trigger("error",this,c,b);return false}return true}}); -e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};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; -"onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment= -this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(l,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize(a)};var q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events, -{tagName:"div",$:function(a){return h(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({}, -this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend= -m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:k(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override", -g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url},j=function(a,b,c){return function(d){a?a(b,d):b.trigger("error",b,d,c)}}})(); diff --git a/NuGet/ServiceStack.Host.Mvc/content/web.config.transform b/NuGet/ServiceStack.Host.Mvc/content/web.config.transform deleted file mode 100644 index 0afaae8735f..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/content/web.config.transform +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/NuGet/ServiceStack.Host.Mvc/servicestack.host.mvc.nuspec b/NuGet/ServiceStack.Host.Mvc/servicestack.host.mvc.nuspec deleted file mode 100644 index 27cb054b515..00000000000 --- a/NuGet/ServiceStack.Host.Mvc/servicestack.host.mvc.nuspec +++ /dev/null @@ -1,25 +0,0 @@ - - - - ServiceStack.Host.Mvc - Starter ASP.NET MVC Website Template - ServiceStack at /api - 3.9.0 - Demis Bellot - Demis Bellot - Opensource .NET and Mono REST Web Services framework - -Host ServiceStack side-by-side with an existing ASP.NET MVC application at the path '/api'. -ServiceStack is a modern, high-performance, code-first web service framework promoting code and web services best practices. Simple, Fast, Elegant. Website: http://www.servicestack.net - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - Fast JSON XML CSV HTML SOAP JSV REST Web Service Framework MONO - en-US - servicestack.net 2012 and contributors - - - - - - \ No newline at end of file diff --git a/NuGet/ServiceStack.Mvc/servicestack.mvc.nuspec b/NuGet/ServiceStack.Mvc/servicestack.mvc.nuspec deleted file mode 100644 index 228f70f5786..00000000000 --- a/NuGet/ServiceStack.Mvc/servicestack.mvc.nuspec +++ /dev/null @@ -1,26 +0,0 @@ - - - - ServiceStack.Mvc - MVC Adapters for integrating with ServiceStack webservices - 3.9.7 - Demis Bellot - Demis Bellot - .NET 4.0 project Integration of ServiceStack with MVC3 - - Full details in Mvc PowerPack: http://servicestack.net/mvc-powerpack/ - Adapter classes to provide tight integration and re-usable functionality between ServiceStack and MVC3. - Including adapters for: MiniProfiler, FluentValidation, Funq IOC Controller Factory, Funq Validator Factory - ControllerBase (configured with access to ServiceStack's ICacheClient, ISession, typed UserSession dependencies). - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - MiniProfiler FluentValidation MVC Controller - en-US - servicestack.net 2012 and contributors - - - - - \ No newline at end of file diff --git a/NuGet/ServiceStack.Plugins.ProtoBuf/content/App_Start/ProtoBuf_AppStart.cs.pp b/NuGet/ServiceStack.Plugins.ProtoBuf/content/App_Start/ProtoBuf_AppStart.cs.pp deleted file mode 100644 index 46c6b587e49..00000000000 --- a/NuGet/ServiceStack.Plugins.ProtoBuf/content/App_Start/ProtoBuf_AppStart.cs.pp +++ /dev/null @@ -1 +0,0 @@ -[assembly: WebActivator.PreApplicationStartMethod(typeof(ServiceStack.Plugins.ProtoBuf.AppStart), "Start")] diff --git a/NuGet/ServiceStack.Plugins.ProtoBuf/servicestack.plugins.protobuf.nuspec b/NuGet/ServiceStack.Plugins.ProtoBuf/servicestack.plugins.protobuf.nuspec deleted file mode 100644 index 5e0605ccf55..00000000000 --- a/NuGet/ServiceStack.Plugins.ProtoBuf/servicestack.plugins.protobuf.nuspec +++ /dev/null @@ -1,25 +0,0 @@ - - - - ServiceStack.Plugins.ProtoBuf - Protocol Buffers support for ServiceStack. Includes typed ProtoBuf Client - 3.9.7 - Demis Bellot - Demis Bellot - ProtoBuf Format Serializer ContentType ServiceClients for ServiceStack - - Add the ProtoBuf binary format and endpoint to a ServiceStack web service host. - Includes the WebActivator App_Start/ProtoBuf_AppStart.cs startup script to auto register and load the ProtoBufFormat plugin. - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - ProtoBuf Fast Binary Serializer Format ContentType ServiceStack REST Web Services - en-US - servicestack.net 2012 and contributors - - - - - - \ No newline at end of file diff --git a/NuGet/ServiceStack/servicestack.nuspec b/NuGet/ServiceStack/servicestack.nuspec deleted file mode 100644 index 8de9028e715..00000000000 --- a/NuGet/ServiceStack/servicestack.nuspec +++ /dev/null @@ -1,28 +0,0 @@ - - - - ServiceStack - ServiceStack webservice framework: Faster, Cleaner, Modern WCF alternative - 3.9.7 - Demis Bellot - Demis Bellot - Opensource .NET and Mono REST Web Services framework - - Binaries for the ServiceStack web framework. - Visit http://www.servicestack.net/ServiceStack.Hello/ - and https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice - for walk throughs and docs on creating your first web service. - - https://github.com/ServiceStack/ServiceStack - https://github.com/ServiceStack/ServiceStack/blob/master/LICENSE - http://www.servicestack.net/logo-100x100.png - Fast JSON XML CSV HTML SOAP JSV REST Web Service Framework MONO - en-US - servicestack.net 2012 and contributors - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 580ac161136..3ec4d2599f8 100644 --- a/README.md +++ b/README.md @@ -1,378 +1,704 @@ -Join the [google group](http://groups.google.com/group/servicestack) or -follow [@demisbellot](http://twitter.com/demisbellot) and [@ServiceStack](http://twitter.com/servicestack) -for twitter updates. You can also join a growing crowd of ServiceStack users on [JabbR](http://jabbr.net/#/rooms/servicestack) if you want to chat. - -Service Stack is a high-performance .NET web services framework _(including a number of high-performance sub-components: see below)_ -that simplifies the development of XML, JSON, JSV and WCF SOAP [Web Services](https://github.com/ServiceStack/ServiceStack/wiki/Service-Stack-Web-Services). -For more info check out [servicestack.net](http://www.servicestack.net). - -Simple REST service example -=========================== - -```csharp -//Web Service Host Configuration -public class AppHost : AppHostBase -{ - public AppHost() : base("Backbone.js TODO", typeof(TodoService).Assembly) {} - - public override void Configure(Funq.Container container) - { - //Register Web Service dependencies - container.Register(new TodoRepository()); - - //Register user-defined REST-ful routes - Routes - .Add("/todos") - .Add("/todos/{Id}"); - } -} - - -//REST Resource DTO -public class Todo -{ - public long Id { get; set; } - public string Content { get; set; } - public int Order { get; set; } - public bool Done { get; set; } -} - -//Todo REST Service implementation -public class TodoService : RestServiceBase -{ - public TodoRepository Repository { get; set; } //Injected by IOC - - public override object OnGet(Todo request) - { - if (request.Id != default(long)) - return Repository.GetById(request.Id); - - return Repository.GetAll(); - } - - public override object OnPost(Todo todo) - { - return Repository.Store(todo); - } - - public override object OnPut(Todo todo) - { - return Repository.Store(todo); - } - - public override object OnDelete(Todo request) - { - Repository.DeleteById(request.Id); - return null; - } -} -``` - -### Calling the above TODO REST service from any C#/.NET Client - -```csharp -//no code-gen required, can re-use above DTO's - -var restClient = new JsonServiceClient("http://localhost/Backbone.Todo"); -var all = restClient.Get>("/todos"); // Count = 0 - -var todo = restClient.Post("/todos", new Todo { Content = "New TODO", Order = 1 }); //todo.Id = 1 -all = restClient.Get>("/todos"); // Count = 1 - -todo.Content = "Updated TODO"; -todo = restClient.Post("/todos", todo); // todo.Content = Updated TODO - -restClient.Delete("/todos/" + todo.Id); -all = restClient.Get>("/todos"); // Count = 0 -``` - -### Calling the TODO REST service from jQuery - - $.getJSON("http://localhost/Backbone.Todo/todos", function(todos) { - alert(todos.length == 1); - }); - - -That's all the application code required to create a simple REST web service. - -##Live Demo of Backbone TODO app (running on Linux/MONO): - -**[http://www.servicestack.net/Backbone.Todos/](http://www.servicestack.net/Backbone.Todos/)** - -Preview links using just the above code sample with (live demo running on Linux): - -ServiceStack's strong-typed nature allows it to infer a greater intelligence of your web services and is able to provide a -host of functionality for free, out of the box without any configuration required: - - * Host on different formats and endpoints: [XML](http://www.servicestack.net/Backbone.Todos/todos?format=xml), - [JSON](http://www.servicestack.net/Backbone.Todos/todos?format=json), [JSV](http://www.servicestack.net/Backbone.Todos/todos?format=jsv), - [CSV](http://www.servicestack.net/Backbone.Todos/todos?format=csv) - - * [A HTML5 Report format to view your webservics data in a human-friendly view](http://www.servicestack.net/Backbone.Todos/todos?format=html) - - * [An auto generated api metadata page, with links to your web service XSD's and WSDL's](http://www.servicestack.net/Backbone.Todos/metadata) - -## Getting Started - - * **[Read the documentation on the ServiceStack Wiki](https://github.com/ServiceStack/ServiceStack/wiki)** - * [Community resources](https://github.com/ServiceStack/ServiceStack/wiki/Community-Resources) - -## Download - -If you have [NuGet](http://nuget.org) installed, the easiest way to get started is to install ServiceStack via NuGet: - -If you just want ServiceStack hosted at `/` - Create an empty ASP.NET Web Application and -![Install-Pacakage ServiceStack.Host.Mvc](http://www.servicestack.net/img/nuget-servicestack.host.aspnet.png) - -Otherwise if you want to host ServiceStack Side-by-Side with MVC: Hosted at `/api` - Create an empty MVC Web Application and -![Install-Pacakage ServiceStack.Host.Mvc](http://www.servicestack.net/img/nuget-servicestack.host.mvc.png) - -The above packages include a complete working Backbone.Todos demo, if just want the binaries (without config) use: -![Install-Pacakage ServiceStack](http://www.servicestack.net/img/nuget-servicestack.png) - -To help get started you should also download the ServiceStack.Examples projects (includes dlls, demos and starter templates): - - * **[ServiceStack.Examples/downloads/](https://github.com/ServiceStack/ServiceStack.Examples/downloads)** - -If you prefer not to use NuGet and just want to download the latest release binaries get them at: - - * **[ServiceStack/downloads/](https://github.com/ServiceStack/ServiceStack/downloads)** - -Alternatively if you want keep up with the latest version you can always use the power of Git :) - - git clone git://github.com/ServiceStack/ServiceStack.git - -[Release notes for major releases](https://github.com/ServiceStack/ServiceStack/wiki/Release-Notes) - -# Features of a modern web services framework - - Developed in the modern age, Service Stack provides an alternate, cleaner POCO-driven way of creating web services, featuring: - -### A DRY, strongly-typed 'pure model' REST Web Services Framework -Unlike other web services frameworks ServiceStack let's you develop web services using strongly-typed models and DTO's. -This lets ServiceStack and other tools to have a greater intelligence about your services allowing: - -- [Multiple serialization formats (JSON, XML, JSV and SOAP with extensible plugin model for more)](http://servicestack.net/ServiceStack.Hello/servicestack/metadata) -- [A single re-usable C# Generic Client (In JSON, JSV, XML and SOAP flavours) that can talk to all your services.](https://github.com/ServiceStack/ServiceStack.Extras/blob/master/doc/UsageExamples/UsingServiceClients.cs) -- [Re-use your Web Service DTOs (i.e. no code-gen) on your client applications so you're never out-of-sync](https://github.com/ServiceStack/ServiceStack.Extras/blob/master/doc/UsageExamples/UsingServiceClients.cs) -- [Automatic serialization of Exceptions in your DTOs ResponseStatus](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.ServiceInterface/ServiceBase.cs#L154) -- [The possibility of a base class for all your services to put high-level application logic (i.e security, logging, etc)](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.ServiceInterface/ServiceBase.cs#L24) -- [Highly testable, your in-memory unit tests for your service can also be used as integration tests](https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs) -- [Built-in rolling web service error logging (if Redis is Configured in your AppHost)](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.ServiceInterface/ServiceBase.cs#L122) -- [Rich REST and HTML support on all web services with x-www-form-urlencoded & multipart/form-data (i.e. FORM posts and file uploads)](http://servicestack.net/ServiceStack.Hello/) - -## Define web services following Martin Fowlers Data Transfer Object Pattern: - -Service Stack was heavily influenced by [**Martin Fowlers Data Transfer Object Pattern**](http://martinfowler.com/eaaCatalog/dataTransferObject.html): - ->When you're working with a remote interface, such as Remote Facade (388), each call to it is expensive. ->As a result you need to reduce the number of calls, and that means that you need to transfer more data ->with each call. One way to do this is to use lots of parameters. ->However, this is often awkward to program - indeed, it's often impossible with languages such as Java ->that return only a single value. -> ->The solution is to create a Data Transfer Object that can hold all the data for the call. It needs to be serializable to go across the connection. ->Usually an assembler is used on the server side to transfer data between the DTO and any domain objects. - -The Request and Response DTO's used to define web services in ServiceStack are standard `DataContract` POCO's while the implementation just needs to inherit from a testable and dependency-free `IService`. As a bonus for keeping your DTO's in a separate dependency-free .dll, you're able to re-use them in your C#/.NET clients providing a strongly-typed API without any code-gen what-so-ever. Also your DTO's *define everything* Service Stack does not pollute your web services with any additional custom artefacts or markup. - -Service Stack re-uses the custom artefacts above and with zero-config and without imposing any extra burden on the developer adds discover-ability and provides hosting of your web service on a number of different physical end-points which as of today includes: XML (+REST), JSON (+REST), JSV (+REST) and SOAP 1.1 / SOAP 1.2. - - -### WCF the anti-DTO Web Services Framework -Unfortunately this best-practices convention is effectively discouraged by Microsoft's WCF SOAP Web Services framework as they encourage you to develop API-specific RPC method calls by mandating the use method signatures to define your web services API. This results in less re-usable, more client-sepcfic APIs that encourages more remote method calls. - -Unhappy with this perceived anit-pattern in WCF, ServiceStack was born providing a Web Sevice framework that embraces best-practices for calling remote services, using config-free, convention-based DTO's. - - -### Full support for unit and integration tests -Your application logic should not be tied to a third party vendor's web service host platform. -In Service Stack they're not, your web service implementations are host and end-point ignorant, dependency-free and can be unit-tested independently of ASP.NET, Service Stack or its IOC. - -Without any code changes unit tests written can be re-used and run as integration tests simply by switching the IServiceClient used to point to a configured end-point host. - -### Built-in Funq IOC container -Configured to auto-wire all of your web services with your registered dependencies. -[Funq](http://funq.codeplex.com) was chosen for it's [high-performance](http://www.codeproject.com/Articles/43296/Introduction-to-Munq-IOC-Container-for-ASP-NET.aspx), low footprint and intuitive full-featured minimalistic API. - -### Encourages development of message-style, re-usable and batch-full web services -Entire POCO types are used to define the request and response DTO's to promote the creation well-defined coarse-grained web services. Message-based interfaces are best-practices when dealing with out-of-process calls as they are can batch more work using less network calls and are ultimately more re-usable as the same operation can be called using different calling semantics. This is in stark contrast to WCF's Operation or Service contracts which encourage RPC-style, application-specific web services by using method signatures to define each operation. - -As it stands in general-purpose computing today, there is nothing more expensive you can do than a remote network call. Although easier for the newbie developer, by using _methods_ to define web service operations, WCF is promoting bad-practices by encouraging them to design and treat web-service calls like normal function calls even though they are millions of times slower. Especially at the app-server tier, nothing hurts performance and scalability of your client and server than multiple dependent and synchronous web service calls. - -Batch-full, message-based web services are ideally suited in development of SOA services as they result in fewer, richer and more re-usable web services that need to be maintained. RPC-style services normally manifest themselves from a *client perspective* that is the result of the requirements of a single applications data access scenario. Single applications come and go over time while your data and services are poised to hang around for the longer term. Ideally you want to think about the definition of your web service from a *services and data perspective* and how you can expose your data so it is more re-usable by a number of your clients. - -### Cross Platform Web Services Framework -With Mono on Linux now reaching full-maturity, Service Stack runs on .NET or Linux with Mono and can either be hosted inside an ASP.NET Web Application, Windows service or Console application running in or independently of a Web Server. - -### Low Coupling for maximum accessibility and testability -No coupling between the transport's endpoint and your web service's payload. You can re-use your existing strongly-typed web service DTO's with any .NET client using the available Soap, Xml and Json Service Clients - giving you a strongly-typed API while at the same time avoiding the need for any generated code. - - * The most popular web service endpoints are configured by default. With no extra effort, each new web service created is immediately available and [discoverable](http://www.servicestack.net/ServiceStack.Examples.Host.Web/ServiceStack/Metadata) on the following end points: - * [XML (+REST)](http://www.servicestack.net/ServiceStack.Examples.Host.Web/ServiceStack/Xml/Metadata?op=GetFactorial) - * [JSON (+REST)](http://www.servicestack.net/ServiceStack.Examples.Host.Web/ServiceStack/Json/Metadata?op=GetFactorial) - * [JSV (+REST)](http://www.servicestack.net/ServiceStack.Examples.Host.Web/ServiceStack/Jsv/Metadata?op=GetFactorial) - * [SOAP 1.1](http://www.servicestack.net/ServiceStack.Hello/servicestack/soap11) - * [SOAP 1.2](http://www.servicestack.net/ServiceStack.Hello/servicestack/soap12) - * View the [Service Stack endpoints page](https://github.com/ServiceStack/ServiceStack/wiki/Service-Stack-Web-Services) for our recommendations on which endpoint to use and when. - -# High Performance Sub Projects -Also included in ServiceStack are libraries that are useful in the development of high performance web services: - - * [ServiceStack.Text](https://github.com/ServiceStack/ServiceStack.Text) - The home of ServiceStack's JSON and JSV text serializers, the fastest text serializers for .NET - * [JsonSerializer](http://www.servicestack.net/mythz_blog/?p=344) - The fastest JSON Serializer for .NET. Over 3 times faster than other .NET JSON serialisers. - * [TypeSerializer](https://github.com/ServiceStack/ServiceStack.Text) - The JSV-format, a fast, compact text serializer that is very resilient to schema changes and is: - * 3.5x quicker and 2.6x smaller than the .NET XML DataContractSerializer and - * 5.3x quicker and 1.3x smaller than the .NET JSON DataContractSerializer - _[view the detailed benchmarks](http://www.servicestack.net/benchmarks/NorthwindDatabaseRowsSerialization.1000000-times.2010-02-06.html)_ - - * [ServiceStack.Redis](https://github.com/ServiceStack/ServiceStack.Redis) - An API complete C# [Redis](http://code.google.com/p/redis/) client with native support for persisting C# POCO objects. - * You can find links to the latest windows builds at the end of [this StackOverflow Answer on Redis](http://stackoverflow.com/questions/1777103/what-nosql-solutions-are-out-there-for-net/2760282#2760282) - * [Redis Admin UI](http://www.servicestack.net/mythz_blog/?p=381) - An Ajax GUI admin tool to help visualize your Redis data. - - * [OrmLite](https://github.com/ServiceStack/ServiceStack.OrmLite) - A convention-based, configuration free lightweight ORM that uses attributes from DataAnnotations to infer the table schema. Currently supports both Sqlite and SqlServer. - - * [Caching](https://github.com/ServiceStack/ServiceStack/wiki/Caching) - A common interface for caching with providers for: - * Memcached - * In Memory Cache - * Redis - - -## Find out More - * Twitter: to get updates of ServiceStack, follow [@demisbellot](http://twitter.com/demisbellot) or [@ServiceStack](http://twitter.com/ServiceStack) on twitter. - * Email any questions to _demis.bellot@gmail.com_ - -## Future Roadmap -Service Stack is under continuous improvement and is always adding features that are useful for high-performance, scalable and resilient web service scenarios. See the -[trello board](https://trello.com/board/servicestack-features-bugs/4e9fbbc91065f8e9c805641c) to get information about the current project status and upcoming features. - -## Similar open source projects -Similar Open source .NET projects for developing or accessing web services include: - - * Open Rasta - REST-ful web service framwork: - * [http://trac.caffeine-it.com/openrasta](http://trac.caffeine-it.com/openrasta) - - * Rest Sharp - an open source REST client for .NET - * [http://restsharp.org](http://restsharp.org) - -## OSS Libraries used - -ServiceStack includes source code of the great libraries below for some of its core functionality. -Each library is released under its respective licence: - - - [Mono](https://github.com/mono/mono) [(Licence)](https://github.com/mono/mono/blob/master/LICENSE) - - [Funq IOC](http://funq.codeplex.com) [(Licence)](http://funq.codeplex.com/license) - - [Fluent Validation](http://fluentvalidation.codeplex.com) [(Licence)](http://fluentvalidation.codeplex.com/license) - - [Mini Profiler](http://code.google.com/p/mvc-mini-profiler/) [(Licence)](http://www.apache.org/licenses/LICENSE-2.0) - - [Dapper](http://code.google.com/p/dapper-dot-net/) [(Licence)](http://www.apache.org/licenses/LICENSE-2.0) - - [TweetStation's OAuth library](https://github.com/migueldeicaza/TweetStation) [(Licence)](https://github.com/migueldeicaza/TweetStation/blob/master/LICENSE) - -## Sponsors - -![JetBrains dotTrace](http://www.jetbrains.com/profiler/features/dt/dt1/dt210x60_white.gif) - -http://www.jetbrains.com/profiler/ - -## Core Team - - - [mythz](https://github.com/mythz) (Demis Bellot) - - [arxisos](https://github.com/arxisos) (Steffen Müller) - - [desunit](https://github.com/desunit) (Sergey Bogdanov) - -## Contributors -A big thanks to GitHub and all of ServiceStack's contributors: - - - [bman654](https://github.com/bman654) (Brandon Wallace) - - [Iristyle](https://github.com/Iristyle) (Ethan Brown) - - [superlogical](https://github.com/superlogical) (Jake Scott) - - [itamar82](https://github.com/itamar82) - - [chadwackerman](https://github.com/chadwackerman) - - [derfsplat](https://github.com/derfsplat) - - [JohnACarruthers](https://github.com/JohnACarruthers) (John Carruthers) - - [mvitorino](https://github.com/mvitorino) (Miguel Vitorino) - - [bsiegel](https://github.com/bsiegel) (Brandon Siegel) - - [mdavid](https://github.com/mdavid) (M. David Peterson) - - [lhaussknecht](https://github.com/lhaussknecht) (Louis Haussknecht) - - [grendello](https://github.com/grendello) (Marek Habersack) - - [SteveDunn](https://github.com/SteveDunn) (Steve Dunn) - - [kcherenkov](https://github.com/kcherenkov) (Konstantin Cherenkov) - - [timryan](https://github.com/timryan) (Tim Ryan) - - [letssellsomebananas](https://github.com/letssellsomebananas) (Tymek Majewski) - - [danbarua](https://github.com/danbarua) (Dan Barua) - - [JonCanning](https://github.com/JonCanning) (Jon Canning) - - [paegun](https://github.com/paegun) (James Gorlick) - - [pvasek](https://github.com/pvasek) (pvasek) - - [derfsplat](https://github.com/derfsplat) (derfsplat) - - [justinrolston](https://github.com/justinrolston) (Justin Rolston) - - [danmiser](https://github.com/danmiser) (Dan Miser) - - [danatkinson](https://github.com/danatkinson) (Dan Atkinson) - - [brainless83](https://github.com/brainless83) (Thomas Grassauer) - - [angelcolmenares](https://github.com/angelcolmenares) (angel colmenares) - - [dbeattie71](https://github.com/dbeattie71) (Derek Beattie) - - [danielwertheim](https://github.com/danielwertheim) (Daniel Wertheim) - - [greghroberts](https://github.com/greghroberts) (Gregh Roberts) - - [int03](https://github.com/int03) (Selim Selçuk) - - [andidog](https://github.com/AndiDog) (AndiDog) - - [chuckb](https://github.com/chuckb) (chuckb) - - [niemyjski](https://github.com/niemyjski) (Blake Niemyjski) - - [mj1856](https://github.com/mj1856) (Matt Johnson) - - [matthieugd](https://github.com/matthieugd) (Matthieu) - - [tomaszkubacki](https://github.com/tomaszkubacki) (Tomasz Kubacki) - - [e11137](https://github.com/e11137) (Rogelio Canedo) - - [davrot](https://github.com/davrot) (David Roth) - - [meebey](https://github.com/meebey) (Mirco Bauer) - - [codedemonuk](https://github.com/codedemonuk) (Pervez Choudhury) - - [jrosskopf](https://github.com/jrosskopf) (Joachim Rosskopf) - - [friism](https://github.com/friism) (Michael Friis) - - [mp3125](https://github.com/mp3125) - - [aurimas86](https://github.com/aurimas86) - - [parnham](https://github.com/parnham) (Dan Parnham) - - [yeurch](https://github.com/yeurch) (Richard Fawcett) - - [damianh](https://github.com/damianh) (Damian Hickey) - - [freeman](https://github.com/freeman) (Michel Rasschaert) - - [kvervo](https://github.com/kvervo) (Kvervo) - - [pauldbau](https://github.com/pauldbau) (Paul Du Bois) - - [justinpihony](https://github.com/JustinPihony) (Justin Pihony) - - [bokmadsen](https://github.com/bokmadsen) (Bo Kingo Damgaard) - - [dragan](https://github.com/dragan) (Dale Ragan) - - [sneal](https://github.com/sneal) (Shawn Neal) - - [johnsheehan](https://github.com/johnsheehan) (John Sheehan) - - [jschlicht](https://github.com/jschlicht) (Jared Schlicht) - - [kumarnitin](https://github.com/kumarnitin) (Nitin Kumar) - - [DavidChristiansen](https://github.com/DavidChristiansen) (David Christiansen) - - [PaulECoyote](https://github.com/PaulECoyote) (Paul Evans) - - [kongo2002](https://github.com/kongo2002) (Gregor Uhlenheuer) - - [BrannonKing](https://github.com/BrannonKing) (Brannon King) - - [alexandrerocco](https://github.com/alexandrerocco) (Alexandre Rocco) - - [cbarbara](https://github.com/cbarbara) - - [assaframan](https://github.com/assaframan) (Assaf Raman) - - [csakshaug](https://github.com/csakshaug) (Christian Sakshaug) - - [johnman](https://github.com/johnman) - - [jarroda](https://github.com/jarroda) - - [ssboisen](https://github.com/ssboisen) (Simon Skov Boisen) - - [paulduran](https://github.com/paulduran) (Paul Duran) - - [pruiz](https://github.com/pruiz) (Pablo Ruiz García) - - [fantasticjamieburns](https://github.com/fantasticjamieburns) - - [pseabury](https://github.com/pseabury) - - [kevingessner](https://github.com/kevingessner) (Kevin Gessner) - - [iskomorokh](https://github.com/iskomorokh) (Igor Skomorokh) - - [royjacobs](https://github.com/royjacobs) (Roy Jacobs) - - [robertmircea](https://github.com/robertmircea) (Robert Mircea) - - [markswiatek](https://github.com/markswiatek) (Mark Swiatek) - - [flq](https://github.com/flq) (Frank Quednau) - - [ashd](https://github.com/ashd) (Ash D) - - [thanhhh](https://github.com/thanhhh) - - [algra](https://github.com/algra) (Alexey Gravanov) - - [jimschubert](https://github.com/jimschubert) (Jim Schubert) - - [gkathire](https://github.com/gkathire) - - [mikaelwaltersson](https://github.com/mikaelwaltersson) (Mikael Waltersson) - - [asunar](https://github.com/asunar) (Alper) - - [chucksavage](https://github.com/chucksavage) (Chuck Savage) - - [sashagit](https://github.com/sashagit) (Sasha) - - [froyke](https://github.com/froyke) (Froyke) - - [dbhobbs](https://github.com/dbhobbs) (Daniel Hobbs) - - [bculberson](https://github.com/bculberson) (Brad Culberson) - -*** - -Runs on both Mono and .NET 3.5. _(Live preview hosted on Mono / CentOS)_ - +Follow [@ServiceStack](https://twitter.com/servicestack) or [view the docs](https://docs.servicestack.net), use [StackOverflow](http://stackoverflow.com/questions/ask) or the [Customer Forums](https://forums.servicestack.net/) for support. + +> View the [Release Notes](https://docs.servicestack.net/release-notes-history) for latest features or see [servicestack.net/features](https://servicestack.net/features) for an overview. + +### Simple, Fast, Versatile and full-featured Services Framework + +ServiceStack is a simple, fast, versatile and highly-productive full-featured [Web](http://razor.servicestack.net) and +[Web Services](https://docs.servicestack.net/web-services.html) Framework that's +thoughtfully-architected to [reduce artificial complexity](https://docs.servicestack.net/why-not-odata.html#why-not-complexity) and promote +[remote services best-practices](https://docs.servicestack.net/advantages-of-message-based-web-services.html) +with a [message-based design](https://docs.servicestack.net/what-is-a-message-based-web-service.html) +that allows for maximum re-use that can leverage an integrated +[Service Gateway](https://docs.servicestack.net/service-gateway.html) +for the creation of loosely-coupled +[Modularized Service](https://docs.servicestack.net/modularizing-services.html) Architectures. +ServiceStack Services are consumable via an array of built-in fast data formats (inc. +[JSON](https://github.com/ServiceStack/ServiceStack.Text), +XML, +[CSV](https://docs.servicestack.net/csv-format.html), +[JSV](https://docs.servicestack.net/json-jsv-and-xml.html), +[ProtoBuf](https://docs.servicestack.net/protobuf-format.html), +[Wire](https://docs.servicestack.net/wire-format.html) and +[MsgPack](https://docs.servicestack.net/messagepack-format.html)) +as well as XSD/WSDL for [SOAP endpoints](https://docs.servicestack.net/soap-support.html) and +[Rabbit MQ](https://docs.servicestack.net/rabbit-mq.html), +[Redis MQ](https://docs.servicestack.net/messaging-and-redis.html) and +[Amazon SQS](https://github.com/ServiceStack/ServiceStack.Aws#sqsmqserver) MQ hosts. + +Its design and simplicity focus offers an unparalleled suite of productivity features that can be declaratively enabled +without code, from creating fully queryable Web API's with just a single Typed Request DTO with +[Auto Query](https://docs.servicestack.net/autoquery.html) supporting +[every major RDBMS](https://github.com/ServiceStack/ServiceStack.OrmLite#8-flavours-of-ormlite-is-on-nuget) +to the built-in support for +[Auto Batched Requests](https://docs.servicestack.net/auto-batched-requests.html) +or effortlessly enabling rich [HTTP Caching](https://docs.servicestack.net/http-caching.html) and +[Encrypted Messaging](https://docs.servicestack.net/encrypted-messaging.html) +for all your existing services via [Plugins](https://docs.servicestack.net/plugins.html). + +Your same Services also serve as the Controller in ServiceStack's [Smart Razor Views](http://razor.servicestack.net/) +reducing the effort to serve both +[Web and Single Page Apps](https://github.com/ServiceStackApps/LiveDemos) as well as +[Rich Desktop and Mobile Clients](https://github.com/ServiceStackApps/HelloMobile) that are able to deliver instant interactive +experiences using ServiceStack's real-time [Server Events](https://docs.servicestack.net/server-events.html). + +ServiceStack Services also maximize productivity for consumers providing an +[instant end-to-end typed API without code-gen](https://docs.servicestack.net/csharp-client.html) enabling +the most productive development experience for developing .NET to .NET Web Services. + +### [Generate Instant Typed APIs from within all Major IDEs!](https://docs.servicestack.net/add-servicestack-reference.html) + +ServiceStack now integrates with all Major IDE's used for creating the best native experiences on the most popular platforms +to enable a highly productive dev workflow for consuming Web Services, making ServiceStack the ideal back-end choice for powering +rich, native iPhone and iPad Apps on iOS with Swift, Mobile and Tablet Apps on the Android platform with Java, OSX Desktop Applications +as well as targeting the most popular .NET PCL platforms including Xamarin.iOS, Xamarin.Android, Windows Store, WPF, WinForms and Silverlight: + + + +#### [VS.NET integration with ServiceStackVS](https://visualstudiogallery.msdn.microsoft.com/5bd40817-0986-444d-a77d-482e43a48da7) + +Providing instant Native Typed API's for +[C#](https://docs.servicestack.net/csharp-add-servicestack-reference.html), +[TypeScript](https://docs.servicestack.net/typescript-add-servicestack-reference.html), +[F#](https://docs.servicestack.net/fsharp-add-servicestack-reference.html) and +[VB.NET](https://docs.servicestack.net/vbnet-add-servicestack-reference.html) +directly in Visual Studio for the +[most popular .NET platforms](https://github.com/ServiceStackApps/HelloMobile) including iOS and Android using +[Xamarin.iOS](https://github.com/ServiceStackApps/HelloMobile#xamarinios-client) and +[Xamarin.Android](https://github.com/ServiceStackApps/HelloMobile#xamarinandroid-client) on Windows. + +#### [Xamarin Studio integration with ServiceStackXS](https://docs.servicestack.net/csharp-add-servicestack-reference.html#xamarin-studio) + +Providing [C# Native Types](https://docs.servicestack.net/csharp-add-servicestack-reference.html) +support for developing iOS and Android mobile Apps using +[Xamarin.iOS](https://github.com/ServiceStackApps/HelloMobile#xamarinios-client) and +[Xamarin.Android](https://github.com/ServiceStackApps/HelloMobile#xamarinandroid-client) with +[Xamarin Studio](https://www.xamarin.com/studio) on OSX. The **ServiceStackXS** plugin also provides a rich web service +development experience developing Client applications with +[Mono Develop on Linux](https://docs.servicestack.net/csharp-add-servicestack-reference.html#xamarin-studio-for-linux) + +#### [Xcode integration with ServiceStackXC Plugin](https://docs.servicestack.net/swift-add-servicestack-reference.html) + +Providing [an instant Native Typed API in Swift](https://docs.servicestack.net/swift-add-servicestack-reference.html) +including generic Service Clients enabling a highly-productive workflow and effortless consumption of Web Services from +native iOS and OSX Applications - directly from within Xcode! + +#### [Android Studio integration with ServiceStackIDEA](https://docs.servicestack.net/java-add-servicestack-reference.html) + +Providing [an instant Native Typed API in Java](https://docs.servicestack.net/java-add-servicestack-reference.html) +and [Kotlin](https://docs.servicestack.net/kotlin-add-servicestack-reference.html) +including idiomatic Java Generic Service Clients supporting Sync and Async Requests by leveraging Android's AsyncTasks to enable the creation of services-rich and responsive native Java or Kotlin Mobile Apps on the Android platform - directly from within Android Studio! + +#### [IntelliJ integration with ServiceStackIDEA](https://docs.servicestack.net/java-add-servicestack-reference.html#install-servicestack-idea-from-the-plugin-repository) + +The ServiceStack IDEA plugin is installable directly from IntelliJ's Plugin repository and enables seamless integration with IntelliJ Java Maven projects for generating a Typed API to quickly and effortlessly consume remote ServiceStack Web Services from pure cross-platform Java or Kotlin Clients. + +#### [Eclipse integration with ServiceStackEclipse](https://github.com/ServiceStack/ServiceStack.Java/tree/master/src/ServiceStackEclipse#eclipse-integration-with-servicestack) + +The unmatched productivity offered by [Java Add ServiceStack Reference](https://docs.servicestack.net/java-add-servicestack-reference.html) is also available in the +[ServiceStackEclipse IDE Plugin](https://github.com/ServiceStack/ServiceStack.Java/tree/master/src/ServiceStackEclipse#eclipse-integration-with-servicestack) that's installable +from the [Eclipse MarketPlace](https://marketplace.eclipse.org/content/servicestackeclipse) to provide deep integration of Add ServiceStack Reference with Eclipse Java Maven Projects +enabling Java Developers to effortlessly Add and Update the references of their evolving remote ServiceStack Web Services. + +#### [servicestack-cli - Simple command-line utilities for ServiceStack](https://docs.servicestack.net/add-servicestack-reference.html#simple-command-line-utilities-for-servicestack) + +In addition to our growing list of supported IDE's, the [servicestack-cli](https://github.com/ServiceStack/servicestack-cli) +cross-platform command-line npm scripts makes it easy for build servers, automated tasks and command-line runners of your +favorite text editors to easily Add and Update ServiceStack References! + +## Simple Customer Database REST Services Example + +This example is also available as a [stand-alone integration test](https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerRestExample.cs): + +```csharp +//Web Service Host Configuration +public class AppHost : AppSelfHostBase +{ + public AppHost() + : base("Customer REST Example", typeof(CustomerService).Assembly) {} + + public override void Configure(Container container) + { + //Register which RDBMS provider to use + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + using (var db = container.Resolve().Open()) + { + //Create the Customer POCO table if it doesn't already exist + db.CreateTableIfNotExists(); + } + } +} + +//Web Service DTO's +[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; } +} + +// POCO DB Model +public class Customer +{ + [AutoIncrement] + public int Id { get; set; } + + public string Name { get; set; } +} + +//Web Services Implementation +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); + } +} + +``` + +### [Calling the above REST Service from any C#/.NET Client](https://docs.servicestack.net/csharp-add-servicestack-reference.html) + +> No code-gen required, can re-use above Server DTOs: + +```csharp +var client = new JsonServiceClient(BaseUri); + +//GET /customers +var all = client.Get(new GetCustomers()); // Count = 0 + +//POST /customers +var customer = client.Post(new CreateCustomer { Name = "Foo" }); + +//GET /customer/1 +customer = client.Get(new GetCustomer { Id = customer.Id }); // Name = Foo + +//GET /customers +all = client.Get(new GetCustomers()); // Count = 1 + +//PUT /customers/1 +customer = client.Put( + new UpdateCustomer { Id = customer.Id, Name = "Bar" }); // Name = Bar + +//DELETE /customers/1 +client.Delete(new DeleteCustomer { Id = customer.Id }); + +//GET /customers +all = client.Get(new GetCustomers()); // Count = 0 +``` + +Same code also works with [Android, iOS, Xamarin.Forms, UWP and WPF clients](https://github.com/ServiceStackApps/HelloMobile). + +> [F#](https://docs.servicestack.net/fsharp-add-servicestack-reference.html) and +[VB.NET](https://docs.servicestack.net/vbnet-add-servicestack-reference.html) can re-use same +[.NET Service Clients](https://docs.servicestack.net/csharp-client.html) and DTO's + +### [Calling from TypeScript](https://docs.servicestack.net/typescript-add-servicestack-reference.html#ideal-typed-message-based-api) + +```ts +const client = new JsonServiceClient(baseUrl); +const { results } = await client.get(new GetCustomers()); +``` + +### [Calling from Swift](https://docs.servicestack.net/swift-add-servicestack-reference.html#jsonserviceclientswift) + +```swift +let client = JsonServiceClient(baseUrl: BaseUri) + +client.getAsync(GetCustomers()) + .then { + let results = $0.results; + } +``` + +### [Calling from Java](https://docs.servicestack.net/java-add-servicestack-reference.html#jsonserviceclient-usage) + +```java +JsonServiceClient client = new JsonServiceClient(BaseUri); + +GetCustomersResponse response = client.get(new GetCustomers()); +List results = response.results; +``` + +### [Calling from Kotlin](https://docs.servicestack.net/kotlin-add-servicestack-reference.html#jsonserviceclient-usage) + +```kotlin +val client = JsonServiceClient(BaseUri) + +val response = client.get(GetCustomers()) +val results = response.results +``` + +### [Calling from Dart](https://docs.servicestack.net/dart-add-servicestack-reference) + +```dart +var client = new JsonServiceClient(BaseUri); + +var response = await client.get(GetCustomers()); +var results = client.results; +``` + +### [Calling from jQuery using TypeScript Definitions](https://docs.servicestack.net/typescript-add-servicestack-reference.html#typescript-interface-definitions) + +```js +$.getJSON($.ss.createUrl("/customers", request), request, (r: GetCustomersResponse) => { + var results = r.results; +}); +``` + +Using TypeScript Definitions with Angular HTTP Client: + +```ts +this.http.get(createUrl('/customers', request)).subscribe(r => { + this.results = r.results; +}); +``` + +### Calling from jQuery + +```js +$.getJSON(baseUri + "/customers", function(r) { + var results = r.results; +}); +``` + +That's all the application code required to create and consume a simple database-enabled REST Web Service! + +## Getting Started + + * [Start with the **Getting Started** section](https://docs.servicestack.net/create-your-first-webservice.html) + * [Example Apps and Demos](https://github.com/ServiceStackApps/LiveDemos) + * [Community resources](https://docs.servicestack.net/community-resources.html) + +### [Release Notes](https://servicestack.net/release-notes) + +## Download + +If you have [NuGet](http://www.nuget.org/) installed, the easiest way to get started is to: + +### [Install ServiceStack via NuGet](https://servicestack.net/download). + +_Latest v4+ on NuGet is a [commercial release](https://servicestack.net/pricing) with [free quotas](https://servicestack.net/download#free-quotas)._ + +### [Docs and Downloads for older v3 BSD releases](https://github.com/ServiceStackV3/ServiceStackV3) + +### [Live Demos](https://github.com/ServiceStackApps/LiveDemos) + +**The [Definitive list of Example Projects, Use-Cases, Demos, Starter Templates](https://github.com/ServiceStackApps/LiveDemos)** + +## Copying + +Since September 2013, ServiceStack source code is available under GNU Affero General Public License/FOSS License Exception, see license.txt in the source. +Alternative commercial licensing is also available, see https://servicestack.net/pricing for details. + +## Contributing + +Contributors need to approve the [Contributor License Agreement](https://docs.google.com/forms/d/16Op0fmKaqYtxGL4sg7w_g-cXXyCoWjzppgkuqzOeKyk/viewform) before any code will be reviewed, see the [Contributing docs](https://docs.servicestack.net/contributing.html) for more details. All contributions must include tests verifying the desired behavior. + +## OSS Libraries used + +ServiceStack includes source code of the great libraries below for some of its core functionality. +Each library is released under its respective licence: + + - [Mono](https://github.com/mono/mono) [(MIT License)](https://github.com/mono/mono/blob/master/LICENSE) + - [Funq IOC](http://funq.codeplex.com) [(MS-PL License)](https://opensource.org/licenses/MS-PL) + - [Fluent Validation](https://github.com/JeremySkinner/FluentValidation) [(Apache License 2.0)](https://github.com/JeremySkinner/FluentValidation/blob/master/License.txt) + - [Mini Profiler](https://github.com/MiniProfiler/dotnet) [(MIT License)](https://github.com/MiniProfiler/dotnet/blob/master/LICENSE.txt) + - [Dapper](https://github.com/StackExchange/Dapper) [(Apache License 2.0)](http://www.apache.org/licenses/LICENSE-2.0) + - [TweetStation's OAuth library](https://github.com/migueldeicaza/TweetStation) [(MIT License)](https://github.com/migueldeicaza/TweetStation/blob/master/LICENSE) + - [MarkdownSharp](https://code.google.com/archive/p/markdownsharp) [(MIT License)](https://opensource.org/licenses/mit-license.php) + - [MarkdownDeep](https://github.com/toptensoftware/markdowndeep) [(Apache License 2.0)](http://www.toptensoftware.com/markdowndeep/license) + - [HtmlCompressor](https://code.google.com/archive/p/htmlcompressor) [(Apache License 2.0)](http://www.apache.org/licenses/LICENSE-2.0) + - [JSMin](https://github.com/douglascrockford/JSMin/blob/master/jsmin.c) [(Apache License 2.0)](http://www.apache.org/licenses/LICENSE-2.0) + - [RecyclableMemoryStream](https://github.com/Microsoft/Microsoft.IO.RecyclableMemoryStream) [(MIT License)](https://github.com/Microsoft/Microsoft.IO.RecyclableMemoryStream/blob/master/LICENSE) + - [ASP.NET MVC](https://github.com/aspnet/Mvc) [(Apache License 2.0)](https://github.com/aspnet/Mvc/blob/release/2.2/LICENSE.txt) + - [CoreFX](https://github.com/dotnet/corefx) [(MIT License)](https://github.com/dotnet/corefx/blob/master/LICENSE.TXT) + - [Nito.AsyncEx](https://github.com/StephenCleary/AsyncEx) [(MIT License)](https://github.com/StephenCleary/AsyncEx/blob/master/LICENSE) + +## Find out More + +Follow [@ServiceStack](https://twitter.com/ServiceStack) and +[+ServiceStack](https://plus.google.com/u/0/communities/112445368900682590445) for project updates. + +----- + +## Core Team + + - [mythz](https://github.com/mythz) (Demis Bellot) + - [layoric](https://github.com/layoric) (Darren Reid) / [@layoric](https://twitter.com/layoric) + - [xplicit](https://github.com/xplicit) (Sergey Zhukov) / [@quantumcalc](https://twitter.com/quantumcalc) + - [desunit](https://github.com/desunit) (Sergey Bogdanov) / [@desunit](https://twitter.com/desunit) + - [arxisos](https://github.com/arxisos) (Steffen Müller) / [@arxisos](https://twitter.com/arxisos) + +## Contributors + +A big thanks to GitHub and all of ServiceStack's contributors: + + - [bman654](https://github.com/bman654) (Brandon Wallace) + - [iristyle](https://github.com/iristyle) (Ethan Brown) + - [superlogical](https://github.com/superlogical) (Jake Scott) + - [itamar82](https://github.com/itamar82) + - [chadwackerman](https://github.com/chadwackerman) + - [derfsplat](https://github.com/derfsplat) + - [johnacarruthers](https://github.com/johnacarruthers) (John Carruthers) + - [mvitorino](https://github.com/mvitorino) (Miguel Vitorino) + - [bsiegel](https://github.com/bsiegel) (Brandon Siegel) + - [mdavid](https://github.com/mdavid) (M. David Peterson) + - [lhaussknecht](https://github.com/lhaussknecht) (Louis Haussknecht) + - [grendello](https://github.com/grendello) (Marek Habersack) + - [SteveDunn](https://github.com/SteveDunn) (Steve Dunn) + - [kcherenkov](https://github.com/kcherenkov) (Konstantin Cherenkov) + - [timryan](https://github.com/timryan) (Tim Ryan) + - [letssellsomebananas](https://github.com/letssellsomebananas) (Tymek Majewski) + - [danbarua](https://github.com/danbarua) (Dan Barua) + - [JonCanning](https://github.com/JonCanning) (Jon Canning) + - [paegun](https://github.com/paegun) (James Gorlick) + - [pvasek](https://github.com/pvasek) (pvasek) + - [derfsplat](https://github.com/derfsplat) (derfsplat) + - [justinrolston](https://github.com/justinrolston) (Justin Rolston) + - [danmiser](https://github.com/danmiser) (Dan Miser) + - [danatkinson](https://github.com/danatkinson) (Dan Atkinson) + - [brainless83](https://github.com/brainless83) (Thomas Grassauer) + - [angelcolmenares](https://github.com/angelcolmenares) (angel colmenares) + - [dbeattie71](https://github.com/dbeattie71) (Derek Beattie) + - [danielwertheim](https://github.com/danielwertheim) (Daniel Wertheim) + - [greghroberts](https://github.com/greghroberts) (Gregh Roberts) + - [int03](https://github.com/int03) (Selim Selçuk) + - [andidog](https://github.com/AndiDog) (AndiDog) + - [chuckb](https://github.com/chuckb) (chuckb) + - [niemyjski](https://github.com/niemyjski) (Blake Niemyjski) + - [mj1856](https://github.com/mj1856) (Matt Johnson) + - [matthieugd](https://github.com/matthieugd) (Matthieu) + - [tomaszkubacki](https://github.com/tomaszkubacki) (Tomasz Kubacki) + - [e11137](https://github.com/e11137) (Rogelio Canedo) + - [davidroth](https://github.com/davidroth) (David Roth) + - [meebey](https://github.com/meebey) (Mirco Bauer) + - [codedemonuk](https://github.com/codedemonuk) (Pervez Choudhury) + - [jrosskopf](https://github.com/jrosskopf) (Joachim Rosskopf) + - [friism](https://github.com/friism) (Michael Friis) + - [mp3125](https://github.com/mp3125) + - [aurimas86](https://github.com/aurimas86) + - [parnham](https://github.com/parnham) (Dan Parnham) + - [yeurch](https://github.com/yeurch) (Richard Fawcett) + - [damianh](https://github.com/damianh) (Damian Hickey) + - [freeman](https://github.com/freeman) (Michel Rasschaert) + - [kvervo](https://github.com/kvervo) (Kvervo) + - [pauldbau](https://github.com/pauldbau) (Paul Du Bois) + - [justinpihony](https://github.com/JustinPihony) (Justin Pihony) + - [bokmadsen](https://github.com/bokmadsen) (Bo Kingo Damgaard) + - [dragan](https://github.com/dragan) (Dale Ragan) + - [sneal](https://github.com/sneal) (Shawn Neal) + - [johnsheehan](https://github.com/johnsheehan) (John Sheehan) + - [jschlicht](https://github.com/jschlicht) (Jared Schlicht) + - [kumarnitin](https://github.com/kumarnitin) (Nitin Kumar) + - [davidchristiansen](https://github.com/davidchristiansen) (David Christiansen) + - [paulecoyote](https://github.com/paulecoyote) (Paul Evans) + - [kongo2002](https://github.com/kongo2002) (Gregor Uhlenheuer) + - [brannonking](https://github.com/brannonking) (Brannon King) + - [alexandrerocco](https://github.com/alexandrerocco) (Alexandre Rocco) + - [cbarbara](https://github.com/cbarbara) + - [assaframan](https://github.com/assaframan) (Assaf Raman) + - [csakshaug](https://github.com/csakshaug) (Christian Sakshaug) + - [johnman](https://github.com/johnman) + - [jarroda](https://github.com/jarroda) + - [ssboisen](https://github.com/ssboisen) (Simon Skov Boisen) + - [paulduran](https://github.com/paulduran) (Paul Duran) + - [pruiz](https://github.com/pruiz) (Pablo Ruiz García) + - [fantasticjamieburns](https://github.com/fantasticjamieburns) + - [pseabury](https://github.com/pseabury) + - [kevingessner](https://github.com/kevingessner) (Kevin Gessner) + - [iskomorokh](https://github.com/iskomorokh) (Igor Skomorokh) + - [royjacobs](https://github.com/royjacobs) (Roy Jacobs) + - [robertmircea](https://github.com/robertmircea) (Robert Mircea) + - [markswiatek](https://github.com/markswiatek) (Mark Swiatek) + - [flq](https://github.com/flq) (Frank Quednau) + - [ashd](https://github.com/ashd) (Ash D) + - [thanhhh](https://github.com/thanhhh) + - [algra](https://github.com/algra) (Alexey Gravanov) + - [jimschubert](https://github.com/jimschubert) (Jim Schubert) + - [gkathire](https://github.com/gkathire) + - [mikaelwaltersson](https://github.com/mikaelwaltersson) (Mikael Waltersson) + - [asunar](https://github.com/asunar) (Alper) + - [chucksavage](https://github.com/chucksavage) (Chuck Savage) + - [sashagit](https://github.com/sashagit) (Sasha) + - [froyke](https://github.com/froyke) (Froyke) + - [dbhobbs](https://github.com/dbhobbs) (Daniel Hobbs) + - [bculberson](https://github.com/bculberson) (Brad Culberson) + - [awr](https://github.com/awr) (Andrew) + - [pingvinen](https://github.com/pingvinen) (Patrick) + - [citndev](https://github.com/CITnDev) (Sebastien Curutchet) + - [cyberprune](https://github.com/cyberprune) + - [jorbor](https://github.com/jorbor) (Jordan Hayashi) + - [bojanv55](https://github.com/bojanv55) + - [i-e-b](https://github.com/i-e-b) (Iain Ballard) + - [pietervp](https://github.com/pietervp) (Pieter Van Parys) + - [franklinwise](https://github.com/franklinwise) + - [ckasabula](https://github.com/ckasabula) (Chuck Kasabula) + - [dortzur](https://github.com/dortzur) (Dor Tzur) + - [allenarthurgay](https://github.com/allenarthurgay) (Allen Gay) + - [viceberg](https://github.com/vIceBerg) + - [vansha](https://github.com/vansha) (Ivan Korneliuk) + - [aaronlerch](https://github.com/aaronlerch) (Aaron Lerch) + - [glikoz](https://github.com/glikoz) + - [danielcrenna](https://github.com/danielcrenna) (Daniel Crenna) + - [stevegraygh](https://github.com/stevegraygh) (Steve Graygh) + - [jrmitch120](https://github.com/jrmitch120) (Jeff Mitchell) + - [manuelnelson](https://github.com/manuelnelson) (Manuel Nelson) + - [babcca](https://github.com/babcca) (Petr Babicka) + - [jgeurts](https://github.com/jgeurts) (Jim Geurts) + - [driis](https://github.com/driis) (Dennis Riis) + - [gshackles](https://github.com/gshackles) (Greg Shackles) + - [jsonmez](https://github.com/jsonmez) (John Sonmez) + - [dchurchland](https://github.com/dchurchland) (David Churchland) + - [softwx](https://github.com/softwx) (Steve Hatchett) + - [ggeurts](https://github.com/ggeurts) (Gerke Geurts) + - [andrewrissing](https://github.com/AndrewRissing) (Andrew Rissing) + - [jjavery](https://github.com/jjavery) (James Javery) + - [suremaker](https://github.com/suremaker) (Wojtek) + - [cheesebaron](https://github.com/cheesebaron) (Tomasz Cielecki) + - [mikkelfish](https://github.com/mikkelfish) (Mikkel Fishman) + - [johngibb](https://github.com/johngibb) (John Gibb) + - [stabbylambda](https://github.com/stabbylambda) (David Stone) + - [mikepugh](https://github.com/mikepugh) (Mike Pugh) + - [permalmberg](https://github.com/permalmberg) (Per Malmberg) + - [adamralph](https://github.com/adamralph) (Adam Ralph) + - [shamsulamry](https://github.com/shamsulamry) (Shamsul Amry) + - [peterlazzarino](https://github.com/peterlazzarino) (Peter Lazzarino) + - [kevin-montrose](https://github.com/kevin-montrose) (Kevin Montrose) + - [msarchet](https://github.com/msarchet) (Michael Sarchet) + - [jeffgabhart](https://github.com/jeffgabhart) (Jeff Gabhart) + - [pkudinov](https://github.com/pkudinov) (Pavel Kudinov) + - [permalmberg](https://github.com/permalmberg) (Per Malmberg) + - [namman](https://github.com/namman) (Nick Miller) + - [leon-andria](https://github.com/leon-andria) (Leon Andria) + - [kkolstad](https://github.com/kkolstad) (Kenneth Kolstad) + - [electricshaman](https://github.com/electricshaman) (Jeff Smith) + - [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) + - [starteleport](https://github.com/starteleport) + - [jfoshee](https://github.com/jfoshee) (Jacob Foshee) + - [nardin](https://github.com/nardin) (Mamaev Michail) + - [cliffstill](https://github.com/cliffstill) + - [somya](https://github.com/somya) (Somya Jain) + - [thinkbeforecoding](https://github.com/thinkbeforecoding) (Jérémie Chassaing) + - [paksys](https://github.com/paksys) (Khalil Ahmad) + - [mcguinness](https://github.com/mcguinness) (Karl McGuinness) + - [jpasichnyk](https://github.com/jpasichnyk) (Jesse Pasichnyk) + - [waynebrantley](https://github.com/waynebrantley) (Wayne Brantley) + - [dcartoon](https://github.com/dcartoon) (Dan Cartoon) + - [alexvodovoz](https://github.com/alexvodovoz) (Alex Vodovoz) + - [jluchiji](https://github.com/jluchiji) (Denis Luchkin-Zhou) + - [grexican](https://github.com/grexican) + - [akoslukacs](https://github.com/akoslukacs) (Ákos Lukács) + - [medianick](https://github.com/medianick) (Nick Jones) + - [arhoads76](https://github.com/arhoads76) + - [dylanvdmerwe](https://github.com/dylanvdmerwe) (Dylan v.d Merwe) + - [mattiasw2](https://github.com/mattiasw2) (Mattias) + - [paultyng](https://github.com/paultyng) (Paul Tyng) + - [h2oman](https://github.com/h2oman) (Jason Waterman) + - [anewton](https://github.com/anewton) (Allen Newton) + - [sami1971](https://github.com/sami1971) + - [russellchadwick](https://github.com/russellchadwick) (Russell Chadwick) + - [cyberzed](https://github.com/cyberzed) (Stefan Daugaard Poulsen) + - [filipw](https://github.com/filipw) (Filip Wojcieszyn) + - [ghuntley](https://github.com/ghuntley) (Geoffrey Huntley) + - [baramuse](https://github.com/baramuse) + - [pdegenhardt](https://github.com/pdegenhardt) (Phil Degenhardt) + - [captncraig](https://github.com/captncraig) (Craig Peterson) + - [abattery](https://github.com/abattery) (Jae sung Chung) + - [biliktamas79](https://github.com/biliktamas79) + - [garuma](https://github.com/garuma) (Jérémie Laval) + - [dsimunic](https://github.com/dsimunic) + - [adamfowleruk](https://github.com/adamfowleruk) (Adam Fowler) + - [bfriesen](https://github.com/bfriesen) (Brian Friesen) + - [roryf](https://github.com/roryf) (Rory Fitzpatrick) + - [stefandevo](https://github.com/stefandevo) + - [gdassac](https://github.com/gdassac) + - [metal10k](https://github.com/metal10k) + - [cmelgarejo](https://github.com/cmelgarejo) + - [skaman](https://github.com/skaman) + - [rossipedia](https://github.com/rossipedia) (Bryan J. Ross) + - [wimatihomer](https://github.com/wimatihomer) (Wim Pool) + - [sword-breaker](https://github.com/sword-breaker) + - [adebisi-fa](https://github.com/adebisi-fa) (Adebisi Foluso A.) + - [mbischoff](https://github.com/mbischoff) (M. Bischoff) + - [ivanfioravanti](https://github.com/ivanfioravanti) (Ivan Fioravanti) + - [inhibition](https://github.com/inhibition) (Keith Hassen) + - [joshearl](https://github.com/joshearl) (Josh Earl) + - [friism](https://github.com/friism) (Michael Friis) + - [corkupine](https://github.com/corkupine) + - [bchavez](https://github.com/bchavez) (Brian Chavez) + - [nhhagen](https://github.com/nhhagen) (Niels Henrik Hagen) + - [daggmano](https://github.com/daggmano) (Darren Oster) + - [chappoo](https://github.com/chappoo) (Steve Chapman) + - [julrichkieffer](https://github.com/julrichkieffer) (Julrich Kieffer) + - [adamclarsen](https://github.com/adamclarsen) (Adam Larsen) + - [joero74](https://github.com/joero74) (Joerg Rosenkranz) + - [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) (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) + - [aleshi](https://github.com/aleshi) (Alexander Shiryaev) + - [alexandryz](https://github.com/alexandryz) (Alexandr Zaozerskiy) + - [mistobaan](https://github.com/mistobaan) (Fabrizio Milo) + - [niemyjski](https://github.com/niemyjski) (Blake Niemyjski) + - [alexandernyquist](https://github.com/alexandernyquist) (Alexander Nyquist) + - [mcduck76](https://github.com/mcduck76) + - [kojoru](https://github.com/kojoru) + - [jeremy-bridges](https://github.com/jeremy-bridges) (Jeremy Bridges) + - [andreabalducci](https://github.com/andreabalducci) (Andrea Balducci) + - [robertthegrey](https://github.com/RobertTheGrey) (Robert Greyling) + - [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) + - [connectassist](https://github.com/connectassist) (Carl Healy) + - [et1975](https://github.com/et1975) (Eugene Tolmachev) + - [barambani](https://github.com/barambani) + - [nhalm](https://github.com/et1975) + + +*** + +## Similar open source projects + +Similar Open source .NET projects for developing or accessing web services include: + + * [Nancy Fx](http://nancyfx.org) - A Sinatra-inspired lightweight Web Framework for .NET: + * [Fubu MVC](https://fubumvc.github.io/) - A "Front Controller" pattern-style MVC framework designed for use in web applications built on ASP.NET: + * [Rest Sharp](http://restsharp.org) - An open source REST client for .NET diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..8910a154ee1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +Please report security issues to https://servicestack.net/#contact diff --git a/build.cmd b/build.cmd deleted file mode 100644 index 79ae3e66758..00000000000 --- a/build.cmd +++ /dev/null @@ -1,8 +0,0 @@ -@echo off - -set target=%1 -if "%target%" == "" ( - set target=UnitTests -) - -%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild Build\build.msbuild /target:%target% /v:M /fl /flp:LogFile=msbuild.log;Verbosity=Normal /nr:false \ No newline at end of file diff --git a/build/7za.exe b/build/7za.exe deleted file mode 100644 index 06e8b434f73..00000000000 Binary files a/build/7za.exe and /dev/null differ diff --git a/build/build-common-core.proj b/build/build-common-core.proj new file mode 100644 index 00000000000..7904c64b0a5 --- /dev/null +++ b/build/build-common-core.proj @@ -0,0 +1,118 @@ + + + + + + 6 + 0 + $(BUILD_NUMBER) + + + + $(MSBuildProjectDirectory)/.. + $(BuildSolutionDir)/src + Release + $(BuildSolutionDir)/NuGet/ + $(MajorVersion).$(MinorVersion).$(PatchVersion) + + + + + BeforeBuildSolutions; + BuildSolutions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <Version>[^<]* + <Version>$(PackageVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/build-common.proj b/build/build-common.proj new file mode 100644 index 00000000000..7441da7383d --- /dev/null +++ b/build/build-common.proj @@ -0,0 +1,115 @@ + + + + + + 6 + 0 + $(BUILD_NUMBER) + + + + $(MSBuildProjectDirectory)/.. + $(BuildSolutionDir)/src + Release + $(BuildSolutionDir)/NuGet/ + $(MajorVersion).$(MinorVersion).$(PatchVersion) + + + + + BeforeBuildSolutions; + BuildSolutions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <Version>[^<]* + <Version>$(PackageVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/build-core.proj b/build/build-core.proj new file mode 100644 index 00000000000..df08fbea29d --- /dev/null +++ b/build/build-core.proj @@ -0,0 +1,175 @@ + + + + + + 6 + 0 + $(BUILD_NUMBER) + + + + $(MSBuildProjectDirectory)/.. + $(BuildSolutionDir)/src + Release + $(BuildSolutionDir)/NuGet/ + $(MajorVersion).$(MinorVersion).$(PatchVersion) + + + + + BeforeBuildSolutions; + BuildSolutions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <Version>[^<]* + <Version>$(PackageVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/build.bat b/build/build.bat index bb32a9587fa..7cd0981c96d 100644 --- a/build/build.bat +++ b/build/build.bat @@ -1,62 +1,4 @@ -SET MSBUILD=C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe - -REM SET BUILD=Debug -SET BUILD=Release - -REM %MSBUILD% build.msbuild - -MD ..\NuGet\ServiceStack\lib\net35 -MD ..\NuGet\ServiceStack\lib\net40 -MD ..\NuGet\ServiceStack.Common\lib\net35 -MD ..\NuGet\ServiceStack.Mvc\lib\net40 -MD ..\NuGet\ServiceStack.Plugins.ProtoBuf\lib\net35 - -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.dll ..\NuGet\ServiceStack\lib\net35 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.pdb ..\NuGet\ServiceStack\lib\net35 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.xml ..\NuGet\ServiceStack\lib\net35 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.ServiceInterface.* ..\NuGet\ServiceStack\lib\net35 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.dll ..\NuGet\ServiceStack\lib\net40 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.pdb ..\NuGet\ServiceStack\lib\net40 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.xml ..\NuGet\ServiceStack\lib\net40 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.ServiceInterface.* ..\NuGet\ServiceStack\lib\net40 -COPY ..\src\ServiceStack.Razor\bin\%BUILD%\ServiceStack.Razor.* ..\NuGet\ServiceStack\lib\net40 - -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.Common.* ..\NuGet\ServiceStack.Common\lib\net35 -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.Interfaces.* ..\NuGet\ServiceStack.Common\lib\net35 - -COPY ..\src\ServiceStack.FluentValidation.Mvc3\bin\%BUILD%\ServiceStack.FluentValidation.Mvc3.* ..\NuGet\ServiceStack.Mvc\lib\net40 -COPY ..\src\ServiceStack.FluentValidation.Mvc3\bin\%BUILD%\ServiceStack.FluentValidation.Mvc3.* ..\NuGet\ServiceStack.Mvc\lib\net40 - -COPY ..\src\ServiceStack.Plugins.ProtoBuf\bin\%BUILD%\ServiceStack.Plugins.ProtoBuf.* ..\NuGet\ServiceStack.Plugins.ProtoBuf\lib\net35 - - -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\*.* ..\..\chaweet\api\lib - -COPY ..\src\ServiceStack.Razor\bin\%BUILD%\*.* ..\..\ServiceStack.Examples\lib -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\*.* ..\..\ServiceStack.Examples\lib -COPY ..\src\ServiceStack\bin\%BUILD%\*.* ..\..\ServiceStack.Contrib\lib -COPY ..\src\ServiceStack\bin\%BUILD%\*.* ..\..\ServiceStack.RedisWebServices\lib -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\ServiceStack.ServiceInterface.* ..\..\ServiceStack.RedisWebServices\lib - -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Interfaces.dll ..\..\ServiceStack.Redis\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Text.dll ..\..\ServiceStack.Redis\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Text.pdb ..\..\ServiceStack.Redis\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Common.dll ..\..\ServiceStack.Redis\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Common.pdb ..\..\ServiceStack.Redis\lib - -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Interfaces.dll ..\..\ServiceStack.OrmLite\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Text.dll ..\..\ServiceStack.OrmLite\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Text.pdb ..\..\ServiceStack.OrmLite\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Common.dll ..\..\ServiceStack.OrmLite\lib -COPY ..\src\ServiceStack\bin\%BUILD%\ServiceStack.Common.pdb ..\..\ServiceStack.OrmLite\lib - -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.SqlServer\lib\*.* ..\release\latest\ServiceStack -COPY ..\..\ServiceStack.Redis\NuGet\lib\net35\*.* ..\release\latest\ServiceStack -COPY ..\..\ServiceStack.Text\NuGet\lib\net35\*.* ..\release\latest\ServiceStack -COPY ..\NuGet\ServiceStack\lib\*.* ..\release\latest\ServiceStack -COPY ..\NuGet\ServiceStack.Common\lib\*.* ..\release\latest\ServiceStack - -COPY ..\src\ServiceStack.ServiceInterface\bin\%BUILD%\*.* ..\..\SocialApiBootstrap\lib -COPY ..\src\ServiceStack.FluentValidation.Mvc3\bin\%BUILD%\ServiceStack.FluentValidation.Mvc3.* ..\..\SocialApiBootstrap\lib -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.SqlServer\lib\*.* ..\..\SocialApiBootstrap\lib -COPY ..\..\ServiceStack.Redis\NuGet\lib\net35\*.* ..\..\SocialApiBootstrap\lib +for /f "usebackq tokens=*" %%i in (`vswhere.exe -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do ( + SET MSBUILD="%%i" +) +%MSBUILD% build.proj /property:Configuration=Release;MinorVersion=8;PatchVersion=1 diff --git a/build/build.msbuild b/build/build.msbuild deleted file mode 100644 index c0a69efd626..00000000000 --- a/build/build.msbuild +++ /dev/null @@ -1,41 +0,0 @@ - - - $(MSBuildProjectDirectory)/.. - Release - /noshadow - - - - - BuildSolutions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/build.proj b/build/build.proj new file mode 100644 index 00000000000..f11eb49847d --- /dev/null +++ b/build/build.proj @@ -0,0 +1,229 @@ + + + + + + 6 + 0 + $(BUILD_NUMBER) + + + + $(MSBuildProjectDirectory)/.. + $(BuildSolutionDir)/src + Release + $(BuildSolutionDir)/NuGet/ + $(MajorVersion).$(MinorVersion).$(PatchVersion) + + + + + BeforeBuildSolutions; + BuildSolutions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <Version>[^<]* + <Version>$(PackageVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/build.tasks b/build/build.tasks new file mode 100644 index 00000000000..e9891357b2f --- /dev/null +++ b/build/build.tasks @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vswhere.exe b/build/vswhere.exe new file mode 100644 index 00000000000..1731aa6ed27 Binary files /dev/null and b/build/vswhere.exe differ diff --git a/lib/ServiceStack.Common.dll b/lib/ServiceStack.Common.dll deleted file mode 100755 index ca1ad5e58f5..00000000000 Binary files a/lib/ServiceStack.Common.dll and /dev/null differ diff --git a/lib/ServiceStack.Interfaces.dll b/lib/ServiceStack.Interfaces.dll deleted file mode 100755 index 955a13c6bd0..00000000000 Binary files a/lib/ServiceStack.Interfaces.dll and /dev/null differ diff --git a/lib/ServiceStack.OrmLite.SqlServer.dll b/lib/ServiceStack.OrmLite.SqlServer.dll deleted file mode 100644 index 69db26b958b..00000000000 Binary files a/lib/ServiceStack.OrmLite.SqlServer.dll and /dev/null differ diff --git a/lib/ServiceStack.OrmLite.Sqlite.dll b/lib/ServiceStack.OrmLite.Sqlite.dll deleted file mode 100644 index 762ff7c8bd9..00000000000 Binary files a/lib/ServiceStack.OrmLite.Sqlite.dll and /dev/null differ diff --git a/lib/ServiceStack.OrmLite.dll b/lib/ServiceStack.OrmLite.dll deleted file mode 100644 index 54f4b4b84ca..00000000000 Binary files a/lib/ServiceStack.OrmLite.dll and /dev/null differ diff --git a/lib/ServiceStack.OrmLite.pdb b/lib/ServiceStack.OrmLite.pdb deleted file mode 100644 index 7c3fac96e70..00000000000 Binary files a/lib/ServiceStack.OrmLite.pdb and /dev/null differ diff --git a/lib/ServiceStack.Redis.XML b/lib/ServiceStack.Redis.XML deleted file mode 100644 index c196bf407c7..00000000000 --- a/lib/ServiceStack.Redis.XML +++ /dev/null @@ -1,1478 +0,0 @@ - - - - ServiceStack.Redis - - - - - Enqueue item - - - - - - Dequeue up to maxBatchSize items from queue - - - - - - - Distributed lock interface - - - - - Wrap the common redis list operations under a IList[string] interface. - - - - - The client wraps the native redis operations into a more readable c# API. - - Where possible these operations are also exposed in common c# interfaces, - e.g. RedisClient.Lists => IList[string] - RedisClient.Sets => ICollection[string] - - - - - This class contains all the common operations for the RedisClient. - The client contains a 1:1 mapping of c# methods to redis operations of the same name. - - Not threadsafe use a pooled manager - - - - - Command to set multuple binary safe arguments - - - - - - - reset buffer index in send buffer - - - - - Requires custom result parsing - - Number of results - - - - Used to manage connection pooling - - - - - Gets or sets object key prefix. - - - - - Interface to Alchemy DB - http://code.google.com/p/alchemydatabase/ - - - - - Native interface to Alchemy DB - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Creates a new instance of the Redis Client from NewFactoryFn. - - - - - Returns key with automatic object id detection in provided value with generic type. - - - - - - - Returns key with explicit object id. - - - - - - - Returns key with explicit object type and id. - - - - - - - - Allows you to get Redis value operations to operate against POCO types. - - - - - - Use this to share the same redis connection with another - - The client. - - - - - - - - Redis operation (transaction/pipeline) that allows queued commands to be completed - - - - - Wrap the common redis set operations under a ICollection[string] interface. - - - - - Adds support for Redis Transactions (i.e. MULTI/EXEC/DISCARD operations). - - - - - Pipeline for redis typed client - - - - - - Queue of commands for redis typed client - - - - - - Put "QUEUED" messages at back of queue - - - - - - Issue exec command (not queued) - - - - - callback for after result count is read in - - - - - - distributed work item queue. Each message must have an associated - work item id. For a given id, all work items are guaranteed to be processed - in the order in which they are received. - - - - - distributed work item queue. Each message must have an associated - work item id. For a given id, all work items are guaranteed to be processed - in the order in which they are received. - - - - - - - distributed work item queue - - - - - Enqueue item in priority queue corresponding to workItemId identifier - - - - - - - Preprare next work item id for dequeueing - - - - - Dequeue up to maxBatchSize items from queue corresponding to workItemId identifier. - Once this method is called, or will not - return any items for workItemId until the dequeue lock returned is unlocked. - - - - - - - - Replace existing work item in workItemId queue - - - - - - - - Queue incoming messages - - - - - - - Must call this periodically to move work items from priority queue to pending queue - - - - - Replace existing work item in workItemId queue - - - - - - - - Pop items from list - - - - - - - Force release of locks held by crashed servers - - - - - release lock held by crashed server - - - - true if lock is released, either by this method or by another client; false otherwise - - - - Unlock work item id, so other servers can process items for this id - - - - - - - - - - - - - - - - - - - - - - - - - - - This class manages a write lock for a local readers/writer lock, - using the Resource Acquisition Is Initialization pattern - - - - - - RAII disposal - - - - - acquire distributed, non-reentrant lock on key - - global key for this lock - timeout for acquiring lock - timeout for lock, in seconds (stored as value against lock key) - - - - - - unlock key - - - - - - - - - - - - - distributed work item queue. Messages are processed in chronological order - - - - - Enqueue incoming messages - - - - - - - - Dequeue next batch of work items - - - - - - - - - Redis command that does not get queued - - - - - Ignore dispose on RedisClientsManager, which should be registered as a singleton - - - - - A complete redis command, with method to send command, receive response, and run callback on success or failure - - - - - Locking strategy interface - - - - - Optimized implementation. Primitive types are manually serialized, the rest are serialized using binary serializer />. - - - - - serialize/deserialize arbitrary objects - (objects must be serializable) - - - - - Serialize object to buffer - - serializable object - - - - - Deserialize buffer to object - - byte array to deserialize - - - - - - - - - - - - - - - - - - - serialize value and wrap with - - - - - - - Unwrap object wrapped in - - - - - - - manages a "region" in the redis key space - namespace can be cleared by incrementing the generation - - - - - get current generation - - - - - - set new generation - - - - - - redis key for generation - - - - - - get redis key that holds all namespace keys - - - - - - get global cache key - - - - - - - get global key inside of this namespace - - - prefixes can be added for name deconfliction - - - - - replace UniqueCharacter with its double, to avoid name clash - - - - - - - - - - - - - - get locking strategy - - - - - Represents a generic collection of key/value pairs that are ordered independently of the key and value. - - The type of the keys in the dictionary - The type of the values in the dictionary - - - - Represents a generic collection of key/value pairs that are ordered independently of the key and value. - - The type of the keys in the dictionary - The type of the values in the dictionary - - - - Adds an entry with the specified key and value into the IOrderedDictionary<TKey,TValue> collection with the lowest available index. - - The key of the entry to add. - The value of the entry to add. - The index of the newly added entry - - You can also use the property to add new elements by setting the value of a key that does not exist in the IOrderedDictionary<TKey,TValue> collection; however, if the specified key already exists in the IOrderedDictionary<TKey,TValue>, setting the property overwrites the old value. In contrast, the method does not modify existing elements. - An element with the same key already exists in the IOrderedDictionary<TKey,TValue> - The IOrderedDictionary<TKey,TValue> is read-only.
      - -or-
      - The IOrderedDictionary<TKey,TValue> has a fized size.
      -
      - - - Inserts a new entry into the IOrderedDictionary<TKey,TValue> collection with the specified key and value at the specified index. - - The zero-based index at which the element should be inserted. - The key of the entry to add. - The value of the entry to add. The value can be if the type of the values in the dictionary is a reference type. - is less than 0.
      - -or-
      - is greater than .
      - An element with the same key already exists in the IOrderedDictionary<TKey,TValue>. - The IOrderedDictionary<TKey,TValue> is read-only.
      - -or-
      - The IOrderedDictionary<TKey,TValue> has a fized size.
      -
      - - - Gets or sets the value at the specified index. - - The zero-based index of the value to get or set. - The value of the item at the specified index. - is less than 0.
      - -or-
      - is equal to or greater than .
      -
      - - - Initializes a new instance of the OrderedDictionary<TKey,TValue> class. - - - - - Initializes a new instance of the OrderedDictionary<TKey,TValue> class using the specified initial capacity. - - The initial number of elements that the OrderedDictionary<TKey,TValue> can contain. - is less than 0 - - - - Initializes a new instance of the OrderedDictionary<TKey,TValue> class using the specified comparer. - - The IEqualityComparer<TKey> to use when comparing keys, or to use the default EqualityComparer<TKey> for the type of the key. - - - - Initializes a new instance of the OrderedDictionary<TKey,TValue> class using the specified initial capacity and comparer. - - The initial number of elements that the OrderedDictionary<TKey,TValue> collection can contain. - The IEqualityComparer<TKey> to use when comparing keys, or to use the default EqualityComparer<TKey> for the type of the key. - is less than 0 - - - - Converts the object passed as a key to the key type of the dictionary - - The key object to check - The key object, cast as the key type of the dictionary - is . - The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . - - - - Converts the object passed as a value to the value type of the dictionary - - The object to convert to the value type of the dictionary - The value object, converted to the value type of the dictionary - is , and the value type of the OrderedDictionary<TKey,TValue> is a value type. - The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . - - - - Inserts a new entry into the OrderedDictionary<TKey,TValue> collection with the specified key and value at the specified index. - - The zero-based index at which the element should be inserted. - The key of the entry to add. - The value of the entry to add. The value can be if the type of the values in the dictionary is a reference type. - is less than 0.
      - -or-
      - is greater than .
      - is . - An element with the same key already exists in the OrderedDictionary<TKey,TValue>. -
      - - - Inserts a new entry into the OrderedDictionary<TKey,TValue> collection with the specified key and value at the specified index. - - The zero-based index at which the element should be inserted. - The key of the entry to add. - The value of the entry to add. The value can be if the type of the values in the dictionary is a reference type. - is less than 0.
      - -or-
      - is greater than .
      - is .
      - -or-
      - is , and the value type of the OrderedDictionary<TKey,TValue> is a value type.
      - The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      - -or-
      - The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      - -or-
      - An element with the same key already exists in the OrderedDictionary<TKey,TValue>.
      -
      - - - Removes the entry at the specified index from the OrderedDictionary<TKey,TValue> collection. - - The zero-based index of the entry to remove. - is less than 0.
      - -or-
      - index is equal to or greater than .
      -
      - - - Adds an entry with the specified key and value into the OrderedDictionary<TKey,TValue> collection with the lowest available index. - - The key of the entry to add. - The value of the entry to add. This value can be . - A key cannot be , but a value can be. - You can also use the property to add new elements by setting the value of a key that does not exist in the OrderedDictionary<TKey,TValue> collection; however, if the specified key already exists in the OrderedDictionary<TKey,TValue>, setting the property overwrites the old value. In contrast, the method does not modify existing elements. - is - An element with the same key already exists in the OrderedDictionary<TKey,TValue> - - - - Adds an entry with the specified key and value into the OrderedDictionary<TKey,TValue> collection with the lowest available index. - - The key of the entry to add. - The value of the entry to add. This value can be . - The index of the newly added entry - A key cannot be , but a value can be. - You can also use the property to add new elements by setting the value of a key that does not exist in the OrderedDictionary<TKey,TValue> collection; however, if the specified key already exists in the OrderedDictionary<TKey,TValue>, setting the property overwrites the old value. In contrast, the method does not modify existing elements. - is - An element with the same key already exists in the OrderedDictionary<TKey,TValue> - - - - Adds an entry with the specified key and value into the OrderedDictionary<TKey,TValue> collection with the lowest available index. - - The key of the entry to add. - The value of the entry to add. This value can be . - is .
      - -or-
      - is , and the value type of the OrderedDictionary<TKey,TValue> is a value type.
      - The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      - -or-
      - The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      -
      - - - Removes all elements from the OrderedDictionary<TKey,TValue> collection. - - The capacity is not changed as a result of calling this method. - - - - Determines whether the OrderedDictionary<TKey,TValue> collection contains a specific key. - - The key to locate in the OrderedDictionary<TKey,TValue> collection. - if the OrderedDictionary<TKey,TValue> collection contains an element with the specified key; otherwise, . - is - - - - Determines whether the OrderedDictionary<TKey,TValue> collection contains a specific key. - - The key to locate in the OrderedDictionary<TKey,TValue> collection. - if the OrderedDictionary<TKey,TValue> collection contains an element with the specified key; otherwise, . - is - The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . - - - - Returns the zero-based index of the specified key in the OrderedDictionary<TKey,TValue> - - The key to locate in the OrderedDictionary<TKey,TValue> - The zero-based index of , if is found in the OrderedDictionary<TKey,TValue>; otherwise, -1 - This method performs a linear search; therefore it has a cost of O(n) at worst. - - - - Removes the entry with the specified key from the OrderedDictionary<TKey,TValue> collection. - - The key of the entry to remove - if the key was found and the corresponding element was removed; otherwise, - - - - Removes the entry with the specified key from the OrderedDictionary<TKey,TValue> collection. - - The key of the entry to remove - - - - Copies the elements of the OrderedDictionary<TKey,TValue> elements to a one-dimensional Array object at the specified index. - - The one-dimensional object that is the destination of the objects copied from the OrderedDictionary<TKey,TValue>. The must have zero-based indexing. - The zero-based index in at which copying begins. - The method preserves the order of the elements in the OrderedDictionary<TKey,TValue> - - - - Gets the value associated with the specified key. - - The key of the value to get. - When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of . This parameter can be passed uninitialized. - if the OrderedDictionary<TKey,TValue> contains an element with the specified key; otherwise, . - - - - Adds the specified value to the OrderedDictionary<TKey,TValue> with the specified key. - - The KeyValuePair<TKey,TValue> structure representing the key and value to add to the OrderedDictionary<TKey,TValue>. - - - - Determines whether the OrderedDictionary<TKey,TValue> contains a specific key and value. - - The KeyValuePair<TKey,TValue> structure to locate in the OrderedDictionary<TKey,TValue>. - if is found in the OrderedDictionary<TKey,TValue>; otherwise, . - - - - Copies the elements of the OrderedDictionary<TKey,TValue> to an array of type , starting at the specified index. - - The one-dimensional array of type KeyValuePair<TKey,TValue> that is the destination of the KeyValuePair<TKey,TValue> elements copied from the OrderedDictionary<TKey,TValue>. The array must have zero-based indexing. - The zero-based index in at which copying begins. - - - - Removes a key and value from the dictionary. - - The KeyValuePair<TKey,TValue> structure representing the key and value to remove from the OrderedDictionary<TKey,TValue>. - if the key and value represented by is successfully found and removed; otherwise, . This method returns if is not found in the OrderedDictionary<TKey,TValue>. - - - - Gets the dictionary object that stores the keys and values - - The dictionary object that stores the keys and values for the OrderedDictionary<TKey,TValue> - Accessing this property will create the dictionary object if necessary - - - - Gets the list object that stores the key/value pairs. - - The list object that stores the key/value pairs for the OrderedDictionary<TKey,TValue> - Accessing this property will create the list object if necessary. - - - - Gets or sets the value at the specified index. - - The zero-based index of the value to get or set. - The value of the item at the specified index. - is less than 0.
      - -or-
      - index is equal to or greater than .
      -
      - - - Gets or sets the value at the specified index. - - The zero-based index of the value to get or set. - The value of the item at the specified index. - is less than 0.
      - -or-
      - index is equal to or greater than .
      - is a null reference, and the value type of the OrderedDictionary<TKey,TValue> is a value type. - The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . -
      - - - Gets a value indicating whether the OrderedDictionary<TKey,TValue> has a fixed size. - - if the OrderedDictionary<TKey,TValue> has a fixed size; otherwise, . The default is . - - - - Gets a value indicating whether the OrderedDictionary<TKey,TValue> collection is read-only. - - if the OrderedDictionary<TKey,TValue> is read-only; otherwise, . The default is . - - A collection that is read-only does not allow the addition, removal, or modification of elements after the collection is created. - A collection that is read-only is simply a collection with a wrapper that prevents modification of the collection; therefore, if changes are made to the underlying collection, the read-only collection reflects those changes. - - - - - Gets an object containing the keys in the OrderedDictionary<TKey,TValue>. - - An object containing the keys in the OrderedDictionary<TKey,TValue>. - The returned object is not a static copy; instead, the collection refers back to the keys in the original OrderedDictionary<TKey,TValue>. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the key collection. - - - - Gets an object containing the values in the OrderedDictionary<TKey,TValue> collection. - - An object containing the values in the OrderedDictionary<TKey,TValue> collection. - The returned object is not a static copy; instead, the refers back to the values in the original OrderedDictionary<TKey,TValue> collection. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the . - - - - Gets or sets the value with the specified key. - - The key of the value to get or set. - The value associated with the specified key. If the specified key is not found, attempting to get it returns , and attempting to set it creates a new element using the specified key. - - - - Gets or sets the value with the specified key. - - The key of the value to get or set. - The value associated with the specified key. If the specified key is not found, attempting to get it returns , and attempting to set it creates a new element using the specified key. - - - - Gets the number of key/values pairs contained in the OrderedDictionary<TKey,TValue> collection. - - The number of key/value pairs contained in the OrderedDictionary<TKey,TValue> collection. - - - - Gets a value indicating whether access to the OrderedDictionary<TKey,TValue> object is synchronized (thread-safe). - - This method always returns false. - - - - Gets an object that can be used to synchronize access to the OrderedDictionary<TKey,TValue> object. - - An object that can be used to synchronize access to the OrderedDictionary<TKey,TValue> object. - - - - Gets an ICollection<TKey> object containing the keys in the OrderedDictionary<TKey,TValue>. - - An ICollection<TKey> object containing the keys in the OrderedDictionary<TKey,TValue>. - The returned ICollection<TKey> object is not a static copy; instead, the collection refers back to the keys in the original OrderedDictionary<TKey,TValue>. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the key collection. - - - - Gets an ICollection<TValue> object containing the values in the OrderedDictionary<TKey,TValue>. - - An ICollection<TValue> object containing the values in the OrderedDictionary<TKey,TValue>. - The returned ICollection<TKey> object is not a static copy; instead, the collection refers back to the values in the original OrderedDictionary<TKey,TValue>. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the value collection. - - - - Wrap the common redis set operations under a ICollection[string] interface. - - - - - Wrap the common redis set operations under a ICollection[string] interface. - - - - - wraps a serialized representation of an object - - - - - - Initializes a new instance of . - - Custom item data. - The serialized item. - - - - The data representing the item being stored/retireved. - - - - - Flags set for this instance. - - - - - Useful wrapper IRedisClientsManager to cut down the boiler plat of most IRedisClient access - - - - - Wrap the common redis set operations under a ICollection[string] interface. - - - - - Adds a node and maps points across the circle - - node to add - An arbitrary number, specifies how often it occurs relative to other targets. - - - - A variation of Binary Search algorithm. Given a number, matches the next highest number from the sorted array. - If a higher number does not exist, then the first number in the array is returned. - - a sorted array to perform the search - number to find the next highest number against - next highest number - - - - Given a key, generates an unsigned 64 bit hash code using MD5 - - - - - - - Redis-specific exception. Thrown if unable to connect to Redis server due to socket exception, for example. - - - - - distributed lock class that follows the Resource Allocation Is Initialization pattern - - - - - Lock - - - - in seconds - in seconds - - - - unlock - - - - - Adds support for Redis Transactions (i.e. MULTI/EXEC/DISCARD operations). - - - - - General purpose pipeline - - - - - - Flush send buffer, and read responses - - - - - Put "QUEUED" messages at back of queue - - - - - - Issue exec command (not queued) - - - - - callback for after result count is read in - - - - - - Transient message queues are a one-pass message queue service that starts - processing messages when Start() is called. Any subsequent Start() calls - while the service is running is ignored. - - The transient service will continue to run until all messages have been - processed after which time it will shutdown all processing until Start() is called again. - - - - - Serialize object to buffer - - serializable object - - - - - - - array of serializable objects - - - - - Deserialize buffer to object - - byte array to deserialize - - - - - - customize the client serializer - - - - - Provides thread-safe pooling of redis client connections. - Allows load-balancing of master-write and read-slave hosts, ideal for - 1 master and multiple replicated read slaves. - - - For interoperabilty GetCacheClient() and GetReadOnlyCacheClient() - return an ICacheClient wrapper around the redis manager which has the affect of calling - GetClient() for all write operations and GetReadOnlyClient() for the read ones. - - This works well for master-slave replication scenarios where you have - 1 master that replicates to multiple read slaves. - - - - - Hosts can be an IP Address or Hostname in the format: host[:port] - e.g. 127.0.0.1:6379 - default is: localhost:6379 - - The write hosts. - The read hosts. - The config. - - - - Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts - - - - - - Called within a lock - - - - - - Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. - - - - - - Called within a lock - - - - - - Disposes the read only client. - - The client. - - - - Disposes the write client. - - The client. - - - - Gets or sets object key prefix. - - - - - Manage a client acquired from the PooledRedisClientManager - Dispose method will release the client back to the pool. - - - - - wrap the acquired client - - - - - - release the wrapped client back to the pool - - - - - access the wrapped client - - - - - Provide the default factory implementation for creating a RedisClient that - can be mocked and used by different 'Redis Client Managers' - - - - - Factory to create SerializingRedisClient objects - - - - - Wrap the common redis set operations under a ICollection[string] interface. - - - - - Wrap the common redis set operations under a ICollection[string] interface. - - - - - Creates a Redis MQ Server that processes each message on its own background thread. - i.e. if you register 3 handlers it will create 7 background threads: - - 1 listening to the Redis MQ Subscription, getting notified of each new message - - 3x1 Normal InQ for each message handler - - 3x1 PriorityQ for each message handler - - When RedisMqServer Starts it creates a background thread subscribed to the Redis MQ Topic that - listens for new incoming messages. It also starts 2 background threads for each message type: - - 1 for processing the services Priority Queue and 1 processing the services normal Inbox Queue. - - Priority Queue's can be enabled on a message-per-message basis by specifying types in the - OnlyEnablePriortyQueuesForTypes property. The DisableAllPriorityQueues property disables all Queues. - - The Start/Stop methods are idempotent i.e. It's safe to call them repeatedly on multiple threads - and the Redis MQ Server will only have Started or Stopped once. - - - - - Execute global transformation or custom logic before a request is processed. - Must be thread-safe. - - - - - Execute global transformation or custom logic on the response. - Must be thread-safe. - - - - - Execute global error handler logic. Must be thread-safe. - - - - - If you only want to enable priority queue handlers (and threads) for specific msg types - - - - - Don't listen on any Priority Queues - - - - - BasicRedisClientManager for ICacheClient - - For more interoperabilty I'm also implementing the ICacheClient on - this cache client manager which has the affect of calling - GetCacheClient() for all write operations and GetReadOnlyCacheClient() - for the read ones. - - This works well for master-slave replication scenarios where you have - 1 master that replicates to multiple read slaves. - - - Provides thread-safe retrievel of redis clients since each client is a new one. - Allows the configuration of different ReadWrite and ReadOnly hosts - - - - - Hosts can be an IP Address or Hostname in the format: host[:port] - e.g. 127.0.0.1:6379 - default is: localhost:6379 - - The write hosts. - The read hosts. - - - - Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts - - - - - - Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. - - - - - - Gets or sets object key prefix. - - - - - This class manages a read lock for a local readers/writer lock, - using the Resource Acquisition Is Initialization pattern - - - - - RAII initialization - - - - - - RAII disposal - - - - - A complete redis command, with method to send command, receive response, and run callback on success or failure - - - - - pop numProcessed items from queue and unlock queue for work item id that dequeued - items are associated with - - - - - - A dequeued work item has been processed. When all of the dequeued items have been processed, - all items will be popped from the queue,and the queue unlocked for the work item id that - the dequeued items are associated with - - - - - Update first unprocessed item with new work item. - - - - - - - - - - - pop remaining items that were returned by dequeue, and unlock queue - - - - - - indicate that an item has been processed by the caller - - - - - Update first unprocessed work item - - - - - - Provides a redis connection pool that can be sharded - - - - - logical name - - - - - An arbitrary weight relative to other nodes - - - - logical name - An arbitrary weight relative to other nodes - redis nodes - - - - Provides sharding of redis client connections. - uses consistent hashing to distribute keys across connection pools - - - - - maps a key to a redis connection pool - - key to map - a redis connection pool - - - - simple distributed work item queue - - - - - - - Queue incoming messages - - - - - - Dequeue next batch of work items for processing. After this method is called, - no other work items with same id will be available for - dequeuing until PostDequeue is called - - KeyValuePair: key is work item id, and value is list of dequeued items. - - - - - Courtesy of @marcgravell - http://code.google.com/p/protobuf-net/source/browse/trunk/protobuf-net/BufferPool.cs - - - - - Provide the factory implementation for creating a RedisCacheClient that - can be mocked and used by different 'Redis Client Managers' - - - - - Creates an MQ Host that processes all messages on a single background thread. - i.e. If you register 3 handlers it will only create 1 background thread. - - The same background thread that listens to the Redis MQ Subscription for new messages - also cycles through each registered handler processing all pending messages one-at-a-time: - first in the message PriorityQ, then in the normal message InQ. - - The Start/Stop methods are idempotent i.e. It's safe to call them repeatedly on multiple threads - and the Redis MQ Host will only have Started/Stopped once. - - - - - Inject your own Reply Client Factory to handle custom Message.ReplyTo urls. - - -
      -
      diff --git a/lib/ServiceStack.Redis.dll b/lib/ServiceStack.Redis.dll deleted file mode 100644 index bdbd51be52a..00000000000 Binary files a/lib/ServiceStack.Redis.dll and /dev/null differ diff --git a/lib/ServiceStack.Text.XML b/lib/ServiceStack.Text.XML deleted file mode 100644 index 1978417d7ec..00000000000 --- a/lib/ServiceStack.Text.XML +++ /dev/null @@ -1,534 +0,0 @@ - - - - ServiceStack.Text - - - - - Determines whether this serializer can create the specified type from a string. - - The type. - - true if this instance [can create from string] the specified type; otherwise, false. - - - - - Parses the specified value. - - The value. - - - - - Deserializes from reader. - - The reader. - - - - - Serializes to string. - - The value. - - - - - Serializes to writer. - - The value. - The writer. - - - - Parses the specified value. - - The value. - - - - - A class to allow the conversion of doubles to string representations of - their exact decimal values. The implementation aims for readability over - efficiency. - - Courtesy of @JonSkeet - http://www.yoda.arachsys.com/csharp/DoubleConverter.cs - - - - - - - - How many digits are *after* the decimal point - - - - - Constructs an arbitrary decimal expansion from the given long. - The long must not be negative. - - - - - Multiplies the current expansion by the given amount, which should - only be 2 or 5. - - - - - Shifts the decimal point; a negative value makes - the decimal expansion bigger (as fewer digits come after the - decimal place) and a positive value makes the decimal - expansion smaller. - - - - - Removes leading/trailing zeroes from the expansion. - - - - - Converts the value to a proper decimal string representation. - - - - - Implement the serializer using a more static approach - - - - - - Pretty Thread-Safe cache class from: - http://code.google.com/p/dapper-dot-net/source/browse/Dapper/SqlMapper.cs - - This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), - and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** - equality. The type is fully thread-safe. - - - - - A fast, standards-based, serialization-issue free DateTime serailizer. - - - - - Creates an instance of a Type from a string value - - - - - micro optimizations: using flags instead of value.IndexOfAny(EscapeChars) - - - - - - - Get the type(string) constructor if exists - - The type. - - - - - Implement the serializer using a more static approach - - - - - - Represents an individual object, allowing access to members by-name - - - - - Use the target types definition of equality - - - - - Obtain the hash of the target object - - - - - Use the target's definition of a string representation - - - - - Wraps an individual object, allowing by-name access to that instance - - - - - Get or Set the value of a named member for the underlying object - - - - - The object represented by this instance - - - - - if the is configured - to take advantage of specification, - to support user-friendly serialized formats, ie emitting camelCasing for JSON - and parsing member names and enum values in a case-insensitive manner. - - - - - Gets or sets a value indicating if the framework should throw serialization exceptions - or continue regardless of deserialization errors. If the framework - will throw; otherwise, it will parse as many fields as possible. The default is . - - - - - Sets which format to use when serializing TimeSpans - - - - - If set to true, Interface types will be prefered over concrete types when serializing. - - - - - Never emit type info for this type - - - - - if the is configured - to take advantage of specification, - to support user-friendly serialized formats, ie emitting camelCasing for JSON - and parsing member names and enum values in a case-insensitive manner. - - - - - Define custom serialization fn for BCL Structs - - - - - Define custom raw serialization fn - - - - - Define custom deserialization fn for BCL Structs - - - - - Exclude specific properties of this type from being serialized - - - - - Opt-in flag to set some Value Types to be treated as a Ref Type - - - - - Whether there is a fn (raw or otherwise) - - - - - Uses the xsd format like PT15H10M20S - - - - - Uses the standard .net ToString method of the TimeSpan class - - - - - Creates an instance of a Type from a string value - - - - - Determines whether the specified type is convertible from string. - - The type. - - true if the specified type is convertible from string; otherwise, false. - - - - - Parses the specified value. - - The value. - - - - - Parses the specified type. - - The type. - The value. - - - - - Useful extension method to get the Dictionary[string,string] representation of any POCO type. - - - - - - Recursively prints the contents of any POCO object in a human-friendly, readable format - - - - - - Print Dump to Console.WriteLine - - - - - Print string.Format to Console.WriteLine - - - - - A hashset implementation that uses an IDictionary - - - - - Shortcut escape when we're sure value doesn't contain any escaped chars - - - - - - - Since Silverlight doesn't have char.ConvertFromUtf32() so putting Mono's implemenation inline. - - - - - - - Get JSON string value converted to T - - - - - Get JSON string value - - - - - Get unescaped string value - - - - - Get unescaped string value - - - - - Get JSON string value - - - - - Class to hold - - - - - - @jonskeet: Collection of utility methods which operate on streams. - r285, February 26th 2009: http://www.yoda.arachsys.com/csharp/miscutil/ - - - - - Reads the given stream up to the end, returning the data as a byte - array. - - - - - Reads the given stream up to the end, returning the data as a byte - array, using the given buffer size. - - - - - Reads the given stream up to the end, returning the data as a byte - array, using the given buffer for transferring data. Note that the - current contents of the buffer is ignored, so the buffer needn't - be cleared beforehand. - - - - - Copies all the data from one stream into another. - - - - - Copies all the data from one stream into another, using a buffer - of the given size. - - - - - Copies all the data from one stream into another, using the given - buffer for transferring data. Note that the current contents of - the buffer is ignored, so the buffer needn't be cleared beforehand. - - - - - Reads exactly the given number of bytes from the specified stream. - If the end of the stream is reached before the specified amount - of data is read, an exception is thrown. - - - - - Reads into a buffer, filling it completely. - - - - - Reads exactly the given number of bytes from the specified stream, - into the given buffer, starting at position 0 of the array. - - - - - Reads exactly the given number of bytes from the specified stream, - into the given buffer, starting at position 0 of the array. - - - - - Same as ReadExactly, but without the argument checks. - - - - - Utils to load types - - - - - Find the type from the name supplied - - [typeName] or [typeName, assemblyName] - - - - - The top-most interface of the given type, if any. - - - - - Find type if it exists - - - - The type if it exists - - - - Converts from base: 0 - 62 - - The source. - From. - To. - - - - - Skip the encoding process for 'safe strings' - - - - - - - Provides by-name member-access to objects of a given type - - - - - Create a new instance of this type - - - - - Provides a type-specific accessor, allowing by-name access for all objects of that type - - The accessor is cached internally; a pre-existing accessor may be returned - - - - Does this type support new instances via a parameterless constructor? - - - - - Get or set the value of a named member on the target instance - - - - - Implement the serializer using a more static approach - - - - - - micro optimizations: using flags instead of value.IndexOfAny(EscapeChars) - - - - - - - Parses the specified value. - - The value. - - - - - WCF Json format: /Date(unixts+0000)/ - - - - - - - WCF Json format: /Date(unixts+0000)/ - - - - - - diff --git a/lib/ServiceStack.Text.dll b/lib/ServiceStack.Text.dll deleted file mode 100644 index 3ff1032214d..00000000000 Binary files a/lib/ServiceStack.Text.dll and /dev/null differ diff --git a/lib/ServiceStack.Ultimate.dll b/lib/ServiceStack.Ultimate.dll deleted file mode 100755 index 53633a5f688..00000000000 Binary files a/lib/ServiceStack.Ultimate.dll and /dev/null differ diff --git a/lib/System.Web.Mvc.dll b/lib/System.Web.Mvc.dll deleted file mode 100644 index eed0d994a05..00000000000 Binary files a/lib/System.Web.Mvc.dll and /dev/null differ diff --git a/lib/System.Web.Mvc.xml b/lib/System.Web.Mvc.xml deleted file mode 100644 index af648fcbf71..00000000000 --- a/lib/System.Web.Mvc.xml +++ /dev/null @@ -1,9395 +0,0 @@ - - - - System.Web.Mvc - - - - Represents an attribute that specifies which HTTP verbs an action method will respond to. - - - Initializes a new instance of the class by using a list of HTTP verbs that the action method will respond to. - The HTTP verbs that the action method will respond to. - The parameter is null or zero length. - - - Initializes a new instance of the class using the HTTP verbs that the action method will respond to. - The HTTP verbs that the action method will respond to. - - - Determines whether the specified method information is valid for the specified controller context. - true if the method information is valid; otherwise, false. - The controller context. - The method information. - The parameter is null. - - - Gets or sets the list of HTTP verbs that the action method will respond to. - The list of HTTP verbs that the action method will respond to. - - - Provides information about an action method, such as its name, controller, parameters, attributes, and filters. - - - Initializes a new instance of the class. - - - Gets the name of the action method. - The name of the action method. - - - Gets the controller descriptor. - The controller descriptor. - - - Executes the action method by using the specified parameters and controller context. - The result of executing the action method. - The controller context. - The parameters of the action method. - - - Returns an array of custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns an array of custom attributes that are defined for this member, identified by type. - An array of custom attributes, or an empty array if no custom attributes of the specified type exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - The parameter is null. - - - Returns the filters that are associated with this action method. - The filters that are associated with this action method. - - - Returns the parameters of the action method. - The parameters of the action method. - - - Returns the action-method selectors. - The action-method selectors. - - - Determines whether one or more instances of the specified attribute type are defined for this member. - true if is defined for this member; otherwise, false. - The type of the custom attribute. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The parameter is null. - - - Gets the unique ID for the action descriptor using lazy initialization. - The unique ID. - - - Provides the context for the ActionExecuted method of the class. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class. - The controller context. - The action method descriptor. - true if the action is canceled. - The exception object. - The parameter is null. - - - Gets or sets the action descriptor. - The action descriptor. - - - Gets or sets a value that indicates that this object is canceled. - true if the context canceled; otherwise, false. - - - Gets or sets the exception that occurred during the execution of the action method, if any. - The exception that occurred during the execution of the action method. - - - Gets or sets a value that indicates whether the exception is handled. - true if the exception is handled; otherwise, false. - - - Gets or sets the result returned by the action method. - The result returned by the action method. - - - Provides the context for the ActionExecuting method of the class. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified controller context, action descriptor, and action-method parameters. - The controller context. - The action descriptor. - The action-method parameters. - The or parameter is null. - - - Gets or sets the action descriptor. - The action descriptor. - - - Gets or sets the action-method parameters. - The action-method parameters. - - - Gets or sets the result that is returned by the action method. - The result that is returned by the action method. - - - Represents the base class for filter attributes. - - - Initializes a new instance of the class. - - - Called by the ASP.NET MVC framework after the action method executes. - The filter context. - - - Called by the ASP.NET MVC framework before the action method executes. - The filter context. - - - Called by the ASP.NET MVC framework after the action result executes. - The filter context. - - - Called by the ASP.NET MVC framework before the action result executes. - The filter context. - - - Represents an attribute that is used to influence the selection of an action method. - - - Initializes a new instance of the class. - - - Determines whether the action method selection is valid for the specified controller context. - true if the action method selection is valid for the specified controller context; otherwise, false. - The controller context. - Information about the action method. - - - Represents an attribute that is used for the name of an action. - - - Initializes a new instance of the class. - Name of the action. - The parameter is null or empty. - - - Determines whether the action name is valid within the specified controller context. - true if the action name is valid within the specified controller context; otherwise, false. - The controller context. - The name of the action. - Information about the action method. - - - Gets or sets the name of the action. - The name of the action. - - - Represents an attribute that affects the selection of an action method. - - - Initializes a new instance of the class. - - - Determines whether the action name is valid in the specified controller context. - true if the action name is valid in the specified controller context; otherwise, false. - The controller context. - The name of the action. - Information about the action method. - - - Encapsulates the result of an action method and is used to perform a framework-level operation on behalf of the action method. - - - Initializes a new instance of the class. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context in which the result is executed. The context information includes the controller, HTTP content, request context, and route data. - - - Represents a delegate that contains the logic for selecting an action method. - true if an action method was successfully selected; otherwise, false. - The current HTTP request context. - - - Provides a class that implements the interface in order to support additional metadata. - - - Initializes a new instance of the class. - The name of the model metadata. - The value of the model metadata. - - - Gets the name of the additional metadata attribute. - The name of the of the additional metadata attribute. - - - Provides metadata to the model metadata creation process. - - - Gets the type of the of the additional metadata attribute. - The type of the of the additional metadata attribute. - - - Gets the value of the of the additional metadata attribute. - The value of the of the additional metadata attribute. - - - Represents support for rendering HTML in AJAX scenarios within a view. - - - Initializes a new instance of the class using the specified view context and view data container. - The view context. - The view data container. - One or both of the parameters is null. - - - Initializes a new instance of the class by using the specified view context, view data container, and route collection. - The view context. - The view data container. - The URL route collection. - One or more of the parameters is null. - - - Gets or sets the root path for the location to use for globalization script files. - The location of the folder where globalization script files are stored. The default location is "~/Scripts/Globalization". - - - Serializes the specified message and returns the resulting JSON-formatted string. - The serialized message as a JSON-formatted string. - The message to serialize. - - - Gets the collection of URL routes for the application. - The collection of routes for the application. - - - Gets the context information about the view. - The context of the view. - - - Gets the current view data dictionary. - The view data dictionary. - - - Gets the view data container. - The view data container. - - - Represents support for rendering HTML in AJAX scenarios within a strongly typed view. - The type of the model. - - - Initializes a new instance of the class by using the specified view context and view data container. - The view context. - The view data container. - - - Initializes a new instance of the class by using the specified view context, view data container, and URL route collection. - The view context. - The view data container. - The URL route collection. - - - Gets the strongly typed version of the view data dictionary. - The strongly typed data dictionary of the view. - - - Represents a class that extends the class by adding the ability to determine whether an HTTP request is an AJAX request. - - - - Allows a request to include HTML markup during model binding by skipping request validation for the property. (It is strongly recommended that your application explicitly check all models where you disable request validation in order to prevent script exploits.) - - - Initializes a new instance of the class. - - - This method supports the ASP.NET MVC validation infrastructure and is not intended to be used directly from your code. - The model metadata. - - - Provides a way to register one or more areas in an ASP.NET MVC application. - - - Initializes a new instance of the class. - - - Gets the name of the area to register. - The name of the area to register. - - - Registers all areas in an ASP.NET MVC application. - - - Registers all areas in an ASP.NET MVC application by using the specified user-defined information. - An object that contains user-defined information to pass to the area. - - - Registers an area in an ASP.NET MVC application using the specified area's context information. - Encapsulates the information that is required in order to register the area. - - - Encapsulates the information that is required in order to register an area within an ASP.NET MVC application. - - - Initializes a new instance of the class using the specified area name and routes collection. - The name of the area to register. - The collection of routes for the application. - - - Initializes a new instance of the class using the specified area name, routes collection, and user-defined data. - The name of the area to register. - The collection of routes for the application. - An object that contains user-defined information to pass to the area. - - - Gets the name of the area to register. - The name of the area to register. - - - Maps the specified URL route and associates it with the area that is specified by the property. - A reference to the mapped route. - The name of the route. - The URL pattern for the route. - The parameter is null. - - - Maps the specified URL route and associates it with the area that is specified by the property, using the specified route default values. - A reference to the mapped route. - The name of the route. - The URL pattern for the route. - An object that contains default route values. - The parameter is null. - - - Maps the specified URL route and associates it with the area that is specified by the property, using the specified route default values and constraint. - A reference to the mapped route. - The name of the route. - The URL pattern for the route. - An object that contains default route values. - A set of expressions that specify valid values for a URL parameter. - The parameter is null. - - - Maps the specified URL route and associates it with the area that is specified by the property, using the specified route default values, constraints, and namespaces. - A reference to the mapped route. - The name of the route. - The URL pattern for the route. - An object that contains default route values. - A set of expressions that specify valid values for a URL parameter. - An enumerable set of namespaces for the application. - The parameter is null. - - - Maps the specified URL route and associates it with the area that is specified by the property, using the specified route default values and namespaces. - A reference to the mapped route. - The name of the route. - The URL pattern for the route. - An object that contains default route values. - An enumerable set of namespaces for the application. - The parameter is null. - - - Maps the specified URL route and associates it with the area that is specified by the property, using the specified namespaces. - A reference to the mapped route. - The name of the route. - The URL pattern for the route. - An enumerable set of namespaces for the application. - The parameter is null. - - - Gets the namespaces for the application. - An enumerable set of namespaces for the application. - - - Gets a collection of defined routes for the application. - A collection of defined routes for the application. - - - Gets an object that contains user-defined information to pass to the area. - An object that contains user-defined information to pass to the area. - - - Provides an abstract class to implement a metadata provider. - - - Called from constructors in a derived class to initialize the class. - - - When overridden in a derived class, creates the model metadata for the property. - The model metadata for the property. - The set of attributes. - The type of the container. - The model accessor. - The type of the model. - The name of the property. - - - Gets a list of attributes. - A list of attributes. - The type of the container. - The property descriptor. - The attribute container. - - - Returns a list of properties for the model. - A list of properties for the model. - The model container. - The type of the container. - - - Returns the metadata for the specified property using the container type and property descriptor. - The metadata for the specified property using the container type and property descriptor. - The model accessor. - The type of the container. - The property descriptor - - - Returns the metadata for the specified property using the container type and property name. - The metadata for the specified property using the container type and property name. - The model accessor. - The type of the container. - The name of the property. - - - Returns the metadata for the specified property using the type of the model. - The metadata for the specified property using the type of the model. - The model accessor. - The type of the model. - - - Returns the type descriptor from the specified type. - The type descriptor. - The type. - - - Provides an abstract class for classes that implement a validation provider. - - - Called from constructors in derived classes to initialize the class. - - - Gets a type descriptor for the specified type. - A type descriptor for the specified type. - The type of the validation provider. - - - Gets the validators for the model using the metadata and controller context. - The validators for the model. - The metadata. - The controller context. - - - Gets the validators for the model using the metadata, the controller context, and a list of attributes. - The validators for the model. - The metadata. - The controller context. - The list of attributes. - - - Provides the base class for asynchronous controllers. - - - Initializes a new instance of the class. - - - Gets the asynchronous manager instance. - The asynchronous manager instance. - - - Called by ASP.NET to initialize asynchronous request processing. - The status of the asynchronous operation. - The request context. - The asynchronous callback method. - The state object. - - - Called by ASP.NET during initialization of asynchronous request processing. - The status of the asynchronous operation. - The asynchronous callback method. - The state object. - - - Creates an action invoker. - An action invoker. - - - Cancels the execution of an asynchronous action method. - The status of the asynchronous result. - - - Called by ASP.NET when the current asynchronous action has completed. - The status of the asynchronous result. - - - Called by ASP.NET to begin the execution of an asynchronous action method. - The status of the asynchronous operation. - The request context. - The asynchronous callback method. - An object that contains information to be used by the callback method. This parameter can be null. - - - Cancels the execution of an asynchronous action method by ASP.NET at the end of the execution of an asynchronous action method. - The status of the asynchronous result. - - - Represents an attribute that is used to set the timeout value, in milliseconds, for an asynchronous method. - - - Initializes a new instance of the class. - The timeout value, in milliseconds. - - - Gets the timeout duration, in milliseconds. - The timeout duration, in milliseconds. - - - Called by ASP.NET before the asynchronous action method executes. - The filter context. - - - Encapsulates the information that is required for using an attribute. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified controller context. - The context within which the result is executed. The context information includes the controller, HTTP content, request context, and route data. - - - Initializes a new instance of the class using the specified controller context and action descriptor. - The context in which the result is executed. The context information includes the controller, HTTP content, request context, and route data. - An object that provides information about an action method, such as its name, controller, parameters, attributes, and filters. - - - Provides information about the action method that is marked by the attribute, such as its name, controller, parameters, attributes, and filters. - The action descriptor for the action method that is marked by the attribute. - - - Gets or sets the result that is returned by an action method. - The result that is returned by an action method. - - - Represents an attribute that is used to restrict access by callers to an action method. - - - Initializes a new instance of the class. - - - When overridden, provides an entry point for custom authorization checks. - true if the user is authorized; otherwise, false. - The HTTP context, which encapsulates all HTTP-specific information about an individual HTTP request. - The parameter is null. - - - Processes HTTP requests that fail authorization. - Encapsulates the information for using . The object contains the controller, HTTP context, request context, action result, and route data. - - - Called when a process requests authorization. - The filter context, which encapsulates information for using . - The parameter is null. - - - Called when the caching module requests authorization. - A reference to the validation status. - The HTTP context, which encapsulates all HTTP-specific information about an individual HTTP request. - The parameter is null. - - - Gets or sets the user roles. - The user roles. - - - Gets the unique identifier for this attribute. - The unique identifier for this attribute. - - - Gets or sets the authorized users. - The authorized users. - - - Represents an attribute that is used to provide details about how model binding to a parameter should occur. - - - Initializes a new instance of the class. - - - Gets or sets a comma-delimited list of property names for which binding is not allowed. - The exclude list. - - - Gets or sets a comma-delimited list of property names for which binding is allowed. - The include list. - - - Determines whether the specified property is allowed. - true if the specified property is allowed; otherwise, false. - The name of the property. - - - Gets or sets the prefix to use when markup is rendered for binding to an action argument or to a model property. - The prefix to use. - - - Represents the base class for views that are compiled by the BuildManager class before being rendered by a view engine. - - - Initializes a new instance of the class using the specified controller context and view path. - The controller context. - The view path. - - - Initializes a new instance of the class using the specified controller context, view path, and view page activator. - Context information for the current controller. This information includes the HTTP context, request context, route data, parent action view context, and more. - The path to the view that will be rendered. - The object responsible for dynamically constructing the view page at run time. - The parameter is null. - The parameter is null or empty. - - - Renders the specified view context by using the specified the writer object. - Information related to rendering a view, such as view data, temporary data, and form context. - The writer object. - The parameter is null. - An instance of the view type could not be created. - - - When overridden in a derived class, renders the specified view context by using the specified writer object and object instance. - Information related to rendering a view, such as view data, temporary data, and form context. - The writer object. - An object that contains additional information that can be used in the view. - - - Gets or sets the view path. - The view path. - - - Provides a base class for view engines. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified view page activator. - The view page activator. - - - Gets a value that indicates whether a file exists in the specified virtual file system (path). - true if the file exists in the virtual file system; otherwise, false. - The controller context. - The virtual path. - - - Gets the view page activator. - The view page activator. - - - Maps a browser request to a byte array. - - - Initializes a new instance of the class. - - - Binds the model by using the specified controller context and binding context. - The bound data object. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - The parameter is null. - - - Represents an attribute that is used to indicate that an action method should be called only as a child action. - - - Initializes a new instance of the class. - - - Called when authorization is required. - An object that encapsulates the information that is required in order to authorize access to the child action. - - - Represents a value provider for values from child actions. - - - Initializes a new instance of the class. - The controller context. - - - Retrieves a value object using the specified key. - The value object for the specified key. - The key. - - - Represents a factory for creating value provider objects for child actions. - - - Initializes a new instance of the class. - - - Returns a object for the specified controller context. - A object. - The controller context. - - - Returns the client data-type model validators. - - - Initializes a new instance of the class. - - - Returns the client data-type model validators. - The client data-type model validators. - The metadata. - The context. - - - Provides an attribute that compares two properties of a model. - - - Initializes a new instance of the class. - The property to compare with the current property. - - - Applies formatting to an error message based on the data field where the compare error occurred. - The formatted error message. - The name of the field that caused the validation failure. - - - Formats the property for client validation by prepending an asterisk (*) and a dot. - The string "*." is prepended to the property. - The property. - - - Gets a list of compare-value client validation rules for the property using the specified model metadata and controller context. - A list of compare-value client validation rules. - The model metadata. - The controller context. - - - Determines whether the specified object is equal to the compared object. - null if the value of the compared property is equal to the value parameter; otherwise, a validation result that contains the error message that indicates that the comparison failed. - The value of the object to compare. - The validation context. - - - Gets the property to compare with the current property. - The property to compare with the current property. - - - Represents a user-defined content type that is the result of an action method. - - - Initializes a new instance of the class. - - - Gets or sets the content. - The content. - - - Gets or sets the content encoding. - The content encoding. - - - Gets or sets the type of the content. - The type of the content. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context within which the result is executed. - The parameter is null. - - - Provides methods that respond to HTTP requests that are made to an ASP.NET MVC Web site. - - - Initializes a new instance of the class. - - - Gets the action invoker for the controller. - The action invoker. - - - Gets or sets the binder. - The binder. - - - Creates a content result object by using a string. - The content result instance. - The content to write to the response. - - - Creates a content result object by using a string and the content type. - The content result instance. - The content to write to the response. - The content type (MIME type). - - - Creates a content result object by using a string, the content type, and content encoding. - The content result instance. - The content to write to the response. - The content type (MIME type). - The content encoding. - - - Creates an action invoker. - An action invoker. - - - Creates a temporary data provider. - A temporary data provider. - - - Releases all resources that are used by the current instance of the class. - - - Releases unmanaged resources and optionally releases managed resources. - true to release both managed and unmanaged resources; false to release only unmanaged resources. - - - Invokes the action in the current controller context. - - - Creates a object by using the file contents and file type. - The file-content result object. - The binary content to send to the response. - The content type (MIME type). - - - Creates a object by using the file contents, content type, and the destination file name. - The file-content result object. - The binary content to send to the response. - The content type (MIME type). - The file name to use in the file-download dialog box that is displayed in the browser. - - - Creates a object by using the object and content type. - The file-content result object. - The stream to send to the response. - The content type (MIME type). - - - Creates a object using the object, the content type, and the target file name. - The file-stream result object. - The stream to send to the response. - The content type (MIME type) - The file name to use in the file-download dialog box that is displayed in the browser. - - - Creates a object by using the file name and the content type. - The file-stream result object. - The path of the file to send to the response. - The content type (MIME type). - - - Creates a object by using the file name, the content type, and the file download name. - The file-stream result object. - The path of the file to send to the response. - The content type (MIME type). - The file name to use in the file-download dialog box that is displayed in the browser. - - - Called when a request matches this controller, but no method with the specified action name is found in the controller. - The name of the attempted action. - - - Gets HTTP-specific information about an individual HTTP request. - The HTTP context. - - - Returns an instance of the class. - An instance of the class. - - - Returns an instance of the class. - An instance of the class. - The status description. - - - Initializes data that might not be available when the constructor is called. - The HTTP context and route data. - - - Creates a object. - The object that writes the script to the response. - The JavaScript code to run on the client - - - Creates a object that serializes the specified object to JavaScript Object Notation (JSON). - The JSON result object that serializes the specified object to JSON format. The result object that is prepared by this method is written to the response by the ASP.NET MVC framework when the object is executed. - The JavaScript object graph to serialize. - - - Creates a object that serializes the specified object to JavaScript Object Notation (JSON) format. - The JSON result object that serializes the specified object to JSON format. - The JavaScript object graph to serialize. - The content type (MIME type). - - - Creates a object that serializes the specified object to JavaScript Object Notation (JSON) format. - The JSON result object that serializes the specified object to JSON format. - The JavaScript object graph to serialize. - The content type (MIME type). - The content encoding. - - - Creates a object that serializes the specified object to JavaScript Object Notation (JSON) format using the content type, content encoding, and the JSON request behavior. - The result object that serializes the specified object to JSON format. - The JavaScript object graph to serialize. - The content type (MIME type). - The content encoding. - The JSON request behavior - - - Creates a object that serializes the specified object to JavaScript Object Notation (JSON) format using the specified content type and JSON request behavior. - The result object that serializes the specified object to JSON format. - The JavaScript object graph to serialize. - The content type (MIME type). - The JSON request behavior - - - Creates a object that serializes the specified object to JavaScript Object Notation (JSON) format using the specified JSON request behavior. - The result object that serializes the specified object to JSON format. - The JavaScript object graph to serialize. - The content type (MIME type). - - - Gets the model state dictionary object that contains the state of the model and of model-binding validation. - The model state dictionary. - - - Called after the action method is invoked. - Information about the current request and action. - - - Called before the action method is invoked. - Information about the current request and action. - - - Called when authorization occurs. - Information about the current request and action. - - - Called when an unhandled exception occurs in the action. - Information about the current request and action. - - - Called after the action result that is returned by an action method is executed. - Information about the current request and action result - - - Called before the action result that is returned by an action method is executed. - Information about the current request and action result - - - Creates a object that renders a partial view. - A partial-view result object. - - - Creates a object that renders a partial view, by using the specified model. - A partial-view result object. - The model that is rendered by the partial view - - - Creates a object that renders a partial view, by using the specified view name. - A partial-view result object. - The name of the view that is rendered to the response. - - - Creates a object that renders a partial view, by using the specified view name and model. - A partial-view result object. - The name of the view that is rendered to the response. - The model that is rendered by the partial view - - - Creates a object that redirects to the specified URL. - The redirect result object. - The URL to redirect to. - - - Returns an instance of the class with the property set to true. - An instance of the class with the property set to true. - The URL to redirect to. - - - Redirects to the specified action using the action name. - The redirect result object. - The name of the action. - - - Redirects to the specified action using the action name and route values. - The redirect result object. - The name of the action. - The parameters for a route. - - - Redirects to the specified action using the action name and controller name. - The redirect result object. - The name of the action. - The name of the controller - - - Redirects to the specified action using the action name, controller name, and route values. - The redirect result object. - The name of the action. - The name of the controller - The parameters for a route. - - - Redirects to the specified action using the action name, controller name, and route dictionary. - The redirect result object. - The name of the action. - The name of the controller - The parameters for a route. - - - Redirects to the specified action using the action name and route dictionary. - The redirect result object. - The name of the action. - The parameters for a route. - - - Returns an instance of the class with the property set to true using the specified action name. - An instance of the class with the property set to true using the specified action name, controller name, and route values. - The action name. - - - Returns an instance of the class with the property set to true using the specified action name, and route values. - An instance of the class with the property set to true using the specified action name, and route values. - The action name. - The route values. - - - Returns an instance of the class with the property set to true using the specified action name, and controller name. - An instance of the class with the property set to true using the specified action name, and controller name. - The action name. - The controller name. - - - Returns an instance of the class with the property set to true using the specified action name, controller name, and route values. - An instance of the class with the property set to true. - The action name. - The controller name. - The route values. - - - Returns an instance of the class with the property set to true using the specified action name, controller name, and route values. - An instance of the class with the property set to true using the specified action name, controller name, and route values. - The action name. - The controller name. - The route values. - - - Returns an instance of the class with the property set to true using the specified action name, and route values. - An instance of the class with the property set to true using the specified action name, and route values. - - - Redirects to the specified route using the specified route values. - The redirect-to-route result object. - The parameters for a route. - - - Redirects to the specified route using the route name. - The redirect-to-route result object. - The name of the route - - - Redirects to the specified route using the route name and route values. - The redirect-to-route result object. - The name of the route - The parameters for a route. - - - Redirects to the specified route using the route name and route dictionary. - The redirect-to-route result object. - The name of the route - The parameters for a route. - - - Redirects to the specified route using the route dictionary. - The redirect-to-route result object. - The parameters for a route. - - - Returns an instance of the class with the property set to true using the specified route values. - Returns . - The route name. - - - Returns an instance of the class with the property set to true using the specified route name. - Returns an instance of the class with the property set to true using the specified route name. - The route name. - - - Returns an instance of the class with the property set to true using the specified route name and route values. - An instance of the class with the property set to true. - The route name. - The route values. - - - Returns an instance of the class with the property set to true using the specified route name and route values. - An instance of the class with the property set to true using the specified route name and route values. - The route name. - The route values. - - - Returns an instance of the class with the property set to true using the specified route values. - An instance of the class with the property set to true using the specified route values. - The route values. - - - Gets the object for the current HTTP request. - The request object. - - - Gets the object for the current HTTP response. - The response object. - - - Gets the route data for the current request. - The route data. - - - Gets the object that provides methods that are used during Web request processing. - The HTTP server object. - - - Gets the object for the current HTTP request. - The HTTP session-state object for the current HTTP request. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The filter context. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The filter context. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The filter context. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The filter context. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The filter context. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The filter context. - - - Gets the temporary-data provider object that is used to store data for the next request. - The temporary-data provider. - - - Updates the specified model instance using values from the controller's current value provider. - true if the update is successful; otherwise, false. - The model instance to update. - The type of the model object. - The parameter or the property is null. - - - Updates the specified model instance using values from the controller's current value provider and a prefix. - true if the update is successful; otherwise, false. - The model instance to update. - The prefix to use when looking up values in the value provider. - The type of the model object. - The parameter or the property is null. - - - Updates the specified model instance using values from the controller's current value provider, a prefix, and included properties. - true if the update is successful; otherwise, false. - The model instance to update. - The prefix to use when looking up values in the value provider. - A list of properties of the model to update. - The type of the model object. - The parameter or the property is null. - - - Updates the specified model instance using values from the controller's current value provider, a prefix, a list of properties to exclude, and a list of properties to include. - true if the update is successful; otherwise, false. - The model instance to update. - The prefix to use when looking up values in the value provider - A list of properties of the model to update. - A list of properties to explicitly exclude from the update. These are excluded even if they are listed in the parameter list. - The type of the model object. - The parameter or the property is null. - - - Updates the specified model instance using values from the value provider, a prefix, a list of properties to exclude , and a list of properties to include. - true if the update is successful; otherwise, false. - The model instance to update. - The prefix to use when looking up values in the value provider. - A list of properties of the model to update. - A list of properties to explicitly exclude from the update. These are excluded even if they are listed in the parameter list. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the value provider, a prefix, and included properties. - true if the update is successful; otherwise, false. - The model instance to update. - The prefix to use when looking up values in the value provider. - A list of properties of the model to update. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the value provider and a prefix. - true if the update is successful; otherwise, false. - The model instance to update. - The prefix to use when looking up values in the value provider. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the controller's current value provider and included properties. - true if the update is successful; otherwise, false. - The model instance to update. - A list of properties of the model to update. - The type of the model object. - The parameter or the property is null. - - - Updates the specified model instance using values from the value provider and a list of properties to include. - true if the update is successful; otherwise, false. - The model instance to update. - A list of properties of the model to update. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the value provider. - true if the update is successful; otherwise, false. - The model instance to update. - A dictionary of values that is used to update the model. - The type of the model object. - - - Validates the specified model instance. - true if the model validation is successful; otherwise, false. - The model instance to validate. - - - Validates the specified model instance using an HTML prefix. - true if the model validation is successful; otherwise, false. - The model to validate. - The prefix to use when looking up values in the model provider. - - - Updates the specified model instance using values from the controller's current value provider. - The model instance to update. - The type of the model object. - The model was not successfully updated. - - - Updates the specified model instance using values from the controller's current value provider and a prefix. - The model instance to update. - A prefix to use when looking up values in the value provider. - The type of the model object. - - - Updates the specified model instance using values from the controller's current value provider, a prefix, and included properties. - The model instance to update. - A prefix to use when looking up values in the value provider. - A list of properties of the model to update. - The type of the model object. - - - Updates the specified model instance using values from the controller's current value provider, a prefix, a list of properties to exclude, and a list of properties to include. - The model instance to update. - A prefix to use when looking up values in the value provider. - A list of properties of the model to update. - A list of properties to explicitly exclude from the update. These are excluded even if they are listed in the list. - The type of the model object. - - - Updates the specified model instance using values from the value provider, a prefix, a list of properties to exclude, and a list of properties to include. - The model instance to update. - The prefix to use when looking up values in the value provider. - A list of properties of the model to update. - A list of properties to explicitly exclude from the update. These are excluded even if they are listed in the parameter list. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the value provider, a prefix, and a list of properties to include. - The model instance to update. - The prefix to use when looking up values in the value provider. - A list of properties of the model to update. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the value provider and a prefix. - The model instance to update. - The prefix to use when looking up values in the value provider. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the controller object's current value provider. - The model instance to update. - A list of properties of the model to update. - The type of the model object. - - - Updates the specified model instance using values from the value provider, a prefix, and a list of properties to include. - The model instance to update. - A list of properties of the model to update. - A dictionary of values that is used to update the model. - The type of the model object. - - - Updates the specified model instance using values from the value provider. - The model instance to update. - A dictionary of values that is used to update the model. - The type of the model object. - - - Gets the URL helper object that is used to generate URLs by using routing. - The URL helper object. - - - Gets the user security information for the current HTTP request. - The user security information for the current HTTP request. - - - Validates the specified model instance. - The model to validate. - - - Validates the specified model instance using an HTML prefix. - The model to validate. - The prefix to use when looking up values in the model provider. - - - Creates a object that renders a view to the response. - The view result that renders a view to the response. - - - Creates a object by using the model that renders a view to the response. - The view result. - The model that is rendered by the view. - - - Creates a object by using the view name that renders a view. - The view result. - The name of the view that is rendered to the response. - - - Creates a object by using the view name and model that renders a view to the response. - The view result. - The name of the view that is rendered to the response. - The model that is rendered by the view. - - - Creates a object using the view name and master-page name that renders a view to the response. - The view result. - The name of the view that is rendered to the response. - The name of the master page or template to use when the view is rendered. - - - Creates a object using the view name, master-page name, and model that renders a view. - The view result. - The name of the view that is rendered to the response. - The name of the master page or template to use when the view is rendered. - The model that is rendered by the view. - - - Creates a object that renders the specified object. - The view result. - The view that is rendered to the response. - - - Creates a object that renders the specified object. - The view result. - The view that is rendered to the response. - The model that is rendered by the view. - - - Represents a class that is responsible for invoking the action methods of a controller. - - - Initializes a new instance of the class. - - - Gets or sets the model binders that are associated with the action. - The model binders that are associated with the action. - - - Creates the action result. - The action result object. - The controller context. - The action descriptor. - The action return value. - - - Finds the information about the action method. - Information about the action method. - The controller context. - The controller descriptor. - The name of the action. - - - Retrieves information about the controller by using the specified controller context. - Information about the controller. - The controller context. - - - Retrieves information about the action filters. - Information about the action filters. - The controller context. - The action descriptor. - - - Gets the value of the specified action-method parameter. - The value of the action-method parameter. - The controller context. - The parameter descriptor. - - - Gets the values of the action-method parameters. - The values of the action-method parameters. - The controller context. - The action descriptor. - - - Invokes the specified action by using the specified controller context. - The result of executing the action. - The controller context. - The name of the action to invoke. - The parameter is null. - The parameter is null or empty. - The thread was aborted during invocation of the action. - An unspecified error occurred during invocation of the action. - - - Invokes the specified action method by using the specified parameters and the controller context. - The result of executing the action method. - The controller context. - The action descriptor. - The parameters. - - - Invokes the specified action method by using the specified parameters, controller context, and action filters. - The context for the ActionExecuted method of the class. - The controller context. - The action filters. - The action descriptor. - The parameters. - - - Invokes the specified action result by using the specified controller context. - The controller context. - The action result. - - - Invokes the specified action result by using the specified action filters and the controller context. - The context for the ResultExecuted method of the class. - The controller context. - The action filters. - The action result. - - - Invokes the specified authorization filters by using the specified action descriptor and controller context. - The context for the object. - The controller context. - The authorization filters. - The action descriptor. - - - Invokes the specified exception filters by using the specified exception and controller context. - The context for the object. - The controller context. - The exception filters. - The exception. - - - Represents the base class for all MVC controllers. - - - Initializes a new instance of the class. - - - Gets or sets the controller context. - The controller context. - - - Executes the specified request context. - The request context. - The parameter is null. - - - Executes the request. - - - Initializes the specified request context. - The request context. - - - Executes the specified request context. - The request context. - - - Gets or sets the dictionary for temporary data. - The dictionary for temporary data. - - - Gets or sets a value that indicates whether request validation is enabled for this request. - true if request validation is enabled for this request; otherwise, false. The default is true. - - - Gets or sets the value provider for the controller. - The value provider for the controller. - - - Gets the dynamic view data dictionary. - The dynamic view data dictionary. - - - Gets or sets the dictionary for view data. - The dictionary for the view data. - - - Represents a class that is responsible for dynamically building a controller. - - - Initializes a new instance of the class. - - - Gets the current controller builder object. - The current controller builder. - - - Gets the default namespaces. - The default namespaces. - - - Gets the associated controller factory. - The controller factory. - - - Sets the controller factory by using the specified type. - The type of the controller factory. - The parameter is null. - The controller factory cannot be assigned from the type in the parameter. - An error occurred while the controller factory was being set. - - - Sets the specified controller factory. - The controller factory. - The parameter is null. - - - Encapsulates information about an HTTP request that matches specified and instances. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified HTTP context, URL route data, and controller. - The HTTP context. - The route data. - The controller. - - - Initializes a new instance of the class by using the specified controller context. - The controller context. - The parameter is null. - - - Initializes a new instance of the class by using the specified request context and controller. - The request context. - The controller. - One or both parameters are null. - - - Gets or sets the controller. - The controller. - - - Gets or sets the HTTP context. - The HTTP context. - - - Gets a value that indicates whether the associated action method is a child action. - true if the associated action method is a child action; otherwise, false. - - - Gets an object that contains the view context information for the parent action method. - An object that contains the view context information for the parent action method. - - - Gets or sets the request context. - The request context. - - - Gets or sets the URL route data. - The URL route data. - - - Encapsulates information that describes a controller, such as its name, type, and actions. - - - Initializes a new instance of the class. - - - Gets the name of the controller. - The name of the controller. - - - Gets the type of the controller. - The type of the controller. - - - Finds an action method by using the specified name and controller context. - The information about the action method. - The controller context. - The name of the action. - - - Retrieves a list of action-method descriptors in the controller. - A list of action-method descriptors in the controller. - - - Retrieves custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Retrieves custom attributes of a specified type that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - The parameter is null (Nothing in Visual Basic). - - - Retrieves a value that indicates whether one or more instance of the specified custom attribute are defined for this member. - true if the is defined for this member; otherwise, false. - The type of the custom attribute. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The parameter is null (Nothing in Visual Basic). - - - When implemented in a derived class, gets the unique ID for the controller descriptor using lazy initialization. - The unique ID. - - - Adds the controller to the instance. - - - Initializes a new instance of the class. - - - Returns the collection of controller instance filters. - The collection of controller instance filters. - The controller context. - The action descriptor. - - - Represents an attribute that invokes a custom model binder. - - - Initializes a new instance of the class. - - - Retrieves the associated model binder. - A reference to an object that implements the interface. - - - Provides a container for common metadata, for the class, and for the class for a data model. - - - Initializes a new instance of the class. - The data-annotations model metadata provider. - The type of the container. - The model accessor. - The type of the model. - The name of the property. - The display column attribute. - - - Returns simple text for the model data. - Simple text for the model data. - - - Implements the default model metadata provider for ASP.NET MVC. - - - Initializes a new instance of the class. - - - Gets the metadata for the specified property. - The metadata for the property. - The attributes. - The type of the container. - The model accessor. - The type of the model. - The name of the property. - - - Represents the method that creates a instance. - - - Provides a model validator. - - - Initializes a new instance of the class. - The metadata for the model. - The controller context for the model. - The validation attribute for the model. - - - Gets the validation attribute for the model validator. - The validation attribute for the model validator. - - - Gets the error message for the validation failure. - The error message for the validation failure. - - - Retrieves a collection of client validation rules. - A collection of client validation rules. - - - Gets a value that indicates whether model validation is required. - true if model validation is required; otherwise, false. - - - Returns a list of validation error messages for the model. - A list of validation error messages for the model, or an empty list if no errors have occurred. - The container for the model. - - - Provides a model validator for a specified validation type. - - - - Initializes a new instance of the class. - The metadata for the model. - The controller context for the model. - The validation attribute for the model. - - - Gets the validation attribute from the model validator. - The validation attribute from the model validator. - - - Implements the default validation provider for ASP.NET MVC. - - - Initializes a new instance of the class. - - - Gets or sets a value that indicates whether non-nullable value types are required. - true if non-nullable value types are required; otherwise, false. - - - Gets a list of validators. - A list of validators. - The metadata. - The context. - The list of validation attributes. - - - Registers an adapter to provide client-side validation. - The type of the validation attribute. - The type of the adapter. - - - Registers an adapter factory for the validation provider. - The type of the attribute. - The factory that will be used to create the object for the specified attribute. - - - Registers the default adapter. - The type of the adapter. - - - Registers the default adapter factory. - The factory that will be used to create the object for the default adapter. - - - Registers an adapter to provide default object validation. - The type of the adapter. - - - Registers an adapter factory for the default object validation provider. - The factory. - - - Registers an adapter to provide object validation. - The type of the model. - The type of the adapter. - - - Registers an adapter factory for the object validation provider. - The type of the model. - The factory. - - - Provides a factory for validators that are based on . - - - Provides a container for the error-information model validator. - - - Initializes a new instance of the class. - - - Gets a list of error-information model validators. - A list of error-information model validators. - The model metadata. - The controller context. - - - Represents the controller factory that is registered by default. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using a controller activator. - An object that implements the controller activator interface. - - - Creates the specified controller by using the specified request context. - The controller. - The context of the HTTP request, which includes the HTTP context and route data. - The name of the controller. - The parameter is null. - The parameter is null or empty. - - - Retrieves the controller instance for the specified request context and controller type. - The controller instance. - The context of the HTTP request, which includes the HTTP context and route data. - The type of the controller. - - is null. - - cannot be assigned. - An instance of cannot be created. - - - Returns the controller's session behavior. - The controller's session behavior. - The request context. - The type of the controller. - - - Retrieves the controller type for the specified name and request context. - The controller type. - The context of the HTTP request, which includes the HTTP context and route data. - The name of the controller. - - - Releases the specified controller. - The controller to release. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. This method calls the method. - The controller's session behavior. - The request context. - The controller name. - - - Maps a browser request to a data object. This class provides a concrete implementation of a model binder. - - - Initializes a new instance of the class. - - - Gets or sets the model binders for the application. - The model binders for the application. - - - Binds the model by using the specified controller context and binding context. - The bound object. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - The parameter is null. - - - Binds the specified property by using the specified controller context and binding context and the specified property descriptor. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - Describes a property to be bound. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value. - - - Creates the specified model type by using the specified controller context and binding context. - A data object of the specified type. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - The type of the model object to return. - - - Creates an index (a subindex) based on a category of components that make up a larger index, where the specified index value is an integer. - The name of the subindex. - The prefix for the subindex. - The index value. - - - Creates an index (a subindex) based on a category of components that make up a larger index, where the specified index value is a string. - The name of the subindex. - The prefix for the subindex. - The index value. - - - Creates the name of the subproperty by using the specified prefix and property name. - The name of the subproperty. - The prefix for the subproperty. - The name of the property. - - - Returns a set of properties that match the property filter restrictions that are established by the specified . - An enumerable set of property descriptors. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - - - Returns the properties of the model by using the specified controller context and binding context. - A collection of property descriptors. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - - - Returns the value of a property using the specified controller context, binding context, property descriptor, and property binder. - An object that represents the property value. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - The descriptor for the property to access. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value. - An object that provides a way to bind the property. - - - Returns the descriptor object for a type that is specified by its controller context and binding context. - A custom type descriptor object. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - - - Determines whether a data model is valid for the specified binding context. - true if the model is valid; otherwise, false. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - The parameter is null. - - - Called when the model is updated. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - - - Called when the model is updating. - true if the model is updating; otherwise, false. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - - - Called when the specified property is validated. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - Describes a property to be validated. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value. - The value to set for the property. - - - Called when the specified property is validating. - true if the property is validating; otherwise, false. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - Describes a property being validated. The descriptor provides information such as component type, property type, and property value. It also provides methods to get or set the property value. - The value to set for the property. - - - Gets or sets the name of the resource file (class key) that contains localized string values. - The name of the resource file (class key). - - - Sets the specified property by using the specified controller context, binding context, and property value. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - Describes a property to be set. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value. - The value to set for the property. - - - Represents a memory cache for view locations. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified cache time span. - The cache time span. - The Ticks attribute of the parameter is set to a negative number. - - - Retrieves the default view location by using the specified HTTP context and cache key. - The default view location. - The HTTP context. - The cache key - The parameter is null. - - - Inserts the view in the specified virtual path by using the specified HTTP context, cache key, and virtual path. - The HTTP context. - The cache key. - The virtual path - The parameter is null. - - - Creates an empty view location cache. - - - Gets or sets the cache time span. - The cache time span. - - - Provides a registration point for dependency resolvers that implement or the Common Service Locator IServiceLocator interface. - - - Initializes a new instance of the class. - - - Gets the implementation of the dependency resolver. - The implementation of the dependency resolver. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - The implementation of the dependency resolver. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - The function that provides the service. - The function that provides the services. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - The common service locator. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - The object that implements the dependency resolver. - - - Provides a registration point for dependency resolvers using the specified service delegate and specified service collection delegates. - The service delegate. - The services delegates. - - - Provides a registration point for dependency resolvers using the provided common service locator when using a service locator interface. - The common service locator. - - - Provides a registration point for dependency resolvers, using the specified dependency resolver interface. - The dependency resolver. - - - Provides a type-safe implementation of and . - - - Resolves singly registered services that support arbitrary object creation. - The requested service or object. - The dependency resolver instance that this method extends. - The type of the requested service or object. - - - Resolves multiply registered services. - The requested services. - The dependency resolver instance that this method extends. - The type of the requested services. - - - Represents the base class for value providers whose values come from a collection that implements the interface. - The type of the value. - - - Initializes a new instance of the class. - The name/value pairs that are used to initialize the value provider. - Information about a specific culture, such as the names of the culture, the writing system, and the calendar used. - The parameter is null. - - - Determines whether the collection contains the specified prefix. - true if the collection contains the specified prefix; otherwise, false. - The prefix to search for. - The parameter is null. - - - Returns a value object using the specified key and controller context. - The value object for the specified key. - The key of the value object to retrieve. - The parameter is null. - - - Provides an empty metadata provider for data models that do not require metadata. - - - Initializes a new instance of the class. - - - Creates a new instance of the class. - A new instance of the class. - The attributes. - The type of the container. - The model accessor. - The type of the model. - The name of the model. - - - Provides an empty validation provider for models that do not require a validator. - - - Initializes a new instance of the class. - - - Gets the empty model validator. - The empty model validator. - The metadata. - The context. - - - Represents a result that does nothing, such as a controller action method that returns nothing. - - - Initializes a new instance of the class. - - - Executes the specified result context. - The result context. - - - Provides the context for using the class. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class for the specified exception by using the specified controller context. - The controller context. - The exception. - The parameter is null. - - - Gets or sets the exception object. - The exception object. - - - Gets or sets a value that indicates whether the exception has been handled. - true if the exception has been handled; otherwise, false. - - - Gets or sets the action result. - The action result. - - - Provides a helper class to get the model name from an expression. - - - Gets the model name from a lambda expression. - The model name. - The expression. - - - Gets the model name from a string expression. - The model name. - The expression. - - - Provides a container for client-side field validation metadata. - - - Initializes a new instance of the class. - - - Gets or sets the name of the data field. - The name of the data field. - - - Gets or sets a value that indicates whether the validation message contents should be replaced with the client validation error. - true if the validation message contents should be replaced with the client validation error; otherwise, false. - - - Gets or sets the validator message ID. - The validator message ID. - - - Gets the client validation rules. - The client validation rules. - - - Sends the contents of a binary file to the response. - - - Initializes a new instance of the class by using the specified file contents and content type. - The byte array to send to the response. - The content type to use for the response. - The parameter is null. - - - The binary content to send to the response. - The file contents. - - - Writes the file content to the response. - The response. - - - Sends the contents of a file to the response. - - - Initializes a new instance of the class by using the specified file name and content type. - The name of the file to send to the response. - The content type of the response. - The parameter is null or empty. - - - Gets or sets the path of the file that is sent to the response. - The path of the file that is sent to the response. - - - Writes the file to the response. - The response. - - - Represents a base class that is used to send binary file content to the response. - - - Initializes a new instance of the class. - The type of the content. - The parameter is null or empty. - - - Gets the content type to use for the response. - The type of the content. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context within which the result is executed. - The parameter is null. - - - Gets or sets the content-disposition header so that a file-download dialog box is displayed in the browser with the specified file name. - The name of the file. - - - Writes the file to the response. - The response. - - - Sends binary content to the response by using a instance. - - - Initializes a new instance of the class. - The stream to send to the response. - The content type to use for the response. - The parameter is null. - - - Gets the stream that will be sent to the response. - The file stream. - - - Writes the file to the response. - The response. - - - Represents a metadata class that contains a reference to the implementation of one or more of the filter interfaces, the filter's order, and the filter's scope. - - - Initializes a new instance of the class. - The instance. - The scope. - The order. - - - Represents a constant that is used to specify the default ordering of filters. - - - Gets the instance of this class. - The instance of this class. - - - Gets the order in which the filter is applied. - The order in which the filter is applied. - - - Gets the scope ordering of the filter. - The scope ordering of the filter. - - - Represents the base class for action and result filter attributes. - - - Initializes a new instance of the class. - - - Gets or sets a value that indicates whether more than one instance of the filter attribute can be specified. - true if more than one instance of the filter attribute can be specified; otherwise, false. - - - Gets or sets the order in which the action filters are executed. - The order in which the action filters are executed. - - - Defines a filter provider for filter attributes. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class and optionally caches attribute instances. - true to cache attribute instances; otherwise, false. - - - Gets a collection of custom action attributes. - A collection of custom action attributes. - The controller context. - The action descriptor. - - - Gets a collection of controller attributes. - A collection of controller attributes. - The controller context. - The action descriptor. - - - Aggregates the filters from all of the filter providers into one collection. - The collection filters from all of the filter providers. - The controller context. - The action descriptor. - - - Encapsulates information about the available action filters. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified filters collection. - The filters collection. - - - Gets all the action filters in the application. - The action filters. - - - Gets all the authorization filters in the application. - The authorization filters. - - - Gets all the exception filters in the application. - The exception filters. - - - Gets all the result filters in the application. - The result filters. - - - Represents the collection of filter providers for the application. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the filter providers collection. - The filter providers collection. - - - Returns the collection of filter providers. - The collection of filter providers. - The controller context. - The action descriptor. - - - Provides a registration point for filters. - - - Provides a registration point for filters. - The collection of filters. - - - Defines values that specify the order in which ASP.NET MVC filters run within the same filter type and filter order. - - - Specifies first. - - - Specifies an order before and after . - - - Specifies an order before and after . - - - Specifies an order before and after . - - - Specifies last. - - - Contains the form value providers for the application. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class. - The collection. - The parameter is null. - - - Gets the specified value provider. - The value provider. - The name of the value provider to get. - The parameter is null or empty. - - - Gets a value that indicates whether the value provider contains an entry that has the specified prefix. - true if the value provider contains an entry that has the specified prefix; otherwise, false. - The prefix to look for. - - - Gets a value from a value provider using the specified key. - A value from a value provider. - The key. - - - Returns a dictionary that contains the value providers. - A dictionary of value providers. - - - Encapsulates information that is required in order to validate and process the input data from an HTML form. - - - Initializes a new instance of the class. - - - Gets the field validators for the form. - A dictionary of field validators for the form. - - - Gets or sets the form identifier. - The form identifier. - - - Returns a serialized object that contains the form identifier and field-validation values for the form. - A serialized object that contains the form identifier and field-validation values for the form. - - - Returns the validation value for the specified input field. - The value to validate the field input with. - The name of the field to retrieve the validation value for. - The parameter is either null or empty. - - - Returns the validation value for the specified input field and a value that indicates what to do if the validation value is not found. - The value to validate the field input with. - The name of the field to retrieve the validation value for. - true to create a validation value if one is not found; otherwise, false. - The parameter is either null or empty. - - - Returns a value that indicates whether the specified field has been rendered in the form. - true if the field has been rendered; otherwise, false. - The field name. - - - Sets a value that indicates whether the specified field has been rendered in the form. - The field name. - true to specify that the field has been rendered in the form; otherwise, false. - - - Determines whether client validation errors should be dynamically added to the validation summary. - true if client validation errors should be added to the validation summary; otherwise, false. - - - Gets or sets the identifier for the validation summary. - The identifier for the validation summary. - - - Enumerates the HTTP request types for a form. - - - Specifies a GET request. - - - Specifies a POST request. - - - Represents a value provider for form values that are contained in a object. - - - Initializes a new instance of the class. - An object that encapsulates information about the current HTTP request. - - - Represents a class that is responsible for creating a new instance of a form-value provider object. - - - Initializes a new instance of the class. - - - Returns a form-value provider object for the specified controller context. - A form-value provider object. - An object that encapsulates information about the current HTTP request. - The parameter is null. - - - Represents a class that contains all the global filters. - - - Initializes a new instance of the class. - - - Adds the specified filter to the global filter collection. - The filter. - - - Adds the specified filter to the global filter collection using the specified filter run order. - The filter. - The filter run order. - - - Removes all filters from the global filter collection. - - - Determines whether a filter is in the global filter collection. - true if is found in the global filter collection; otherwise, false. - The filter. - - - Gets the number of filters in the global filter collection. - The number of filters in the global filter collection. - - - Returns an enumerator that iterates through the global filter collection. - An enumerator that iterates through the global filter collection. - - - Removes all the filters that match the specified filter. - The filter to remove. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - An enumerator that iterates through the global filter collection. - - - This API supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - An enumerator that iterates through the global filter collection. - The controller context. - The action descriptor. - - - Represents the global filter collection. - - - Gets or sets the global filter collection. - The global filter collection. - - - Represents an attribute that is used to handle an exception that is thrown by an action method. - - - Initializes a new instance of the class. - - - Gets or sets the type of the exception. - The type of the exception. - - - Gets or sets the master view for displaying exception information. - The master view. - - - Called when an exception occurs. - The action-filter context. - The parameter is null. - - - Gets the unique identifier for this attribute. - The unique identifier for this attribute. - - - Gets or sets the page view for displaying exception information. - The page view. - - - Encapsulates information for handling an error that was thrown by an action method. - - - Initializes a new instance of the class. - The exception. - The name of the controller. - The name of the action. - The parameter is null. - The or parameter is null or empty. - - - Gets or sets the name of the action that was executing when the exception was thrown. - The name of the action. - - - Gets or sets the name of the controller that contains the action method that threw the exception. - The name of the controller. - - - Gets or sets the exception object. - The exception object. - - - Represents an attribute that is used to indicate whether a property or field value should be rendered as a hidden input element. - - - Initializes a new instance of the class. - - - Gets or sets a value that indicates whether to display the value of the hidden input element. - true if the value should be displayed; otherwise, false. - - - Represents support for rendering HTML controls in a view. - - - Initializes a new instance of the class by using the specified view context and view data container. - The view context. - The view data container. - The or the parameter is null. - - - Initializes a new instance of the class by using the specified view context, view data container, and route collection. - The view context. - The view data container. - The route collection. - One or more parameters is null. - - - Replaces underscore characters (_) with hyphens (-) in the specified HTML attributes. - The HTML attributes with underscore characters replaced by hyphens. - The HTML attributes. - - - Generates a hidden form field (anti-forgery token) that is validated when the form is submitted. - The generated form field (anti-forgery token). - - - Generates a hidden form field (anti-forgery token) that is validated when the form is submitted. The field value is generated using the specified salt value. - The generated form field (anti-forgery token). - The salt value, which can be any non-empty string. - - - Generates a hidden form field (anti-forgery token) that is validated when the form is submitted. The field value is generated using the specified salt value, domain, and path. - The generated form field (anti-forgery token). - The salt value, which can be any non-empty string. - The application domain. - The virtual path. - - - Converts the specified attribute object to an HTML-encoded string. - The HTML-encoded string. If the value parameter is null or empty, this method returns an empty string. - The object to encode. - - - Converts the specified attribute string to an HTML-encoded string. - The HTML-encoded string. If the value parameter is null or empty, this method returns an empty string. - The string to encode. - - - Gets or sets a value that indicates whether client validation is enabled. - true if enable client validation is enabled; otherwise, false. - - - Enables input validation that is performed by using client script in the browser. - - - Enables or disables client validation. - true to enable client validation; otherwise, false. - - - Enables unobtrusive JavaScript. - - - Enables or disables unobtrusive JavaScript. - true to enable unobtrusive JavaScript; otherwise, false. - - - Converts the value of the specified object to an HTML-encoded string. - The HTML-encoded string. - The object to encode. - - - Converts the specified string to an HTML-encoded string. - The HTML-encoded string. - The string to encode. - - - Creates an HTML element ID using the specified element name. - The ID of the HTML element. - The name of the HTML element. - The parameter is null. - - - Creates an HTML element ID using the specified element name and a string that replaces dots in the name. - The ID of the HTML element. - The name of the HTML element. - The string that replaces dots (.) in the parameter. - The parameter or the parameter is null. - - - Generates an HTML anchor element (a element) that links to the specified action method, and enables the user to specify the communication protocol, name of the host, and a URL fragment. - An HTML element that links to the specified action method. - The context of the HTTP request. - The collection of URL routes. - The text caption to display for the link. - The name of the route that is used to return a virtual path. - The name of the action method. - The name of the controller. - The communication protocol, such as HTTP or HTTPS. If this parameter is null, the protocol defaults to HTTP. - The name of the host. - The fragment identifier. - An object that contains the parameters for a route. - An object that contains the HTML attributes for the element. - - - Generates an HTML anchor element (a element) that links to the specified action method. - An HTML element that links to the specified action method. - The context of the HTTP request. - The collection of URL routes. - The text caption to display for the link. - The name of the route that is used to return a virtual path. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - An object that contains the HTML attributes for the element. - - - Generates an HTML anchor element (a element) that links to the specified URL route, and enables the user to specify the communication protocol, name of the host, and a URL fragment. - An HTML element that links to the specified URL route. - The context of the HTTP request. - The collection of URL routes. - The text caption to display for the link. - The name of the route that is used to return a virtual path. - The communication protocol, such as HTTP or HTTPS. If this parameter is null, the protocol defaults to HTTP. - The name of the host. - The fragment identifier. - An object that contains the parameters for a route. - An object that contains the HTML attributes for the element. - - - Generates an HTML anchor element (a element) that links to the specified URL route. - An HTML element that links to the specified URL route. - The context of the HTTP request. - The collection of URL routes. - The text caption to display for the link. - The name of the route that is used to return a virtual path. - An object that contains the parameters for a route. - An object that contains the HTML attributes for the element. - - - Returns the HTTP method that handles form input (GET or POST) as a string. - The form method string, either "get" or "post". - The HTTP method that handles the form. - - - Returns the HTML input control type as a string. - The input type string ("checkbox", "hidden", "password", "radio", or "text"). - The enumerated input type. - - - Gets the collection of unobtrusive JavaScript validation attributes using the specified HTML name attribute. - The collection of unobtrusive JavaScript validation attributes. - The HTML name attribute. - - - Gets the collection of unobtrusive JavaScript validation attributes using the specified HTML name attribute and model metadata. - The collection of unobtrusive JavaScript validation attributes. - The HTML name attribute. - The model metadata. - - - Returns a hidden input element that identifies the override method for the specified HTTP data-transfer method that was used by the client. - The override method that uses the HTTP data-transfer method that was used by the client. - The HTTP data-transfer method that was used by the client (DELETE, HEAD, or PUT). - The parameter is not "PUT", "DELETE", or "HEAD". - - - Returns a hidden input element that identifies the override method for the specified verb that represents the HTTP data-transfer method used by the client. - The override method that uses the verb that represents the HTTP data-transfer method used by the client. - The verb that represents the HTTP data-transfer method used by the client. - The parameter is not "PUT", "DELETE", or "HEAD". - - - Gets or sets the character that replaces periods in the ID attribute of an element. - The character that replaces periods in the ID attribute of an element. - - - Returns markup that is not HTML encoded. - The HTML markup without encoding. - The HTML markup. - - - Gets or sets the collection of routes for the application. - The collection of routes for the application. - - - Gets or sets a value that indicates whether unobtrusive JavaScript is enabled. - true if unobtrusive JavaScript is enabled; otherwise, false. - - - The name of the CSS class that is used to style an input field when a validation error occurs. - - - The name of the CSS class that is used to style an input field when the input is valid. - - - The name of the CSS class that is used to style the error message when a validation error occurs. - - - The name of the CSS class that is used to style the validation message when the input is valid. - - - The name of the CSS class that is used to style validation summary error messages. - - - The name of the CSS class that is used to style the validation summary when the input is valid. - - - Gets or sets the context information about the view. - The context of the view. - - - Gets the current view data dictionary. - The view data dictionary. - - - Gets or sets the view data container. - The view data container. - - - Represents support for rendering HTML controls in a strongly typed view. - The type of the model. - - - Initializes a new instance of the class by using the specified view context and view data container. - The view context. - The view data container. - - - Initializes a new instance of the class by using the specified view context, view data container, and route collection. - The view context. - The view data container. - The route collection. - - - Gets the strongly typed view data dictionary. - The strongly typed view data dictionary. - - - Represents an attribute that is used to restrict an action method so that the method handles only HTTP DELETE requests. - - - Initializes a new instance of the class. - - - Determines whether a request is a valid HTTP DELETE request. - true if the request is valid; otherwise, false. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - Encapsulates information about a method, such as its type, return type, and arguments. - - - Represents a value provider to use with values that come from a collection of HTTP files. - - - Initializes a new instance of the class. - An object that encapsulates information about the current HTTP request. - - - Represents a class that is responsible for creating a new instance of an HTTP file collection value provider object. - - - Initializes a new instance of the class. - - - Returns a value provider object for the specified controller context. - An HTTP file collection value provider. - An object that encapsulates information about the HTTP request. - The parameter is null. - - - Represents an attribute that is used to restrict an action method so that the method handles only HTTP GET requests. - - - Initializes a new instance of the class. - - - Determines whether a request is a valid HTTP GET request. - true if the request is valid; otherwise, false. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - Encapsulates information about a method, such as its type, return type, and arguments. - - - Defines an object that is used to indicate that the requested resource was not found. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using a status description. - The status description. - - - Represents an attribute that is used to restrict an action method so that the method handles only HTTP POST requests. - - - Initializes a new instance of the class. - - - Determines whether a request is a valid HTTP POST request. - true if the request is valid; otherwise, false. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - Encapsulates information about a method, such as its type, return type, and arguments. - - - Binds a model to a posted file. - - - Initializes a new instance of the class. - - - Binds the model. - The bound value. - The controller context. - The binding context. - One or both parameters are null. - - - Represents an attribute that is used to restrict an action method so that the method handles only HTTP PUT requests. - - - Initializes a new instance of the class. - - - Determines whether a request is a valid HTTP PUT request. - true if the request is valid; otherwise, false. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - Encapsulates information about a method, such as its type, return type, and arguments. - - - Extends the class that contains the HTTP values that were sent by a client during a Web request. - - - Retrieves the HTTP data-transfer method override that was used by the client. - The HTTP data-transfer method override that was used by the client. - An object that contains the HTTP values that were sent by a client during a Web request. - The parameter is null. - The HTTP data-transfer method override was not implemented. - - - Provides a way to return an action result with a specific HTTP response status code and description. - - - Initializes a new instance of the class using a status code. - The status code. - - - Initializes a new instance of the class using a status code and status description. - The status code. - The status description. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context in which the result is executed. The context information includes the controller, HTTP content, request context, and route data. - - - Gets the HTTP status code. - The HTTP status code. - - - Gets the HTTP status description. - the HTTP status description. - - - Represents the result of an unauthorized HTTP request. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the status description. - The status description. - - - Enumerates the HTTP verbs. - - - Retrieves the information or entity that is identified by the URI of the request. - - - Posts a new entity as an addition to a URI. - - - Replaces an entity that is identified by a URI. - - - Requests that a specified URI be deleted. - - - Retrieves the message headers for the information or entity that is identified by the URI of the request. - - - Defines the methods that are used in an action filter. - - - Called after the action method executes. - The filter context. - - - Called before an action method executes. - The filter context. - - - Defines the contract for an action invoker, which is used to invoke an action in response to an HTTP request. - - - Invokes the specified action by using the specified controller context. - true if the action was found; otherwise, false. - The controller context. - The name of the action. - - - Defines the methods that are required for an authorization filter. - - - Called when authorization is required. - The filter context. - - - Provides a way for the ASP.NET MVC validation framework to discover at run time whether a validator has support for client validation. - - - When implemented in a class, returns client validation rules for that class. - The client validation rules for this validator. - The model metadata. - The controller context. - - - Defines the methods that are required for a controller. - - - Executes the specified request context. - The request context. - - - Provides fine-grained control over how controllers are instantiated using dependency injection. - - - When implemented in a class, creates a controller. - The created controller. - The request context. - The controller type. - - - Defines the methods that are required for a controller factory. - - - Creates the specified controller by using the specified request context. - The controller. - The request context. - The name of the controller. - - - Gets the controller's session behavior. - The controller's session behavior. - The request context. - The name of the controller whose session behavior you want to get. - - - Releases the specified controller. - The controller. - - - Defines the methods that simplify service location and dependency resolution. - - - Resolves singly registered services that support arbitrary object creation. - The requested service or object. - The type of the requested service or object. - - - Resolves multiply registered services. - The requested services. - The type of the requested services. - - - Defines the methods that are required for an exception filter. - - - Called when an exception occurs. - The filter context. - - - Provides an interface for finding filters. - - - Returns an enumerator that contains all the instances in the service locator. - The enumerator that contains all the instances in the service locator. - The controller context. - The action descriptor. - - - Provides an interface for exposing attributes to the class. - - - When implemented in a class, provides metadata to the model metadata creation process. - The model metadata. - - - Defines the methods that are required for a model binder. - - - Binds the model to a value by using the specified controller context and binding context. - The bound value. - The controller context. - The binding context. - - - Defines methods that enable dynamic implementations of model binding for classes that implement the interface. - - - Returns the model binder for the specified type. - The model binder for the specified type. - The type of the model. - - - Defines members that specify the order of filters and whether multiple filters are allowed. - - - When implemented in a class, gets or sets a value that indicates whether multiple filters are allowed. - true if multiple filters are allowed; otherwise, false. - - - When implemented in a class, gets the filter order. - The filter order. - - - Enumerates the types of input controls. - - - A check box. - - - A hidden field. - - - A password box. - - - A radio button. - - - A text box. - - - Defines the methods that are required for a result filter. - - - Called after an action result executes. - The filter context. - - - Called before an action result executes. - The filter context. - - - Associates a route with an area in an ASP.NET MVC application. - - - Gets the name of the area to associate the route with. - The name of the area to associate the route with. - - - Defines the contract for temporary-data providers that store data that is viewed on the next request. - - - Loads the temporary data. - The temporary data. - The controller context. - - - Saves the temporary data. - The controller context. - The values. - - - Represents an interface that can skip request validation. - - - Retrieves the value of the object that is associated with the specified key. - The value of the object for the specified key. - The key. - true if validation should be skipped; otherwise, false. - - - Defines the methods that are required for a value provider in ASP.NET MVC. - - - Determines whether the collection contains the specified prefix. - true if the collection contains the specified prefix; otherwise, false. - The prefix to search for. - - - Retrieves a value object using the specified key. - The value object for the specified key. - The key of the value object to retrieve. - - - Defines the methods that are required for a view. - - - Renders the specified view context by using the specified the writer object. - The view context. - The writer object. - - - Defines the methods that are required for a view data dictionary. - - - Gets or sets the view data dictionary. - The view data dictionary. - - - Defines the methods that are required for a view engine. - - - Finds the specified partial view by using the specified controller context. - The partial view. - The controller context. - The name of the partial view. - true to specify that the view engine returns the cached view, if a cached view exists; otherwise, false. - - - Finds the specified view by using the specified controller context. - The page view. - The controller context. - The name of the view. - The name of the master. - true to specify that the view engine returns the cached view, if a cached view exists; otherwise, false. - - - Releases the specified view by using the specified controller context. - The controller context. - The view. - - - Defines the methods that are required in order to cache view locations in memory. - - - Gets the view location by using the specified HTTP context and the cache key. - The view location. - The HTTP context. - The cache key. - - - Inserts the specified view location into the cache by using the specified HTTP context and the cache key. - The HTTP context. - The cache key. - The virtual path. - - - Provides fine-grained control over how view pages are instantiated using dependency injection. - - - The created view page. - The controller context. - The type of the controller. - - - Sends JavaScript content to the response. - - - Initializes a new instance of the class. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context within which the result is executed. - The parameter is null. - - - Gets or sets the script. - The script. - - - Specifies whether HTTP GET requests from the client are allowed. - - - HTTP GET requests from the client are allowed. - - - HTTP GET requests from the client are not allowed. - - - Represents a class that is used to send JSON-formatted content to the response. - - - Initializes a new instance of the class. - - - Gets or sets the content encoding. - The content encoding. - - - Gets or sets the type of the content. - The type of the content. - - - Gets or sets the data. - The data. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context within which the result is executed. - The parameter is null. - - - Gets or sets a value that indicates whether HTTP GET requests from the client are allowed. - A value that indicates whether HTTP GET requests from the client are allowed. - - - Enables action methods to send and receive JSON-formatted text and to model-bind the JSON text to parameters of action methods. - - - Initializes a new instance of the class. - - - Returns a JSON value-provider object for the specified controller context. - A JSON value-provider object for the specified controller context. - The controller context. - - - Maps a browser request to a LINQ object. - - - Initializes a new instance of the class. - - - Binds the model by using the specified controller context and binding context. - The bound data object. If the model cannot be bound, this method returns null. - The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data. - The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider. - - - Represents an attribute that is used to associate a model type to a model-builder type. - - - Initializes a new instance of the class. - The type of the binder. - The parameter is null. - - - Gets or sets the type of the binder. - The type of the binder. - - - Retrieves an instance of the model binder. - A reference to an object that implements the interface. - An error occurred while an instance of the model binder was being created. - - - Represents a class that contains all model binders for the application, listed by binder type. - - - Initializes a new instance of the class. - - - Adds the specified item to the model binder dictionary. - The object to add to the instance. - The object is read-only. - - - Adds the specified item to the model binder dictionary using the specified key. - The key of the element to add. - The value of the element to add. - The object is read-only. - - is null. - An element that has the same key already exists in the object. - - - Removes all items from the model binder dictionary. - The object is read-only. - - - Determines whether the model binder dictionary contains a specified value. - true if is found in the model binder dictionary; otherwise, false. - The object to locate in the object. - - - Determines whether the model binder dictionary contains an element that has the specified key. - true if the model binder dictionary contains an element that has the specified key; otherwise, false. - The key to locate in the object. - - is null. - - - Copies the elements of the model binder dictionary to an array, starting at a specified index. - The one-dimensional array that is the destination of the elements copied from . The array must have zero-based indexing. - The zero-based index in at which copying starts. - - is null. - - is less than 0. - - is multidimensional.-or- is equal to or greater than the length of .-or- The number of elements in the source object is greater than the available space from to the end of the destination array. -or- Type cannot be cast automatically to the type of the destination array. - - - Gets the number of elements in the model binder dictionary. - The number of elements in the model binder dictionary. - - - Gets or sets the default model binder. - The default model binder. - - - Retrieves the model binder for the specified type. - The model binder. - The type of the model to retrieve. - The parameter is null. - - - Retrieves the model binder for the specified type or retrieves the default model binder. - The model binder. - The type of the model to retrieve. - true to retrieve the default model binder. - The parameter is null. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Gets a value that indicates whether the model binder dictionary is read-only. - true if the model binder dictionary is read-only; otherwise, false. - - - Gets or sets the specified key in an object that implements the interface. - The key for the specified item. - The item key. - - - Gets a collection that contains the keys in the model binder dictionary. - A collection that contains the keys in the model binder dictionary. - - - Removes the first occurrence of the specified element from the model binder dictionary. - true if was successfully removed from the model binder dictionary; otherwise, false. This method also returns false if is not found in the model binder dictionary. - The object to remove from the object. - The object is read-only. - - - Removes the element that has the specified key from the model binder dictionary. - true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the model binder dictionary. - The key of the element to remove. - The object is read-only. - - is null. - - - Returns an enumerator that can be used to iterate through a collection. - An enumerator that can be used to iterate through the collection. - - - Gets the value that is associated with the specified key. - true if the object that implements contains an element that has the specified key; otherwise, false. - The key of the value to get. - When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - - is null. - - - Gets a collection that contains the values in the model binder dictionary. - A collection that contains the values in the model binder dictionary. - - - Provides a container for model binder providers. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using a list of model binder providers. - A list of model binder providers. - - - Returns a model binder of the specified type. - A model binder of the specified type. - The type of the model binder. - - - Inserts a model binder provider into the at the specified index. - The index. - The model binder provider. - - - Replaces the model binder provider element at the specified index. - The index. - The model binder provider. - - - Provides a container for model binder providers. - - - Provides a registration point for model binder providers for applications that do not use dependency injection. - The model binder provider collection. - - - Provides global access to the model binders for the application. - - - Gets the model binders for the application. - The model binders for the application. - - - Provides the context in which a model binder functions. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the binding context. - The binding context. - - - Gets or sets a value that indicates whether the binder should use an empty prefix. - true if the binder should use an empty prefix; otherwise, false. - - - Gets or sets the model. - The model. - - - Gets or sets the model metadata. - The model metadata. - - - Gets or sets the name of the model. - The name of the model. - - - Gets or sets the state of the model. - The state of the model. - - - Gets or sets the type of the model. - The type of the model. - - - Gets or sets the property filter. - The property filter. - - - Gets the property metadata. - The property metadata. - - - Gets or sets the value provider. - The value provider. - - - Provides a container for an equality validation rule that is sent to the browser. - - - Initializes a new instance of the class. - The error message. - The model value used for equality comparison. - - - Provides a container for a range-validation rule that is sent to the browser. - - - Initializes a new instance of the class. - The error message. - The minimum value. - The maximum value. - - - Provides a container for a regular-expression client validation rule that is sent to the browser. - - - Initializes a new instance of the class. - The error message to display when the regular expression validation fails. - The regular expression. - - - Provides a container for a remote validation rule that is sent to the browser. - - - Initializes a new instance of the class. - The error message. - The URL for the validation parameters. - The HTTP method for the validation parameters. - - - Provides a container for client validation for required field. - - - Initializes a new instance of the class. - The error message to display when a value for the required field is not provided. - - - Provides a base class container for a client validation rule that is sent to the browser. - - - Initializes a new instance of the class. - - - Gets or sets the error message for the client validation rule. - The error message for the client validation rule. - - - Gets the list of validation parameters. - A list of validation parameters. - - - Gets or sets the validation type. - The validation type. - - - Provides a container for a string-length validation rule that is sent to the browser. - - - Initializes a new instance of the class. - The validation error message. - The minimum length of the string. - The maximum length of the string. - - - Represents an error that occurs during model binding. - - - Initializes a new instance of the class by using the specified exception. - The exception. - The parameter is null. - - - Initializes a new instance of the class by using the specified exception and error message. - The exception. - The error message. - The parameter is null. - - - Initializes a new instance of the class by using the specified error message. - The error message. - - - Gets or sets the error message. - The error message. - - - Gets or sets the exception object. - The exception object. - - - A collection of instances. - - - Initializes a new instance of the class. - - - Adds the specified object to the model-error collection. - The exception. - - - Adds the specified error message to the model-error collection. - The error message. - - - Provides a container for common metadata, for the class, and for the class for a data model. - - - Initializes a new instance of the class. - The provider. - The type of the container. - The model accessor. - The type of the model. - The name of the model. - - - Gets a dictionary that contains additional metadata about the model. - A dictionary that contains additional metadata about the model. - - - Gets or sets the type of the container for the model. - The type of the container for the model. - - - Gets or sets a value that indicates whether empty strings that are posted back in forms should be converted to null. - true if empty strings that are posted back in forms should be converted to null; otherwise, false. The default value is true. - - - Gets or sets meta information about the data type. - Meta information about the data type. - - - The default order value, which is 10000. - - - Gets or sets the description of the model. - The description of the model. The default value is null. - - - Gets or sets the display format string for the model. - The display format string for the model. - - - Gets or sets the display name of the model. - The display name of the model. - - - Gets or sets the edit format string of the model. - The edit format string of the model. - - - Returns the metadata from the parameter for the model. - The metadata. - An expression that identifies the model. - The view data dictionary. - The type of the parameter. - The type of the value. - - - Gets the metadata from the expression parameter for the model. - The metadata for the model. - An expression that identifies the model. - The view data dictionary. - - - Gets the display name for the model. - The display name for the model. - - - Returns the simple description of the model. - The simple description of the model. - - - Gets a list of validators for the model. - A list of validators for the model. - The controller context. - - - Gets or sets a value that indicates whether the model object should be rendered using associated HTML elements. - true if the associated HTML elements that contains the model object should be included with the object; otherwise, false. - - - Gets or sets a value that indicates whether the model is a complex type. - A value that indicates whether the model is considered a complex type by the MVC framework. - - - Gets a value that indicates whether the type is nullable. - true if the type is nullable; otherwise, false. - - - Gets or sets a value that indicates whether the model is read-only. - true if the model is read-only; otherwise, false. - - - Gets or sets a value that indicates whether the model is required. - true if the model is required; otherwise, false. - - - Gets the value of the model. - The value of the model. For more information about , see the entry ASP.NET MVC 2 Templates, Part 2: ModelMetadata on Brad Wilson's blog - - - Gets the type of the model. - The type of the model. - - - Gets or sets the string to display for null values. - The string to display for null values. - - - Gets or sets a value that represents order of the current metadata. - The order value of the current metadata. - - - Gets a collection of model metadata objects that describe the properties of the model. - A collection of model metadata objects that describe the properties of the model. - - - Gets the property name. - The property name. - - - Gets or sets the provider. - The provider. - - - Gets or sets a value that indicates whether request validation is enabled. - true if request validation is enabled; otherwise, false. - - - Gets or sets a short display name. - The short display name. - - - Gets or sets a value that indicates whether the property should be displayed in read-only views such as list and detail views. - true if the model should be displayed in read-only views; otherwise, false. - - - Gets or sets a value that indicates whether the model should be displayed in editable views. - true if the model should be displayed in editable views; otherwise, false. - - - Gets or sets the simple display string for the model. - The simple display string for the model. - - - Gets or sets a hint that suggests what template to use for this model. - A hint that suggests what template to use for this model. - - - Gets or sets a value that can be used as a watermark. - The watermark. - - - Provides an abstract base class for a custom metadata provider. - - - When overridden in a derived class, initializes a new instance of the object that derives from the class. - - - Gets a object for each property of a model. - A object for each property of a model. - The container. - The type of the container. - - - Gets metadata for the specified property. - A object for the property. - The model accessor. - The type of the container. - The property to get the metadata model for. - - - Gets metadata for the specified model accessor and model type. - A object for the specified model accessor and model type. - The model accessor. - The type of the model. - - - Provides a container for the current instance. - - - Gets or sets the current object. - The current object. - - - Encapsulates the state of model binding to a property of an action-method argument, or to the argument itself. - - - Initializes a new instance of the class. - - - Returns a object that contains any errors that occurred during model binding. - The errors. - - - Returns a object that encapsulates the value that was being bound during model binding. - The value. - - - Represents the state of an attempt to bind a posted form to an action method, which includes validation information. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using values that are copied from the specified model-state dictionary. - The model-state dictionary. - The parameter is null. - - - Adds the specified item to the model-state dictionary. - The object to add to the model-state dictionary. - The model-state dictionary is read-only. - - - Adds an element that has the specified key and value to the model-state dictionary. - The key of the element to add. - The value of the element to add. - The model-state dictionary is read-only. - - is null. - An element that has the specified key already occurs in the model-state dictionary. - - - Adds the specified model error to the errors collection for the model-state dictionary that is associated with the specified key. - The key. - The exception. - - - Adds the specified error message to the errors collection for the model-state dictionary that is associated with the specified key. - The key. - The error message. - - - Removes all items from the model-state dictionary. - The model-state dictionary is read-only. - - - Determines whether the model-state dictionary contains a specific value. - true if is found in the model-state dictionary; otherwise, false. - The object to locate in the model-state dictionary. - - - Determines whether the model-state dictionary contains the specified key. - true if the model-state dictionary contains the specified key; otherwise, false. - The key to locate in the model-state dictionary. - - - Copies the elements of the model-state dictionary to an array, starting at a specified index. - The one-dimensional array that is the destination of the elements copied from the object. The array must have zero-based indexing. - The zero-based index in at which copying starts. - - is null. - - is less than 0. - - is multidimensional.-or- is equal to or greater than the length of .-or- The number of elements in the source collection is greater than the available space from to the end of the destination .-or- Type cannot be cast automatically to the type of the destination . - - - Gets the number of key/value pairs in the collection. - The number of key/value pairs in the collection. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Gets a value that indicates whether the collection is read-only. - true if the collection is read-only; otherwise, false. - - - Gets a value that indicates whether this instance of the model-state dictionary is valid. - true if this instance is valid; otherwise, false. - - - Determines whether there are any objects that are associated with or prefixed with the specified key. - true if the model-state dictionary contains a value that is associated with the specified key; otherwise, false. - The key. - The parameter is null. - - - Gets or sets the value that is associated with the specified key. - The model state item. - The key. - - - Gets a collection that contains the keys in the dictionary. - A collection that contains the keys of the model-state dictionary. - - - Copies the values from the specified object into this dictionary, overwriting existing values if keys are the same. - The dictionary. - - - Removes the first occurrence of the specified object from the model-state dictionary. - true if was successfully removed the model-state dictionary; otherwise, false. This method also returns false if is not found in the model-state dictionary. - The object to remove from the model-state dictionary. - The model-state dictionary is read-only. - - - Removes the element that has the specified key from the model-state dictionary. - true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the model-state dictionary. - The key of the element to remove. - The model-state dictionary is read-only. - - is null. - - - Sets the value for the specified key by using the specified value provider dictionary. - The key. - The value. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Attempts to gets the value that is associated with the specified key. - true if the object that implements contains an element that has the specified key; otherwise, false. - The key of the value to get. - When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - - is null. - - - Gets a collection that contains the values in the dictionary. - A collection that contains the values of the model-state dictionary. - - - Provides a container for a validation result. - - - Initializes a new instance of the class. - - - Gets or sets the name of the member. - The name of the member. - - - Gets or sets the validation result message. - The validation result message. - - - Provides a base class for implementing validation logic. - - - Called from constructors in derived classes to initialize the class. - The metadata. - The controller context. - - - Gets the controller context. - The controller context. - - - When implemented in a derived class, returns metadata for client validation. - The metadata for client validation. - - - Returns a composite model validator for the model. - A composite model validator for the model. - The metadata. - The controller context. - - - Gets or sets a value that indicates whether a model property is required. - true if the model property is required; otherwise, false. - - - Gets the metadata for the model validator. - The metadata for the model validator. - - - When implemented in a derived class, validates the object. - A list of validation results. - The container. - - - Provides a list of validators for a model. - - - When implemented in a derived class, initializes a new instance of the class. - - - Gets a list of validators. - A list of validators. - The metadata. - The context. - - - Provides a container for a list of validation providers. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using a list of model-validation providers. - A list of model-validation providers. - - - Returns the list of model validators. - The list of model validators. - The model metadata. - The controller context. - - - Inserts a model-validator provider into the collection. - The zero-based index at which item should be inserted. - The model-validator provider object to insert. - - - Replaces the model-validator provider element at the specified index. - The zero-based index of the model-validator provider element to replace. - The new value for the model-validator provider element. - - - Provides a container for the current validation provider. - - - Gets the model validator provider collection. - The model validator provider collection. - - - Represents a list of items that users can select more than one item from. - - - Initializes a new instance of the class by using the specified items to include in the list. - The items. - The parameter is null. - - - Initializes a new instance of the class by using the specified items to include in the list and the selected values. - The items. - The selected values. - The parameter is null. - - - Initializes a new instance of the class by using the items to include in the list, the data value field, and the data text field. - The items. - The data value field. - The data text field. - The parameter is null. - - - Initializes a new instance of the class by using the items to include in the list, the data value field, the data text field, and the selected values. - The items. - The data value field. - The data text field. - The selected values. - The parameter is null. - - - Gets or sets the data text field. - The data text field. - - - Gets or sets the data value field. - The data value field. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Gets or sets the items in the list. - The items in the list. - - - Gets or sets the selected values. - The selected values. - - - Returns an enumerator can be used to iterate through a collection. - An enumerator that can be used to iterate through the collection. - - - When implemented in a derived class, provides a metadata class that contains a reference to the implementation of one or more of the filter interfaces, the filter's order, and the filter's scope. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class and specifies the order of filters and whether multiple filters are allowed. - true to specify that multiple filters of the same type are allowed; otherwise, false. - The filter order. - - - Gets a value that indicates whether more than one instance of the filter attribute can be specified. - true if more than one instance of the filter attribute is allowed; otherwise, false. - - - Gets a value that indicates the order in which a filter is applied. - A value that indicates the order in which a filter is applied. - - - Selects the controller that will handle an HTTP request. - - - Initializes a new instance of the class. - The request context. - The parameter is null. - - - Adds the version header by using the specified HTTP context. - The HTTP context. - - - Called by ASP.NET to begin asynchronous request processing. - The status of the asynchronous call. - The HTTP context. - The asynchronous callback method. - The state of the asynchronous object. - - - Called by ASP.NET to begin asynchronous request processing using the base HTTP context. - The status of the asynchronous call. - The HTTP context. - The asynchronous callback method. - The state of the asynchronous object. - - - Gets or sets a value that indicates whether the MVC response header is disabled. - true if the MVC response header is disabled; otherwise, false. - - - Called by ASP.NET when asynchronous request processing has ended. - The asynchronous result. - - - Gets a value that indicates whether another request can use the instance. - true if the instance is reusable; otherwise, false. - - - Contains the header name of the ASP.NET MVC version. - - - Processes the request by using the specified HTTP request context. - The HTTP context. - - - Processes the request by using the specified base HTTP request context. - The HTTP context. - - - Gets the request context. - The request context. - - - Called by ASP.NET to begin asynchronous request processing using the base HTTP context. - The status of the asynchronous call. - The HTTP context. - The asynchronous callback method. - The data. - - - Called by ASP.NET when asynchronous request processing has ended. - The asynchronous result. - - - Gets a value that indicates whether another request can use the instance. - true if the instance is reusable; otherwise, false. - - - Enables processing of HTTP Web requests by a custom HTTP handler that implements the interface. - An object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) that are used to service HTTP requests. - - - Represents an HTML-encoded string that should not be encoded again. - - - Initializes a new instance of the class. - The string to create. If no value is assigned, the object is created using an empty-string value. - - - Creates an HTML-encoded string using the specified text value. - An HTML-encoded string. - The value of the string to create . - - - Contains an empty HTML string. - - - Determines whether the specified string contains content or is either null or empty. - true if the string is null or empty; otherwise, false. - The string. - - - Verifies and processes an HTTP request. - - - Initializes a new instance of the class. - - - Called by ASP.NET to begin asynchronous request processing. - The status of the asynchronous call. - The HTTP context. - The asynchronous callback method. - The state. - - - Called by ASP.NET to begin asynchronous request processing. - The status of the asynchronous call. - The base HTTP context. - The asynchronous callback method. - The state. - - - Called by ASP.NET when asynchronous request processing has ended. - The asynchronous result. - - - Called by ASP.NET to begin asynchronous request processing. - The status of the asynchronous call. - The context. - The asynchronous callback method. - An object that contains data. - - - Called by ASP.NET when asynchronous request processing has ended. - The status of the asynchronous operations. - - - Verifies and processes an HTTP request. - The HTTP handler. - The HTTP context. - - - Creates an object that implements the IHttpHandler interface and passes the request context to it. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified factory controller object. - The controller factory. - - - Returns the HTTP handler by using the specified HTTP context. - The HTTP handler. - The request context. - - - Returns the session behavior. - The session behavior. - The request context. - - - Returns the HTTP handler by using the specified request context. - The HTTP handler. - The request context. - - - Creates instances of files. - - - Initializes a new instance of the class. - - - Creates a Razor host. - A Razor host. - The virtual path to the target file. - The physical path to the target file. - - - Extends a NameValueCollection object so that the collection can be copied to a specified dictionary. - - - Copies the specified collection to the specified destination. - The collection. - The destination. - - - Copies the specified collection to the specified destination, and optionally replaces previous entries. - The collection. - The destination. - true to replace previous entries; otherwise, false. - - - Represents the base class for value providers whose values come from a object. - - - Initializes a new instance of the class using the specified unvalidated collection. - A collection that contains the values that are used to initialize the provider. - A collection that contains the values that are used to initialize the provider. This collection will not be validated. - An object that contains information about the target culture. - - - Initializes a new instance of the class. - A collection that contains the values that are used to initialize the provider. - An object that contains information about the target culture. - The parameter is null. - - - Determines whether the collection contains the specified prefix. - true if the collection contains the specified prefix; otherwise, false. - The prefix to search for. - The parameter is null. - - - Returns a value object using the specified key. - The value object for the specified key. - The key of the value object to retrieve. - The parameter is null. - - - Returns a value object using the specified key and validation directive. - The value object for the specified key. - The key. - true if validation should be skipped; otherwise, false. - - - Provides a convenience wrapper for the attribute. - - - Initializes a new instance of the class. - - - Represents an attribute that is used to indicate that a controller method is not an action method. - - - Initializes a new instance of the class. - - - Determines whether the attribute marks a method that is not an action method by using the specified controller context. - true if the attribute marks a valid non-action method; otherwise, false. - The controller context. - The method information. - - - Represents an attribute that is used to mark an action method whose output will be cached. - - - Initializes a new instance of the class. - - - Gets or sets the cache profile name. - The cache profile name. - - - Gets or sets the child action cache. - The child action cache. - - - Gets or sets the cache duration, in seconds. - The cache duration. - - - Returns a value that indicates whether a child action cache is active. - true if the child action cache is active; otherwise, false. - The controller context. - - - Gets or sets the location. - The location. - - - Gets or sets a value that indicates whether to store the cache. - true if the cache should be stored; otherwise, false. - - - This method is an implementation of and supports the ASP.NET MVC infrastructure. It is not intended to be used directly from your code. - The filter context. - - - This method is an implementation of and supports the ASP.NET MVC infrastructure. It is not intended to be used directly from your code. - The filter context. - - - This method is an implementation of and supports the ASP.NET MVC infrastructure. It is not intended to be used directly from your code. - The filter context. - - - This method is an implementation of and supports the ASP.NET MVC infrastructure. It is not intended to be used directly from your code. - The filter context. - - - Called before the action result executes. - The filter context, which encapsulates information for using . - The parameter is null. - - - Gets or sets the SQL dependency. - The SQL dependency. - - - Gets or sets the vary-by-content encoding. - The vary-by-content encoding. - - - Gets or sets the vary-by-custom value. - The vary-by-custom value. - - - Gets or sets the vary-by-header value. - The vary-by-header value. - - - Gets or sets the vary-by-param value. - The vary-by-param value. - - - Encapsulates information for binding action-method parameters to a data model. - - - Initializes a new instance of the class. - - - Gets the model binder. - The model binder. - - - Gets a comma-delimited list of property names for which binding is disabled. - The exclude list. - - - Gets a comma-delimited list of property names for which binding is enabled. - The include list. - - - Gets the prefix to use when the MVC framework binds a value to an action parameter or to a model property. - The prefix. - - - Contains information that describes a parameter. - - - Initializes a new instance of the class. - - - Gets the action descriptor. - The action descriptor. - - - Gets the binding information. - The binding information. - - - Gets the default value of the parameter. - The default value of the parameter. - - - Returns an array of custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns an array of custom attributes that are defined for this member, identified by type. - An array of custom attributes, or an empty array if no custom attributes exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - The parameter is null. - - - Indicates whether one or more instances of a custom attribute type are defined for this member. - true if the custom attribute type is defined for this member; otherwise, false. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The parameter is null. - - - Gets the name of the parameter. - The name of the parameter. - - - Gets the type of the parameter. - The type of the parameter. - - - Represents a base class that is used to send a partial view to the response. - - - Initializes a new instance of the class. - - - Returns the object that is used to render the view. - The view engine result. - The controller context. - An error occurred while the method was attempting to find the view. - - - Provides a registration point for ASP.NET Razor pre-application start code. - - - Registers Razor pre-application start code. - - - Represents a value provider for query strings that are contained in a object. - - - Initializes a new instance of the class. - An object that encapsulates information about the current HTTP request. - - - Represents a class that is responsible for creating a new instance of a query-string value-provider object. - - - Initializes a new instance of the class. - - - Returns a value-provider object for the specified controller context. - A query-string value-provider object. - An object that encapsulates information about the current HTTP request. - The parameter is null. - - - Provides an adapter for the attribute. - - - Initializes a new instance of the class. - The model metadata. - The controller context. - The range attribute. - - - Gets a list of client validation rules for a range check. - A list of client validation rules for a range check. - - - Represents the class used to create views that have Razor syntax. - - - Initializes a new instance of the class. - The controller context. - The view path. - The layout or master page. - A value that indicates whether view start files should be executed before the view. - The set of extensions that will be used when looking up view start files. - - - Initializes a new instance of the class using the view page activator. - The controller context. - The view path. - The layout or master page. - A value that indicates whether view start files should be executed before the view. - The set of extensions that will be used when looking up view start files. - The view page activator. - - - Gets the layout or master page. - The layout or master page. - - - Renders the specified view context by using the specified writer and instance. - The view context. - The writer that is used to render the view to the response. - The instance. - - - Gets a value that indicates whether view start files should be executed before the view. - A value that indicates whether view start files should be executed before the view. - - - Gets or sets the set of file extensions that will be used when looking up view start files. - The set of file extensions that will be used when looking up view start files. - - - Represents a view engine that is used to render a Web page that uses the ASP.NET Razor syntax. - - - Initializes a new instance of the class. - - - - Creates a partial view using the specified controller context and partial path. - The partial view. - The controller context. - The path to the partial view. - - - Creates a view by using the specified controller context and the paths of the view and master view. - The view. - The controller context. - The path to the view. - The path to the master view. - - - Controls the processing of application actions by redirecting to a specified URI. - - - Initializes a new instance of the class. - The target URL. - The parameter is null. - - - Initializes a new instance of the class using the specified URL and permanent-redirection flag. - The URL. - A value that indicates whether the redirection should be permanent. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context within which the result is executed. - The parameter is null. - - - Gets a value that indicates whether the redirection should be permanent. - true if the redirection should be permanent; otherwise, false. - - - Gets or sets the target URL. - The target URL. - - - Represents a result that performs a redirection by using the specified route values dictionary. - - - Initializes a new instance of the class by using the specified route name and route values. - The name of the route. - The route values. - - - Initializes a new instance of the class by using the specified route name, route values, and permanent-redirection flag. - The name of the route. - The route values. - A value that indicates whether the redirection should be permanent. - - - Initializes a new instance of the class by using the specified route values. - The route values. - - - Enables processing of the result of an action method by a custom type that inherits from the class. - The context within which the result is executed. - The parameter is null. - - - Gets a value that indicates whether the redirection should be permanent. - true if the redirection should be permanent; otherwise, false. - - - Gets or sets the name of the route. - The name of the route. - - - Gets or sets the route values. - The route values. - - - Contains information that describes a reflected action method. - - - Initializes a new instance of the class. - The action-method information. - The name of the action. - The controller descriptor. - Either the or parameter is null. - The parameter is null or empty. - - - Gets the name of the action. - The name of the action. - - - Gets the controller descriptor. - The controller descriptor. - - - Executes the specified controller context by using the specified action-method parameters. - The action return value. - The controller context. - The parameters. - The or parameter is null. - - - Returns an array of custom attributes defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns an array of custom attributes defined for this member, identified by type. - An array of custom attributes, or an empty array if no custom attributes exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Retrieves the parameters of the action method. - The parameters of the action method. - - - Retrieves the action selectors. - The action selectors. - - - Indicates whether one or more instances of a custom attribute type are defined for this member. - true if the custom attribute type is defined for this member; otherwise, false. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Gets or sets the action-method information. - The action-method information. - - - Gets the unique ID for the reflected action descriptor using lazy initialization. - The unique ID. - - - Contains information that describes a reflected controller. - - - Initializes a new instance of the class. - The type of the controller. - The parameter is null. - - - Gets the type of the controller. - The type of the controller. - - - Finds the specified action for the specified controller context. - The information about the action. - The controller context. - The name of the action. - The parameter is null. - The parameter is null or empty. - - - Returns the list of actions for the controller. - A list of action descriptors for the controller. - - - Returns an array of custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns an array of custom attributes that are defined for this member, identified by type. - An array of custom attributes, or an empty array if no custom attributes exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns a value that indicates whether one or more instances of a custom attribute type are defined for this member. - true if the custom attribute type is defined for this member; otherwise, false. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Contains information that describes a reflected action-method parameter. - - - Initializes a new instance of the class. - The parameter information. - The action descriptor. - The or parameter is null. - - - Gets the action descriptor. - The action descriptor. - - - Gets the binding information. - The binding information. - - - Gets the default value of the reflected parameter. - The default value of the reflected parameter. - - - Returns an array of custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns an array of custom attributes that are defined for this member, identified by type. - An array of custom attributes, or an empty array if no custom attributes exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - The custom attribute type cannot be loaded. - There is more than one attribute of type defined for this member. - - - Returns a value that indicates whether one or more instances of a custom attribute type are defined for this member. - true if the custom attribute type is defined for this member; otherwise, false. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Gets or sets the parameter information. - The parameter information. - - - Gets the name of the parameter. - The name of the parameter. - - - Gets the type of the parameter. - The type of the parameter. - - - Provides an adapter for the attribute. - - - Initializes a new instance of the class. - The model metadata. - The controller context. - The regular expression attribute. - - - Gets a list of regular-expression client validation rules. - A list of regular-expression client validation rules. - - - Provides an attribute that uses the jQuery validation plug-in remote validator. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified route name. - The route name. - - - Initializes a new instance of the class using the specified action-method name and controller name. - The name of the action method. - The name of the controller. - - - Initializes a new instance of the class using the specified action-method name, controller name, and area name. - The name of the action method. - The name of the controller. - The name of the area. - - - Gets or sets the additional fields that are required for validation. - The additional fields that are required for validation. - - - Returns a comma-delimited string of validation field names. - A comma-delimited string of validation field names. - The name of the validation property. - - - Formats the error message that is displayed when validation fails. - A formatted error message. - A name to display with the error message. - - - Formats the property for client validation by prepending an asterisk (*) and a dot. - The string "*." Is prepended to the property. - The property. - - - Gets a list of client validation rules for the property. - A list of remote client validation rules for the property. - The model metadata. - The controller context. - - - Gets the URL for the remote validation call. - The URL for the remote validation call. - The controller context. - - - Gets or sets the HTTP method used for remote validation. - The HTTP method used for remote validation. The default value is "Get". - - - This method always returns true. - true - The validation target. - - - Gets the route data dictionary. - The route data dictionary. - - - Gets or sets the route name. - The route name. - - - Gets the route collection from the route table. - The route collection from the route table. - - - Provides an adapter for the attribute. - - - Initializes a new instance of the class. - The model metadata. - The controller context. - The required attribute. - - - Gets a list of required-value client validation rules. - A list of required-value client validation rules. - - - Represents an attribute that forces an unsecured HTTP request to be re-sent over HTTPS. - - - Initializes a new instance of the class. - - - Handles unsecured HTTP requests that are sent to the action method. - An object that encapsulates information that is required in order to use the attribute. - The HTTP request contains an invalid transfer method override. All GET requests are considered invalid. - - - Determines whether a request is secured (HTTPS) and, if it is not, calls the method. - An object that encapsulates information that is required in order to use the attribute. - The parameter is null. - - - Provides the context for the method of the class. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class. - The controller context. - The result object. - true to cancel execution; otherwise, false. - The exception object. - The parameter is null. - - - Gets or sets a value that indicates whether this instance is canceled. - true if the instance is canceled; otherwise, false. - - - Gets or sets the exception object. - The exception object. - - - Gets or sets a value that indicates whether the exception has been handled. - true if the exception has been handled; otherwise, false. - - - Gets or sets the action result. - The action result. - - - Provides the context for the method of the class. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified controller context and action result. - The controller context. - The action result. - The parameter is null. - - - Gets or sets a value that indicates whether this value is "cancel". - true if the value is "cancel"; otherwise, false. - - - Gets or sets the action result. - The action result. - - - Extends a object for MVC routing. - - - Returns an object that contains information about the route and virtual path that are the result of generating a URL in the current area. - An object that contains information about the route and virtual path that are the result of generating a URL in the current area. - An object that contains the routes for the applications. - An object that encapsulates information about the requested route. - The name of the route to use when information about the URL path is retrieved. - An object that contains the parameters for a route. - - - Returns an object that contains information about the route and virtual path that are the result of generating a URL in the current area. - An object that contains information about the route and virtual path that are the result of generating a URL in the current area. - An object that contains the routes for the applications. - An object that encapsulates information about the requested route. - An object that contains the parameters for a route. - - - Ignores the specified URL route for the given list of available routes. - A collection of routes for the application. - The URL pattern for the route to ignore. - The or parameter is null. - - - Ignores the specified URL route for the given list of the available routes and a list of constraints. - A collection of routes for the application. - The URL pattern for the route to ignore. - A set of expressions that specify values for the parameter. - The or parameter is null. - - - Maps the specified URL route. - A reference to the mapped route. - A collection of routes for the application. - The name of the route to map. - The URL pattern for the route. - The or parameter is null. - - - Maps the specified URL route and sets default route values. - A reference to the mapped route. - A collection of routes for the application. - The name of the route to map. - The URL pattern for the route. - An object that contains default route values. - The or parameter is null. - - - Maps the specified URL route and sets default route values and constraints. - A reference to the mapped route. - A collection of routes for the application. - The name of the route to map. - The URL pattern for the route. - An object that contains default route values. - A set of expressions that specify values for the parameter. - The or parameter is null. - - - Maps the specified URL route and sets default route values, constraints, and namespaces. - A reference to the mapped route. - A collection of routes for the application. - The name of the route to map. - The URL pattern for the route. - An object that contains default route values. - A set of expressions that specify values for the parameter. - A set of namespaces for the application. - The or parameter is null. - - - Maps the specified URL route and sets default route values and namespaces. - A reference to the mapped route. - A collection of routes for the application. - The name of the route to map. - The URL pattern for the route. - An object that contains default route values. - A set of namespaces for the application. - The or parameter is null. - - - Maps the specified URL route and sets the namespaces. - A reference to the mapped route. - A collection of routes for the application. - The name of the route to map. - The URL pattern for the route. - A set of namespaces for the application. - The or parameter is null. - - - Represents a value provider for route data that is contained in an object that implements the interface. - - - Initializes a new instance of the class. - An object that contain information about the HTTP request. - - - Represents a factory for creating route-data value provider objects. - - - Initialized a new instance of the class. - - - Returns a value-provider object for the specified controller context. - A value-provider object. - An object that encapsulates information about the current HTTP request. - The parameter is null. - - - Represents a list that lets users select one item. - - - Initializes a new instance of the class by using the specified items for the list. - The items. - - - Initializes a new instance of the class by using the specified items for the list and a selected value. - The items. - The selected value. - - - Initializes a new instance of the class by using the specified items for the list, the data value field, and the data text field. - The items. - The data value field. - The data text field. - - - Initializes a new instance of the class by using the specified items for the list, the data value field, the data text field, and a selected value. - The items. - The data value field. - The data text field. - The selected value. - - - Gets the list value that was selected by the user. - The selected value. - - - Represents the selected item in an instance of the class. - - - Initializes a new instance of the class. - - - Gets or sets a value that indicates whether this is selected. - true if the item is selected; otherwise, false. - - - Gets or sets the text of the selected item. - The text. - - - Gets or sets the value of the selected item. - The value. - - - Specifies the session state of the controller. - - - Initializes a new instance of the class - The type of the session state. - - - Get the session state behavior for the controller. - The session state behavior for the controller. - - - Provides session-state data to the current object. - - - Initializes a new instance of the class. - - - Loads the temporary data by using the specified controller context. - The temporary data. - The controller context. - An error occurred when the session context was being retrieved. - - - Saves the specified values in the temporary data dictionary by using the specified controller context. - The controller context. - The values. - An error occurred the session context was being retrieved. - - - Provides an adapter for the attribute. - - - Initializes a new instance of the class. - The model metadata. - The controller context. - The string-length attribute. - - - Gets a list of string-length client validation rules. - A list of string-length client validation rules. - - - Represents a set of data that persists only from one request to the next. - - - Initializes a new instance of the class. - - - Adds an element that has the specified key and value to the object. - The key of the element to add. - The value of the element to add. - The object is read-only. - - is null. - An element that has the same key already exists in the object. - - - Removes all items from the instance. - The object is read-only. - - - Determines whether the instance contains an element that has the specified key. - true if the instance contains an element that has the specified key; otherwise, false. - The key to locate in the instance. - - is null. - - - Determines whether the dictionary contains the specified value. - true if the dictionary contains the specified value; otherwise, false. - The value. - - - Gets the number of elements in the object. - The number of elements in the object. - - - Gets the enumerator. - The enumerator. - - - Gets or sets the object that has the specified key. - The object that has the specified key. - The key to access. - - - Marks all keys in the dictionary for retention. - - - Marks the specified key in the dictionary for retention. - The key to retain in the dictionary. - - - Gets an object that contains the keys of elements in the object. - The keys of the elements in the object. - - - Loads the specified controller context by using the specified data provider. - The controller context. - The temporary data provider. - - - Returns an object that contains the element that is associated with the specified key, without marking the key for deletion. - An object that contains the element that is associated with the specified key. - The key of the element to return. - - - Removes the element that has the specified key from the object. - true if the element was removed successfully; otherwise, false. This method also returns false if was not found in the . instance. - The key of the element to remove. - The object is read-only. - - is null. - - - Saves the specified controller context by using the specified data provider. - The controller context. - The temporary data provider. - - - Adds the specified key/value pair to the dictionary. - The key/value pair. - - - Determines whether a sequence contains a specified element by using the default equality comparer. - true if the dictionary contains the specified key/value pair; otherwise, false. - The key/value pair to search for. - - - Copies a key/value pair to the specified array at the specified index. - The target array. - The index. - - - Gets a value that indicates whether the dictionary is read-only. - true if the dictionary is read-only; otherwise, false. - - - Deletes the specified key/value pair from the dictionary. - true if the key/value pair was removed successfully; otherwise, false. - The key/value pair. - - - Returns an enumerator that can be used to iterate through a collection. - An object that can be used to iterate through the collection. - - - Gets the value of the element that has the specified key. - true if the object that implements contains an element that has the specified key; otherwise, false. - The key of the value to get. - When this method returns, the value that is associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - - is null. - - - Gets the object that contains the values in the object. - The values of the elements in the object that implements . - - - Encapsulates information about the current template context. - - - Initializes a new instance of the class. - - - Gets or sets the formatted model value. - The formatted model value. - - - Retrieves the full DOM ID of a field using the specified HTML name attribute. - The full DOM ID. - The value of the HTML name attribute. - - - Retrieves the fully qualified name (including a prefix) for a field using the specified HTML name attribute. - The prefixed name of the field. - The value of the HTML name attribute. - - - Gets or sets the HTML field prefix. - The HTML field prefix. - - - Contains the number of objects that were visited by the user. - The number of objects. - - - Determines whether the template has been visited by the user. - true if the template has been visited by the user; otherwise, false. - An object that encapsulates information that describes the model. - - - Contains methods to build URLs for ASP.NET MVC within an application. - - - Initializes a new instance of the class using the specified request context. - An object that contains information about the current request and about the route that it matched. - The parameter is null. - - - Initializes a new instance of the class by using the specified request context and route collection. - An object that contains information about the current request and about the route that it matched. - A collection of routes. - The or the parameter is null. - - - Generates a fully qualified URL to an action method by using the specified action name. - The fully qualified URL to an action method. - The name of the action method. - - - Generates a fully qualified URL to an action method by using the specified action name and route values. - The fully qualified URL to an action method. - The name of the action method. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - - - Generates a fully qualified URL to an action method by using the specified action name and controller name. - The fully qualified URL to an action method. - The name of the action method. - The name of the controller. - - - Generates a fully qualified URL to an action method by using the specified action name, controller name, and route values. - The fully qualified URL to an action method. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - - - Generates a fully qualified URL to an action method by using the specified action name, controller name, route values, and protocol to use. - The fully qualified URL to an action method. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - The protocol for the URL, such as "http" or "https". - - - Generates a fully qualified URL to an action method by using the specified action name, controller name, and route values. - The fully qualified URL to an action method. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - - - Generates a fully qualified URL for an action method by using the specified action name, controller name, route values, protocol to use, and host name. - The fully qualified URL to an action method. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - - - Generates a fully qualified URL to an action method for the specified action name and route values. - The fully qualified URL to an action method. - The name of the action method. - An object that contains the parameters for a route. - - - Converts a virtual (relative) path to an application absolute path. - The application absolute path. - The virtual path of the content. - - - Encodes special characters in a URL string into character-entity equivalents. - An encoded URL string. - The text to encode. - - - Returns a string that contains a content URL. - A string that contains a content URL. - The content path. - The HTTP context. - - - Returns a string that contains a URL. - A string that contains a URL. - The route name. - The action name. - The controller name. - The HTTP protocol. - The host name. - The fragment. - The route values. - The route collection. - The request context. - true to include implicit MVC values; otherwise false. - - - Returns a string that contains a URL. - A string that contains a URL. - The route name. - The action name. - The controller name. - The route values. - The route collection. - The request context. - true to include implicit MVC values; otherwise. false. - - - Returns a value that indicates whether the URL is local. - true if the URL is local; otherwise, false. - The URL. - - - Gets information about an HTTP request that matches a defined route. - The request context. - - - Gets a collection that contains the routes that are registered for the application. - The route collection. - - - Generates a fully qualified URL for the specified route values. - The fully qualified URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - - - Generates a fully qualified URL for the specified route name. - The fully qualified URL. - The name of the route that is used to generate the URL. - - - Generates a fully qualified URL for the specified route values by using a route name. - The fully qualified URL. - The name of the route that is used to generate the URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - - - Generates a fully qualified URL for the specified route values by using a route name and the protocol to use. - The fully qualified URL. - The name of the route that is used to generate the URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - The protocol for the URL, such as "http" or "https". - - - Generates a fully qualified URL for the specified route values by using a route name. - The fully qualified URL. - The name of the route that is used to generate the URL. - An object that contains the parameters for a route. - - - Generates a fully qualified URL for the specified route values by using the specified route name, protocol to use, and host name. - The fully qualified URL. - The name of the route that is used to generate the URL. - An object that contains the parameters for a route. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - - - Generates a fully qualified URL for the specified route values. - The fully qualified URL. - An object that contains the parameters for a route. - - - Represents an optional parameter that is used by the class during routing. - - - Contains the read-only value for the optional parameter. - - - Returns an empty string. This method supports the ASP.NET MVC infrastructure and is not intended to be used directly from your code. - An empty string. - - - Provides an object adapter that can be validated. - - - Initializes a new instance of the class. - The model metadata. - The controller context. - - - Validates the specified object. - A list of validation results. - The container. - - - Represents an attribute that is used to detect whether a server request has been tampered with. - - - Initializes a new instance of the class. - - - Called when authorization is required. - The filter context. - The parameter is null. - - - Gets or sets the salt string. - The salt string. - - - Represents an attribute that is used to mark action methods whose input must be validated. - - - Initializes a new instance of the class. - true to enable validation. - - - Gets or sets a value that indicates whether to enable validation. - true if validation is enabled; otherwise, false. - - - Called when authorization is required. - The filter context. - The parameter is null. - - - Represents the collection of value-provider objects for the application. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class and registers the specified value providers. - The list of value providers to register. - - - Determines whether the collection contains the specified prefix. - true if the collection contains the specified prefix; otherwise, false. - The prefix to search for. - - - Returns a value object using the specified key. - The value object for the specified key. - The key of the value object to retrieve. - - - Returns a value object using the specified key and skip-validation parameter. - The value object for the specified key. - The key of the value object to retrieve. - true to specify that validation should be skipped; otherwise, false. - - - Inserts the specified value-provider object into the collection at the specified index location. - The zero-based index location at which to insert the value provider into the collection. - The value-provider object to insert. - The parameter is null. - - - Replaces the value provider at the specified index location with a new value provider. - The zero-based index of the element to replace. - The new value for the element at the specified index. - The parameter is null. - - - Represents a dictionary of value providers for the application. - - - Initializes a new instance of the class. - The controller context. - - - Adds the specified item to the collection of value providers. - The object to add to the object. - The object is read-only. - - - Adds an element that has the specified key and value to the collection of value providers. - The key of the element to add. - The value of the element to add. - The object is read-only. - - is null. - An element that has the specified key already exists in the object. - - - Adds an element that has the specified key and value to the collection of value providers. - The key of the element to add. - The value of the element to add. - The object is read-only. - - is null. - An element that has the specified key already exists in the object. - - - Removes all items from the collection of value providers. - The object is read-only. - - - Determines whether the collection of value providers contains the specified item. - true if is found in the collection of value providers; otherwise, false. - The object to locate in the instance. - - - Determines whether the collection of value providers contains an element that has the specified key. - true if the collection of value providers contains an element that has the key; otherwise, false. - The key of the element to find in the instance. - - is null. - - - Gets or sets the controller context. - The controller context. - - - Copies the elements of the collection to an array, starting at the specified index. - The one-dimensional array that is the destination of the elements copied from the object. The array must have zero-based indexing. - The zero-based index in at which copying starts. - - is null. - - is less than 0. - - is multidimensional.-or- is equal to or greater than the length of .-or-The number of elements in the source collection is greater than the available space from to the end of the destination .-or-Type cannot be cast automatically to the type of the destination array. - - - Gets the number of elements in the collection. - The number of elements in the collection. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Gets a value that indicates whether the collection is read-only. - true if the collection is read-only; otherwise, false. - - - Gets or sets the object that has the specified key. - The object. - The key. - - - Gets a collection that contains the keys of the instance. - A collection that contains the keys of the object that implements the interface. - - - Removes the first occurrence of the specified item from the collection of value providers. - true if was successfully removed from the collection; otherwise, false. This method also returns false if is not found in the collection. - The object to remove from the instance. - The object is read-only. - - - Removes the element that has the specified key from the collection of value providers. - true if the element was successfully removed; otherwise, false. This method also returns false if was not found in the collection. - The key of the element to remove. - The object is read-only. - - is null. - - - Returns an enumerator that can be used to iterate through a collection. - An enumerator that can be used to iterate through the collection. - - - Determines whether the collection contains the specified prefix. - true if the collection contains the specified prefix; otherwise, false. - The prefix to search for. - - - Returns a value object using the specified key. - The value object for the specified key. - The key of the value object to return. - - - Gets the value of the element that has the specified key. - true if the object that implements contains an element that has the specified key; otherwise, false. - The key of the element to get. - When this method returns, the value that is associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - - is null. - - - Gets a collection that contains the values in the object. - A collection of the values in the object that implements the interface. - - - Represents a container for value-provider factory objects. - - - Gets the collection of value-provider factories for the application. - The collection of value-provider factory objects. - - - Represents a factory for creating value-provider objects. - - - Initializes a new instance of the class. - - - Returns a value-provider object for the specified controller context. - A value-provider object. - An object that encapsulates information about the current HTTP request. - - - Represents the collection of value-provider factories for the application. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified list of value-provider factories. - A list of value-provider factories to initialize the collection with. - - - Returns the value-provider factory for the specified controller context. - The value-provider factory object for the specified controller context. - An object that encapsulates information about the current HTTP request. - - - Inserts the specified value-provider factory object at the specified index location. - The zero-based index location at which to insert the value provider into the collection. - The value-provider factory object to insert. - The parameter is null. - - - Sets the specified value-provider factory object at the given index location. - The zero-based index location at which to insert the value provider into the collection. - The value-provider factory object to set. - The parameter is null. - - - Represents the result of binding a value (such as from a form post or query string) to an action-method argument property, or to the argument itself. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified raw value, attempted value, and culture information. - The raw value. - The attempted value. - The culture. - - - Gets or sets the raw value that is converted to a string for display. - The raw value. - - - Converts the value that is encapsulated by this result to the specified type. - The converted value. - The target type. - The parameter is null. - - - Converts the value that is encapsulated by this result to the specified type by using the specified culture information. - The converted value. - The target type. - The culture to use in the conversion. - The parameter is null. - - - Gets or sets the culture. - The culture. - - - Gets or set the raw value that is supplied by the value provider. - The raw value. - - - Encapsulates information that is related to rendering a view. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified controller context, view, view data dictionary, temporary data dictionary, and text writer. - Encapsulates information about the HTTP request. - The view to render. - The dictionary that contains the data that is required in order to render the view. - The dictionary that contains temporary data for the view. - The text writer object that is used to write HTML output. - One of the parameters is null. - - - Gets or sets a value that indicates whether client-side validation is enabled. - true if client-side validation is enabled; otherwise, false. - - - Gets or sets an object that encapsulates information that is required in order to validate and process the input data from an HTML form. - An object that encapsulates information that is required in order to validate and process the input data from an HTML form. - - - Writes the client validation information to the HTTP response. - - - Gets data that is associated with this request and that is available for only one request. - The temporary data. - - - Gets or sets a value that indicates whether unobtrusive JavaScript is enabled. - true if unobtrusive JavaScript is enabled; otherwise, false. - - - Gets an object that implements the interface to render in the browser. - The view. - - - Gets the view data that is passed to the view. - The view data. - - - Gets or sets the text writer object that is used to write HTML output. - The object that is used to write the HTML output. - - - Represents a container that is used to pass data between a controller and a view. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified model. - The model. - - - Initializes a new instance of the class by using the specified dictionary. - The dictionary. - The parameter is null. - - - Adds the specified item to the collection. - The object to add to the collection. - The collection is read-only. - - - Adds an element to the collection using the specified key and value . - The key of the element to add. - The value of the element to add. - The object is read-only. - - is null. - An element with the same key already exists in the object. - - - Removes all items from the collection. - The object is read-only. - - - Determines whether the collection contains the specified item. - true if is found in the collection; otherwise, false. - The object to locate in the collection. - - - Determines whether the collection contains an element that has the specified key. - true if the collection contains an element that has the specified key; otherwise, false. - The key of the element to locate in the collection. - - is null. - - - Copies the elements of the collection to an array, starting at a particular index. - The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing. - The zero-based index in at which copying begins. - - is null. - - is less than 0. - - is multidimensional.-or- is equal to or greater than the length of .-or- The number of elements in the source collection is greater than the available space from to the end of the destination .-or- Type cannot be cast automatically to the type of the destination . - - - Gets the number of elements in the collection. - The number of elements in the collection. - - - Evaluates the specified expression. - The results of the evaluation. - The expression. - The parameter is null or empty. - - - Evaluates the specified expression by using the specified format. - The results of the evaluation. - The expression. - The format. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Returns information about the view data as defined by the parameter. - An object that contains the view data information that is defined by the parameter. - A set of key/value pairs that define the view-data information to return. - The parameter is either null or empty. - - - Gets a value that indicates whether the collection is read-only. - true if the collection is read-only; otherwise, false. - - - Gets or sets the item that is associated with the specified key. - The value of the selected item. - The key. - - - Gets a collection that contains the keys of this dictionary. - A collection that contains the keys of the object that implements . - - - Gets or sets the model that is associated with the view data. - The model that is associated with the view data. - - - Gets or sets information about the model. - Information about the model. - - - Gets the state of the model. - The state of the model. - - - Removes the first occurrence of a specified object from the collection. - true if was successfully removed from the collection; otherwise, false. This method also returns false if is not found in the collection. - The object to remove from the collection. - The collection is read-only. - - - Removes the element from the collection using the specified key. - true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original collection. - The key of the element to remove. - The collection is read-only. - - is null. - - - Sets the data model to use for the view. - The data model to use for the view. - - - Returns an enumerator that can be used to iterate through the collection. - An enumerator that can be used to iterate through the collection. - - - Gets or sets an object that encapsulates information about the current template context. - An object that contains information about the current template. - - - Attempts to retrieve the value that is associated with the specified key. - true if the collection contains an element with the specified key; otherwise, false. - The key of the value to get. - When this method returns, the value that is associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - - is null. - - - Gets a collection that contains the values in this dictionary. - A collection that contains the values of the object that implements . - - - Represents a container that is used to pass strongly typed data between a controller and a view. - The type of the model. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified view data dictionary. - An existing view data dictionary to copy into this instance. - - - Initializes a new instance of the class by using the specified model. - The data model to use for the view. - - - Gets or sets the model. - A reference to the data model. - - - Gets or sets information about the model. - Information about the model. - - - Sets the data model to use for the view. - The data model to use for the view. - An error occurred while the model was being set. - - - Encapsulates information about the current template content that is used to develop templates and about HTML helpers that interact with templates. - - - Initializes a new instance of the class. - - - Initializes a new instance of the T:System.Web.Mvc.ViewDataInfo class and associates a delegate for accessing the view data information. - A delegate that defines how the view data information is accessed. - - - Gets or sets the object that contains the values to be displayed by the template. - The object that contains the values to be displayed by the template. - - - Gets or sets the description of the property to be displayed by the template. - The description of the property to be displayed by the template. - - - Gets or sets the current value to be displayed by the template. - The current value to be displayed by the template. - - - Represents a collection of view engines that are available to the application. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class by using the specified list of view engines. - The list that is wrapped by the new collection. - - is null. - - - Finds the specified partial view by using the specified controller context. - The partial view. - The controller context. - The name of the partial view. - The parameter is null. - The parameter is null or empty. - - - Finds the specified view by using the specified controller context and master view. - The view. - The controller context. - The name of the view. - The name of the master view. - The parameter is null. - The parameter is null or empty. - - - Inserts an element into the collection at the specified index. - The zero-based index at which should be inserted. - The object to insert. - - is less than zero.-or- is greater than the number of items in the collection. - The parameter is null. - - - Replaces the element at the specified index. - The zero-based index of the element to replace. - The new value for the element at the specified index. - - is less than zero.-or- is greater than the number of items in the collection. - The parameter is null. - - - Represents the result of locating a view engine. - - - Initializes a new instance of the class by using the specified searched locations. - The searched locations. - The parameter is null. - - - Initializes a new instance of the class by using the specified view and view engine. - The view. - The view engine. - The or parameter is null. - - - Gets or sets the searched locations. - The searched locations. - - - Gets or sets the view. - The view. - - - Gets or sets the view engine. - The view engine. - - - Represents a collection of view engines that are available to the application. - - - Gets the view engines. - The view engines. - - - Represents the information that is needed to build a master view page. - - - Initializes a new instance of the class. - - - Gets the AJAX script for the master page. - The AJAX script for the master page. - - - Gets the HTML for the master page. - The HTML for the master page. - - - Gets the model. - The model. - - - Gets the temporary data. - The temporary data. - - - Gets the URL. - The URL. - - - Gets the dynamic view-bag dictionary. - The dynamic view-bag dictionary. - - - Gets the view context. - The view context. - - - Gets the view data. - The view data. - - - Gets the writer that is used to render the master page. - The writer that is used to render the master page. - - - Represents the information that is required in order to build a strongly typed master view page. - The type of the model. - - - Initializes a new instance of the class. - - - Gets the AJAX script for the master page. - The AJAX script for the master page. - - - Gets the HTML for the master page. - The HTML for the master page. - - - Gets the model. - A reference to the data model. - - - Gets the view data. - The view data. - - - Represents the properties and methods that are needed to render a view as a Web Forms page. - - - Initializes a new instance of the class. - - - Gets or sets the object that is used to render HTML in Ajax scenarios. - The Ajax helper object that is associated with the view. - - - Gets or sets the object that is used to render HTML elements. - The HTML helper object that is associated with the view. - - - Initializes the , , and properties. - - - Gets or sets the path of the master view. - The path of the master view. - - - Gets the Model property of the associated object. - The Model property of the associated object. - - - Raises the event at the beginning of page initialization. - The event data. - - - Enables processing of the specified HTTP request by the ASP.NET MVC framework. - An object that encapsulates HTTP-specific information about the current HTTP request. - - - Initializes the object that receives the page content to be rendered. - The object that receives the page content. - - - Renders the view page to the response using the specified view context. - An object that encapsulates the information that is required in order to render the view, which includes the controller context, form context, the temporary data, and the view data for the associated view. - - - Sets the text writer that is used to render the view to the response. - The writer that is used to render the view to the response. - - - Sets the view data dictionary for the associated view. - A dictionary of data to pass to the view. - - - Gets the temporary data to pass to the view. - The temporary data to pass to the view. - - - Gets or sets the URL of the rendered page. - The URL of the rendered page. - - - Gets the view bag. - The view bag. - - - Gets or sets the information that is used to render the view. - The information that is used to render the view, which includes the form context, the temporary data, and the view data of the associated view. - - - Gets or sets a dictionary that contains data to pass between the controller and the view. - A dictionary that contains data to pass between the controller and the view. - - - Gets the text writer that is used to render the view to the response. - The text writer that is used to render the view to the response. - - - Represents the information that is required in order to render a strongly typed view as a Web Forms page. - The type of the model. - - - Initializes a new instance of the class. - - - Gets or sets the object that supports rendering HTML in Ajax scenarios. - The Ajax helper object that is associated with the view. - - - Gets or sets the object that provides support for rendering elements. - The HTML helper object that is associated with the view. - - - Instantiates and initializes the and properties. - - - Gets the property of the associated object. - A reference to the data model. - - - Sets the view data dictionary for the associated view. - A dictionary of data to pass to the view. - - - Gets or sets a dictionary that contains data to pass between the controller and the view. - A dictionary that contains data to pass between the controller and the view. - - - Represents a class that is used to render a view by using an instance that is returned by an object. - - - Initializes a new instance of the class. - - - Searches the registered view engines and returns the object that is used to render the view. - The object that is used to render the view. - The controller context. - An error occurred while the method was searching for the view. - - - Gets the name of the master view (such as a master page or template) to use when the view is rendered. - The name of the master view. - - - Represents a base class that is used to provide the model to the view and then render the view to the response. - - - Initializes a new instance of the class. - - - When called by the action invoker, renders the view to the response. - The context that the result is executed in. - The parameter is null. - - - Returns the object that is used to render the view. - The view engine. - The context. - - - Gets the view data model. - The view data model. - - - Gets or sets the object for this result. - The temporary data. - - - Gets or sets the object that is rendered to the response. - The view. - - - Gets the view bag. - The view bag. - - - Gets or sets the view data object for this result. - The view data. - - - Gets or sets the collection of view engines that are associated with this result. - The collection of view engines. - - - Gets or sets the name of the view to render. - The name of the view. - - - Provides an abstract class that can be used to implement a view start (master) page. - - - When implemented in a derived class, initializes a new instance of the class. - - - When implemented in a derived class, gets the HTML markup for the view start page. - The HTML markup for the view start page. - - - When implemented in a derived class, gets the URL for the view start page. - The URL for the view start page. - - - When implemented in a derived class, gets the view context for the view start page. - The view context for the view start page. - - - Provides a container for objects. - - - Initializes a new instance of the class. - - - Provides a container for objects. - The type of the model. - - - Initializes a new instance of the class. - - - Gets the formatted value. - The formatted value. - - - Represents the type of a view. - - - Initializes a new instance of the class. - - - Gets or sets the name of the type. - The name of the type. - - - Represents the information that is needed to build a user control. - - - Initializes a new instance of the class. - - - Gets the AJAX script for the view. - The AJAX script for the view. - - - Ensures that view data is added to the object of the user control if the view data exists. - - - Gets the HTML for the view. - The HTML for the view. - - - Gets the model. - The model. - - - Renders the view by using the specified view context. - The view context. - - - Sets the text writer that is used to render the view to the response. - The writer that is used to render the view to the response. - - - Sets the view-data dictionary by using the specified view data. - The view data. - - - Gets the temporary-data dictionary. - The temporary-data dictionary. - - - Gets the URL for the view. - The URL for the view. - - - Gets the view bag. - The view bag. - - - Gets or sets the view context. - The view context. - - - Gets or sets the view-data dictionary. - The view-data dictionary. - - - Gets or sets the view-data key. - The view-data key. - - - Gets the writer that is used to render the view to the response. - The writer that is used to render the view to the response. - - - Represents the information that is required in order to build a strongly typed user control. - The type of the model. - - - Initializes a new instance of the class. - - - Gets the AJAX script for the view. - The AJAX script for the view. - - - Gets the HTML for the view. - The HTML for the view. - - - Gets the model. - A reference to the data model. - - - Sets the view data for the view. - The view data. - - - Gets or sets the view data. - The view data. - - - Represents an abstract base-class implementation of the interface. - - - Initializes a new instance of the class. - - - Gets or sets the area-enabled master location formats. - The area-enabled master location formats. - - - Gets or sets the area-enabled partial-view location formats. - The area-enabled partial-view location formats. - - - Gets or sets the area-enabled view location formats. - The area-enabled view location formats. - - - Creates the specified partial view by using the specified controller context. - A reference to the partial view. - The controller context. - The partial path for the new partial view. - - - Creates the specified view by using the controller context, path of the view, and path of the master view. - A reference to the view. - The controller context. - The path of the view. - The path of the master view. - - - Returns a value that indicates whether the file is in the specified path by using the specified controller context. - true if the file is in the specified path; otherwise, false. - The controller context. - The virtual path. - - - Gets or sets the file-name extensions that are used to locate a view. - The file-name extensions that are used to locate a view. - - - Finds the specified partial view by using the specified controller context. - The partial view. - The controller context. - The name of the partial view. - true to use the cached partial view. - The parameter is null (Nothing in Visual Basic). - The parameter is null or empty. - - - Finds the specified view by using the specified controller context and master view name. - The page view. - The controller context. - The name of the view. - The name of the master view. - true to use the cached view. - The parameter is null (Nothing in Visual Basic). - The parameter is null or empty. - - - Gets or sets the master location formats. - The master location formats. - - - Gets or sets the partial-view location formats. - The partial-view location formats. - - - Releases the specified view by using the specified controller context. - The controller context. - The view to release. - - - Gets or sets the view location cache. - The view location cache. - - - Gets or sets the view location formats. - The view location formats. - - - Gets or sets the virtual path provider. - The virtual path provider. - - - Represents the information that is needed to build a Web Forms page in ASP.NET MVC. - - - Initializes a new instance of the class using the controller context and view path. - The controller context. - The view path. - - - Initializes a new instance of the class using the controller context, view path, and the path to the master page. - The controller context. - The view path. - The path to the master page. - - - Initializes a new instance of the class using the controller context, view path, the path to the master page, and a instance. - The controller context. - The view path. - The path to the master page. - An instance of the view page activator interface. - - - Gets or sets the master path. - The master path. - - - Renders the view to the response. - An object that encapsulates the information that is required in order to render the view, which includes the controller context, form context, the temporary data, and the view data for the associated view. - The text writer object that is used to write HTML output. - The view page instance. - - - Represents a view engine that is used to render a Web Forms page to the response. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the specified view page activator. - An instance of a class that implements the interface. - - - Creates the specified partial view by using the specified controller context. - The partial view. - The controller context. - The partial path. - - - Creates the specified view by using the specified controller context and the paths of the view and master view. - The view. - The controller context. - The view path. - The master-view path. - - - Represents the properties and methods that are needed in order to render a view that uses ASP.NET Razor syntax. - - - Initializes a new instance of the class. - - - Gets or sets the object that is used to render HTML using Ajax. - The object that is used to render HTML using Ajax. - - - Sets the view context and view data for the page. - The parent page. - - - Gets the object that is associated with the page. - The object that is associated with the page. - - - Runs the page hierarchy for the ASP.NET Razor execution pipeline. - - - Gets or sets the object that is used to render HTML elements. - The object that is used to render HTML elements. - - - Initializes the , , and classes. - - - Gets the Model property of the associated object. - The Model property of the associated object. - - - Sets the view data. - The view data. - - - Gets the temporary data to pass to the view. - The temporary data to pass to the view. - - - Gets or sets the URL of the rendered page. - The URL of the rendered page. - - - Gets the view bag. - The view bag. - - - Gets or sets the information that is used to render the view. - The information that is used to render the view, which includes the form context, the temporary data, and the view data of the associated view. - - - Gets or sets a dictionary that contains data to pass between the controller and the view. - A dictionary that contains data to pass between the controller and the view. - - - Represents the properties and methods that are needed in order to render a view that uses ASP.NET Razor syntax. - The type of the view data model. - - - Initializes a new instance of the class. - - - Gets or sets the object that is used to render HTML markup using Ajax. - The object that is used to render HTML markup using Ajax. - - - Gets or sets the object that is used to render HTML elements. - The object that is used to render HTML elements. - - - Initializes the , , and classes. - - - Gets the Model property of the associated object. - The Model property of the associated object. - - - Sets the view data. - The view data. - - - Gets or sets a dictionary that contains data to pass between the controller and the view. - A dictionary that contains data to pass between the controller and the view. - - - Represents support for ASP.NET AJAX within an ASP.NET MVC application. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the URL to the specified action method; when the action link is clicked, the action method is invoked asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the action method. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - The name of the controller. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - The name of the controller. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - The name of the controller. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - The name of the action method that will handle the request. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element.. - - - Writes an opening <form> tag to the response. - An opening <form> tag. - The AJAX helper. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response using the specified routing information. - An opening <form> tag. - The AJAX helper. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response using the specified routing information. - An opening <form> tag. - The AJAX helper. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response using the specified routing information. - An opening <form> tag. - The AJAX helper. - The name of the route to use to obtain the form post URL. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response using the specified routing information. - An opening <form> tag. - The AJAX helper. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - - - Writes an opening <form> tag to the response using the specified routing information. - An opening <form> tag. - The AJAX helper. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - - - Returns an HTML script element that contains a reference to a globalization script that defines the culture information. - A script element whose src attribute is set to the globalization script, as in the following example: <script type="text/javascript" src="/MvcApplication1/Scripts/Globalization/en-US.js"></script> - The AJAX helper object that this method extends. - - - Returns an HTML script element that contains a reference to a globalization script that defines the specified culture information. - An HTML script element whose src attribute is set to the globalization script, as in the following example:<script type="text/javascript" src="/MvcApplication1/Scripts/Globalization/en-US.js"></script> - The AJAX helper object that this method extends. - Encapsulates information about the target culture, such as date formats. - The parameter is null. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - The name of the route to use to obtain the form post URL. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - The parameter is null or empty. - - - Returns an anchor element that contains the virtual path for the specified route values; when the link is clicked, a request is made to the virtual path asynchronously by using JavaScript. - An anchor element. - The AJAX helper. - The inner text of the anchor element. - An object that contains the parameters for a route. - An object that provides options for the asynchronous request. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Represents option settings for running Ajax scripts in an ASP.NET MVC application. - - - Initializes a new instance of the class. - - - Gets or sets the message to display in a confirmation window before a request is submitted. - The message to display in a confirmation window. - - - Gets or sets the HTTP request method ("Get" or "Post"). - The HTTP request method. The default value is "Post". - - - Gets or sets the mode that specifies how to insert the response into the target DOM element. - The insertion mode ("InsertAfter", "InsertBefore", or "Replace"). The default value is "Replace". - - - Gets or sets a value, in milliseconds, that controls the duration of the animation when showing or hiding the loading element. - A value, in milliseconds, that controls the duration of the animation when showing or hiding the loading element. - - - Gets or sets the id attribute of an HTML element that is displayed while the Ajax function is loading. - The ID of the element that is displayed while the Ajax function is loading. - - - Gets or sets the name of the JavaScript function to call immediately before the page is updated. - The name of the JavaScript function to call before the page is updated. - - - Gets or sets the JavaScript function to call when response data has been instantiated but before the page is updated. - The JavaScript function to call when the response data has been instantiated. - - - Gets or sets the JavaScript function to call if the page update fails. - The JavaScript function to call if the page update fails. - - - Gets or sets the JavaScript function to call after the page is successfully updated. - The JavaScript function to call after the page is successfully updated. - - - Returns the Ajax options as a collection of HTML attributes to support unobtrusive JavaScript. - The Ajax options as a collection of HTML attributes to support unobtrusive JavaScript. - - - Gets or sets the ID of the DOM element to update by using the response from the server. - The ID of the DOM element to update. - - - Gets or sets the URL to make the request to. - The URL to make the request to. - - - Enumerates the AJAX script insertion modes. - - - Replace the element. - - - Insert before the element. - - - Insert after the element. - - - Provides information about an asynchronous action method, such as its name, controller, parameters, attributes, and filters. - - - Initializes a new instance of the class. - - - Invokes the asynchronous action method by using the specified parameters and controller context. - An object that contains the result of an asynchronous call. - The controller context. - The parameters of the action method. - The callback method. - An object that contains information to be used by the callback method. This parameter can be null. - - - Returns the result of an asynchronous operation. - The result of an asynchronous operation. - An object that represents the status of an asynchronous operation. - - - Executes the asynchronous action method by using the specified parameters and controller context. - The result of executing the asynchronous action method. - The controller context. - The parameters of the action method. - - - Represents a class that is responsible for invoking the action methods of an asynchronous controller. - - - Initializes a new instance of the class. - - - Invokes the asynchronous action method by using the specified controller context, action name, callback method, and state. - An object that contains the result of an asynchronous operation. - The controller context. - The name of the action. - The callback method. - An object that contains information to be used by the callback method. This parameter can be null. - - - Invokes the asynchronous action method by using the specified controller context, action descriptor, parameters, callback method, and state. - An object that contains the result of an asynchronous operation. - The controller context. - The action descriptor. - The parameters for the asynchronous action method. - The callback method. - An object that contains information to be used by the callback method. This parameter can be null. - - - Invokes the asynchronous action method by using the specified controller context, filters, action descriptor, parameters, callback method, and state. - An object that contains the result of an asynchronous operation. - The controller context. - The filters. - The action descriptor. - The parameters for the asynchronous action method. - The callback method. - An object that contains information to be used by the callback method. This parameter can be null. - - - Cancels the action. - true if the action was canceled; otherwise, false. - The user-defined object that qualifies or contains information about an asynchronous operation. - - - Cancels the action. - true if the action was canceled; otherwise, false. - The user-defined object that qualifies or contains information about an asynchronous operation. - - - Cancels the action. - true if the action was canceled; otherwise, false. - The user-defined object that qualifies or contains information about an asynchronous operation. - - - Returns the controller descriptor. - The controller descriptor. - The controller context. - - - Provides asynchronous operations for the class. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class using the synchronization context. - The synchronization context. - - - Notifies ASP.NET that all asynchronous operations are complete. - - - Occurs when the method is called. - - - Gets the number of outstanding operations. - The number of outstanding operations. - - - Gets the parameters that were passed to the asynchronous completion method. - The parameters that were passed to the asynchronous completion method. - - - Executes a callback in the current synchronization context. - The asynchronous action. - - - Gets or sets the asynchronous timeout value, in milliseconds. - The asynchronous timeout value, in milliseconds. - - - Defines the interface for an action invoker, which is used to invoke an asynchronous action in response to an HTTP request. - - - Invokes the specified action. - The status of the asynchronous result. - The controller context. - The name of the asynchronous action. - The callback method. - The state. - - - Cancels the asynchronous action. - true if the asynchronous method could be canceled; otherwise, false. - The asynchronous result. - - - Defines the methods that are required for an asynchronous controller. - - - Executes the specified request context. - The status of the asynchronous operation. - The request context. - The asynchronous callback method. - The state. - - - Ends the asynchronous operation. - The asynchronous result. - - - Provides a container for the asynchronous manager object. - - - Gets the asynchronous manager object. - The asynchronous manager object. - - - Provides a container that maintains a count of pending asynchronous operations. - - - Initializes a new instance of the class. - - - Occurs when an asynchronous method completes. - - - Gets the operation count. - The operation count. - - - Reduces the operation count by 1. - The updated operation count. - - - Reduces the operation count by the specified value. - The updated operation count. - The number of operations to reduce the count by. - - - Increments the operation count by one. - The updated operation count. - - - Increments the operation count by the specified value. - The updated operation count. - The number of operations to increment the count by. - - - Provides information about an asynchronous action method, such as its name, controller, parameters, attributes, and filters. - - - Initializes a new instance of the class. - An object that contains information about the method that begins the asynchronous operation (the method whose name ends with "Asynch"). - An object that contains information about the completion method (method whose name ends with "Completed"). - The name of the action. - The controller descriptor. - - - Gets the name of the action method. - The name of the action method. - - - Gets the method information for the asynchronous action method. - The method information for the asynchronous action method. - - - Begins running the asynchronous action method by using the specified parameters and controller context. - An object that contains the result of an asynchronous call. - The controller context. - The parameters of the action method. - The callback method. - An object that contains information to be used by the callback method. This parameter can be null. - - - Gets the method information for the asynchronous completion method. - The method information for the asynchronous completion method. - - - Gets the controller descriptor for the asynchronous action method. - The controller descriptor for the asynchronous action method. - - - Returns the result of an asynchronous operation. - The result of an asynchronous operation. - An object that represents the status of an asynchronous operation. - - - Returns an array of custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Returns an array of custom attributes that are defined for this member, identified by type. - An array of custom attributes, or an empty array if no custom attributes of the specified type exist. - The type of the custom attributes to return. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Returns the parameters of the action method. - The parameters of the action method. - - - Returns the action-method selectors. - The action-method selectors. - - - Determines whether one or more instances of the specified attribute type are defined for the action member. - true if an attribute of type that is represented by is defined for this member; otherwise, false. - The type of the custom attribute. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Gets the lazy initialized unique ID of the instance of this class. - The lazy initialized unique ID of the instance of this class. - - - Encapsulates information that describes an asynchronous controller, such as its name, type, and actions. - - - Initializes a new instance of the class. - The type of the controller. - - - Gets the type of the controller. - The type of the controller. - - - Finds an action method by using the specified name and controller context. - The information about the action method. - The controller context. - The name of the action. - - - Returns a list of action method descriptors in the controller. - A list of action method descriptors in the controller. - - - Returns custom attributes that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Returns custom attributes of a specified type that are defined for this member, excluding named attributes. - An array of custom attributes, or an empty array if no custom attributes exist. - The type of the custom attributes. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Returns a value that indicates whether one or more instances of the specified custom attribute are defined for this member. - true if an attribute of the type represented by is defined for this member; otherwise, false. - The type of the custom attribute. - true to look up the hierarchy chain for the inherited custom attribute; otherwise, false. - - - Represents an exception that occurred during the synchronous processing of an HTTP request in an ASP.NET MVC application. - - - Initializes a new instance of the class using a system-supplied message. - - - Initializes a new instance of the class using the specified message. - The message that describes the exception. The caller of this constructor must make sure that this string has been localized for the current system culture. - - - Initializes a new instance of the class using a specified error message and a reference to the inner exception that is the cause of this exception. - The message that describes the exception. The caller of this constructor must make sure that this string has been localized for the current system culture. - The exception that is the cause of the current exception. If the parameter is not null, the current exception is raised in a catch block that handles the inner exception. - - - Represents support for calling child action methods and rendering the result inline in a parent view. - - - Invokes the specified child action method and returns the result as an HTML string. - The child action result as an HTML string. - The HTML helper instance that this method extends. - The name of the action method to invoke. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method with the specified parameters and returns the result as an HTML string. - The child action result as an HTML string. - The HTML helper instance that this method extends. - The name of the action method to invoke. - An object that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified controller name and returns the result as an HTML string. - The child action result as an HTML string. - The HTML helper instance that this method extends. - The name of the action method to invoke. - The name of the controller that contains the action method. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and controller name and returns the result as an HTML string. - The child action result as an HTML string. - The HTML helper instance that this method extends. - The name of the action method to invoke. - The name of the controller that contains the action method. - An object that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and controller name and returns the result as an HTML string. - The child action result as an HTML string. - The HTML helper instance that this method extends. - The name of the action method to invoke. - The name of the controller that contains the action method. - A dictionary that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and returns the result as an HTML string. - The child action result as an HTML string. - The HTML helper instance that this method extends. - The name of the action method to invoke. - A dictionary that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method and renders the result inline in the parent view. - The HTML helper instance that this method extends. - The name of the child action method to invoke. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and renders the result inline in the parent view. - The HTML helper instance that this method extends. - The name of the child action method to invoke. - An object that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified controller name and renders the result inline in the parent view. - The HTML helper instance that this method extends. - The name of the child action method to invoke. - The name of the controller that contains the action method. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and controller name and renders the result inline in the parent view. - The HTML helper instance that this method extends. - The name of the child action method to invoke. - The name of the controller that contains the action method. - An object that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and controller name and renders the result inline in the parent view. - The HTML helper instance that this method extends. - The name of the child action method to invoke. - The name of the controller that contains the action method. - A dictionary that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Invokes the specified child action method using the specified parameters and renders the result inline in the parent view. - The HTML helper instance that this method extends. - The name of the child action method to invoke. - A dictionary that contains the parameters for a route. You can use to provide the parameters that are bound to the action method parameters. The parameter is merged with the original route values and overrides them. - The parameter is null. - The parameter is null or empty. - The required virtual path data cannot be found. - - - Represents support for rendering object values as HTML. - - - Returns HTML markup for each property in the object that is represented by a string expression. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - - - Returns HTML markup for each property in the object that is represented by a string expression, using additional view data. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns HTML markup for each property in the object that is represented by the expression, using the specified template. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - - - Returns HTML markup for each property in the object that is represented by the expression, using the specified template and additional view data. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns HTML markup for each property in the object that is represented by the expression, using the specified template and an HTML field ID. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - - - Returns HTML markup for each property in the object that is represented by the expression, using the specified template, HTML field ID, and additional view data. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns HTML markup for each property in the object that is represented by the expression. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The type of the model. - The type of the value. - - - Returns a string that contains each property value in the object that is represented by the specified expression, using additional view data. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - The type of the model. - The type of the value. - - - Returns a string that contains each property value in the object that is represented by the , using the specified template. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - The type of the model. - The type of the value. - - - Returns a string that contains each property value in the object that is represented by the specified expression, using the specified template and additional view data. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - The type of the model. - The type of the value. - - - Returns HTML markup for each property in the object that is represented by the , using the specified template and an HTML field ID. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - The type of the model. - The type of the value. - - - Returns HTML markup for each property in the object that is represented by the specified expression, using the template, an HTML field ID, and additional view data. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template that is used to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - The type of the model. - The type of the value. - - - Returns HTML markup for each property in the model. - The HTML markup for each property in the model. - The HTML helper instance that this method extends. - - - Returns HTML markup for each property in the model, using additional view data. - The HTML markup for each property in the model. - The HTML helper instance that this method extends. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns HTML markup for each property in the model using the specified template. - The HTML markup for each property in the model. - The HTML helper instance that this method extends. - The name of the template that is used to render the object. - - - Returns HTML markup for each property in the model, using the specified template and additional view data. - The HTML markup for each property in the model. - The HTML helper instance that this method extends. - The name of the template that is used to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns HTML markup for each property in the model using the specified template and HTML field ID. - The HTML markup for each property in the model. - The HTML helper instance that this method extends. - The name of the template that is used to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - - - Returns HTML markup for each property in the model, using the specified template, an HTML field ID, and additional view data. - The HTML markup for each property in the model. - The HTML helper instance that this method extends. - The name of the template that is used to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Provides a way to render object values as HTML. - - - Returns HTML markup for each property in the object that is represented by the specified expression. - The HTML markup for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - - - Returns HTML markup for each property in the object that is represented by the specified expression. - The HTML markup for each property.zz 12/29/2010 1:25:49 PM - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The type of the model. - The type of the result. - - - Represents support for the HTML input element in an application. - - - Returns an HTML input element for each property in the object that is represented by the expression. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - - - Returns an HTML input element for each property in the object that is represented by the expression, using additional view data. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template and additional view data. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template and HTML field name. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template, HTML field name, and additional view data. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns an HTML input element for each property in the object that is represented by the expression. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The type of the model. - The type of the value. - - - Returns an HTML input element for each property in the object that is represented by the expression, using additional view data. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - The type of the model. - The type of the value. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - The type of the model. - The type of the value. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template and additional view data. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - The type of the model. - The type of the value. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template and HTML field name. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - The type of the model. - The type of the value. - - - Returns an HTML input element for each property in the object that is represented by the expression, using the specified template, HTML field name, and additional view data. - An HTML input element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - The name of the template to use to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - The type of the model. - The type of the value. - - - Returns an HTML input element for each property in the model. - An HTML input element for each property in the model. - The HTML helper instance that this method extends. - - - Returns an HTML input element for each property in the model, using additional view data. - An HTML input element for each property in the model. - The HTML helper instance that this method extends. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns an HTML input element for each property in the model, using the specified template. - An HTML input element for each property in the model and in the specified template. - The HTML helper instance that this method extends. - The name of the template to use to render the object. - - - Returns an HTML input element for each property in the model, using the specified template and additional view data. - An HTML input element for each property in the model. - The HTML helper instance that this method extends. - The name of the template to use to render the object. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Returns an HTML input element for each property in the model, using the specified template name and HTML field name. - An HTML input element for each property in the model and in the named template. - The HTML helper instance that this method extends. - The name of the template to use to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - - - Returns an HTML input element for each property in the model, using the template name, HTML field name, and additional view data. - An HTML input element for each property in the model. - The HTML helper instance that this method extends. - The name of the template to use to render the object. - A string that is used to disambiguate the names of HTML input elements that are rendered for properties that have the same name. - An anonymous object that can contain additional view data that will be merged into the instance that is created for the template. - - - Represents support for HTML in an application. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - The HTTP method for processing the form, either GET or POST. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - The HTTP method for processing the form, either GET or POST. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - The HTTP method for processing the form, either GET or POST. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the action method. - The name of the controller. - An object that contains the parameters for a route. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. - An opening <form> tag. - The HTML helper instance that this method extends. - An object that contains the parameters for a route. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - The HTTP method for processing the form, either GET or POST. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. This object is typically created by using object initializer syntax. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - The HTTP method for processing the form, either GET or POST. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - An object that contains the parameters for a route - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - An object that contains the parameters for a route - The HTTP method for processing the form, either GET or POST. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - The name of the route to use to obtain the form-post URL. - An object that contains the parameters for a route - The HTTP method for processing the form, either GET or POST. - An object that contains the HTML attributes to set for the element. - - - Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by the route target. - An opening <form> tag. - The HTML helper instance that this method extends. - An object that contains the parameters for a route - - - Renders the closing </form> tag to the response. - The HTML helper instance that this method extends. - - - Represents support for HTML input controls in an application.12/23/2010 12:04:24 PM zz - - - Returns a check box input element by using the specified HTML helper and the name of the form field. - An input element whose type attribute is set to "checkbox". - The HTML helper instance that this method extends. - The name of the form field. - - - Returns a check box input element by using the specified HTML helper, the name of the form field, and a value to indicate whether the check box is selected. - An input element whose type attribute is set to "checkbox". - The HTML helper instance that this method extends. - The name of the form field. - true to select the check box; otherwise, false. - - - Returns a check box input element by using the specified HTML helper, the name of the form field, a value to indicate whether the check box is selected, and the HTML attributes. - An input element whose type attribute is set to "checkbox". - The HTML helper instance that this method extends. - The name of the form field. - true to select the check box; otherwise, false. - An object that contains the HTML attributes to set for the element. - - - Returns a check box input element by using the specified HTML helper, the name of the form field, a value that indicates whether the check box is selected, and the HTML attributes. - An input element whose type attribute is set to "checkbox". - The HTML helper instance that this method extends. - The name of the form field. - true to select the check box; otherwise, false. - An object that contains the HTML attributes to set for the element. - - - Returns a check box input element by using the specified HTML helper, the name of the form field, and the HTML attributes. - An input element whose type attribute is set to "checkbox". - The HTML helper instance that this method extends. - The name of the form field. - An object that contains the HTML attributes to set for the element. - - - Returns a check box input element by using the specified HTML helper, the name of the form field, and the HTML attributes. - An input element whose type attribute is set to "checkbox". - The HTML helper instance that this method extends. - The name of the form field. - An object that contains the HTML attributes to set for the element. - - - Returns a check box input element for each property in the object that is represented by the specified expression. - An HTML input element whose type attribute is set to "checkbox" for each property in the object that is represented by the specified expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The parameter is null. - - - Returns a check box input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "checkbox" for each property in the object that is represented by the specified expression, using the specified HTML attributes. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The parameter is null. - - - Returns a check box input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "checkbox" for each property in the object that is represented by the specified expression, using the specified HTML attributes. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - An object that contains the HTML attributes to set for the element. - The type of the model. - The parameter is null. - - - Returns a hidden input element by using the specified HTML helper and the name of the form field. - An input element whose type attribute is set to "hidden". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - - - Returns a hidden input element by using the specified HTML helper, the name of the form field, and the value. - An input element whose type attribute is set to "hidden". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the hidden input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - - - Returns a hidden input element by using the specified HTML helper, the name of the form field, the value, and the HTML attributes. - An input element whose type attribute is set to "hidden". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the hidden input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - An object that contains the HTML attributes to set for the element. - - - Returns a hidden input element by using the specified HTML helper, the name of the form field, the value, and the HTML attributes. - An input element whose type attribute is set to "hidden". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the hidden input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - An object that contains the HTML attributes to set for the element. - - - Returns an HTML hidden input element for each property in the object that is represented by the specified expression. - An input element whose type attribute is set to "hidden" for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The type of the property. - - - Returns an HTML hidden input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An input element whose type attribute is set to "hidden" for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - An object that contains the HTML attributes to set for the element. - The type of the model. - The type of the property. - - - Returns an HTML hidden input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An input element whose type attribute is set to "hidden" for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - An object that contains the HTML attributes to set for the element. - The type of the model. - The type of the property. - - - Returns a password input element by using the specified HTML helper and the name of the form field. - An input element whose type attribute is set to "password". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - - - Returns a password input element by using the specified HTML helper, the name of the form field, and the value. - An input element whose type attribute is set to "password". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the password input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - - - Returns a password input element by using the specified HTML helper, the name of the form field, the value, and the HTML attributes. - An input element whose type attribute is set to "password". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the password input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - An object that contains the HTML attributes to set for the element. - - - Returns a password input element by using the specified HTML helper, the name of the form field, the value, and the HTML attributes. - An input element whose type attribute is set to "password". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the password input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - An object that contains the HTML attributes to set for the element. - - - Returns a password input element for each property in the object that is represented by the specified expression. - An HTML input element whose type attribute is set to "password" for each property in the object that is represented by the specified expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a password input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "password" for each property in the object that is represented by the specified expression, using the specified HTML attributes. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a password input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "password" for each property in the object that is represented by the specified expression, using the specified HTML attributes. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - An object that contains the HTML attributes to set for the element. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a radio button input element that is used to present mutually exclusive options. - An input element whose type attribute is set to "radio". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - The parameter is null or empty. - The parameter is null. - - - Returns a radio button input element that is used to present mutually exclusive options. - An input element whose type attribute is set to "radio". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - true to select the radio button; otherwise, false. - The parameter is null or empty. - The parameter is null. - - - Returns a radio button input element that is used to present mutually exclusive options. - An input element whose type attribute is set to "radio". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - true to select the radio button; otherwise, false. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - The parameter is null. - - - Returns a radio button input element that is used to present mutually exclusive options. - An input element whose type attribute is set to "radio". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - true to select the radio button; otherwise, false. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - The parameter is null. - - - Returns a radio button input element that is used to present mutually exclusive options. - An input element whose type attribute is set to "radio". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - The parameter is null. - - - Returns a radio button input element that is used to present mutually exclusive options. - An input element whose type attribute is set to "radio". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - The parameter is null. - - - Returns a radio button input element for each property in the object that is represented by the specified expression. - An HTML input element whose type attribute is set to "radio" for each property in the object that is represented by the specified expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a radio button input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "radio" for each property in the object that is represented by the specified expression, using the specified HTML attributes. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a radio button input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "radio" for each property in the object that is represented by the specified expression, using the specified HTML attributes. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - If this radio button is selected, the value of the radio button that is submitted when the form is posted. If the value of the selected radio button in the or the object matches this value, this radio button is selected. - An object that contains the HTML attributes to set for the element. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a text input element by using the specified HTML helper and the name of the form field. - An input element whose type attribute is set to "text". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - - - Returns a text input element by using the specified HTML helper, the name of the form field, and the value. - An input element whose type attribute is set to "text". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the text input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - - - Returns a text input element by using the specified HTML helper, the name of the form field, the value, and the HTML attributes. - An input element whose type attribute is set to "text". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the text input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - An object that contains the HTML attributes to set for the element. - - - Returns a text input element by using the specified HTML helper, the name of the form field, the value, and the HTML attributes. - An input element whose type attribute is set to "text". - The HTML helper instance that this method extends. - The name of the form field and the key that is used to look up the value. - The value of the text input element. If this value is null, the value of the element is retrieved from the object. If no value exists there, the value is retrieved from the object. - An object that contains the HTML attributes to set for the element. - - - Returns a text input element for each property in the object that is represented by the specified expression. - An HTML input element whose type attribute is set to "text" for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The type of the value. - The parameter is null or empty. - - - Returns a text input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element type attribute is set to "text" for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the value. - The parameter is null or empty. - - - Returns a text input element for each property in the object that is represented by the specified expression, using the specified HTML attributes. - An HTML input element whose type attribute is set to "text" for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - An object that contains the HTML attributes to set for the element. - The type of the model. - The type of the value. - The parameter is null or empty. - - - Represents support for the HTML label element in an ASP.NET MVC view. - - - Returns an HTML label element and the property name of the property that is represented by the specified expression. - An HTML label element and the property name of the property that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the property to display. - - - Returns . - - - An HTML label element and the property name of the property that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the property to display. - The type of the model. - The type of the value. - - - An HTML label element and the property name of the property that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the property to display. - The label text. - The type of the model. - The type of the value. - - - Returns an HTML label element and the property name of the property that is represented by the model. - An HTML label element and the property name of the property that is represented by the model. - The HTML helper instance that this method extends. - - - Returns . - - - Represents support for HTML links in an application. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - An object that contains the HTML attributes for the element. The attributes are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - The name of the controller. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - The name of the controller. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - The name of the controller. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - The name of the controller. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - The name of the controller. - An object that contains the parameters for a route. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - An object that contains the parameters for a route. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the action. - An object that contains the parameters for a route. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - The protocol for the URL, such as "http" or "https". - The host name for the URL. - The URL fragment name (the anchor name). - An object that contains the parameters for a route. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - An object that contains the parameters for a route. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - The name of the route that is used to return a virtual path. - An object that contains the parameters for a route. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - An object that contains the parameters for a route. - The parameter is null or empty. - - - Returns an anchor element (a element) that contains the virtual path of the specified action. - An anchor element (a element). - The HTML helper instance that this method extends. - The inner text of the anchor element. - An object that contains the parameters for a route. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Represents an HTML form element in an MVC view. - - - Initializes a new instance of the class using the specified HTTP response object. - The HTTP response object. - The parameter is null. - - - Initializes a new instance of the class using the specified view context. - An object that encapsulates the information that is required in order to render a view. - The parameter is null. - - - Releases all resources that are used by the current instance of the class. - - - Releases unmanaged and, optionally, managed resources used by the current instance of the class. - true to release both managed and unmanaged resources; false to release only unmanaged resources. - - - Ends the form and disposes of all form resources. - - - Represents the functionality to render a partial view as an HTML-encoded string. - - - Renders the specified partial view as an HTML-encoded string. - The partial view that is rendered as an HTML-encoded string. - The HTML helper instance that this method extends. - The name of the partial view to render. - - - Renders the specified partial view as an HTML-encoded string. - The partial view that is rendered as an HTML-encoded string. - The HTML helper instance that this method extends. - The name of the partial view to render. - The model for the partial view. - - - Renders the specified partial view as an HTML-encoded string. - The partial view that is rendered as an HTML-encoded string. - The HTML helper instance that this method extends. - The name of the partial view. - The model for the partial view. - The view data dictionary for the partial view. - - - Renders the specified partial view as an HTML-encoded string. - The partial view that is rendered as an HTML-encoded string. - The HTML helper instance that this method extends. - The name of the partial view to render. - The view data dictionary for the partial view. - - - Provides support for rendering a partial view. - - - Renders the specified partial view by using the specified HMTL helper. - The HTML helper. - The name of the partial view - - - Renders the specified partial view, passing it a copy of the current object, but with the Model property set to the specified model. - The HTML helper. - The name of the partial view. - The model. - - - Renders the specified partial view, replacing the partial view's ViewData property with the specified object and setting the Model property of the view data to the specified model. - The HTML helper. - The name of the partial view. - The model for the partial view. - The view data for the partial view. - - - Renders the specified partial view, replacing its ViewData property with the specified object. - The HTML helper. - The name of the partial view. - The view data. - - - Represents support for making selections in a list. - - - Returns a single-selection select element using the specified HTML helper and the name of the form field. - An HTML select element. - The HTML helper instance that this method extends. - The name of the form field to return. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, and the specified list items. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, the specified list items, and the specified HTML attributes. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, the specified list items, and the specified HTML attributes. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, the specified list items, and an option label. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - The text for a default empty item. This parameter can be null. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, the specified list items, an option label, and the specified HTML attributes. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - The text for a default empty item. This parameter can be null. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, the specified list items, an option label, and the specified HTML attributes. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - The text for a default empty item. This parameter can be null. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns a single-selection select element using the specified HTML helper, the name of the form field, and an option label. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - The text for a default empty item. This parameter can be null. - The parameter is null or empty. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the value. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items and HTML attributes. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the value. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items and HTML attributes. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the value. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items and option label. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the value. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items, option label, and HTML attributes. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the value. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items, option label, and HTML attributes. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the value. - The parameter is null. - - - Returns a multi-select select element using the specified HTML helper and the name of the form field. - An HTML select element. - The HTML helper instance that this method extends. - The name of the form field to return. - The parameter is null or empty. - - - Returns a multi-select select element using the specified HTML helper, the name of the form field, and the specified list items. - An HTML select element with an option subelement for each item in the list. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - The parameter is null or empty. - - - Returns a multi-select select element using the specified HTML helper, the name of the form field, the specified list items, and the specified HMTL attributes. - An HTML select element with an option subelement for each item in the list.. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns a multi-select select element using the specified HTML helper, the name of the form field, and the specified list items. - An HTML select element with an option subelement for each item in the list.. - The HTML helper instance that this method extends. - The name of the form field to return. - A collection of objects that are used to populate the drop-down list. - An object that contains the HTML attributes to set for the element. - The parameter is null or empty. - - - Returns an HTML select element for each property in the object that is represented by the specified expression and using the specified list items. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the property. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items and HTML attributes. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the property. - The parameter is null. - - - Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items and HTML attributes. - An HTML select element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to display. - A collection of objects that are used to populate the drop-down list. - The type of the model. - The type of the property. - The parameter is null. - - - Represents support for HTML textarea controls. - - - Returns the specified textarea element by using the specified HTML helper and the name of the form field. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - - - Returns the specified textarea element by using the specified HTML helper, the name of the form field, and the specified HTML attributes. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - An object that contains the HTML attributes to set for the element. - - - Returns the specified textarea element by using the specified HTML helper and HTML attributes. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - An object that contains the HTML attributes to set for the element. - - - Returns the specified textarea element by using the specified HTML helper, the name of the form field, and the text content. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - The text content. - - - Returns the specified textarea element by using the specified HTML helper, the name of the form field, the text content, and the specified HTML attributes. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - The text content. - An object that contains the HTML attributes to set for the element. - - - Returns the specified textarea element by using the specified HTML helper, the name of the form field, the text content, the number of rows and columns, and the specified HTML attributes. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - The text content. - The number of rows. - The number of columns. - An object that contains the HTML attributes to set for the element. - - - Returns the specified textarea element by using the specified HTML helper, the name of the form field, the text content, the number of rows and columns, and the specified HTML attributes. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - The text content. - The number of rows. - The number of columns. - An object that contains the HTML attributes to set for the element. - - - Returns the specified textarea element by using the specified HTML helper, the name of the form field, the text content, and the specified HTML attributes. - The textarea element. - The HTML helper instance that this method extends. - The name of the form field to return. - The text content. - An object that contains the HTML attributes to set for the element. - - - Returns an HTML textarea element for each property in the object that is represented by the specified expression. - An HTML textarea element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The type of the property. - The parameter is null. - - - Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes. - An HTML textarea element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the property. - The parameter is null. - - - Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes and the number of rows and columns. - An HTML textarea element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The number of rows. - The number of columns. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the property. - The parameter is null. - - - Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes and the number of rows and columns. - An HTML textarea element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The number of rows. - The number of columns. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the property. - The parameter is null. - - - Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes. - An HTML textarea element for each property in the object that is represented by the expression. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - A dictionary that contains the HTML attributes to set for the element. - The type of the model. - The type of the property. - The parameter is null. - - - Provides support for validating the input from an HTML form. - - - Gets or sets the name of the resource file (class key) that contains localized string values. - The name of the resource file (class key). - - - Retrieves the validation metadata for the specified model and applies each rule to the data field. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - The parameter is null. - - - Retrieves the validation metadata for the specified model and applies each rule to the data field. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The type of the property. - - - Displays a validation message if an error exists for the specified field in the object. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - - - Displays a validation message if an error exists for the specified field in the object. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - An object that contains the HTML attributes for the element. - - - Displays a validation message if an error exists for the specified field in the object. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - An object that contains the HTML attributes for the element. - - - Displays a validation message if an error exists for the specified field in the object. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - The message to display if the specified field contains an error. - - - Displays a validation message if an error exists for the specified field in the object. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - The message to display if the specified field contains an error. - An object that contains the HTML attributes for the element. - - - Displays a validation message if an error exists for the specified field in the object. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - The name of the property or model object that is being validated. - The message to display if the specified field contains an error. - An object that contains the HTML attributes for the element. - - - Returns the HTML markup for a validation-error message for each data field that is represented by the specified expression. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The type of the model. - The type of the property. - - - Returns the HTML markup for a validation-error message for each data field that is represented by the specified expression, using the specified message. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The message to display if the specified field contains an error. - The type of the model. - The type of the property. - - - Returns the HTML markup for a validation-error message for each data field that is represented by the specified expression, using the specified message and HTML attributes. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The message to display if the specified field contains an error. - An object that contains the HTML attributes for the element. - The type of the model. - The type of the property. - - - Returns the HTML markup for a validation-error message for each data field that is represented by the specified expression, using the specified message and HTML attributes. - If the property or object is valid, an empty string; otherwise, a span element that contains an error message. - The HTML helper instance that this method extends. - An expression that identifies the object that contains the properties to render. - The message to display if the specified field contains an error. - An object that contains the HTML attributes for the element. - The type of the model. - The type of the property. - - - Returns an unordered list (ul element) of validation messages that are in the object. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - - - Returns an unordered list (ul element) of validation messages that are in the object and optionally displays only model-level errors. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - true to have the summary display model-level errors only, or false to have the summary display all errors. - - - Returns an unordered list (ul element) of validation messages that are in the object and optionally displays only model-level errors. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - true to have the summary display model-level errors only, or false to have the summary display all errors. - The message to display with the validation summary. - - - Returns an unordered list (ul element) of validation messages that are in the object and optionally displays only model-level errors. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - true to have the summary display model-level errors only, or false to have the summary display all errors. - The message to display with the validation summary. - A dictionary that contains the HTML attributes for the element. - - - Returns an unordered list (ul element) of validation messages that are in the object and optionally displays only model-level errors. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - true to have the summary display model-level errors only, or false to have the summary display all errors. - The message to display with the validation summary. - An object that contains the HTML attributes for the element. - - - Returns an unordered list (ul element) of validation messages that are in the object. - A string that contains an unordered list (ul element) of validation messages. - The HMTL helper instance that this method extends. - The message to display if the specified field contains an error. - - - Returns an unordered list (ul element) of validation messages that are in the object. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - The message to display if the specified field contains an error. - A dictionary that contains the HTML attributes for the element. - - - Returns an unordered list (ul element) of validation messages in the object. - A string that contains an unordered list (ul element) of validation messages. - The HTML helper instance that this method extends. - The message to display if the specified field contains an error. - An object that contains the HTML attributes for the element. - - - Provides a model-aware class for ASP.NET MVC. - - - Initializes a new instance of the class. - The start of the span. - The content. - The type name of the model. - - - Gets a value that indicates whether the current object is identical to the specified object. - true if the current object is identical to the specified object; otherwise, false. - The model span object. - - - Returns the hash code of the object. - The hash code of the object. - - - Gets the type name of the model. - The type name of the model. - - - Compiles ASP.NET Razor views into classes. - - - Initializes a new instance of the class. - The class name. - The root namespace. - The name of the source file. - The ASP.NET Razor engine host. - - - Returns a value that indicates whether the specified model span is an instance of . - true if the value of the parameter is an instance of ; otherwise, false. - The model span. - - - - - - Compiles ASP.NET Razor views into classes. - - - - - Extends the VBCodeParser class by adding support for the @model keyword. - - - Initializes a new instance of the class. - - - - Configures the ASP.NET Razor parser and code generator for a specified file. - - - Initializes a new instance of the class. - The virtual path of the ASP.NET Razor file. - The physical path of the ASP.NET Razor file. - - - - - \ No newline at end of file diff --git a/lib/System.Web.Razor.dll b/lib/System.Web.Razor.dll deleted file mode 100644 index 1ee1122a6a7..00000000000 Binary files a/lib/System.Web.Razor.dll and /dev/null differ diff --git a/lib/protobuf-net.dll b/lib/protobuf-net.dll deleted file mode 100644 index 99bbb956f80..00000000000 Binary files a/lib/protobuf-net.dll and /dev/null differ diff --git a/lib/tests/Mono.Data.Sqlite.dll b/lib/tests/Mono.Data.Sqlite.dll deleted file mode 100644 index dad79f065d7..00000000000 Binary files a/lib/tests/Mono.Data.Sqlite.dll and /dev/null differ diff --git a/lib/tests/Moq.dll b/lib/tests/Moq.dll deleted file mode 100644 index abcb72ee64c..00000000000 Binary files a/lib/tests/Moq.dll and /dev/null differ diff --git a/lib/tests/Moq.pdb b/lib/tests/Moq.pdb deleted file mode 100644 index 034ab186e52..00000000000 Binary files a/lib/tests/Moq.pdb and /dev/null differ diff --git a/lib/tests/Moq.xml b/lib/tests/Moq.xml deleted file mode 100644 index a29e2306a7c..00000000000 --- a/lib/tests/Moq.xml +++ /dev/null @@ -1,2930 +0,0 @@ - - - - Moq - - - - - A that returns an empty default value - for invocations that do not have expectations or return values, with loose mocks. - This is the default behavior for a mock. - - - - - Interface to be implemented by classes that determine the - default value of non-expected invocations. - - - - - Provides a value for the given member and arguments. - - The member to provide a default - value for. - Optional arguments passed in - to the call that requires a default value. - - - Type to mock, which can be an interface or a class. - - Provides a mock implementation of . - - - Only abstract and virtual members of classes can be mocked. - - The behavior of the mock with regards to the expectations and the actual calls is determined - by the optional that can be passed to the - constructor. - - - - The following example shows setting expectations with specific values - for method invocations: - - //setup - data - var order = new Order(TALISKER, 50); - var mock = new Mock<IWarehouse>(); - - //setup - expectations - mock.Expect(x => x.HasInventory(TALISKER, 50)).Returns(true); - - //exercise - order.Fill(mock.Object); - - //verify - Assert.True(order.IsFilled); - - The following example shows how to use the class - to specify conditions for arguments instead of specific values: - - //setup - data - var order = new Order(TALISKER, 50); - var mock = new Mock<IWarehouse>(); - - //setup - expectations - //shows how to expect a value within a range - mock.Expect(x => x.HasInventory( - It.IsAny<string>(), - It.IsInRange(0, 100, Range.Inclusive))) - .Returns(false); - - //shows how to throw for unexpected calls. contrast with the "verify" approach of other mock libraries. - mock.Expect(x => x.Remove( - It.IsAny<string>(), - It.IsAny<int>())) - .Throws(new InvalidOperationException()); - - //exercise - order.Fill(mock.Object); - - //verify - Assert.False(order.IsFilled); - - - - - - Helper interface used to hide the base - members from the fluent API to make it much cleaner - in Visual Studio intellisense. - - - - - - - - - - - - - - - - - Adds an interface implementation to the mock, - allowing expectations to be set for it. - - - This method can only be called before the first use - of the mock property, at which - point the runtime type has already been generated - and no more interfaces can be added to it. - - Also, must be an - interface and not a class, which must be specified - when creating the mock instead. - - - The mock type - has already been generated by accessing the property. - The specified - is not an interface. - - The following example creates a mock for the main interface - and later adds to it to verify - it's called by the consumer code: - - var mock = new Mock<IProcessor>(); - mock.Expect(x => x.Execute("ping")); - - // add IDisposable interface - var disposable = mock.As<IDisposable>(); - disposable.Expect(d => d.Dispose()).Verifiable(); - - - Type of interface to cast the mock to. - - - - Sets an expectation on the mocked type for a call to - to a value returning method. - - Type of the return value. Typically omitted as it can be inferred from the expression. - - If more than one expectation is set for the same method or property, - the latest one wins and is the one that will be executed. - - Lambda expression that specifies the expected method invocation. - - - mock.Expect(x => x.HasInventory("Talisker", 50)).Returns(true); - - - - - - Sets an expectation on the mocked type for a call to - to a void method. - - - If more than one expectation is set for the same method or property, - the latest one wins and is the one that will be executed. - - Lambda expression that specifies the expected method invocation. - - - var mock = new Mock<IProcessor>(); - mock.Expect(x => x.Execute("ping")); - - - - - - Sets an expectation on the mocked type for a call to - to a property getter. - - - If more than one expectation is set for the same property getter, - the latest one wins and is the one that will be executed. - - Type of the property. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected property getter. - - - mock.ExpectGet(x => x.Suspended) - .Returns(true); - - - - - - Sets an expectation on the mocked type for a call to - to a property setter. - - - If more than one expectation is set for the same property setter, - the latest one wins and is the one that will be executed. - - Type of the property. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected property setter. - - - mock.ExpectSet(x => x.Suspended); - - - - - - Sets an expectation on the mocked type for a call to - to a property setter with a specific value. - - - More than one expectation can be set for the setter with - different values. - - Type of the property. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected property setter. - The value expected to be set for the property. - - - mock.ExpectSet(x => x.Suspended, true); - - - - - - Implements . - - - - - Implements . - - - - - Verifies that a specific invocation matching the given - expression was performed on the mock. Use in conjuntion - with the default . - - - This example assumes that the mock has been used, - and later we want to verify that a given invocation - with specific parameters was performed: - - var mock = new Mock<IProcessor>(); - // exercise mock - //... - // Will throw if the test code didn't call Execute with a "ping" string argument. - mock.Verify(proc => proc.Execute("ping")); - - - The invocation was not performed on the mock. - Expression to verify. - - - - Verifies that a specific invocation matching the given - expression was performed on the mock. Use in conjuntion - with the default . - - - This example assumes that the mock has been used, - and later we want to verify that a given invocation - with specific parameters was performed: - - var mock = new Mock<IWarehouse>(); - // exercise mock - //... - // Will throw if the test code didn't call HasInventory. - mock.Verify(warehouse => warehouse.HasInventory(TALISKER, 50)); - - - The invocation was not performed on the mock. - Expression to verify. - Type of return value from the expression. - - - - Verifies that a property was read on the mock. - Use in conjuntion with the default . - - - This example assumes that the mock has been used, - and later we want to verify that a given property - was retrieved from it: - - var mock = new Mock<IWarehouse>(); - // exercise mock - //... - // Will throw if the test code didn't retrieve the IsClosed property. - mock.VerifyGet(warehouse => warehouse.IsClosed); - - - The invocation was not performed on the mock. - Expression to verify. - Type of the property to verify. Typically omitted as it can - be inferred from the expression's return type. - - - - Verifies that a property has been set on the mock. - Use in conjuntion with the default . - - - This example assumes that the mock has been used, - and later we want to verify that a given invocation - with specific parameters was performed: - - var mock = new Mock<IWarehouse>(); - // exercise mock - //... - // Will throw if the test code didn't set the IsClosed property. - mock.VerifySet(warehouse => warehouse.IsClosed); - - - The invocation was not performed on the mock. - Expression to verify. - Type of the property to verify. Typically omitted as it can - be inferred from the expression's return type. - - - - Verifies that a property has been set on the mock to the given value. - Use in conjuntion with the default . - - - This example assumes that the mock has been used, - and later we want to verify that a given invocation - with specific parameters was performed: - - var mock = new Mock<IWarehouse>(); - // exercise mock - //... - // Will throw if the test code didn't set the IsClosed property to true - mock.VerifySet(warehouse => warehouse.IsClosed, true); - - - The invocation was not performed on the mock. - Expression to verify. - The value that should have been set on the property. - Type of the property to verify. Typically omitted as it can - be inferred from the expression's return type. - - - - Exposes the mocked object instance. - - - - - Specifies the behavior to use when returning default values for - unexpected invocations. - - - - - Behavior of the mock, according to the value set in the constructor. - - - - - Implements the fluent API. - - - - - Defines the Callback verb and overloads. - - - - - Specifies a callback to invoke when the method is called. - - Callback method to invoke. - - The following example specifies a callback to set a boolean - value that can be used later: - - bool called = false; - mock.Expect(x => x.Execute()) - .Callback(() => called = true); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Argument type of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation argument value. - - Notice how the specific string argument is retrieved by simply declaring - it as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute(It.IsAny<string>())) - .Callback((string command) => Console.WriteLine(command)); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation arguments values. - - Notice how the specific arguments are retrieved by simply declaring - them as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>())) - .Callback((string arg1, string arg2) => Console.WriteLine(arg1 + arg2)); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Type of the third argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation arguments values. - - Notice how the specific arguments are retrieved by simply declaring - them as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>(), - It.IsAny<int>())) - .Callback((string arg1, string arg2, int arg3) => Console.WriteLine(arg1 + arg2 + arg3)); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Type of the third argument of the invoked method. - Type of the fourth argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation arguments values. - - Notice how the specific arguments are retrieved by simply declaring - them as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>(), - It.IsAny<int>(), - It.IsAny<bool>())) - .Callback((string arg1, string arg2, int arg3, bool arg4) => Console.WriteLine(arg1 + arg2 + arg3 + arg4)); - - - - - - Defines occurrence members to constraint expectations. - - - - - The expected invocation can happen at most once. - - - - var mock = new Mock<ICommand>(); - mock.Expect(foo => foo.Execute("ping")) - .AtMostOnce(); - - - - - - The expected invocation can happen at most specified number of times. - - - - var mock = new Mock<ICommand>(); - mock.Expect(foo => foo.Execute("ping")) - .AtMost( 5 ); - - - - - - Defines the Verifiable verb. - - - - - Marks the expectation as verifiable, meaning that a call - to will check if this particular - expectation was met. - - - The following example marks the expectation as verifiable: - - mock.Expect(x => x.Execute("ping")) - .Returns(true) - .Verifiable(); - - - - - - Defines the Raises verb. - - - - - Specifies the mocked event that will be raised - when the expectation is met. - - The mocked event, retrieved from - or . - - The event args to pass when raising the event. - - The following example shows how to set an expectation that will - raise an event when it's met: - - var mock = new Mock<IContainer>(); - // create handler to associate with the event to raise - var handler = mock.CreateEventHandler(); - // associate the handler with the event to raise - mock.Object.Added += handler; - // set the expectation and the handler to raise - mock.Expect(add => add.Add(It.IsAny<string>(), It.IsAny<object>())) - .Raises(handler, EventArgs.Empty); - - - - - - Specifies the mocked event that will be raised - when the expectation is met. - - The mocked event, retrieved from - or . - - A function that will build the - to pass when raising the event. - - - - - Specifies the mocked event that will be raised - when the expectation is met. - - The mocked event, retrieved from - or . - - A function that will build the - to pass when raising the event. - Type of the argument received by the expected invocation. - - - - - Specifies the mocked event that will be raised - when the expectation is met. - - The mocked event, retrieved from - or . - - A function that will build the - to pass when raising the event. - Type of the first argument received by the expected invocation. - Type of the second argument received by the expected invocation. - - - - - Specifies the mocked event that will be raised - when the expectation is met. - - The mocked event, retrieved from - or . - - A function that will build the - to pass when raising the event. - Type of the first argument received by the expected invocation. - Type of the second argument received by the expected invocation. - Type of the third argument received by the expected invocation. - - - - - Specifies the mocked event that will be raised - when the expectation is met. - - The mocked event, retrieved from - or . - - A function that will build the - to pass when raising the event. - Type of the first argument received by the expected invocation. - Type of the second argument received by the expected invocation. - Type of the third argument received by the expected invocation. - Type of the fourth argument received by the expected invocation. - - - - - Marks a method as a matcher, which allows complete replacement - of the built-in class with your own argument - matching rules. - - - The argument matching is used to determine whether a concrete - invocation in the mock matches a given expectation. This - matching mechanism is fully extensible. - - There are two parts of a matcher: the compiler matcher - and the runtime matcher. - - - Compiler matcher - Used to satisfy the compiler requirements for the - argument. Needs to be a method optionally receiving any arguments - you might need for the matching, but with a return type that - matches that of the argument. - - Let's say I want to match a lists of orders that contains - a particular one. I might create a compiler matcher like the following: - - - public static class Orders - { - [Matcher] - public static IEnumerable<Order> Contains(Order order) - { - return null; - } - } - - Now we can invoke this static method instead of an argument in an - invocation: - - var order = new Order { ... }; - var mock = new Mock<IRepository<Order>>(); - - mock.Expect(x => x.Save(Orders.Contains(order))) - .Throws<ArgumentException>(); - - Note that the return value from the compiler matcher is irrelevant. - This method will never be called, and is just used to satisfy the - compiler and to signal Moq that this is not a method that we want - to be invoked at runtime. - - - - Runtime matcher - - The runtime matcher is the one that will actually perform evaluation - when the test is run, and is defined by convention to have the - same signature as the compiler matcher, but where the return - value is the first argument to the call, which contains the - object received by the actual invocation at runtime: - - public static bool Contains(IEnumerable<Order> orders, Order order) - { - return orders.Contains(order); - } - - At runtime, the mocked method will be invoked with a specific - list of orders. This value will be passed to this runtime - matcher as the first argument, while the second argument is the - one specified in the expectation (x.Save(Orders.Contains(order))). - - The boolean returned determines whether the given argument has been - matched. If all arguments to the expected method are matched, then - the expectation is verified. - - - - - - Using this extensible infrastructure, you can easily replace the entire - set of matchers with your own. You can also avoid the - typical (and annoying) lengthy expressions that result when you have - multiple arguments that use generics. - - - The following is the complete example explained above: - - public static class Orders - { - [Matcher] - public static IEnumerable<Order> Contains(Order order) - { - return null; - } - - public static bool Contains(IEnumerable<Order> orders, Order order) - { - return orders.Contains(order); - } - } - - And the concrete test using this matcher: - - var order = new Order { ... }; - var mock = new Mock<IRepository<Order>>(); - - mock.Expect(x => x.Save(Orders.Contains(order))) - .Throws<ArgumentException>(); - - // use mock, invoke Save, and have the matcher filter. - - - - - - Casts the expression to a lambda expression, removing - a cast if there's any. - - - - - Casts the body of the lambda expression to a . - - If the body is not a method call. - - - - Converts the body of the lambda expression into the referenced by it. - - - - - Checks whether the body of the lambda expression is a property access. - - - - - Checks whether the expression is a property access. - - - - - Checks whether the body of the lambda expression is a property indexer, which is true - when the expression is an whose - has - equal to . - - - - - Checks whether the expression is a property indexer, which is true - when the expression is an whose - has - equal to . - - - - - Creates an expression that casts the given expression to the - type. - - - - - TODO: remove this code when https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=331583 - is fixed. - - - - - Base class for visitors of expression trees. - - - Provides the functionality of the internal visitor base class that - comes with Linq. - Matt's comments on the implementation: - - In this variant there is only one visitor class that dispatches calls to the general - Visit function out to specific VisitXXX methods corresponding to different node types. - Note not every node type gets it own method, for example all binary operators are - treated in one VisitBinary method. The nodes themselves do not directly participate - in the visitation process. They are treated as just data. - The reason for this is that the quantity of visitors is actually open ended. - You can write your own. Therefore no semantics of visiting is coupled into the node classes. - It’s all in the visitors. The default visit behavior for node XXX is baked into the base - class’s version of VisitXXX. - - - Another variant is that all VisitXXX methods return a node. - The Expression tree nodes are immutable. In order to change the tree you must construct - a new one. The default VisitXXX methods will construct a new node if any of its sub-trees change. - If no changes are made then the same node is returned. That way if you make a change - to a node (by making a new node) deep down in a tree, the rest of the tree is rebuilt - automatically for you. - - See: http://blogs.msdn.com/mattwar/archive/2007/07/31/linq-building-an-iqueryable-provider-part-ii.aspx. - - Matt Warren: http://blogs.msdn.com/mattwar - Documented by InSTEDD: http://www.instedd.org - - - - Default constructor used by derived visitors. - - - - - Visits the , determining which - of the concrete Visit methods to call. - - - - - Visits the generic , determining and - calling the appropriate Visit method according to the - , which will result - in calls to , - or . - - - - - - - Visits the initializer by - calling the for the - . - - - - - Visits the expression by - calling with the expression. - - - - - Visits the by calling - with the , - and - expressions. - - - - - Visits the by calling - with the - expression. - - - - - Visits the , by default returning the - same without further behavior. - - - - - Visits the by calling - with the , - and - expressions. - - - - - Visits the returning it - by default without further behavior. - - - - - Visits the by calling - with the - expression. - - - - - Visits the by calling - with the expression, - and then with the . - - - - - - - Visits the by iterating - the list and visiting each in it. - - - - - - - Visits the by calling - with the expression. - - - - - - - Visits the by calling - with the . - - - - - - - Visits the by calling - with the - . - - - - - - - Visits the by - calling for each in the - collection. - - - - - - - Visits the by - calling for each - in the collection. - - - - - - - Visits the by calling - with the expression. - - - - - - - Visits the by calling - with the - expressions. - - - - - - - Visits the by calling - with the - expression, then with the - . - - - - - Visits the by calling - with the - expression, and then with the - . - - - - - - - Visits the by calling - with the - expressions. - - - - - - - Visits the by calling - with the - expressions. - - - - - - - Provides partial evaluation of subtrees, whenever they can be evaluated locally. - - Matt Warren: http://blogs.msdn.com/mattwar - Documented by InSTEDD: http://www.instedd.org - - - - Performs evaluation and replacement of independent sub-trees - - The root of the expression tree. - A function that decides whether a given expression - node can be part of the local function. - A new tree with sub-trees evaluated and replaced. - - - - Performs evaluation and replacement of independent sub-trees - - The root of the expression tree. - A new tree with sub-trees evaluated and replaced. - - - - Evaluates and replaces sub-trees when first candidate is reached (top-down) - - - - - Performs bottom-up analysis to determine which nodes can possibly - be part of an evaluated sub-tree. - - - - - Checks an argument to ensure it isn't null. - - The argument value to check. - The name of the argument. - - - - Checks a string argument to ensure it isn't null or empty. - - The argument value to check. - The name of the argument. - - - - Defines the Returns verb for property get expectations. - - Type of the property. - - - - Base interface for . - - - - - Specifies the value to return. - - The value to return, or . - - Return a true value from the property getter call: - - mock.ExpectGet(x => x.Suspended) - .Returns(true); - - - - - - Specifies a function that will calculate the value to return for the property. - - The function that will calculate the return value. - - Return a calculated value when the property is retrieved: - - mock.ExpectGet(x => x.Suspended) - .Returns(() => returnValues[0]); - - The lambda expression to retrieve the return value is lazy-executed, - meaning that its value may change depending on the moment the property - is retrieved and the value the returnValues array has at - that moment. - - - - - Defines the Callback verb for property getter expectations. - - - Type of the property. - - - - Specifies a callback to invoke when the property is retrieved. - - Callback method to invoke. - - Invokes the given callback with the property value being set. - - mock.ExpectGet(x => x.Suspended) - .Callback(() => called = true) - .Returns(true); - - - - - - Implements the fluent API. - - - - - Implements the fluent API. - - - - - Defines the Returns verb. - - Type of the return value from the expression. - - - - Specifies the value to return. - - The value to return, or . - - Return a true value from the method call: - - mock.Expect(x => x.Execute("ping")) - .Returns(true); - - - - - - Specifies a function that will calculate the value to return from the method. - - The function that will calculate the return value. - - Return a calculated value when the method is called: - - mock.Expect(x => x.Execute("ping")) - .Returns(() => returnValues[0]); - - The lambda expression to retrieve the return value is lazy-executed, - meaning that its value may change depending on the moment the method - is executed and the value the returnValues array has at - that moment. - - - - - Specifies a function that will calculate the value to return from the method, - retrieving the arguments for the invocation. - - Type of the argument of the invoked method. - The function that will calculate the return value. - - Return a calculated value which is evaluated lazily at the time of the invocation. - - The lookup list can change between invocations and the expectation - will return different values accordingly. Also, notice how the specific - string argument is retrieved by simply declaring it as part of the lambda - expression: - - - mock.Expect(x => x.Execute(It.IsAny<string>())) - .Returns((string command) => returnValues[command]); - - - - - - Specifies a function that will calculate the value to return from the method, - retrieving the arguments for the invocation. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - The function that will calculate the return value. - - Return a calculated value which is evaluated lazily at the time of the invocation. - - The return value is calculated from the value of the actual method invocation arguments. - Notice how the arguments are retrieved by simply declaring them as part of the lambda - expression: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>())) - .Returns((string arg1, string arg2) => arg1 + arg2); - - - - - - Specifies a function that will calculate the value to return from the method, - retrieving the arguments for the invocation. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Type of the third argument of the invoked method. - The function that will calculate the return value. - - Return a calculated value which is evaluated lazily at the time of the invocation. - - The return value is calculated from the value of the actual method invocation arguments. - Notice how the arguments are retrieved by simply declaring them as part of the lambda - expression: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>(), - It.IsAny<int>())) - .Returns((string arg1, string arg2, int arg3) => arg1 + arg2 + arg3); - - - - - - Specifies a function that will calculate the value to return from the method, - retrieving the arguments for the invocation. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Type of the third argument of the invoked method. - Type of the fourth argument of the invoked method. - The function that will calculate the return value. - - Return a calculated value which is evaluated lazily at the time of the invocation. - - The return value is calculated from the value of the actual method invocation arguments. - Notice how the arguments are retrieved by simply declaring them as part of the lambda - expression: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>(), - It.IsAny<int>(), - It.IsAny<bool>())) - .Returns((string arg1, string arg2, int arg3, bool arg4) => arg1 + arg2 + arg3 + arg4); - - - - - - Defines the Throws verb. - - - - - Specifies the exception to throw when the method is invoked. - - Exception instance to throw. - - This example shows how to throw an exception when the method is - invoked with an empty string argument: - - mock.Expect(x => x.Execute("")) - .Throws(new ArgumentException()); - - - - - - Specifies the type of exception to throw when the method is invoked. - - Type of exception to instantiate and throw when the expectation is met. - - This example shows how to throw an exception when the method is - invoked with an empty string argument: - - mock.Expect(x => x.Execute("")) - .Throws<ArgumentException>(); - - - - - - Implements the fluent API. - - - - - Implements the fluent API. - - - - - Defines the Callback verb and overloads for callbacks on - expectations that return a value. - - Type of the return value of the expectation. - - - - Specifies a callback to invoke when the method is called. - - Callback method to invoke. - - The following example specifies a callback to set a boolean - value that can be used later: - - bool called = false; - mock.Expect(x => x.Execute()) - .Callback(() => called = true) - .Returns(true); - - Note that in the case of value-returning methods, after the Callback - call you can still specify the return value. - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation argument value. - - Notice how the specific string argument is retrieved by simply declaring - it as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute(It.IsAny<string>())) - .Callback((string command) => Console.WriteLine(command)) - .Returns(true); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation arguments values. - - Notice how the specific arguments are retrieved by simply declaring - them as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>())) - .Callback((string arg1, string arg2) => Console.WriteLine(arg1 + arg2)) - .Returns(true); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Type of the third argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation arguments values. - - Notice how the specific arguments are retrieved by simply declaring - them as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>(), - It.IsAny<int>())) - .Callback((string arg1, string arg2, int arg3) => Console.WriteLine(arg1 + arg2 + arg3)) - .Returns(true); - - - - - - Specifies a callback to invoke when the method is called that receives the original - arguments. - - Type of the first argument of the invoked method. - Type of the second argument of the invoked method. - Type of the third argument of the invoked method. - Type of the fourth argument of the invoked method. - Callback method to invoke. - - Invokes the given callback with the concrete invocation arguments values. - - Notice how the specific arguments are retrieved by simply declaring - them as part of the lambda expression for the callback: - - - mock.Expect(x => x.Execute( - It.IsAny<string>(), - It.IsAny<string>(), - It.IsAny<int>(), - It.IsAny<bool>())) - .Callback((string arg1, string arg2, int arg3, bool arg4) => Console.WriteLine(arg1 + arg2 + arg3 + arg4)) - .Returns(true); - - - - - - Implemented by all generated mock object instances. - - - - - Implemented by all generated mock object instances. - - - - - Reference the Mock that contains this as the mock.Object value. - - - - - Reference the Mock that contains this as the mock.Object value. - - - - - Implements the actual interception and method invocation for - all mocks. - - - - - Get an eventInfo for a given event name. Search type ancestors depth first if necessary. - - Name of the event, with the set_ or get_ prefix already removed - - - - Given a type return all of its ancestors, both types and interfaces. - - The type to find immediate ancestors of - - - - Implements the fluent API. - - - - - Defines the Never verb. - - - - - The expected invocation is never expected to happen. - - - - var mock = new Mock<ICommand>(); - mock.Expect(foo => foo.Execute("ping")) - .Never(); - - - - is always verified inmediately as - the invocations are performed, like strict mocks do - with unexpected invocations. - - - - - Implements the fluent API. - - - - - Implements the fluent API. - - - - - Implements the fluent API. - - - - - Defines the Callback verb for property setter expectations. - - - - Type of the property. - - - - Specifies a callback to invoke when the property is set that receives the - property value being set. - - Callback method to invoke. - - Invokes the given callback with the property value being set. - - mock.ExpectSet(x => x.Suspended) - .Callback((bool state) => Console.WriteLine(state)); - - - - - - Allows the specification of a matching condition for an - argument in a method invocation, rather than a specific - argument value. "It" refers to the argument being matched. - - - This class allows the expectation to match a method invocation - with an arbitrary value, with a value in a specified range, or - even one that matches a given predicate. - - - - - Matches any value of the given type. - - - Typically used when the actual argument value for a method - call is not relevant. - - - - // Throws an exception for a call to Remove with any string value. - mock.Expect(x => x.Remove(It.IsAny<string>())).Throws(new InvalidOperationException()); - - - Type of the value. - - - - Matches any value that satisfies the given predicate. - - Type of the argument to check. - The predicate used to match the method argument. - - Allows the specification of a predicate to perform matching - of method call arguments. - - - This example shows how to return the value 1 whenever the argument to the - Do method is an even number. - - mock.Expect(x => x.Do(It.Is<int>(i => i % 2 == 0))) - .Returns(1); - - This example shows how to throw an exception if the argument to the - method is a negative number: - - mock.Expect(x => x.GetUser(It.Is<int>(i => i < 0))) - .Throws(new ArgumentException()); - - - - - - Matches any value that is in the range specified. - - Type of the argument to check. - The lower bound of the range. - The upper bound of the range. - The kind of range. See . - - The following example shows how to expect a method call - with an integer argument within the 0..100 range. - - mock.Expect(x => x.HasInventory( - It.IsAny<string>(), - It.IsInRange(0, 100, Range.Inclusive))) - .Returns(false); - - - - - - Matches a string argument if it matches the given regular expression pattern. - - The pattern to use to match the string argument value. - - The following example shows how to expect a call to a method where the - string argument matches the given regular expression: - - mock.Expect(x => x.Check(It.IsRegex("[a-z]+"))).Returns(1); - - - - - - Matches a string argument if it matches the given regular expression pattern. - - The pattern to use to match the string argument value. - The options used to interpret the pattern. - - The following example shows how to expect a call to a method where the - string argument matches the given regular expression, in a case insensitive way: - - mock.Expect(x => x.Check(It.IsRegex("[a-z]+", RegexOptions.IgnoreCase))).Returns(1); - - - - - - Matcher to treat static functions as matchers. - - mock.Expect(x => x.StringMethod(A.MagicString())); - - pbulic static class A - { - [Matcher] - public static string MagicString() { return null; } - public static bool MagicString(string arg) - { - return arg == "magic"; - } - } - - Will success if: mock.Object.StringMethod("magic"); - and fail with any other call. - - - - - We need this non-generics base class so that - we can use from - generic code. - - - - - Base class for mocks and static helper class with methods that - apply to mocked objects, such as to - retrieve a from an object instance. - - - - - Base mock interface exposing non-generic members. - - - - - Creates a handler that can be associated to an event receiving - the given and can be used - to raise the event. - - Type of - data passed in to the event. - - This example shows how to invoke an event with a custom event arguments - class in a view that will cause its corresponding presenter to - react by changing its state: - - var mockView = new Mock<IOrdersView>(); - var mockedEvent = mockView.CreateEventHandler<OrderEventArgs>(); - - var presenter = new OrdersPresenter(mockView.Object); - - // Check that the presenter has no selection by default - Assert.Null(presenter.SelectedOrder); - - // Create a mock event handler of the appropriate type - var handler = mockView.CreateEventHandler<OrderEventArgs>(); - // Associate it with the event we want to raise - mockView.Object.Cancel += handler; - // Finally raise the event with a specific arguments data - handler.Raise(new OrderEventArgs { Order = new Order("moq", 500) }); - - // Now the presenter reacted to the event, and we have a selected order - Assert.NotNull(presenter.SelectedOrder); - Assert.Equal("moq", presenter.SelectedOrder.ProductName); - - - - - - Creates a handler that can be associated to an event receiving - a generic and can be used - to raise the event. - - - This example shows how to invoke a generic event in a view that will - cause its corresponding presenter to react by changing its state: - - var mockView = new Mock<IOrdersView>(); - var mockedEvent = mockView.CreateEventHandler(); - - var presenter = new OrdersPresenter(mockView.Object); - - // Check that the presenter is not in the "Canceled" state - Assert.False(presenter.IsCanceled); - - // Create a mock event handler of the appropriate type - var handler = mockView.CreateEventHandler(); - // Associate it with the event we want to raise - mockView.Object.Cancel += handler; - // Finally raise the event - handler.Raise(EventArgs.Empty); - - // Now the presenter reacted to the event, and changed its state - Assert.True(presenter.IsCanceled); - - - - - - Verifies that all verifiable expectations have been met. - - - This example sets up an expectation and marks it as verifiable. After - the mock is used, a call is issued on the mock - to ensure the method in the expectation was invoked: - - var mock = new Mock<IWarehouse>(); - mock.Expect(x => x.HasInventory(TALISKER, 50)).Verifiable().Returns(true); - ... - // other test code - ... - // Will throw if the test code has didn't call HasInventory. - mock.Verify(); - - - Not all verifiable expectations were met. - - - - Verifies all expectations regardless of whether they have - been flagged as verifiable. - - - This example sets up an expectation without marking it as verifiable. After - the mock is used, a call is issued on the mock - to ensure that all expectations are met: - - var mock = new Mock<IWarehouse>(); - mock.Expect(x => x.HasInventory(TALISKER, 50)).Returns(true); - ... - // other test code - ... - // Will throw if the test code has didn't call HasInventory, even - // that expectation was not marked as verifiable. - mock.VerifyAll(); - - - At least one expectation was not met. - - - - Whether the base member virtual implementation will be called - for mocked classes if no expectation is met. Defaults to . - - - - - Determines how to generate default values for loose mocks on - unexpected invocations. - - - - - The mocked object instance. - - - - - Retrieves the mock object for the given object instance. - - Type of the mock to retrieve. Can be omitted as it's inferred - from the object instance passed in as the instance. - The instance of the mocked object. - The mock associated with the mocked object. - The received instance - was not created by Moq. - - The following example shows how to add a new expectation to an object - instance which is not the original but rather - the object associated with it: - - // Typed instance, not the mock, is retrieved from some test API. - HttpContextBase context = GetMockContext(); - - // context.Request is the typed object from the "real" API - // so in order to add an expectation to it, we need to get - // the mock that "owns" it - Mock<HttpRequestBase> request = Mock.Get(context.Request); - mock.Expect(req => req.AppRelativeCurrentExecutionFilePath) - .Returns(tempUrl); - - - - - - Initializes the mock - - - - - Returns the mocked object value. - - - - - Implements . - - - - - Implements . - - - - - Gets the interceptor target for the given expression and root mock, - building the intermediate hierarchy of mock objects if necessary. - - - - - Implements . - - Type of event argument class. - - - - Implements - - - - - Base class for mocks and static helper class with methods that - apply to mocked objects, such as to - retrieve a from an object instance. - - - - - Exposes the list of extra interfaces implemented by the mock. - - - - - Implements . - - - - - Implements . - - - - - Implements . - - - - - Specifies the class that will determine the default - value to return when invocations are made that - have no expectations and need to return a default - value (for loose mocks). - - - - - The mocked object instance. Implements . - - - - - Retrieves the type of the mocked object, its generic type argument. - This is used in the auto-mocking of hierarchy access. - - - - - Represents a generic event that has been mocked and can - be rised. - - - - - Provided solely to allow the interceptor to determine when the attached - handler is coming from this mocked event so we can assign the - corresponding EventInfo for it. - - - - - Raises the associated event with the given - event argument data. - - - - - Provides support for attaching a to - a generic event. - - Event to convert. - - - - Event raised whenever the mocked event is rised. - - - - - Options to customize the behavior of the mock. - - - - - Causes the mock to always throw - an exception for invocations that don't have a - corresponding expectation. - - - - - Will never throw exceptions, returning default - values when necessary (null for reference types, - zero for value types or empty enumerables and arrays). - - - - - Default mock behavior, which equals . - - - - - Exception thrown by mocks when expectations are not met, - the mock is not properly setup, etc. - - - A distinct exception type is provided so that exceptions - thrown by the mock can be differentiated in tests that - expect other exceptions to be thrown (i.e. ArgumentException). - - Richer exception hierarchy/types are not provided as - tests typically should not catch or expect exceptions - from the mocks. These are typically the result of changes - in the tested class or its collaborators implementation, and - result in fixes in the mock setup so that they dissapear and - allow the test to pass. - - - - - - Supports the serialization infrastructure. - - Serialization information. - Streaming context. - - - - Supports the serialization infrastructure. - - Serialization information. - Streaming context. - - - - Made internal as it's of no use for - consumers, but it's important for - our own tests. - - - - - Used by the mock factory to accumulate verification - failures. - - - - - Supports the serialization infrastructure. - - - - - Utility factory class to use to construct multiple - mocks when consistent verification is - desired for all of them. - - - If multiple mocks will be created during a test, passing - the desired (if different than the - or the one - passed to the factory constructor) and later verifying each - mock can become repetitive and tedious. - - This factory class helps in that scenario by providing a - simplified creation of multiple mocks with a default - (unless overriden by calling - ) and posterior verification. - - - - The following is a straightforward example on how to - create and automatically verify strict mocks using a : - - var factory = new MockFactory(MockBehavior.Strict); - - var foo = factory.Create<IFoo>(); - var bar = factory.Create<IBar>(); - - // no need to call Verifiable() on the expectation - // as we'll be validating all expectations anyway. - foo.Expect(f => f.Do()); - bar.Expect(b => b.Redo()); - - // exercise the mocks here - - factory.VerifyAll(); - // At this point all expectations are already checked - // and an optional MockException might be thrown. - // Note also that because the mocks are strict, any invocation - // that doesn't have a matching expectation will also throw a MockException. - - The following examples shows how to setup the factory - to create loose mocks and later verify only verifiable expectations: - - var factory = new MockFactory(MockBehavior.Loose); - - var foo = factory.Create<IFoo>(); - var bar = factory.Create<IBar>(); - - // this expectation will be verified at the end of the "using" block - foo.Expect(f => f.Do()).Verifiable(); - - // this expectation will NOT be verified - foo.Expect(f => f.Calculate()); - - // this expectation will be verified at the end of the "using" block - bar.Expect(b => b.Redo()).Verifiable(); - - // exercise the mocks here - // note that because the mocks are Loose, members - // called in the interfaces for which no matching - // expectations exist will NOT throw exceptions, - // and will rather return default values. - - factory.Verify(); - // At this point verifiable expectations are already checked - // and an optional MockException might be thrown. - - The following examples shows how to setup the factory with a - default strict behavior, overriding that default for a - specific mock: - - var factory = new MockFactory(MockBehavior.Strict); - - // this particular one we want loose - var foo = factory.Create<IFoo>(MockBehavior.Loose); - var bar = factory.Create<IBar>(); - - // set expectations - - // exercise the mocks here - - factory.Verify(); - - - - - - - Initializes the factory with the given - for newly created mocks from the factory. - - The behavior to use for mocks created - using the factory method if not overriden - by using the overload. - - - - Creates a new mock with the default - specified at factory construction time. - - Type to mock. - A new . - - - var factory = new MockFactory(MockBehavior.Strict); - - var foo = factory.Create<IFoo>(); - // use mock on tests - - factory.VerifyAll(); - - - - - - Creates a new mock with the default - specified at factory construction time and with the - the given constructor arguments for the class. - - - The mock will try to find the best match constructor given the - constructor arguments, and invoke that to initialize the instance. - This applies only to classes, not interfaces. - - Type to mock. - Constructor arguments for mocked classes. - A new . - - - var factory = new MockFactory(MockBehavior.Default); - - var mock = factory.Create<MyBase>("Foo", 25, true); - // use mock on tests - - factory.Verify(); - - - - - - Creates a new mock with the given . - - Type to mock. - Behavior to use for the mock, which overrides - the default behavior specified at factory construction time. - A new . - - The following example shows how to create a mock with a different - behavior to that specified as the default for the factory: - - var factory = new MockFactory(MockBehavior.Strict); - - var foo = factory.Create<IFoo>(MockBehavior.Loose); - - - - - - Creates a new mock with the given - and with the the given constructor arguments for the class. - - - The mock will try to find the best match constructor given the - constructor arguments, and invoke that to initialize the instance. - This applies only to classes, not interfaces. - - Type to mock. - Behavior to use for the mock, which overrides - the default behavior specified at factory construction time. - Constructor arguments for mocked classes. - A new . - - The following example shows how to create a mock with a different - behavior to that specified as the default for the factory, passing - constructor arguments: - - var factory = new MockFactory(MockBehavior.Default); - - var mock = factory.Create<MyBase>(MockBehavior.Strict, "Foo", 25, true); - - - - - - Implements creation of a new mock within the factory. - - Type to mock. - The behavior for the new mock. - Optional arguments for the construction of the mock. - - - - Verifies all verifiable expectations on all mocks created - by this factory. - - - One or more mocks had expectations that were not satisfied. - - - - Verifies all verifiable expectations on all mocks created - by this factory. - - - One or more mocks had expectations that were not satisfied. - - - - Invokes for each mock - in , and accumulates the resulting - that might be - thrown from the action. - - The action to execute against - each mock. - - - - Whether the base member virtual implementation will be called - for mocked classes if no expectation is met. Defaults to . - - - - - Specifies the behavior to use when returning default values for - unexpected invocations on loose mocks. - - - - - Gets the mocks that have been created by this factory and - that will get verified together. - - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Looks up a localized string similar to Mock type has already been initialized by accessing its Object property. Adding interfaces must be done before that.. - - - - - Looks up a localized string similar to Can only add interfaces to the mock.. - - - - - Looks up a localized string similar to Can't set return value for void method {0}.. - - - - - Looks up a localized string similar to Constructor arguments cannot be passed for interface mocks.. - - - - - Looks up a localized string similar to A matching constructor for the given arguments was not found on the mocked type.. - - - - - Looks up a localized string similar to Invalid expectation on a non-overridable member: - {0}. - - - - - Looks up a localized string similar to A lambda expression is expected as the argument to It.Is<T>.. - - - - - Looks up a localized string similar to Invocation {0} should not have been made.. - - - - - Looks up a localized string similar to Expression is not a method invocation: {0}. - - - - - Looks up a localized string similar to Expression is not a property access: {0}. - - - - - Looks up a localized string similar to Expression {0} involves a field access, which is not supported. Use properties instead.. - - - - - Looks up a localized string similar to Type to mock must be an interface or an abstract or non-sealed class. . - - - - - Looks up a localized string similar to Cannot retrieve a mock with the given object type {0} as it's not the main type of the mock or any of its additional interfaces. - Please cast the argument to one of the supported types: {1}. - Remember that there's no generics covariance in the CLR, so your object must be one of these types in order for the call to succeed.. - - - - - Looks up a localized string similar to Member {0}.{1} does not exist.. - - - - - Looks up a localized string similar to Method {0}.{1} is public. Use strong-typed Expect overload instead: - mock.Expect(x => x.{1}()); - . - - - - - Looks up a localized string similar to {0} invocation failed with mock behavior {1}. - {2}. - - - - - Looks up a localized string similar to Expected only {0} calls to {1}.. - - - - - Looks up a localized string similar to Expected only one call to {0}.. - - - - - Looks up a localized string similar to All invocations on the mock must have a corresponding expectation.. - - - - - Looks up a localized string similar to The given invocation was not performed on the mock.. - - - - - Looks up a localized string similar to Object instance was not created by Moq.. - - - - - Looks up a localized string similar to Property {0}.{1} does not exist.. - - - - - Looks up a localized string similar to Property {0}.{1} is write-only.. - - - - - Looks up a localized string similar to Property {0}.{1} is read-only.. - - - - - Looks up a localized string similar to Cannot raise a mocked event unless it has been associated (attached) to a concrete event in a mocked object.. - - - - - Looks up a localized string similar to Invocation needs to return a value and therefore must have a corresponding expectation that provides it.. - - - - - Looks up a localized string similar to To set expectations for public property {0}.{1}, use the typed overloads, such as: - mock.Expect(x => x.{1}).Returns(value); - mock.ExpectGet(x => x.{1}).Returns(value); //equivalent to previous one - mock.ExpectSet(x => x.{1}).Callback(callbackDelegate); - . - - - - - Looks up a localized string similar to Expression {0} is not supported.. - - - - - Looks up a localized string similar to Only property accesses are supported in intermediate invocations on an expectation. Unsupported expression {0}.. - - - - - Looks up a localized string similar to Expression contains intermediate property access {0}.{1} which is of type {2} and cannot be mocked. Unsupported expression {3}.. - - - - - Looks up a localized string similar to Member {0} is not supported for protected mocking.. - - - - - Looks up a localized string similar to To set expectations for protected property {0}.{1}, use: - mock.Expect<{2}>(x => x.{1}).Returns(value); - mock.ExpectGet(x => x.{1}).Returns(value); //equivalent to previous one - mock.ExpectSet(x => x.{1}).Callback(callbackDelegate);. - - - - - Looks up a localized string similar to The following expectations were not met: - {0}. - - - - - Allows expectations to be set for protected members by using their - name as a string, rather than strong-typing them which is not possible - due to their visibility. - - - - - Sets an expectation on the void method with the given - , optionally specifying - arguments for the method call. - - Name of the void method to be invoke. - Optional arguments for the invocation. - - - - Sets an expectation on a property or a non void method with the given - , optionally specifying - arguments for the method call. - - Name of the method or property to be invoke. - Optional arguments for the invocation. - Return type of the method or property. - - - - Sets an expectation on a property getter with the given - . - - Name of the property. - Type of the property. - - - - Sets an expectation on a property setter with the given - . - - Name of the property. - Type of the property. - - - - Allows the specification of a matching condition for an - argument in a protected member expectation, rather than a specific - argument value. "ItExpr" refers to the argument being matched. - - - Use this variant of argument matching instead of - for protected expectations. - This class allows the expectation to match a method invocation - with an arbitrary value, with a value in a specified range, or - even one that matches a given predicate. - - - - - Matches any value of the given type. - - - Typically used when the actual argument value for a method - call is not relevant. - - - - // Throws an exception for a call to Remove with any string value. - mock.Protected() - .Expect("Remove", ItExpr.IsAny<string>()) - .Throws(new InvalidOperationException()); - - - Type of the value. - - - - Matches any value that satisfies the given predicate. - - Type of the argument to check. - The predicate used to match the method argument. - - Allows the specification of a predicate to perform matching - of method call arguments. - - - This example shows how to return the value 1 whenever the argument to the - Do method is an even number. - - mock.Protected() - .Expect("Do", ItExpr.Is<int>(i => i % 2 == 0)) - .Returns(1); - - This example shows how to throw an exception if the argument to the - method is a negative number: - - mock.Protected() - .Expect("GetUser", ItExpr.Is<int>(i => i < 0)) - .Throws(new ArgumentException()); - - - - - - Matches any value that is in the range specified. - - Type of the argument to check. - The lower bound of the range. - The upper bound of the range. - The kind of range. See . - - The following example shows how to expect a method call - with an integer argument within the 0..100 range. - - mock.Protected() - .Expect("HasInventory", - ItExpr.IsAny<string>(), - ItExpr.IsInRange(0, 100, Range.Inclusive)) - .Returns(false); - - - - - - Matches a string argument if it matches the given regular expression pattern. - - The pattern to use to match the string argument value. - - The following example shows how to expect a call to a method where the - string argument matches the given regular expression: - - mock.Protected() - .Expect("Check", ItExpr.IsRegex("[a-z]+")) - .Returns(1); - - - - - - Matches a string argument if it matches the given regular expression pattern. - - The pattern to use to match the string argument value. - The options used to interpret the pattern. - - The following example shows how to expect a call to a method where the - string argument matches the given regular expression, in a case insensitive way: - - mock.Protected() - .Expect("Check", ItExpr.IsRegex("[a-z]+", RegexOptions.IgnoreCase)) - .Returns(1); - - - - - - Enables the Protected() method on , - allowing expectations to be set for protected members by using their - name as a string, rather than strong-typing them which is not possible - due to their visibility. - - - - - Enable protected expectations for the mock. - - Mocked object type. Typically omitted as it can be inferred from the mock instance. - The mock to set the protected expectations on. - - - - - - - - - - - - Kind of range to use in a filter specified through - . - - - - - The range includes the to and - from values. - - - - - The range does not include the to and - from values. - - - - - Determines the way default values are generated - calculated for loose mocks. - - - - - Default behavior, which generates empty values for - value types (i.e. default(int)), empty array and - enumerables, and nulls for all other reference types. - - - - - Whenever the default value generated by - is null, replaces this value with a mock (if the type - can be mocked). - - - For sealed classes, a null value will be generated. - - - - - Core implementation of the interface. - - - Type to mock. - - - - Initializes an instance of the mock with default behavior and with - the given constructor arguments for the class. (Only valid when is a class) - - - The mock will try to find the best match constructor given the constructor arguments, and invoke that - to initialize the instance. This applies only for classes, not interfaces. - - - var mock = new Mock<MyProvider>(someArgument, 25); - - Optional constructor arguments if the mocked type is a class. - - - - Initializes an instance of the mock with default behavior. - - - var mock = new Mock<IFormatProvider>(); - - - - - Initializes an instance of the mock with the specified behavior. - - - var mock = new Mock<IFormatProvider>(MockBehavior.Relaxed); - - Behavior of the mock. - - - - Initializes an instance of the mock with a specific behavior with - the given constructor arguments for the class. - - - The mock will try to find the best match constructor given the constructor arguments, and invoke that - to initialize the instance. This applies only to classes, not interfaces. - - - var mock = new Mock<MyProvider>(someArgument, 25); - - Behavior of the mock. - Optional constructor arguments if the mocked type is a class. - - - - Returns the mocked object value. - - - - - Implements . - - Lambda expression that specifies the expected method invocation. - - - - Implements . - - Type of the return value. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected method invocation. - - - - Implements . - - Type of the property. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected property getter. - - - - Implements . - - Type of the property. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected property setter. - - - - Implements . - - Type of the property. Typically omitted as it can be inferred from the expression. - Lambda expression that specifies the expected property setter. - The value expected to be set for the property. - - - - Implements . - - Expression to verify. - - - - Implements . - - Expression to verify. - Type of return value from the expression. - - - - Implements . - - Expression to verify. - Type of the property to verify. Typically omitted as it can - be inferred from the expression's return type. - - - - Implements . - - Expression to verify. - Type of the property to verify. Typically omitted as it can - be inferred from the expression's return type. - - - - Implements . - - Expression to verify. - The value that should have been set on the property. - Type of the property to verify. Typically omitted as it can - be inferred from the expression's return type. - - - - Implements . - - - - - Implements . - - - - - Implements . - - Type of interface to cast the mock to. - - - - Exposes the mocked object instance. - - - - - A that returns an empty default value - for non-mockeable types, and mocks for all other types (interfaces and - non-sealed classes) that can be mocked. - - - - - Provides a typed for a - specific type of . - - The type of event arguments required by the event. - - The mocked event can either be a or custom - event handler which follows .NET practice of providing object sender, EventArgs args - kind of signature. - - - - - Raises the associated event with the given - event argument data. - - Data to pass to the event. - - - - Provides support for attaching a to - a generic event. - - Event to convert. - - - - Provided solely to allow the interceptor to determine when the attached - handler is coming from this mocked event so we can assign the - corresponding EventInfo for it. - - - - - Adds Stub extension method to a mock so that you can - stub properties. - - - - - Specifies that the given property should have stub behavior, - meaning that setting its value will cause it to be saved and - later returned when the property is requested. - - Mocked type, inferred from the object - where this method is being applied (does not need to be specified). - Type of the property, inferred from the property - expression (does not need to be specified). - The instance to stub. - Property expression to stub. - - If you have an interface with an int property Value, you might - stub it using the following straightforward call: - - var mock = new Mock<IHaveValue>(); - mock.Stub(v => v.Value); - - After the Stub call has been issued, setting and - retrieving the object value will behave as expected: - - IHaveValue v = mock.Object; - - v.Value = 5; - Assert.Equal(5, v.Value); - - - - - - Specifies that the given property should have stub behavior, - meaning that setting its value will cause it to be saved and - later returned when the property is requested. This overload - allows setting the initial value for the property. - - Mocked type, inferred from the object - where this method is being applied (does not need to be specified). - Type of the property, inferred from the property - expression (does not need to be specified). - The instance to stub. - Property expression to stub. - Initial value for the property. - - If you have an interface with an int property Value, you might - stub it using the following straightforward call: - - var mock = new Mock<IHaveValue>(); - mock.Stub(v => v.Value, 5); - - After the Stub call has been issued, setting and - retrieving the object value will behave as expected: - - IHaveValue v = mock.Object; - // Initial value was stored - Assert.Equal(5, v.Value); - - // New value set which changes the initial value - v.Value = 6; - Assert.Equal(6, v.Value); - - - - - - Stubs all properties on the mock, setting the default value to - the one generated as specified by the - property. - - Mocked type, typically omitted as it can be inferred from the mock argument. - The mock to stub. - - If the mock is set to , - the mocked default values will also be stubbed recursively. - - - - diff --git a/lib/tests/Northwind.Common.dll b/lib/tests/Northwind.Common.dll deleted file mode 100644 index 972e89303b3..00000000000 Binary files a/lib/tests/Northwind.Common.dll and /dev/null differ diff --git a/lib/tests/Northwind.Common.pdb b/lib/tests/Northwind.Common.pdb deleted file mode 100644 index dfc5120ce61..00000000000 Binary files a/lib/tests/Northwind.Common.pdb and /dev/null differ diff --git a/lib/tests/nunit-console-runner.dll b/lib/tests/nunit-console-runner.dll deleted file mode 100644 index e637d6523b6..00000000000 Binary files a/lib/tests/nunit-console-runner.dll and /dev/null differ diff --git a/lib/tests/nunit-console-x86.exe b/lib/tests/nunit-console-x86.exe deleted file mode 100644 index 0f9a832d3be..00000000000 Binary files a/lib/tests/nunit-console-x86.exe and /dev/null differ diff --git a/lib/tests/nunit-console-x86.exe.config b/lib/tests/nunit-console-x86.exe.config deleted file mode 100644 index 8a6a2a6a669..00000000000 --- a/lib/tests/nunit-console-x86.exe.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/tests/nunit-console.exe b/lib/tests/nunit-console.exe deleted file mode 100644 index db1700badd1..00000000000 Binary files a/lib/tests/nunit-console.exe and /dev/null differ diff --git a/lib/tests/nunit-console.exe.config b/lib/tests/nunit-console.exe.config deleted file mode 100644 index 8a6a2a6a669..00000000000 --- a/lib/tests/nunit-console.exe.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/tests/nunit.core.dll b/lib/tests/nunit.core.dll deleted file mode 100644 index 1c57782550d..00000000000 Binary files a/lib/tests/nunit.core.dll and /dev/null differ diff --git a/lib/tests/nunit.core.interfaces.dll b/lib/tests/nunit.core.interfaces.dll deleted file mode 100644 index 941d4931d98..00000000000 Binary files a/lib/tests/nunit.core.interfaces.dll and /dev/null differ diff --git a/lib/tests/nunit.framework.dll b/lib/tests/nunit.framework.dll deleted file mode 100644 index 215767d2fb3..00000000000 Binary files a/lib/tests/nunit.framework.dll and /dev/null differ diff --git a/lib/tests/nunit.framework.extensions.dll b/lib/tests/nunit.framework.extensions.dll deleted file mode 100644 index 91e05857a68..00000000000 Binary files a/lib/tests/nunit.framework.extensions.dll and /dev/null differ diff --git a/lib/tests/nunit.framework.xml b/lib/tests/nunit.framework.xml deleted file mode 100644 index 7b0e798cada..00000000000 --- a/lib/tests/nunit.framework.xml +++ /dev/null @@ -1,10892 +0,0 @@ - - - - nunit.framework - - - - - Attribute used to apply a category to a test - - - - - The name of the category - - - - - Construct attribute for a given category based on - a name. The name may not contain the characters ',', - '+', '-' or '!'. However, this is not checked in the - constructor since it would cause an error to arise at - as the test was loaded without giving a clear indication - of where the problem is located. The error is handled - in NUnitFramework.cs by marking the test as not - runnable. - - The name of the category - - - - Protected constructor uses the Type name as the name - of the category. - - - - - The name of the category - - - - - Used to mark a field for use as a datapoint when executing a theory - within the same fixture that requires an argument of the field's Type. - - - - - Used to mark an array as containing a set of datapoints to be used - executing a theory within the same fixture that requires an argument - of the Type of the array elements. - - - - - Attribute used to provide descriptive text about a - test case or fixture. - - - - - Construct the attribute - - Text describing the test - - - - Gets the test description - - - - - Enumeration indicating how the expected message parameter is to be used - - - - Expect an exact match - - - Expect a message containing the parameter string - - - Match the regular expression provided as a parameter - - - Expect a message that starts with the parameter string - - - - ExpectedExceptionAttribute - - - - - - Constructor for a non-specific exception - - - - - Constructor for a given type of exception - - The type of the expected exception - - - - Constructor for a given exception name - - The full name of the expected exception - - - - Gets or sets the expected exception type - - - - - Gets or sets the full Type name of the expected exception - - - - - Gets or sets the expected message text - - - - - Gets or sets the user message displayed in case of failure - - - - - Gets or sets the type of match to be performed on the expected message - - - - - Gets the name of a method to be used as an exception handler - - - - - ExplicitAttribute marks a test or test fixture so that it will - only be run if explicitly executed from the gui or command line - or if it is included by use of a filter. The test will not be - run simply because an enclosing suite is run. - - - - - Default constructor - - - - - Constructor with a reason - - The reason test is marked explicit - - - - The reason test is marked explicit - - - - - Attribute used to mark a test that is to be ignored. - Ignored tests result in a warning message when the - tests are run. - - - - - Constructs the attribute without giving a reason - for ignoring the test. - - - - - Constructs the attribute giving a reason for ignoring the test - - The reason for ignoring the test - - - - The reason for ignoring a test - - - - - Abstract base for Attributes that are used to include tests - in the test run based on environmental settings. - - - - - Constructor with no included items specified, for use - with named property syntax. - - - - - Constructor taking one or more included items - - Comma-delimited list of included items - - - - Name of the item that is needed in order for - a test to run. Multiple itemss may be given, - separated by a comma. - - - - - Name of the item to be excluded. Multiple items - may be given, separated by a comma. - - - - - The reason for including or excluding the test - - - - - PlatformAttribute is used to mark a test fixture or an - individual method as applying to a particular platform only. - - - - - Constructor with no platforms specified, for use - with named property syntax. - - - - - Constructor taking one or more platforms - - Comma-deliminted list of platforms - - - - CultureAttribute is used to mark a test fixture or an - individual method as applying to a particular Culture only. - - - - - Constructor with no cultures specified, for use - with named property syntax. - - - - - Constructor taking one or more cultures - - Comma-deliminted list of cultures - - - - Marks a test to use a combinatorial join of any argument data - provided. NUnit will create a test case for every combination of - the arguments provided. This can result in a large number of test - cases and so should be used judiciously. This is the default join - type, so the attribute need not be used except as documentation. - - - - - PropertyAttribute is used to attach information to a test as a name/value pair.. - - - - - Construct a PropertyAttribute with a name and string value - - The name of the property - The property value - - - - Construct a PropertyAttribute with a name and int value - - The name of the property - The property value - - - - Construct a PropertyAttribute with a name and double value - - The name of the property - The property value - - - - Constructor for derived classes that set the - property dictionary directly. - - - - - Constructor for use by derived classes that use the - name of the type as the property name. Derived classes - must ensure that the Type of the property value is - a standard type supported by the BCL. Any custom - types will cause a serialization Exception when - in the client. - - - - - Gets the property dictionary for this attribute - - - - - Default constructor - - - - - Marks a test to use pairwise join of any argument data provided. - NUnit will attempt too excercise every pair of argument values at - least once, using as small a number of test cases as it can. With - only two arguments, this is the same as a combinatorial join. - - - - - Default constructor - - - - - Marks a test to use a sequential join of any argument data - provided. NUnit will use arguements for each parameter in - sequence, generating test cases up to the largest number - of argument values provided and using null for any arguments - for which it runs out of values. Normally, this should be - used with the same number of arguments for each parameter. - - - - - Default constructor - - - - - Summary description for MaxTimeAttribute. - - - - - Construct a MaxTimeAttribute, given a time in milliseconds. - - The maximum elapsed time in milliseconds - - - - RandomAttribute is used to supply a set of random values - to a single parameter of a parameterized test. - - - - - ValuesAttribute is used to provide literal arguments for - an individual parameter of a test. - - - - - Abstract base class for attributes that apply to parameters - and supply data for the parameter. - - - - - Gets the data to be provided to the specified parameter - - - - - The collection of data to be returned. Must - be set by any derived attribute classes. - We use an object[] so that the individual - elements may have their type changed in GetData - if necessary. - - - - - Construct with one argument - - - - - - Construct with two arguments - - - - - - - Construct with three arguments - - - - - - - - Construct with an array of arguments - - - - - - Get the collection of values to be used as arguments - - - - - Construct a set of doubles from 0.0 to 1.0, - specifying only the count. - - - - - - Construct a set of doubles from min to max - - - - - - - - Construct a set of ints from min to max - - - - - - - - Get the collection of values to be used as arguments - - - - - RangeAttribute is used to supply a range of values to an - individual parameter of a parameterized test. - - - - - Construct a range of ints using default step of 1 - - - - - - - Construct a range of ints specifying the step size - - - - - - - - Construct a range of longs - - - - - - - - Construct a range of doubles - - - - - - - - Construct a range of floats - - - - - - - - RepeatAttribute may be applied to test case in order - to run it multiple times. - - - - - Construct a RepeatAttribute - - The number of times to run the test - - - - RequiredAddinAttribute may be used to indicate the names of any addins - that must be present in order to run some or all of the tests in an - assembly. If the addin is not loaded, the entire assembly is marked - as NotRunnable. - - - - - Initializes a new instance of the class. - - The required addin. - - - - Gets the name of required addin. - - The required addin name. - - - - Summary description for SetCultureAttribute. - - - - - Construct given the name of a culture - - - - - - Summary description for SetUICultureAttribute. - - - - - Construct given the name of a culture - - - - - - SetUpAttribute is used in a TestFixture to identify a method - that is called immediately before each test is run. It is - also used in a SetUpFixture to identify the method that is - called once, before any of the subordinate tests are run. - - - - - Attribute used to mark a class that contains one-time SetUp - and/or TearDown methods that apply to all the tests in a - namespace or an assembly. - - - - - Attribute used to mark a static (shared in VB) property - that returns a list of tests. - - - - - Attribute used in a TestFixture to identify a method that is - called immediately after each test is run. It is also used - in a SetUpFixture to identify the method that is called once, - after all subordinate tests have run. In either case, the method - is guaranteed to be called, even if an exception is thrown. - - - - - Provide actions to execute before and after tests. - - - - - When implemented by an attribute, this interface implemented to provide actions to execute before and after tests. - - - - - Executed before each test is run - - Provides details about the test that is going to be run. - - - - Executed after each test is run - - Provides details about the test that has just been run. - - - - Provides the target for the action attribute - - The target for the action attribute - - - - Adding this attribute to a method within a - class makes the method callable from the NUnit test runner. There is a property - called Description which is optional which you can provide a more detailed test - description. This class cannot be inherited. - - - - [TestFixture] - public class Fixture - { - [Test] - public void MethodToTest() - {} - - [Test(Description = "more detailed description")] - publc void TestDescriptionMethod() - {} - } - - - - - - Descriptive text for this test - - - - - TestCaseAttribute is used to mark parameterized test cases - and provide them with their arguments. - - - - - The ITestCaseData interface is implemented by a class - that is able to return complete testcases for use by - a parameterized test method. - - NOTE: This interface is used in both the framework - and the core, even though that results in two different - types. However, sharing the source code guarantees that - the various implementations will be compatible and that - the core is able to reflect successfully over the - framework implementations of ITestCaseData. - - - - - Gets the argument list to be provided to the test - - - - - Gets the expected result - - - - - Indicates whether a result has been specified. - This is necessary because the result may be - null, so it's value cannot be checked. - - - - - Gets the expected exception Type - - - - - Gets the FullName of the expected exception - - - - - Gets the name to be used for the test - - - - - Gets the description of the test - - - - - Gets a value indicating whether this is ignored. - - true if ignored; otherwise, false. - - - - Gets a value indicating whether this is explicit. - - true if explicit; otherwise, false. - - - - Gets the ignore reason. - - The ignore reason. - - - - Construct a TestCaseAttribute with a list of arguments. - This constructor is not CLS-Compliant - - - - - - Construct a TestCaseAttribute with a single argument - - - - - - Construct a TestCaseAttribute with a two arguments - - - - - - - Construct a TestCaseAttribute with a three arguments - - - - - - - - Gets the list of arguments to a test case - - - - - Gets or sets the expected result. - - The result. - - - - Gets the expected result. - - The result. - - - - Gets a flag indicating whether an expected - result has been set. - - - - - Gets a list of categories associated with this test; - - - - - Gets or sets the category associated with this test. - May be a single category or a comma-separated list. - - - - - Gets or sets the expected exception. - - The expected exception. - - - - Gets or sets the name the expected exception. - - The expected name of the exception. - - - - Gets or sets the expected message of the expected exception - - The expected message of the exception. - - - - Gets or sets the type of match to be performed on the expected message - - - - - Gets or sets the description. - - The description. - - - - Gets or sets the name of the test. - - The name of the test. - - - - Gets or sets the ignored status of the test - - - - - Gets or sets the ignored status of the test - - - - - Gets or sets the explicit status of the test - - - - - Gets or sets the reason for not running the test - - - - - Gets or sets the reason for not running the test. - Set has the side effect of marking the test as ignored. - - The ignore reason. - - - - FactoryAttribute indicates the source to be used to - provide test cases for a test method. - - - - - Construct with the name of the factory - for use with languages - that don't support params arrays. - - An array of the names of the factories that will provide data - - - - Construct with a Type and name - for use with languages - that don't support params arrays. - - The Type that will provide data - The name of the method, property or field that will provide data - - - - The name of a the method, property or fiend to be used as a source - - - - - A Type to be used as a source - - - - - Gets or sets the category associated with this test. - May be a single category or a comma-separated list. - - - - - [TestFixture] - public class ExampleClass - {} - - - - - Default constructor - - - - - Construct with a object[] representing a set of arguments. - In .NET 2.0, the arguments may later be separated into - type arguments and constructor arguments. - - - - - - Descriptive text for this fixture - - - - - Gets and sets the category for this fixture. - May be a comma-separated list of categories. - - - - - Gets a list of categories for this fixture - - - - - The arguments originally provided to the attribute - - - - - Gets or sets a value indicating whether this should be ignored. - - true if ignore; otherwise, false. - - - - Gets or sets the ignore reason. May set Ignored as a side effect. - - The ignore reason. - - - - Get or set the type arguments. If not set - explicitly, any leading arguments that are - Types are taken as type arguments. - - - - - Attribute used to identify a method that is - called before any tests in a fixture are run. - - - - - Attribute used to identify a method that is called after - all the tests in a fixture have run. The method is - guaranteed to be called, even if an exception is thrown. - - - - - Adding this attribute to a method within a - class makes the method callable from the NUnit test runner. There is a property - called Description which is optional which you can provide a more detailed test - description. This class cannot be inherited. - - - - [TestFixture] - public class Fixture - { - [Test] - public void MethodToTest() - {} - - [Test(Description = "more detailed description")] - publc void TestDescriptionMethod() - {} - } - - - - - - Used on a method, marks the test with a timeout value in milliseconds. - The test will be run in a separate thread and is cancelled if the timeout - is exceeded. Used on a method or assembly, sets the default timeout - for all contained test methods. - - - - - Construct a TimeoutAttribute given a time in milliseconds - - The timeout value in milliseconds - - - - Marks a test that must run in the STA, causing it - to run in a separate thread if necessary. - - On methods, you may also use STAThreadAttribute - to serve the same purpose. - - - - - Construct a RequiresSTAAttribute - - - - - Marks a test that must run in the MTA, causing it - to run in a separate thread if necessary. - - On methods, you may also use MTAThreadAttribute - to serve the same purpose. - - - - - Construct a RequiresMTAAttribute - - - - - Marks a test that must run on a separate thread. - - - - - Construct a RequiresThreadAttribute - - - - - Construct a RequiresThreadAttribute, specifying the apartment - - - - - ValueSourceAttribute indicates the source to be used to - provide data for one parameter of a test method. - - - - - Construct with the name of the factory - for use with languages - that don't support params arrays. - - The name of the data source to be used - - - - Construct with a Type and name - for use with languages - that don't support params arrays. - - The Type that will provide data - The name of the method, property or field that will provide data - - - - The name of a the method, property or fiend to be used as a source - - - - - A Type to be used as a source - - - - - AttributeExistsConstraint tests for the presence of a - specified attribute on a Type. - - - - - The Constraint class is the base of all built-in constraints - within NUnit. It provides the operator overloads used to combine - constraints. - - - - - The IConstraintExpression interface is implemented by all - complete and resolvable constraints and expressions. - - - - - Return the top-level constraint for this expression - - - - - - Static UnsetObject used to detect derived constraints - failing to set the actual value. - - - - - The actual value being tested against a constraint - - - - - The display name of this Constraint for use by ToString() - - - - - Argument fields used by ToString(); - - - - - The builder holding this constraint - - - - - Construct a constraint with no arguments - - - - - Construct a constraint with one argument - - - - - Construct a constraint with two arguments - - - - - Sets the ConstraintBuilder holding this constraint - - - - - Write the failure message to the MessageWriter provided - as an argument. The default implementation simply passes - the constraint and the actual value to the writer, which - then displays the constraint description and the value. - - Constraints that need to provide additional details, - such as where the error occured can override this. - - The MessageWriter on which to display the message - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Test whether the constraint is satisfied by an - ActualValueDelegate that returns the value to be tested. - The default implementation simply evaluates the delegate - but derived classes may override it to provide for delayed - processing. - - An ActualValueDelegate - True for success, false for failure - - - - Test whether the constraint is satisfied by a given reference. - The default implementation simply dereferences the value but - derived classes may override it to provide for delayed processing. - - A reference to the value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - Default override of ToString returns the constraint DisplayName - followed by any arguments within angle brackets. - - - - - - Returns the string representation of this constraint - - - - - This operator creates a constraint that is satisfied only if both - argument constraints are satisfied. - - - - - This operator creates a constraint that is satisfied if either - of the argument constraints is satisfied. - - - - - This operator creates a constraint that is satisfied if the - argument constraint is not satisfied. - - - - - Returns a DelayedConstraint with the specified delay time. - - The delay in milliseconds. - - - - - Returns a DelayedConstraint with the specified delay time - and polling interval. - - The delay in milliseconds. - The interval at which to test the constraint. - - - - - The display name of this Constraint for use by ToString(). - The default value is the name of the constraint with - trailing "Constraint" removed. Derived classes may set - this to another name in their constructors. - - - - - Returns a ConstraintExpression by appending And - to the current constraint. - - - - - Returns a ConstraintExpression by appending And - to the current constraint. - - - - - Returns a ConstraintExpression by appending Or - to the current constraint. - - - - - Class used to detect any derived constraints - that fail to set the actual value in their - Matches override. - - - - - Constructs an AttributeExistsConstraint for a specific attribute Type - - - - - - Tests whether the object provides the expected attribute. - - A Type, MethodInfo, or other ICustomAttributeProvider - True if the expected attribute is present, otherwise false - - - - Writes the description of the constraint to the specified writer - - - - - AttributeConstraint tests that a specified attribute is present - on a Type or other provider and that the value of the attribute - satisfies some other constraint. - - - - - Abstract base class used for prefixes - - - - - The base constraint - - - - - Construct given a base constraint - - - - - - Constructs an AttributeConstraint for a specified attriute - Type and base constraint. - - - - - - - Determines whether the Type or other provider has the - expected attribute and if its value matches the - additional constraint specified. - - - - - Writes a description of the attribute to the specified writer. - - - - - Writes the actual value supplied to the specified writer. - - - - - Returns a string representation of the constraint. - - - - - BasicConstraint is the abstract base for constraints that - perform a simple comparison to a constant value. - - - - - Initializes a new instance of the class. - - The expected. - The description. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - NullConstraint tests that the actual value is null - - - - - Initializes a new instance of the class. - - - - - TrueConstraint tests that the actual value is true - - - - - Initializes a new instance of the class. - - - - - FalseConstraint tests that the actual value is false - - - - - Initializes a new instance of the class. - - - - - NaNConstraint tests that the actual value is a double or float NaN - - - - - Test that the actual value is an NaN - - - - - - - Write the constraint description to a specified writer - - - - - - BinaryConstraint is the abstract base of all constraints - that combine two other constraints in some fashion. - - - - - The first constraint being combined - - - - - The second constraint being combined - - - - - Construct a BinaryConstraint from two other constraints - - The first constraint - The second constraint - - - - AndConstraint succeeds only if both members succeed. - - - - - Create an AndConstraint from two other constraints - - The first constraint - The second constraint - - - - Apply both member constraints to an actual value, succeeding - succeeding only if both of them succeed. - - The actual value - True if the constraints both succeeded - - - - Write a description for this contraint to a MessageWriter - - The MessageWriter to receive the description - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - OrConstraint succeeds if either member succeeds - - - - - Create an OrConstraint from two other constraints - - The first constraint - The second constraint - - - - Apply the member constraints to an actual value, succeeding - succeeding as soon as one of them succeeds. - - The actual value - True if either constraint succeeded - - - - Write a description for this contraint to a MessageWriter - - The MessageWriter to receive the description - - - - CollectionConstraint is the abstract base class for - constraints that operate on collections. - - - - - Construct an empty CollectionConstraint - - - - - Construct a CollectionConstraint - - - - - - Determines whether the specified enumerable is empty. - - The enumerable. - - true if the specified enumerable is empty; otherwise, false. - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Protected method to be implemented by derived classes - - - - - - - CollectionItemsEqualConstraint is the abstract base class for all - collection constraints that apply some notion of item equality - as a part of their operation. - - - - - Construct an empty CollectionConstraint - - - - - Construct a CollectionConstraint - - - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied Comparison object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IEqualityComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IEqualityComparer object. - - The IComparer object to use. - Self. - - - - Compares two collection members for equality - - - - - Return a new CollectionTally for use in making tests - - The collection to be included in the tally - - - - Flag the constraint to ignore case and return self. - - - - - EmptyCollectionConstraint tests whether a collection is empty. - - - - - Check that the collection is empty - - - - - - - Write the constraint description to a MessageWriter - - - - - - UniqueItemsConstraint tests whether all the items in a - collection are unique. - - - - - Check that all items are unique. - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - CollectionContainsConstraint is used to test whether a collection - contains an expected object as a member. - - - - - Construct a CollectionContainsConstraint - - - - - - Test whether the expected item is contained in the collection - - - - - - - Write a descripton of the constraint to a MessageWriter - - - - - - CollectionEquivalentCOnstraint is used to determine whether two - collections are equivalent. - - - - - Construct a CollectionEquivalentConstraint - - - - - - Test whether two collections are equivalent - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - CollectionSubsetConstraint is used to determine whether - one collection is a subset of another - - - - - Construct a CollectionSubsetConstraint - - The collection that the actual value is expected to be a subset of - - - - Test whether the actual collection is a subset of - the expected collection provided. - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - CollectionOrderedConstraint is used to test whether a collection is ordered. - - - - - Construct a CollectionOrderedConstraint - - - - - Modifies the constraint to use an IComparer and returns self. - - - - - Modifies the constraint to use an IComparer<T> and returns self. - - - - - Modifies the constraint to use a Comparison<T> and returns self. - - - - - Modifies the constraint to test ordering by the value of - a specified property and returns self. - - - - - Test whether the collection is ordered - - - - - - - Write a description of the constraint to a MessageWriter - - - - - - Returns the string representation of the constraint. - - - - - - If used performs a reverse comparison - - - - - CollectionTally counts (tallies) the number of - occurences of each object in one or more enumerations. - - - - - Construct a CollectionTally object from a comparer and a collection - - - - - Try to remove an object from the tally - - The object to remove - True if successful, false if the object was not found - - - - Try to remove a set of objects from the tally - - The objects to remove - True if successful, false if any object was not found - - - - The number of objects remaining in the tally - - - - - ComparisonAdapter class centralizes all comparisons of - values in NUnit, adapting to the use of any provided - IComparer, IComparer<T> or Comparison<T> - - - - - Returns a ComparisonAdapter that wraps an IComparer - - - - - Returns a ComparisonAdapter that wraps an IComparer<T> - - - - - Returns a ComparisonAdapter that wraps a Comparison<T> - - - - - Compares two objects - - - - - Gets the default ComparisonAdapter, which wraps an - NUnitComparer object. - - - - - Construct a ComparisonAdapter for an IComparer - - - - - Compares two objects - - - - - - - - Construct a default ComparisonAdapter - - - - - ComparisonAdapter<T> extends ComparisonAdapter and - allows use of an IComparer<T> or Comparison<T> - to actually perform the comparison. - - - - - Construct a ComparisonAdapter for an IComparer<T> - - - - - Compare a Type T to an object - - - - - Construct a ComparisonAdapter for a Comparison<T> - - - - - Compare a Type T to an object - - - - - Abstract base class for constraints that compare values to - determine if one is greater than, equal to or less than - the other. This class supplies the Using modifiers. - - - - - ComparisonAdapter to be used in making the comparison - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - - - - Modifies the constraint to use an IComparer and returns self - - - - - Modifies the constraint to use an IComparer<T> and returns self - - - - - Modifies the constraint to use a Comparison<T> and returns self - - - - - Delegate used to delay evaluation of the actual value - to be used in evaluating a constraint - - - - - ConstraintBuilder maintains the stacks that are used in - processing a ConstraintExpression. An OperatorStack - is used to hold operators that are waiting for their - operands to be reognized. a ConstraintStack holds - input constraints as well as the results of each - operator applied. - - - - - Initializes a new instance of the class. - - - - - Appends the specified operator to the expression by first - reducing the operator stack and then pushing the new - operator on the stack. - - The operator to push. - - - - Appends the specified constraint to the expresson by pushing - it on the constraint stack. - - The constraint to push. - - - - Sets the top operator right context. - - The right context. - - - - Reduces the operator stack until the topmost item - precedence is greater than or equal to the target precedence. - - The target precedence. - - - - Resolves this instance, returning a Constraint. If the builder - is not currently in a resolvable state, an exception is thrown. - - The resolved constraint - - - - Gets a value indicating whether this instance is resolvable. - - - true if this instance is resolvable; otherwise, false. - - - - - OperatorStack is a type-safe stack for holding ConstraintOperators - - - - - Initializes a new instance of the class. - - The builder. - - - - Pushes the specified operator onto the stack. - - The op. - - - - Pops the topmost operator from the stack. - - - - - - Gets a value indicating whether this is empty. - - true if empty; otherwise, false. - - - - Gets the topmost operator without modifying the stack. - - The top. - - - - ConstraintStack is a type-safe stack for holding Constraints - - - - - Initializes a new instance of the class. - - The builder. - - - - Pushes the specified constraint. As a side effect, - the constraint's builder field is set to the - ConstraintBuilder owning this stack. - - The constraint. - - - - Pops this topmost constrait from the stack. - As a side effect, the constraint's builder - field is set to null. - - - - - - Gets a value indicating whether this is empty. - - true if empty; otherwise, false. - - - - Gets the topmost constraint without modifying the stack. - - The topmost constraint - - - - ConstraintExpression represents a compound constraint in the - process of being constructed from a series of syntactic elements. - - Individual elements are appended to the expression as they are - reognized. Once an actual Constraint is appended, the expression - returns a resolvable Constraint. - - - - - ConstraintExpressionBase is the abstract base class for the - ConstraintExpression class, which represents a - compound constraint in the process of being constructed - from a series of syntactic elements. - - NOTE: ConstraintExpressionBase is separate because the - ConstraintExpression class was generated in earlier - versions of NUnit. The two classes may be combined - in a future version. - - - - - The ConstraintBuilder holding the elements recognized so far - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the - class passing in a ConstraintBuilder, which may be pre-populated. - - The builder. - - - - Returns a string representation of the expression as it - currently stands. This should only be used for testing, - since it has the side-effect of resolving the expression. - - - - - - Appends an operator to the expression and returns the - resulting expression itself. - - - - - Appends a self-resolving operator to the expression and - returns a new ResolvableConstraintExpression. - - - - - Appends a constraint to the expression and returns that - constraint, which is associated with the current state - of the expression being built. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the - class passing in a ConstraintBuilder, which may be pre-populated. - - The builder. - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding only if a specified number of them succeed. - - - - - Returns a new PropertyConstraintExpression, which will either - test for the existence of the named property on the object - being tested or apply any following constraint to that property. - - - - - Returns a new AttributeConstraint checking for the - presence of a particular attribute on an object. - - - - - Returns a new AttributeConstraint checking for the - presence of a particular attribute on an object. - - - - - Returns the constraint provided as an argument - used to allow custom - custom constraints to easily participate in the syntax. - - - - - Returns the constraint provided as an argument - used to allow custom - custom constraints to easily participate in the syntax. - - - - - Returns a constraint that tests two items for equality - - - - - Returns a constraint that tests that two references are the same object - - - - - Returns a constraint that tests whether the - actual value is greater than the suppled argument - - - - - Returns a constraint that tests whether the - actual value is greater than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is greater than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than or equal to the suppled argument - - - - - Returns a constraint that tests whether the actual - value is of the exact type supplied as an argument. - - - - - Returns a constraint that tests whether the actual - value is of the exact type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is a collection containing the same elements as the - collection supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is a subset of the collection supplied as an argument. - - - - - Returns a new CollectionContainsConstraint checking for the - presence of a particular object in the collection. - - - - - Returns a new CollectionContainsConstraint checking for the - presence of a particular object in the collection. - - - - - Returns a new ContainsConstraint. This constraint - will, in turn, make use of the appropriate second-level - constraint, depending on the type of the actual argument. - This overload is only used if the item sought is a string, - since any other type implies that we are looking for a - collection member. - - - - - Returns a constraint that succeeds if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value matches the Regex pattern supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value matches the Regex pattern supplied as an argument. - - - - - Returns a constraint that tests whether the path provided - is the same as an expected path after canonicalization. - - - - - Returns a constraint that tests whether the path provided - is the same path or under an expected path after canonicalization. - - - - - Returns a constraint that tests whether the path provided - is the same path or under an expected path after canonicalization. - - - - - Returns a constraint that tests whether the actual value falls - within a specified range. - - - - - Returns a ConstraintExpression that negates any - following constraint. - - - - - Returns a ConstraintExpression that negates any - following constraint. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them succeed. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if at least one of them succeeds. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them fail. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Length property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Count property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Message property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the InnerException property of the object being tested. - - - - - With is currently a NOP - reserved for future use. - - - - - Returns a constraint that tests for null - - - - - Returns a constraint that tests for True - - - - - Returns a constraint that tests for False - - - - - Returns a constraint that tests for a positive value - - - - - Returns a constraint that tests for a negative value - - - - - Returns a constraint that tests for NaN - - - - - Returns a constraint that tests for empty - - - - - Returns a constraint that tests whether a collection - contains all unique items. - - - - - Returns a constraint that tests whether an object graph is serializable in binary format. - - - - - Returns a constraint that tests whether an object graph is serializable in xml format. - - - - - Returns a constraint that tests whether a collection is ordered - - - - - Helper class with properties and methods that supply - a number of constraints used in Asserts. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding only if a specified number of them succeed. - - - - - Returns a new PropertyConstraintExpression, which will either - test for the existence of the named property on the object - being tested or apply any following constraint to that property. - - - - - Returns a new AttributeConstraint checking for the - presence of a particular attribute on an object. - - - - - Returns a new AttributeConstraint checking for the - presence of a particular attribute on an object. - - - - - Returns a constraint that tests two items for equality - - - - - Returns a constraint that tests that two references are the same object - - - - - Returns a constraint that tests whether the - actual value is greater than the suppled argument - - - - - Returns a constraint that tests whether the - actual value is greater than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is greater than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than or equal to the suppled argument - - - - - Returns a constraint that tests whether the actual - value is of the exact type supplied as an argument. - - - - - Returns a constraint that tests whether the actual - value is of the exact type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is a collection containing the same elements as the - collection supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is a subset of the collection supplied as an argument. - - - - - Returns a new CollectionContainsConstraint checking for the - presence of a particular object in the collection. - - - - - Returns a new CollectionContainsConstraint checking for the - presence of a particular object in the collection. - - - - - Returns a new ContainsConstraint. This constraint - will, in turn, make use of the appropriate second-level - constraint, depending on the type of the actual argument. - This overload is only used if the item sought is a string, - since any other type implies that we are looking for a - collection member. - - - - - Returns a constraint that succeeds if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that fails if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that fails if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that fails if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value matches the Regex pattern supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value matches the Regex pattern supplied as an argument. - - - - - Returns a constraint that fails if the actual - value matches the pattern supplied as an argument. - - - - - Returns a constraint that tests whether the path provided - is the same as an expected path after canonicalization. - - - - - Returns a constraint that tests whether the path provided - is the same path or under an expected path after canonicalization. - - - - - Returns a constraint that tests whether the path provided - is the same path or under an expected path after canonicalization. - - - - - Returns a constraint that tests whether the actual value falls - within a specified range. - - - - - Returns a ConstraintExpression that negates any - following constraint. - - - - - Returns a ConstraintExpression that negates any - following constraint. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them succeed. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if at least one of them succeeds. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them fail. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Length property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Count property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Message property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the InnerException property of the object being tested. - - - - - Returns a constraint that tests for null - - - - - Returns a constraint that tests for True - - - - - Returns a constraint that tests for False - - - - - Returns a constraint that tests for a positive value - - - - - Returns a constraint that tests for a negative value - - - - - Returns a constraint that tests for NaN - - - - - Returns a constraint that tests for empty - - - - - Returns a constraint that tests whether a collection - contains all unique items. - - - - - Returns a constraint that tests whether an object graph is serializable in binary format. - - - - - Returns a constraint that tests whether an object graph is serializable in xml format. - - - - - Returns a constraint that tests whether a collection is ordered - - - - - The ConstraintOperator class is used internally by a - ConstraintBuilder to represent an operator that - modifies or combines constraints. - - Constraint operators use left and right precedence - values to determine whether the top operator on the - stack should be reduced before pushing a new operator. - - - - - The precedence value used when the operator - is about to be pushed to the stack. - - - - - The precedence value used when the operator - is on the top of the stack. - - - - - Reduce produces a constraint from the operator and - any arguments. It takes the arguments from the constraint - stack and pushes the resulting constraint on it. - - - - - - The syntax element preceding this operator - - - - - The syntax element folowing this operator - - - - - The precedence value used when the operator - is about to be pushed to the stack. - - - - - The precedence value used when the operator - is on the top of the stack. - - - - - PrefixOperator takes a single constraint and modifies - it's action in some way. - - - - - Reduce produces a constraint from the operator and - any arguments. It takes the arguments from the constraint - stack and pushes the resulting constraint on it. - - - - - - Returns the constraint created by applying this - prefix to another constraint. - - - - - - - Negates the test of the constraint it wraps. - - - - - Constructs a new NotOperator - - - - - Returns a NotConstraint applied to its argument. - - - - - Abstract base for operators that indicate how to - apply a constraint to items in a collection. - - - - - Constructs a CollectionOperator - - - - - Represents a constraint that succeeds if all the - members of a collection match a base constraint. - - - - - Returns a constraint that will apply the argument - to the members of a collection, succeeding if - they all succeed. - - - - - Represents a constraint that succeeds if any of the - members of a collection match a base constraint. - - - - - Returns a constraint that will apply the argument - to the members of a collection, succeeding if - any of them succeed. - - - - - Represents a constraint that succeeds if none of the - members of a collection match a base constraint. - - - - - Returns a constraint that will apply the argument - to the members of a collection, succeeding if - none of them succeed. - - - - - Represents a constraint that succeeds if the specified - count of members of a collection match a base constraint. - - - - - Construct an ExactCountOperator for a specified count - - The expected count - - - - Returns a constraint that will apply the argument - to the members of a collection, succeeding if - none of them succeed. - - - - - Represents a constraint that simply wraps the - constraint provided as an argument, without any - further functionality, but which modifes the - order of evaluation because of its precedence. - - - - - Constructor for the WithOperator - - - - - Returns a constraint that wraps its argument - - - - - Abstract base class for operators that are able to reduce to a - constraint whether or not another syntactic element follows. - - - - - Operator used to test for the presence of a named Property - on an object and optionally apply further tests to the - value of that property. - - - - - Constructs a PropOperator for a particular named property - - - - - Reduce produces a constraint from the operator and - any arguments. It takes the arguments from the constraint - stack and pushes the resulting constraint on it. - - - - - - Gets the name of the property to which the operator applies - - - - - Operator that tests for the presence of a particular attribute - on a type and optionally applies further tests to the attribute. - - - - - Construct an AttributeOperator for a particular Type - - The Type of attribute tested - - - - Reduce produces a constraint from the operator and - any arguments. It takes the arguments from the constraint - stack and pushes the resulting constraint on it. - - - - - Operator that tests that an exception is thrown and - optionally applies further tests to the exception. - - - - - Construct a ThrowsOperator - - - - - Reduce produces a constraint from the operator and - any arguments. It takes the arguments from the constraint - stack and pushes the resulting constraint on it. - - - - - Abstract base class for all binary operators - - - - - Reduce produces a constraint from the operator and - any arguments. It takes the arguments from the constraint - stack and pushes the resulting constraint on it. - - - - - - Abstract method that produces a constraint by applying - the operator to its left and right constraint arguments. - - - - - Gets the left precedence of the operator - - - - - Gets the right precedence of the operator - - - - - Operator that requires both it's arguments to succeed - - - - - Construct an AndOperator - - - - - Apply the operator to produce an AndConstraint - - - - - Operator that requires at least one of it's arguments to succeed - - - - - Construct an OrOperator - - - - - Apply the operator to produce an OrConstraint - - - - - ContainsConstraint tests a whether a string contains a substring - or a collection contains an object. It postpones the decision of - which test to use until the type of the actual argument is known. - This allows testing whether a string is contained in a collection - or as a substring of another string using the same syntax. - - - - - Initializes a new instance of the class. - - The expected. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied Comparison object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IEqualityComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IEqualityComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to ignore case and return self. - - - - - Applies a delay to the match so that a match can be evaluated in the future. - - - - - Creates a new DelayedConstraint - - The inner constraint two decorate - The time interval after which the match is performed - If the value of is less than 0 - - - - Creates a new DelayedConstraint - - The inner constraint two decorate - The time interval after which the match is performed - The time interval used for polling - If the value of is less than 0 - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for if the base constraint fails, false if it succeeds - - - - Test whether the constraint is satisfied by a delegate - - The delegate whose value is to be tested - True for if the base constraint fails, false if it succeeds - - - - Test whether the constraint is satisfied by a given reference. - Overridden to wait for the specified delay period before - calling the base constraint with the dereferenced value. - - A reference to the value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a MessageWriter. - - The writer on which the actual value is displayed - - - - Returns the string representation of the constraint. - - - - - EmptyDirectoryConstraint is used to test that a directory is empty - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - EmptyConstraint tests a whether a string or collection is empty, - postponing the decision about which test is applied until the - type of the actual argument is known. - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - EqualConstraint is able to compare an actual value with the - expected value provided in its constructor. Two objects are - considered equal if both are null, or if both have the same - value. NUnit has special semantics for some object types. - - - - - If true, strings in error messages will be clipped - - - - - NUnitEqualityComparer used to test equality. - - - - - Initializes a new instance of the class. - - The expected value. - - - - Flag the constraint to use a tolerance when determining equality. - - Tolerance value to be used - Self. - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied Comparison object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IEqualityComparer object. - - The IComparer object to use. - Self. - - - - Flag the constraint to use the supplied IEqualityComparer object. - - The IComparer object to use. - Self. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write a failure message. Overridden to provide custom - failure messages for EqualConstraint. - - The MessageWriter to write to - - - - Write description of this constraint - - The MessageWriter to write to - - - - Display the failure information for two collections that did not match. - - The MessageWriter on which to display - The expected collection. - The actual collection - The depth of this failure in a set of nested collections - - - - Displays a single line showing the types and sizes of the expected - and actual enumerations, collections or arrays. If both are identical, - the value is only shown once. - - The MessageWriter on which to display - The expected collection or array - The actual collection or array - The indentation level for the message line - - - - Displays a single line showing the point in the expected and actual - arrays at which the comparison failed. If the arrays have different - structures or dimensions, both values are shown. - - The MessageWriter on which to display - The expected array - The actual array - Index of the failure point in the underlying collections - The indentation level for the message line - - - - Display the failure information for two IEnumerables that did not match. - - The MessageWriter on which to display - The expected enumeration. - The actual enumeration - The depth of this failure in a set of nested collections - - - - Flag the constraint to ignore case and return self. - - - - - Flag the constraint to suppress string clipping - and return self. - - - - - Flag the constraint to compare arrays as collections - and return self. - - - - - Switches the .Within() modifier to interpret its tolerance as - a distance in representable values (see remarks). - - Self. - - Ulp stands for "unit in the last place" and describes the minimum - amount a given value can change. For any integers, an ulp is 1 whole - digit. For floating point values, the accuracy of which is better - for smaller numbers and worse for larger numbers, an ulp depends - on the size of the number. Using ulps for comparison of floating - point results instead of fixed tolerances is safer because it will - automatically compensate for the added inaccuracy of larger numbers. - - - - - Switches the .Within() modifier to interpret its tolerance as - a percentage that the actual values is allowed to deviate from - the expected value. - - Self - - - - Causes the tolerance to be interpreted as a TimeSpan in days. - - Self - - - - Causes the tolerance to be interpreted as a TimeSpan in hours. - - Self - - - - Causes the tolerance to be interpreted as a TimeSpan in minutes. - - Self - - - - Causes the tolerance to be interpreted as a TimeSpan in seconds. - - Self - - - - Causes the tolerance to be interpreted as a TimeSpan in milliseconds. - - Self - - - - Causes the tolerance to be interpreted as a TimeSpan in clock ticks. - - Self - - - - EqualityAdapter class handles all equality comparisons - that use an IEqualityComparer, IEqualityComparer<T> - or a ComparisonAdapter. - - - - - Compares two objects, returning true if they are equal - - - - - Returns true if the two objects can be compared by this adapter. - The base adapter cannot handle IEnumerables except for strings. - - - - - Returns an EqualityAdapter that wraps an IComparer. - - - - - Returns an EqualityAdapter that wraps an IEqualityComparer. - - - - - Returns an EqualityAdapter that wraps an IEqualityComparer<T>. - - - - - Returns an EqualityAdapter that wraps an IComparer<T>. - - - - - Returns an EqualityAdapter that wraps a Comparison<T>. - - - - - EqualityAdapter that wraps an IComparer. - - - - - Returns true if the two objects can be compared by this adapter. - Generic adapter requires objects of the specified type. - - - - - EqualityAdapter that wraps an IComparer. - - - - Helper routines for working with floating point numbers - - - The floating point comparison code is based on this excellent article: - http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm - - - "ULP" means Unit in the Last Place and in the context of this library refers to - the distance between two adjacent floating point numbers. IEEE floating point - numbers can only represent a finite subset of natural numbers, with greater - accuracy for smaller numbers and lower accuracy for very large numbers. - - - If a comparison is allowed "2 ulps" of deviation, that means the values are - allowed to deviate by up to 2 adjacent floating point values, which might be - as low as 0.0000001 for small numbers or as high as 10.0 for large numbers. - - - - - Compares two floating point values for equality - First floating point value to be compared - Second floating point value t be compared - - Maximum number of representable floating point values that are allowed to - be between the left and the right floating point values - - True if both numbers are equal or close to being equal - - - Floating point values can only represent a finite subset of natural numbers. - For example, the values 2.00000000 and 2.00000024 can be stored in a float, - but nothing inbetween them. - - - This comparison will count how many possible floating point values are between - the left and the right number. If the number of possible values between both - numbers is less than or equal to maxUlps, then the numbers are considered as - being equal. - - - Implementation partially follows the code outlined here: - http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/ - - - - - Compares two double precision floating point values for equality - First double precision floating point value to be compared - Second double precision floating point value t be compared - - Maximum number of representable double precision floating point values that are - allowed to be between the left and the right double precision floating point values - - True if both numbers are equal or close to being equal - - - Double precision floating point values can only represent a limited series of - natural numbers. For example, the values 2.0000000000000000 and 2.0000000000000004 - can be stored in a double, but nothing inbetween them. - - - This comparison will count how many possible double precision floating point - values are between the left and the right number. If the number of possible - values between both numbers is less than or equal to maxUlps, then the numbers - are considered as being equal. - - - Implementation partially follows the code outlined here: - http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/ - - - - - - Reinterprets the memory contents of a floating point value as an integer value - - - Floating point value whose memory contents to reinterpret - - - The memory contents of the floating point value interpreted as an integer - - - - - Reinterprets the memory contents of a double precision floating point - value as an integer value - - - Double precision floating point value whose memory contents to reinterpret - - - The memory contents of the double precision floating point value - interpreted as an integer - - - - - Reinterprets the memory contents of an integer as a floating point value - - Integer value whose memory contents to reinterpret - - The memory contents of the integer value interpreted as a floating point value - - - - - Reinterprets the memory contents of an integer value as a double precision - floating point value - - Integer whose memory contents to reinterpret - - The memory contents of the integer interpreted as a double precision - floating point value - - - - Union of a floating point variable and an integer - - - The union's value as a floating point variable - - - The union's value as an integer - - - The union's value as an unsigned integer - - - Union of a double precision floating point variable and a long - - - The union's value as a double precision floating point variable - - - The union's value as a long - - - The union's value as an unsigned long - - - - Tests whether a value is greater than the value supplied to its constructor - - - - - The value against which a comparison is to be made - - - - - Initializes a new instance of the class. - - The expected value. - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Tests whether a value is greater than or equal to the value supplied to its constructor - - - - - The value against which a comparison is to be made - - - - - Initializes a new instance of the class. - - The expected value. - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Tests whether a value is less than the value supplied to its constructor - - - - - The value against which a comparison is to be made - - - - - Initializes a new instance of the class. - - The expected value. - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Tests whether a value is less than or equal to the value supplied to its constructor - - - - - The value against which a comparison is to be made - - - - - Initializes a new instance of the class. - - The expected value. - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - MessageWriter is the abstract base for classes that write - constraint descriptions and messages in some form. The - class has separate methods for writing various components - of a message, allowing implementations to tailor the - presentation as needed. - - - - - Construct a MessageWriter given a culture - - - - - Method to write single line message with optional args, usually - written to precede the general failure message. - - The message to be written - Any arguments used in formatting the message - - - - Method to write single line message with optional args, usually - written to precede the general failure message, at a givel - indentation level. - - The indentation level of the message - The message to be written - Any arguments used in formatting the message - - - - Display Expected and Actual lines for a constraint. This - is called by MessageWriter's default implementation of - WriteMessageTo and provides the generic two-line display. - - The constraint that failed - - - - Display Expected and Actual lines for given values. This - method may be called by constraints that need more control over - the display of actual and expected values than is provided - by the default implementation. - - The expected value - The actual value causing the failure - - - - Display Expected and Actual lines for given values, including - a tolerance value on the Expected line. - - The expected value - The actual value causing the failure - The tolerance within which the test was made - - - - Display the expected and actual string values on separate lines. - If the mismatch parameter is >=0, an additional line is displayed - line containing a caret that points to the mismatch point. - - The expected string value - The actual string value - The point at which the strings don't match or -1 - If true, case is ignored in locating the point where the strings differ - If true, the strings should be clipped to fit the line - - - - Writes the text for a connector. - - The connector. - - - - Writes the text for a predicate. - - The predicate. - - - - Writes the text for an expected value. - - The expected value. - - - - Writes the text for a modifier - - The modifier. - - - - Writes the text for an actual value. - - The actual value. - - - - Writes the text for a generalized value. - - The value. - - - - Writes the text for a collection value, - starting at a particular point, to a max length - - The collection containing elements to write. - The starting point of the elements to write - The maximum number of elements to write - - - - Abstract method to get the max line length - - - - - Static methods used in creating messages - - - - - Static string used when strings are clipped - - - - - Returns the representation of a type as used in NUnitLite. - This is the same as Type.ToString() except for arrays, - which are displayed with their declared sizes. - - - - - - - Converts any control characters in a string - to their escaped representation. - - The string to be converted - The converted string - - - - Return the a string representation for a set of indices into an array - - Array of indices for which a string is needed - - - - Get an array of indices representing the point in a enumerable, - collection or array corresponding to a single int index into the - collection. - - The collection to which the indices apply - Index in the collection - Array of indices - - - - Clip a string to a given length, starting at a particular offset, returning the clipped - string with ellipses representing the removed parts - - The string to be clipped - The maximum permitted length of the result string - The point at which to start clipping - The clipped string - - - - Clip the expected and actual strings in a coordinated fashion, - so that they may be displayed together. - - - - - - - - - Shows the position two strings start to differ. Comparison - starts at the start index. - - The expected string - The actual string - The index in the strings at which comparison should start - Boolean indicating whether case should be ignored - -1 if no mismatch found, or the index where mismatch found - - - - The Numerics class contains common operations on numeric values. - - - - - Checks the type of the object, returning true if - the object is a numeric type. - - The object to check - true if the object is a numeric type - - - - Checks the type of the object, returning true if - the object is a floating point numeric type. - - The object to check - true if the object is a floating point numeric type - - - - Checks the type of the object, returning true if - the object is a fixed point numeric type. - - The object to check - true if the object is a fixed point numeric type - - - - Test two numeric values for equality, performing the usual numeric - conversions and using a provided or default tolerance. If the tolerance - provided is Empty, this method may set it to a default tolerance. - - The expected value - The actual value - A reference to the tolerance in effect - True if the values are equal - - - - Compare two numeric values, performing the usual numeric conversions. - - The expected value - The actual value - The relationship of the values to each other - - - - NUnitComparer encapsulates NUnit's default behavior - in comparing two objects. - - - - - Compares two objects - - - - - - - - Returns the default NUnitComparer. - - - - - Generic version of NUnitComparer - - - - - - Compare two objects of the same type - - - - - NUnitEqualityComparer encapsulates NUnit's handling of - equality tests between objects. - - - - - - - - - - Compares two objects for equality within a tolerance - - The first object to compare - The second object to compare - The tolerance to use in the comparison - - - - - If true, all string comparisons will ignore case - - - - - If true, arrays will be treated as collections, allowing - those of different dimensions to be compared - - - - - Comparison objects used in comparisons for some constraints. - - - - - Compares two objects for equality within a tolerance. - - - - - Helper method to compare two arrays - - - - - Method to compare two DirectoryInfo objects - - first directory to compare - second directory to compare - true if equivalent, false if not - - - - Returns the default NUnitEqualityComparer - - - - - Gets and sets a flag indicating whether case should - be ignored in determining equality. - - - - - Gets and sets a flag indicating that arrays should be - compared as collections, without regard to their shape. - - - - - Gets and sets an external comparer to be used to - test for equality. It is applied to members of - collections, in place of NUnit's own logic. - - - - - Gets the list of failure points for the last Match performed. - - - - - FailurePoint class represents one point of failure - in an equality test. - - - - - The location of the failure - - - - - The expected value - - - - - The actual value - - - - - Indicates whether the expected value is valid - - - - - Indicates whether the actual value is valid - - - - - PathConstraint serves as the abstract base of constraints - that operate on paths and provides several helper methods. - - - - - The expected path used in the constraint - - - - - The actual path being tested - - - - - Flag indicating whether a caseInsensitive comparison should be made - - - - - Construct a PathConstraint for a give expected path - - The expected path - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Returns true if the expected path and actual path match - - - - - Returns the string representation of this constraint - - - - - Canonicalize the provided path - - - The path in standardized form - - - - Test whether two paths are the same - - The first path - The second path - Indicates whether case should be ignored - - - - - Test whether one path is under another path - - The first path - supposed to be the parent path - The second path - supposed to be the child path - Indicates whether case should be ignored - - - - - Test whether one path is the same as or under another path - - The first path - supposed to be the parent path - The second path - supposed to be the child path - - - - - Modifies the current instance to be case-insensitve - and returns it. - - - - - Modifies the current instance to be case-sensitve - and returns it. - - - - - Summary description for SamePathConstraint. - - - - - Initializes a new instance of the class. - - The expected path - - - - Test whether the constraint is satisfied by a given value - - The expected path - The actual path - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - SubPathConstraint tests that the actual path is under the expected path - - - - - Initializes a new instance of the class. - - The expected path - - - - Test whether the constraint is satisfied by a given value - - The expected path - The actual path - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - SamePathOrUnderConstraint tests that one path is under another - - - - - Initializes a new instance of the class. - - The expected path - - - - Test whether the constraint is satisfied by a given value - - The expected path - The actual path - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Predicate constraint wraps a Predicate in a constraint, - returning success if the predicate is true. - - - - - Construct a PredicateConstraint from a predicate - - - - - Determines whether the predicate succeeds when applied - to the actual value. - - - - - Writes the description to a MessageWriter - - - - - NotConstraint negates the effect of some other constraint - - - - - Initializes a new instance of the class. - - The base constraint to be negated. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for if the base constraint fails, false if it succeeds - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a MessageWriter. - - The writer on which the actual value is displayed - - - - AllItemsConstraint applies another constraint to each - item in a collection, succeeding if they all succeed. - - - - - Construct an AllItemsConstraint on top of an existing constraint - - - - - - Apply the item constraint to each item in the collection, - failing if any item fails. - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - SomeItemsConstraint applies another constraint to each - item in a collection, succeeding if any of them succeeds. - - - - - Construct a SomeItemsConstraint on top of an existing constraint - - - - - - Apply the item constraint to each item in the collection, - succeeding if any item succeeds. - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - NoItemConstraint applies another constraint to each - item in a collection, failing if any of them succeeds. - - - - - Construct a NoItemConstraint on top of an existing constraint - - - - - - Apply the item constraint to each item in the collection, - failing if any item fails. - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - ExactCoutConstraint applies another constraint to each - item in a collection, succeeding only if a specified - number of items succeed. - - - - - Construct an ExactCountConstraint on top of an existing constraint - - - - - - - Apply the item constraint to each item in the collection, - succeeding only if the expected number of items pass. - - - - - - - Write a description of this constraint to a MessageWriter - - - - - - PropertyExistsConstraint tests that a named property - exists on the object provided through Match. - - Originally, PropertyConstraint provided this feature - in addition to making optional tests on the vaue - of the property. The two constraints are now separate. - - - - - Initializes a new instance of the class. - - The name of the property. - - - - Test whether the property exists for a given object - - The object to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. - - The writer on which the actual value is displayed - - - - Returns the string representation of the constraint. - - - - - - PropertyConstraint extracts a named property and uses - its value as the actual value for a chained constraint. - - - - - Initializes a new instance of the class. - - The name. - The constraint to apply to the property. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - Returns the string representation of the constraint. - - - - - - RangeConstraint tests whethe two values are within a - specified range. - - - - - Initializes a new instance of the class. - - From. - To. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - ResolvableConstraintExpression is used to represent a compound - constraint being constructed at a point where the last operator - may either terminate the expression or may have additional - qualifying constraints added to it. - - It is used, for example, for a Property element or for - an Exception element, either of which may be optionally - followed by constraints that apply to the property or - exception. - - - - - Create a new instance of ResolvableConstraintExpression - - - - - Create a new instance of ResolvableConstraintExpression, - passing in a pre-populated ConstraintBuilder. - - - - - Resolve the current expression to a Constraint - - - - - This operator creates a constraint that is satisfied only if both - argument constraints are satisfied. - - - - - This operator creates a constraint that is satisfied only if both - argument constraints are satisfied. - - - - - This operator creates a constraint that is satisfied only if both - argument constraints are satisfied. - - - - - This operator creates a constraint that is satisfied if either - of the argument constraints is satisfied. - - - - - This operator creates a constraint that is satisfied if either - of the argument constraints is satisfied. - - - - - This operator creates a constraint that is satisfied if either - of the argument constraints is satisfied. - - - - - This operator creates a constraint that is satisfied if the - argument constraint is not satisfied. - - - - - Appends an And Operator to the expression - - - - - Appends an Or operator to the expression. - - - - - ReusableConstraint wraps a resolved constraint so that it - may be saved and reused as needed. - - - - - Construct a ReusableConstraint - - The constraint or expression to be reused - - - - Conversion operator from a normal constraint to a ReusableConstraint. - - The original constraint to be wrapped as a ReusableConstraint - - - - - Returns the string representation of the constraint. - - A string representing the constraint - - - - Resolves the ReusableConstraint by returning the constraint - that it originally wrapped. - - A resolved constraint - - - - SameAsConstraint tests whether an object is identical to - the object passed to its constructor - - - - - Initializes a new instance of the class. - - The expected object. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - BinarySerializableConstraint tests whether - an object is serializable in binary format. - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - Returns the string representation - - - - - BinarySerializableConstraint tests whether - an object is serializable in binary format. - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - Returns the string representation of this constraint - - - - - StringConstraint is the abstract base for constraints - that operate on strings. It supports the IgnoreCase - modifier for string operations. - - - - - The expected value - - - - - Indicates whether tests should be case-insensitive - - - - - Constructs a StringConstraint given an expected value - - The expected value - - - - Modify the constraint to ignore case in matching. - - - - - EmptyStringConstraint tests whether a string is empty. - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - NullEmptyStringConstraint tests whether a string is either null or empty. - - - - - Constructs a new NullOrEmptyStringConstraint - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - SubstringConstraint can test whether a string contains - the expected substring. - - - - - Initializes a new instance of the class. - - The expected. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - StartsWithConstraint can test whether a string starts - with an expected substring. - - - - - Initializes a new instance of the class. - - The expected string - - - - Test whether the constraint is matched by the actual value. - This is a template method, which calls the IsMatch method - of the derived class. - - - - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - EndsWithConstraint can test whether a string ends - with an expected substring. - - - - - Initializes a new instance of the class. - - The expected string - - - - Test whether the constraint is matched by the actual value. - This is a template method, which calls the IsMatch method - of the derived class. - - - - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - RegexConstraint can test whether a string matches - the pattern provided. - - - - - Initializes a new instance of the class. - - The pattern. - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True for success, false for failure - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - ThrowsConstraint is used to test the exception thrown by - a delegate by applying a constraint to it. - - - - - Initializes a new instance of the class, - using a constraint to be applied to the exception. - - A constraint to apply to the caught exception. - - - - Executes the code of the delegate and captures any exception. - If a non-null base constraint was provided, it applies that - constraint to the exception. - - A delegate representing the code to be tested - True if an exception is thrown and the constraint succeeds, otherwise false - - - - Converts an ActualValueDelegate to a TestDelegate - before calling the primary overload. - - - - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - Returns the string representation of this constraint - - - - - Get the actual exception thrown - used by Assert.Throws. - - - - - ThrowsNothingConstraint tests that a delegate does not - throw an exception. - - - - - Test whether the constraint is satisfied by a given value - - The value to be tested - True if no exception is thrown, otherwise false - - - - Converts an ActualValueDelegate to a TestDelegate - before calling the primary overload. - - - - - - - Write the constraint description to a MessageWriter - - The writer on which the description is displayed - - - - Write the actual value for a failing constraint test to a - MessageWriter. The default implementation simply writes - the raw value of actual, leaving it to the writer to - perform any formatting. - - The writer on which the actual value is displayed - - - - Modes in which the tolerance value for a comparison can - be interpreted. - - - - - The tolerance was created with a value, without specifying - how the value would be used. This is used to prevent setting - the mode more than once and is generally changed to Linear - upon execution of the test. - - - - - The tolerance is used as a numeric range within which - two compared values are considered to be equal. - - - - - Interprets the tolerance as the percentage by which - the two compared values my deviate from each other. - - - - - Compares two values based in their distance in - representable numbers. - - - - - The Tolerance class generalizes the notion of a tolerance - within which an equality test succeeds. Normally, it is - used with numeric types, but it can be used with any - type that supports taking a difference between two - objects and comparing that difference to a value. - - - - - Constructs a linear tolerance of a specdified amount - - - - - Constructs a tolerance given an amount and ToleranceMode - - - - - Tests that the current Tolerance is linear with a - numeric value, throwing an exception if it is not. - - - - - Returns an empty Tolerance object, equivalent to - specifying no tolerance. In most cases, it results - in an exact match but for floats and doubles a - default tolerance may be used. - - - - - Returns a zero Tolerance object, equivalent to - specifying an exact match. - - - - - Gets the ToleranceMode for the current Tolerance - - - - - Gets the value of the current Tolerance instance. - - - - - Returns a new tolerance, using the current amount as a percentage. - - - - - Returns a new tolerance, using the current amount in Ulps. - - - - - Returns a new tolerance with a TimeSpan as the amount, using - the current amount as a number of days. - - - - - Returns a new tolerance with a TimeSpan as the amount, using - the current amount as a number of hours. - - - - - Returns a new tolerance with a TimeSpan as the amount, using - the current amount as a number of minutes. - - - - - Returns a new tolerance with a TimeSpan as the amount, using - the current amount as a number of seconds. - - - - - Returns a new tolerance with a TimeSpan as the amount, using - the current amount as a number of milliseconds. - - - - - Returns a new tolerance with a TimeSpan as the amount, using - the current amount as a number of clock ticks. - - - - - Returns true if the current tolerance is empty. - - - - - TypeConstraint is the abstract base for constraints - that take a Type as their expected value. - - - - - The expected Type used by the constraint - - - - - Construct a TypeConstraint for a given Type - - - - - - Write the actual value for a failing constraint test to a - MessageWriter. TypeConstraints override this method to write - the name of the type. - - The writer on which the actual value is displayed - - - - ExactTypeConstraint is used to test that an object - is of the exact type provided in the constructor - - - - - Construct an ExactTypeConstraint for a given Type - - The expected Type. - - - - Test that an object is of the exact type specified - - The actual value. - True if the tested object is of the exact type provided, otherwise false. - - - - Write the description of this constraint to a MessageWriter - - The MessageWriter to use - - - - ExceptionTypeConstraint is a special version of ExactTypeConstraint - used to provided detailed info about the exception thrown in - an error message. - - - - - Constructs an ExceptionTypeConstraint - - - - - Write the actual value for a failing constraint test to a - MessageWriter. Overriden to write additional information - in the case of an Exception. - - The MessageWriter to use - - - - InstanceOfTypeConstraint is used to test that an object - is of the same type provided or derived from it. - - - - - Construct an InstanceOfTypeConstraint for the type provided - - The expected Type - - - - Test whether an object is of the specified type or a derived type - - The object to be tested - True if the object is of the provided type or derives from it, otherwise false. - - - - Write a description of this constraint to a MessageWriter - - The MessageWriter to use - - - - AssignableFromConstraint is used to test that an object - can be assigned from a given Type. - - - - - Construct an AssignableFromConstraint for the type provided - - - - - - Test whether an object can be assigned from the specified type - - The object to be tested - True if the object can be assigned a value of the expected Type, otherwise false. - - - - Write a description of this constraint to a MessageWriter - - The MessageWriter to use - - - - AssignableToConstraint is used to test that an object - can be assigned to a given Type. - - - - - Construct an AssignableToConstraint for the type provided - - - - - - Test whether an object can be assigned to the specified type - - The object to be tested - True if the object can be assigned a value of the expected Type, otherwise false. - - - - Write a description of this constraint to a MessageWriter - - The MessageWriter to use - - - - Thrown when an assertion failed. - - - - - The error message that explains - the reason for the exception - - - The error message that explains - the reason for the exception - The exception that caused the - current exception - - - - Serialization Constructor - - - - - Thrown when an assertion failed. - - - - - - - The error message that explains - the reason for the exception - The exception that caused the - current exception - - - - Serialization Constructor - - - - - Thrown when a test executes inconclusively. - - - - - The error message that explains - the reason for the exception - - - The error message that explains - the reason for the exception - The exception that caused the - current exception - - - - Serialization Constructor - - - - - Thrown when an assertion failed. - - - - - - - The error message that explains - the reason for the exception - The exception that caused the - current exception - - - - Serialization Constructor - - - - - - - - - - - Compares two objects of a given Type for equality within a tolerance - - The first object to compare - The second object to compare - The tolerance to use in the comparison - - - - - The different targets a test action attribute can be applied to - - - - - Default target, which is determined by where the action attribute is attached - - - - - Target a individual test case - - - - - Target a suite of test cases - - - - - Delegate used by tests that execute code and - capture any thrown exception. - - - - - The Assert class contains a collection of static methods that - implement the most common assertions used in NUnit. - - - - - We don't actually want any instances of this object, but some people - like to inherit from it to add other static methods. Hence, the - protected constructor disallows any instances of this object. - - - - - The Equals method throws an AssertionException. This is done - to make sure there is no mistake by calling this function. - - - - - - - override the default ReferenceEquals to throw an AssertionException. This - implementation makes sure there is no mistake in calling this function - as part of Assert. - - - - - - - Helper for Assert.AreEqual(double expected, double actual, ...) - allowing code generation to work consistently. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Throws a with the message and arguments - that are passed in. This allows a test to be cut short, with a result - of success returned to NUnit. - - The message to initialize the with. - Arguments to be used in formatting the message - - - - Throws a with the message and arguments - that are passed in. This allows a test to be cut short, with a result - of success returned to NUnit. - - The message to initialize the with. - - - - Throws a with the message and arguments - that are passed in. This allows a test to be cut short, with a result - of success returned to NUnit. - - - - - Throws an with the message and arguments - that are passed in. This is used by the other Assert functions. - - The message to initialize the with. - Arguments to be used in formatting the message - - - - Throws an with the message that is - passed in. This is used by the other Assert functions. - - The message to initialize the with. - - - - Throws an . - This is used by the other Assert functions. - - - - - Throws an with the message and arguments - that are passed in. This causes the test to be reported as ignored. - - The message to initialize the with. - Arguments to be used in formatting the message - - - - Throws an with the message that is - passed in. This causes the test to be reported as ignored. - - The message to initialize the with. - - - - Throws an . - This causes the test to be reported as ignored. - - - - - Throws an with the message and arguments - that are passed in. This causes the test to be reported as inconclusive. - - The message to initialize the with. - Arguments to be used in formatting the message - - - - Throws an with the message that is - passed in. This causes the test to be reported as inconclusive. - - The message to initialize the with. - - - - Throws an . - This causes the test to be reported as Inconclusive. - - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint expression to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint expression to be applied - An ActualValueDelegate returning the value to be tested - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint expression to be applied - An ActualValueDelegate returning the value to be tested - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - An ActualValueDelegate returning the value to be tested - A Constraint expression to be applied - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display if the condition is false - Arguments to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display if the condition is false - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - - - - Asserts that the code represented by a delegate throws an exception - that satisfies the constraint provided. - - A TestDelegate to be executed - A ThrowsConstraint used in the test - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - Used as a synonym for That in rare cases where a private setter - causes a Visual Basic compilation error. - - A Constraint to be applied - The actual value to test - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - Used as a synonym for That in rare cases where a private setter - causes a Visual Basic compilation error. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - Used as a synonym for That in rare cases where a private setter - causes a Visual Basic compilation error. - - - This method is provided for use by VB developers needing to test - the value of properties with private setters. - - A Constraint expression to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws a particular exception when called. - - A constraint to be satisfied by the exception - A TestSnippet delegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws a particular exception when called. - - A constraint to be satisfied by the exception - A TestSnippet delegate - The message that will be displayed on failure - - - - Verifies that a delegate throws a particular exception when called. - - A constraint to be satisfied by the exception - A TestSnippet delegate - - - - Verifies that a delegate throws a particular exception when called. - - The exception Type expected - A TestSnippet delegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws a particular exception when called. - - The exception Type expected - A TestSnippet delegate - The message that will be displayed on failure - - - - Verifies that a delegate throws a particular exception when called. - - The exception Type expected - A TestSnippet delegate - - - - Verifies that a delegate throws a particular exception when called. - - Type of the expected exception - A TestSnippet delegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws a particular exception when called. - - Type of the expected exception - A TestSnippet delegate - The message that will be displayed on failure - - - - Verifies that a delegate throws a particular exception when called. - - Type of the expected exception - A TestSnippet delegate - - - - Verifies that a delegate throws an exception when called - and returns it. - - A TestDelegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws an exception when called - and returns it. - - A TestDelegate - The message that will be displayed on failure - - - - Verifies that a delegate throws an exception when called - and returns it. - - A TestDelegate - - - - Verifies that a delegate throws an exception of a certain Type - or one derived from it when called and returns it. - - The expected Exception Type - A TestDelegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws an exception of a certain Type - or one derived from it when called and returns it. - - The expected Exception Type - A TestDelegate - The message that will be displayed on failure - - - - Verifies that a delegate throws an exception of a certain Type - or one derived from it when called and returns it. - - The expected Exception Type - A TestDelegate - - - - Verifies that a delegate throws an exception of a certain Type - or one derived from it when called and returns it. - - The expected Exception Type - A TestDelegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate throws an exception of a certain Type - or one derived from it when called and returns it. - - The expected Exception Type - A TestDelegate - The message that will be displayed on failure - - - - Verifies that a delegate throws an exception of a certain Type - or one derived from it when called and returns it. - - The expected Exception Type - A TestDelegate - - - - Verifies that a delegate does not throw an exception - - A TestSnippet delegate - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Verifies that a delegate does not throw an exception. - - A TestSnippet delegate - The message that will be displayed on failure - - - - Verifies that a delegate does not throw an exception. - - A TestSnippet delegate - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display in case of failure - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display in case of failure - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - - - - Asserts that a condition is false. If the condition is true the method throws - an . - - The evaluated condition - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that a condition is false. If the condition is true the method throws - an . - - The evaluated condition - The message to display in case of failure - - - - Asserts that a condition is false. If the condition is true the method throws - an . - - The evaluated condition - - - - Asserts that a condition is false. If the condition is true the method throws - an . - - The evaluated condition - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that a condition is false. If the condition is true the method throws - an . - - The evaluated condition - The message to display in case of failure - - - - Asserts that a condition is false. If the condition is true the method throws - an . - - The evaluated condition - - - - Verifies that the object that is passed in is not equal to null - If the object is null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the object that is passed in is not equal to null - If the object is null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - - - - Verifies that the object that is passed in is not equal to null - If the object is null then an - is thrown. - - The object that is to be tested - - - - Verifies that the object that is passed in is not equal to null - If the object is null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the object that is passed in is not equal to null - If the object is null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - - - - Verifies that the object that is passed in is not equal to null - If the object is null then an - is thrown. - - The object that is to be tested - - - - Verifies that the object that is passed in is equal to null - If the object is not null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the object that is passed in is equal to null - If the object is not null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - - - - Verifies that the object that is passed in is equal to null - If the object is not null then an - is thrown. - - The object that is to be tested - - - - Verifies that the object that is passed in is equal to null - If the object is not null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the object that is passed in is equal to null - If the object is not null then an - is thrown. - - The object that is to be tested - The message to display in case of failure - - - - Verifies that the object that is passed in is equal to null - If the object is not null then an - is thrown. - - The object that is to be tested - - - - Verifies that the double that is passed in is an NaN value. - If the object is not NaN then an - is thrown. - - The value that is to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the double that is passed in is an NaN value. - If the object is not NaN then an - is thrown. - - The value that is to be tested - The message to display in case of failure - - - - Verifies that the double that is passed in is an NaN value. - If the object is not NaN then an - is thrown. - - The value that is to be tested - - - - Verifies that the double that is passed in is an NaN value. - If the object is not NaN then an - is thrown. - - The value that is to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the double that is passed in is an NaN value. - If the object is not NaN then an - is thrown. - - The value that is to be tested - The message to display in case of failure - - - - Verifies that the double that is passed in is an NaN value. - If the object is not NaN then an - is thrown. - - The value that is to be tested - - - - Assert that a string is empty - that is equal to string.Empty - - The string to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Assert that a string is empty - that is equal to string.Empty - - The string to be tested - The message to display in case of failure - - - - Assert that a string is empty - that is equal to string.Empty - - The string to be tested - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing ICollection - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing ICollection - The message to display in case of failure - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing ICollection - - - - Assert that a string is not empty - that is not equal to string.Empty - - The string to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Assert that a string is not empty - that is not equal to string.Empty - - The string to be tested - The message to display in case of failure - - - - Assert that a string is not empty - that is not equal to string.Empty - - The string to be tested - - - - Assert that an array, list or other collection is not empty - - An array, list or other collection implementing ICollection - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Assert that an array, list or other collection is not empty - - An array, list or other collection implementing ICollection - The message to display in case of failure - - - - Assert that an array, list or other collection is not empty - - An array, list or other collection implementing ICollection - - - - Assert that a string is either null or equal to string.Empty - - The string to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Assert that a string is either null or equal to string.Empty - - The string to be tested - The message to display in case of failure - - - - Assert that a string is either null or equal to string.Empty - - The string to be tested - - - - Assert that a string is not null or empty - - The string to be tested - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Assert that a string is not null or empty - - The string to be tested - The message to display in case of failure - - - - Assert that a string is not null or empty - - The string to be tested - - - - Asserts that an object may be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object may be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - - - - Asserts that an object may be assigned a value of a given Type. - - The expected Type. - The object under examination - - - - Asserts that an object may be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object may be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - - - - Asserts that an object may be assigned a value of a given Type. - - The expected Type. - The object under examination - - - - Asserts that an object may not be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object may not be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - - - - Asserts that an object may not be assigned a value of a given Type. - - The expected Type. - The object under examination - - - - Asserts that an object may not be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object may not be assigned a value of a given Type. - - The expected Type. - The object under examination - The message to display in case of failure - - - - Asserts that an object may not be assigned a value of a given Type. - - The expected Type. - The object under examination - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - - - - Asserts that an object is an instance of a given type. - - The expected Type - The object being examined - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - The message to display in case of failure - - - - Asserts that an object is not an instance of a given type. - - The expected Type - The object being examined - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are equal. If they are not, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two doubles are equal considering a delta. If the - expected value is infinity then the delta value is ignored. If - they are not equal then an is - thrown. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two doubles are equal considering a delta. If the - expected value is infinity then the delta value is ignored. If - they are not equal then an is - thrown. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - The message to display in case of failure - - - - Verifies that two doubles are equal considering a delta. If the - expected value is infinity then the delta value is ignored. If - they are not equal then an is - thrown. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - - - - Verifies that two doubles are equal considering a delta. If the - expected value is infinity then the delta value is ignored. If - they are not equal then an is - thrown. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two doubles are equal considering a delta. If the - expected value is infinity then the delta value is ignored. If - they are not equal then an is - thrown. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - The message to display in case of failure - - - - Verifies that two doubles are equal considering a delta. If the - expected value is infinity then the delta value is ignored. If - they are not equal then an is - thrown. - - The expected value - The actual value - The maximum acceptable difference between the - the expected and the actual - - - - Verifies that two objects are equal. Two objects are considered - equal if both are null, or if both have the same value. NUnit - has special semantics for some object types. - If they are not equal an is thrown. - - The value that is expected - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two objects are equal. Two objects are considered - equal if both are null, or if both have the same value. NUnit - has special semantics for some object types. - If they are not equal an is thrown. - - The value that is expected - The actual value - The message to display in case of failure - - - - Verifies that two objects are equal. Two objects are considered - equal if both are null, or if both have the same value. NUnit - has special semantics for some object types. - If they are not equal an is thrown. - - The value that is expected - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - The message to display in case of failure - - - - Verifies that two values are not equal. If they are equal, then an - is thrown. - - The expected value - The actual value - - - - Verifies that two objects are not equal. Two objects are considered - equal if both are null, or if both have the same value. NUnit - has special semantics for some object types. - If they are equal an is thrown. - - The value that is expected - The actual value - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that two objects are not equal. Two objects are considered - equal if both are null, or if both have the same value. NUnit - has special semantics for some object types. - If they are equal an is thrown. - - The value that is expected - The actual value - The message to display in case of failure - - - - Verifies that two objects are not equal. Two objects are considered - equal if both are null, or if both have the same value. NUnit - has special semantics for some object types. - If they are equal an is thrown. - - The value that is expected - The actual value - - - - Asserts that two objects refer to the same object. If they - are not the same an is thrown. - - The expected object - The actual object - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that two objects refer to the same object. If they - are not the same an is thrown. - - The expected object - The actual object - The message to display in case of failure - - - - Asserts that two objects refer to the same object. If they - are not the same an is thrown. - - The expected object - The actual object - - - - Asserts that two objects do not refer to the same object. If they - are the same an is thrown. - - The expected object - The actual object - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that two objects do not refer to the same object. If they - are the same an is thrown. - - The expected object - The actual object - The message to display in case of failure - - - - Asserts that two objects do not refer to the same object. If they - are the same an is thrown. - - The expected object - The actual object - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than the second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - The message to display in case of failure - - - - Verifies that the first value is greater than or equal tothe second - value. If it is not, then an - is thrown. - - The first value, expected to be greater - The second value, expected to be less - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - The message to display in case of failure - - - - Verifies that the first value is less than or equal to the second - value. If it is not, then an - is thrown. - - The first value, expected to be less - The second value, expected to be greater - - - - Asserts that an object is contained in a list. - - The expected object - The list to be examined - The message to display in case of failure - Array of objects to be used in formatting the message - - - - Asserts that an object is contained in a list. - - The expected object - The list to be examined - The message to display in case of failure - - - - Asserts that an object is contained in a list. - - The expected object - The list to be examined - - - - Gets the number of assertions executed so far and - resets the counter to zero. - - - - - AssertionHelper is an optional base class for user tests, - allowing the use of shorter names for constraints and - asserts and avoiding conflict with the definition of - , from which it inherits much of its - behavior, in certain mock object frameworks. - - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. Works - identically to Assert.That - - A Constraint to be applied - The actual value to test - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. Works - identically to Assert.That. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. Works - identically to Assert.That - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint expression to be applied - An ActualValueDelegate returning the value to be tested - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint expression to be applied - An ActualValueDelegate returning the value to be tested - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - An ActualValueDelegate returning the value to be tested - A Constraint expression to be applied - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an assertion exception on failure. - - A Constraint to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . Works Identically to Assert.That. - - The evaluated condition - The message to display if the condition is false - Arguments to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . Works Identically to Assert.That. - - The evaluated condition - The message to display if the condition is false - - - - Asserts that a condition is true. If the condition is false the method throws - an . Works Identically Assert.That. - - The evaluated condition - - - - Asserts that the code represented by a delegate throws an exception - that satisfies the constraint provided. - - A TestDelegate to be executed - A ThrowsConstraint used in the test - - - - Returns a ListMapper based on a collection. - - The original collection - - - - - Provides static methods to express the assumptions - that must be met for a test to give a meaningful - result. If an assumption is not met, the test - should produce an inconclusive result. - - - - - The Equals method throws an AssertionException. This is done - to make sure there is no mistake by calling this function. - - - - - - - override the default ReferenceEquals to throw an AssertionException. This - implementation makes sure there is no mistake in calling this function - as part of Assert. - - - - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - The actual value to test - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - An ActualValueDelegate returning the value to be tested - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - An ActualValueDelegate returning the value to be tested - The message that will be displayed on failure - - - - Apply a constraint to an actual value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - An ActualValueDelegate returning the value to be tested - A Constraint expression to be applied - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - The actual value to test - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - The actual value to test - The message that will be displayed on failure - - - - Apply a constraint to a referenced value, succeeding if the constraint - is satisfied and throwing an InconclusiveException on failure. - - A Constraint expression to be applied - The actual value to test - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display if the condition is false - Arguments to be used in formatting the message - - - - Asserts that a condition is true. If the condition is false the method throws - an . - - The evaluated condition - The message to display if the condition is false - - - - Asserts that a condition is true. If the condition is false the - method throws an . - - The evaluated condition - - - - Asserts that the code represented by a delegate throws an exception - that satisfies the constraint provided. - - A TestDelegate to be executed - A ThrowsConstraint used in the test - - - - A set of Assert methods operationg on one or more collections - - - - - The Equals method throws an AssertionException. This is done - to make sure there is no mistake by calling this function. - - - - - - - override the default ReferenceEquals to throw an AssertionException. This - implementation makes sure there is no mistake in calling this function - as part of Assert. - - - - - - - Asserts that all items contained in collection are of the type specified by expectedType. - - IEnumerable containing objects to be considered - System.Type that all objects in collection must be instances of - - - - Asserts that all items contained in collection are of the type specified by expectedType. - - IEnumerable containing objects to be considered - System.Type that all objects in collection must be instances of - The message that will be displayed on failure - - - - Asserts that all items contained in collection are of the type specified by expectedType. - - IEnumerable containing objects to be considered - System.Type that all objects in collection must be instances of - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that all items contained in collection are not equal to null. - - IEnumerable containing objects to be considered - - - - Asserts that all items contained in collection are not equal to null. - - IEnumerable containing objects to be considered - The message that will be displayed on failure - - - - Asserts that all items contained in collection are not equal to null. - - IEnumerable of objects to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Ensures that every object contained in collection exists within the collection - once and only once. - - IEnumerable of objects to be considered - - - - Ensures that every object contained in collection exists within the collection - once and only once. - - IEnumerable of objects to be considered - The message that will be displayed on failure - - - - Ensures that every object contained in collection exists within the collection - once and only once. - - IEnumerable of objects to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that expected and actual are exactly equal. The collections must have the same count, - and contain the exact same objects in the same order. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - - - - Asserts that expected and actual are exactly equal. The collections must have the same count, - and contain the exact same objects in the same order. - If comparer is not null then it will be used to compare the objects. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The IComparer to use in comparing objects from each IEnumerable - - - - Asserts that expected and actual are exactly equal. The collections must have the same count, - and contain the exact same objects in the same order. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - - - - Asserts that expected and actual are exactly equal. The collections must have the same count, - and contain the exact same objects in the same order. - If comparer is not null then it will be used to compare the objects. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The IComparer to use in comparing objects from each IEnumerable - The message that will be displayed on failure - - - - Asserts that expected and actual are exactly equal. The collections must have the same count, - and contain the exact same objects in the same order. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that expected and actual are exactly equal. The collections must have the same count, - and contain the exact same objects in the same order. - If comparer is not null then it will be used to compare the objects. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The IComparer to use in comparing objects from each IEnumerable - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - - - - Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - - - - Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that expected and actual are not exactly equal. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - - - - Asserts that expected and actual are not exactly equal. - If comparer is not null then it will be used to compare the objects. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The IComparer to use in comparing objects from each IEnumerable - - - - Asserts that expected and actual are not exactly equal. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - - - - Asserts that expected and actual are not exactly equal. - If comparer is not null then it will be used to compare the objects. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The IComparer to use in comparing objects from each IEnumerable - The message that will be displayed on failure - - - - Asserts that expected and actual are not exactly equal. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that expected and actual are not exactly equal. - If comparer is not null then it will be used to compare the objects. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The IComparer to use in comparing objects from each IEnumerable - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that expected and actual are not equivalent. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - - - - Asserts that expected and actual are not equivalent. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - - - - Asserts that expected and actual are not equivalent. - - The first IEnumerable of objects to be considered - The second IEnumerable of objects to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that collection contains actual as an item. - - IEnumerable of objects to be considered - Object to be found within collection - - - - Asserts that collection contains actual as an item. - - IEnumerable of objects to be considered - Object to be found within collection - The message that will be displayed on failure - - - - Asserts that collection contains actual as an item. - - IEnumerable of objects to be considered - Object to be found within collection - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that collection does not contain actual as an item. - - IEnumerable of objects to be considered - Object that cannot exist within collection - - - - Asserts that collection does not contain actual as an item. - - IEnumerable of objects to be considered - Object that cannot exist within collection - The message that will be displayed on failure - - - - Asserts that collection does not contain actual as an item. - - IEnumerable of objects to be considered - Object that cannot exist within collection - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that superset is not a subject of subset. - - The IEnumerable superset to be considered - The IEnumerable subset to be considered - - - - Asserts that superset is not a subject of subset. - - The IEnumerable superset to be considered - The IEnumerable subset to be considered - The message that will be displayed on failure - - - - Asserts that superset is not a subject of subset. - - The IEnumerable superset to be considered - The IEnumerable subset to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Asserts that superset is a subset of subset. - - The IEnumerable superset to be considered - The IEnumerable subset to be considered - - - - Asserts that superset is a subset of subset. - - The IEnumerable superset to be considered - The IEnumerable subset to be considered - The message that will be displayed on failure - - - - Asserts that superset is a subset of subset. - - The IEnumerable superset to be considered - The IEnumerable subset to be considered - The message that will be displayed on failure - Arguments to be used in formatting the message - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing IEnumerable - The message to be displayed on failure - Arguments to be used in formatting the message - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing IEnumerable - The message to be displayed on failure - - - - Assert that an array,list or other collection is empty - - An array, list or other collection implementing IEnumerable - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing IEnumerable - The message to be displayed on failure - Arguments to be used in formatting the message - - - - Assert that an array, list or other collection is empty - - An array, list or other collection implementing IEnumerable - The message to be displayed on failure - - - - Assert that an array,list or other collection is empty - - An array, list or other collection implementing IEnumerable - - - - Assert that an array, list or other collection is ordered - - An array, list or other collection implementing IEnumerable - The message to be displayed on failure - Arguments to be used in formatting the message - - - - Assert that an array, list or other collection is ordered - - An array, list or other collection implementing IEnumerable - The message to be displayed on failure - - - - Assert that an array, list or other collection is ordered - - An array, list or other collection implementing IEnumerable - - - - Assert that an array, list or other collection is ordered - - An array, list or other collection implementing IEnumerable - A custom comparer to perform the comparisons - The message to be displayed on failure - Arguments to be used in formatting the message - - - - Assert that an array, list or other collection is ordered - - An array, list or other collection implementing IEnumerable - A custom comparer to perform the comparisons - The message to be displayed on failure - - - - Assert that an array, list or other collection is ordered - - An array, list or other collection implementing IEnumerable - A custom comparer to perform the comparisons - - - - Static helper class used in the constraint-based syntax - - - - - Creates a new SubstringConstraint - - The value of the substring - A SubstringConstraint - - - - Creates a new CollectionContainsConstraint. - - The item that should be found. - A new CollectionContainsConstraint - - - - Summary description for DirectoryAssert - - - - - The Equals method throws an AssertionException. This is done - to make sure there is no mistake by calling this function. - - - - - - - override the default ReferenceEquals to throw an AssertionException. This - implementation makes sure there is no mistake in calling this function - as part of Assert. - - - - - - - We don't actually want any instances of this object, but some people - like to inherit from it to add other static methods. Hence, the - protected constructor disallows any instances of this object. - - - - - Verifies that two directories are equal. Two directories are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A directory containing the value that is expected - A directory containing the actual value - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Verifies that two directories are equal. Two directories are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A directory containing the value that is expected - A directory containing the actual value - The message to display if directories are not equal - - - - Verifies that two directories are equal. Two directories are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A directory containing the value that is expected - A directory containing the actual value - - - - Verifies that two directories are equal. Two directories are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A directory path string containing the value that is expected - A directory path string containing the actual value - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Verifies that two directories are equal. Two directories are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A directory path string containing the value that is expected - A directory path string containing the actual value - The message to display if directories are not equal - - - - Verifies that two directories are equal. Two directories are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A directory path string containing the value that is expected - A directory path string containing the actual value - - - - Asserts that two directories are not equal. If they are equal - an is thrown. - - A directory containing the value that is expected - A directory containing the actual value - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Asserts that two directories are not equal. If they are equal - an is thrown. - - A directory containing the value that is expected - A directory containing the actual value - The message to display if directories are not equal - - - - Asserts that two directories are not equal. If they are equal - an is thrown. - - A directory containing the value that is expected - A directory containing the actual value - - - - Asserts that two directories are not equal. If they are equal - an is thrown. - - A directory path string containing the value that is expected - A directory path string containing the actual value - The message to display if directories are equal - Arguments to be used in formatting the message - - - - Asserts that two directories are not equal. If they are equal - an is thrown. - - A directory path string containing the value that is expected - A directory path string containing the actual value - The message to display if directories are equal - - - - Asserts that two directories are not equal. If they are equal - an is thrown. - - A directory path string containing the value that is expected - A directory path string containing the actual value - - - - Asserts that the directory is empty. If it is not empty - an is thrown. - - A directory to search - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Asserts that the directory is empty. If it is not empty - an is thrown. - - A directory to search - The message to display if directories are not equal - - - - Asserts that the directory is empty. If it is not empty - an is thrown. - - A directory to search - - - - Asserts that the directory is empty. If it is not empty - an is thrown. - - A directory to search - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Asserts that the directory is empty. If it is not empty - an is thrown. - - A directory to search - The message to display if directories are not equal - - - - Asserts that the directory is empty. If it is not empty - an is thrown. - - A directory to search - - - - Asserts that the directory is not empty. If it is empty - an is thrown. - - A directory to search - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Asserts that the directory is not empty. If it is empty - an is thrown. - - A directory to search - The message to display if directories are not equal - - - - Asserts that the directory is not empty. If it is empty - an is thrown. - - A directory to search - - - - Asserts that the directory is not empty. If it is empty - an is thrown. - - A directory to search - The message to display if directories are not equal - Arguments to be used in formatting the message - - - - Asserts that the directory is not empty. If it is empty - an is thrown. - - A directory to search - The message to display if directories are not equal - - - - Asserts that the directory is not empty. If it is empty - an is thrown. - - A directory to search - - - - Asserts that path contains actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - Arguments to be used in formatting the message - - - - Asserts that path contains actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - - - - Asserts that path contains actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - - - - Asserts that path contains actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - Arguments to be used in formatting the message - - - - Asserts that path contains actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - - - - Asserts that path contains actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - - - - Asserts that path does not contain actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - Arguments to be used in formatting the message - - - - Asserts that path does not contain actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - - - - Asserts that path does not contain actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - - - - Asserts that path does not contain actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - Arguments to be used in formatting the message - - - - Asserts that path does not contain actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - The message to display if directory is not within the path - - - - Asserts that path does not contain actual as a subdirectory or - an is thrown. - - A directory to search - sub-directory asserted to exist under directory - - - - Summary description for FileAssert. - - - - - The Equals method throws an AssertionException. This is done - to make sure there is no mistake by calling this function. - - - - - - - override the default ReferenceEquals to throw an AssertionException. This - implementation makes sure there is no mistake in calling this function - as part of Assert. - - - - - - - We don't actually want any instances of this object, but some people - like to inherit from it to add other static methods. Hence, the - protected constructor disallows any instances of this object. - - - - - Verifies that two Streams are equal. Two Streams are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - The expected Stream - The actual Stream - The message to display if Streams are not equal - Arguments to be used in formatting the message - - - - Verifies that two Streams are equal. Two Streams are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - The expected Stream - The actual Stream - The message to display if objects are not equal - - - - Verifies that two Streams are equal. Two Streams are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - The expected Stream - The actual Stream - - - - Verifies that two files are equal. Two files are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A file containing the value that is expected - A file containing the actual value - The message to display if Streams are not equal - Arguments to be used in formatting the message - - - - Verifies that two files are equal. Two files are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A file containing the value that is expected - A file containing the actual value - The message to display if objects are not equal - - - - Verifies that two files are equal. Two files are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - A file containing the value that is expected - A file containing the actual value - - - - Verifies that two files are equal. Two files are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - The path to a file containing the value that is expected - The path to a file containing the actual value - The message to display if Streams are not equal - Arguments to be used in formatting the message - - - - Verifies that two files are equal. Two files are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - The path to a file containing the value that is expected - The path to a file containing the actual value - The message to display if objects are not equal - - - - Verifies that two files are equal. Two files are considered - equal if both are null, or if both have the same value byte for byte. - If they are not equal an is thrown. - - The path to a file containing the value that is expected - The path to a file containing the actual value - - - - Asserts that two Streams are not equal. If they are equal - an is thrown. - - The expected Stream - The actual Stream - The message to be displayed when the two Stream are the same. - Arguments to be used in formatting the message - - - - Asserts that two Streams are not equal. If they are equal - an is thrown. - - The expected Stream - The actual Stream - The message to be displayed when the Streams are the same. - - - - Asserts that two Streams are not equal. If they are equal - an is thrown. - - The expected Stream - The actual Stream - - - - Asserts that two files are not equal. If they are equal - an is thrown. - - A file containing the value that is expected - A file containing the actual value - The message to display if Streams are not equal - Arguments to be used in formatting the message - - - - Asserts that two files are not equal. If they are equal - an is thrown. - - A file containing the value that is expected - A file containing the actual value - The message to display if objects are not equal - - - - Asserts that two files are not equal. If they are equal - an is thrown. - - A file containing the value that is expected - A file containing the actual value - - - - Asserts that two files are not equal. If they are equal - an is thrown. - - The path to a file containing the value that is expected - The path to a file containing the actual value - The message to display if Streams are not equal - Arguments to be used in formatting the message - - - - Asserts that two files are not equal. If they are equal - an is thrown. - - The path to a file containing the value that is expected - The path to a file containing the actual value - The message to display if objects are not equal - - - - Asserts that two files are not equal. If they are equal - an is thrown. - - The path to a file containing the value that is expected - The path to a file containing the actual value - - - - GlobalSettings is a place for setting default values used - by the framework in performing asserts. - - - - - Default tolerance for floating point equality - - - - - Helper class with properties and methods that supply - a number of constraints used in Asserts. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding only if a specified number of them succeed. - - - - - Returns a new PropertyConstraintExpression, which will either - test for the existence of the named property on the object - being tested or apply any following constraint to that property. - - - - - Returns a new AttributeConstraint checking for the - presence of a particular attribute on an object. - - - - - Returns a new AttributeConstraint checking for the - presence of a particular attribute on an object. - - - - - Returns a new CollectionContainsConstraint checking for the - presence of a particular object in the collection. - - - - - Returns a ConstraintExpression that negates any - following constraint. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them succeed. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if at least one of them succeeds. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them fail. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Length property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Count property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the Message property of the object being tested. - - - - - Returns a new ConstraintExpression, which will apply the following - constraint to the InnerException property of the object being tested. - - - - - Interface implemented by a user fixture in order to - validate any expected exceptions. It is only called - for test methods marked with the ExpectedException - attribute. - - - - - Method to handle an expected exception - - The exception to be handled - - - - Helper class with properties and methods that supply - a number of constraints used in Asserts. - - - - - Returns a constraint that tests two items for equality - - - - - Returns a constraint that tests that two references are the same object - - - - - Returns a constraint that tests whether the - actual value is greater than the suppled argument - - - - - Returns a constraint that tests whether the - actual value is greater than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is greater than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than or equal to the suppled argument - - - - - Returns a constraint that tests whether the - actual value is less than or equal to the suppled argument - - - - - Returns a constraint that tests whether the actual - value is of the exact type supplied as an argument. - - - - - Returns a constraint that tests whether the actual - value is of the exact type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is of the type supplied as an argument or a derived type. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is assignable from the type supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is a collection containing the same elements as the - collection supplied as an argument. - - - - - Returns a constraint that tests whether the actual value - is a subset of the collection supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value matches the Regex pattern supplied as an argument. - - - - - Returns a constraint that tests whether the path provided - is the same as an expected path after canonicalization. - - - - - Returns a constraint that tests whether the path provided - is the same path or under an expected path after canonicalization. - - - - - Returns a constraint that tests whether the path provided - is the same path or under an expected path after canonicalization. - - - - - Returns a constraint that tests whether the actual value falls - within a specified range. - - - - - Returns a ConstraintExpression that negates any - following constraint. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them succeed. - - - - - Returns a constraint that tests for null - - - - - Returns a constraint that tests for True - - - - - Returns a constraint that tests for False - - - - - Returns a constraint that tests for a positive value - - - - - Returns a constraint that tests for a negative value - - - - - Returns a constraint that tests for NaN - - - - - Returns a constraint that tests for empty - - - - - Returns a constraint that tests whether a collection - contains all unique items. - - - - - Returns a constraint that tests whether an object graph is serializable in binary format. - - - - - Returns a constraint that tests whether an object graph is serializable in xml format. - - - - - Returns a constraint that tests whether a collection is ordered - - - - - The Iz class is a synonym for Is intended for use in VB, - which regards Is as a keyword. - - - - - The List class is a helper class with properties and methods - that supply a number of constraints used with lists and collections. - - - - - List.Map returns a ListMapper, which can be used to map - the original collection to another collection. - - - - - - - ListMapper is used to transform a collection used as an actual argument - producing another collection to be used in the assertion. - - - - - Construct a ListMapper based on a collection - - The collection to be transformed - - - - Produces a collection containing all the values of a property - - The collection of property values - - - - - Randomizer returns a set of random values in a repeatable - way, to allow re-running of tests if necessary. - - - - - Get a randomizer for a particular member, returning - one that has already been created if it exists. - This ensures that the same values are generated - each time the tests are reloaded. - - - - - Get a randomizer for a particular parameter, returning - one that has already been created if it exists. - This ensures that the same values are generated - each time the tests are reloaded. - - - - - Construct a randomizer using a random seed - - - - - Construct a randomizer using a specified seed - - - - - Return an array of random doubles between 0.0 and 1.0. - - - - - - - Return an array of random doubles with values in a specified range. - - - - - Return an array of random ints with values in a specified range. - - - - - Get a random seed for use in creating a randomizer. - - - - - The SpecialValue enum is used to represent TestCase arguments - that cannot be used as arguments to an Attribute. - - - - - Null represents a null value, which cannot be used as an - argument to an attriute under .NET 1.x - - - - - Basic Asserts on strings. - - - - - The Equals method throws an AssertionException. This is done - to make sure there is no mistake by calling this function. - - - - - - - override the default ReferenceEquals to throw an AssertionException. This - implementation makes sure there is no mistake in calling this function - as part of Assert. - - - - - - - Asserts that a string is found within another string. - - The expected string - The string to be examined - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string is found within another string. - - The expected string - The string to be examined - The message to display in case of failure - - - - Asserts that a string is found within another string. - - The expected string - The string to be examined - - - - Asserts that a string is not found within another string. - - The expected string - The string to be examined - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string is found within another string. - - The expected string - The string to be examined - The message to display in case of failure - - - - Asserts that a string is found within another string. - - The expected string - The string to be examined - - - - Asserts that a string starts with another string. - - The expected string - The string to be examined - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string starts with another string. - - The expected string - The string to be examined - The message to display in case of failure - - - - Asserts that a string starts with another string. - - The expected string - The string to be examined - - - - Asserts that a string does not start with another string. - - The expected string - The string to be examined - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string does not start with another string. - - The expected string - The string to be examined - The message to display in case of failure - - - - Asserts that a string does not start with another string. - - The expected string - The string to be examined - - - - Asserts that a string ends with another string. - - The expected string - The string to be examined - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string ends with another string. - - The expected string - The string to be examined - The message to display in case of failure - - - - Asserts that a string ends with another string. - - The expected string - The string to be examined - - - - Asserts that a string does not end with another string. - - The expected string - The string to be examined - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string does not end with another string. - - The expected string - The string to be examined - The message to display in case of failure - - - - Asserts that a string does not end with another string. - - The expected string - The string to be examined - - - - Asserts that two strings are equal, without regard to case. - - The expected string - The actual string - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that two strings are equal, without regard to case. - - The expected string - The actual string - The message to display in case of failure - - - - Asserts that two strings are equal, without regard to case. - - The expected string - The actual string - - - - Asserts that two strings are not equal, without regard to case. - - The expected string - The actual string - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that two strings are Notequal, without regard to case. - - The expected string - The actual string - The message to display in case of failure - - - - Asserts that two strings are not equal, without regard to case. - - The expected string - The actual string - - - - Asserts that a string matches an expected regular expression pattern. - - The regex pattern to be matched - The actual string - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string matches an expected regular expression pattern. - - The regex pattern to be matched - The actual string - The message to display in case of failure - - - - Asserts that a string matches an expected regular expression pattern. - - The regex pattern to be matched - The actual string - - - - Asserts that a string does not match an expected regular expression pattern. - - The regex pattern to be used - The actual string - The message to display in case of failure - Arguments used in formatting the message - - - - Asserts that a string does not match an expected regular expression pattern. - - The regex pattern to be used - The actual string - The message to display in case of failure - - - - Asserts that a string does not match an expected regular expression pattern. - - The regex pattern to be used - The actual string - - - - The TestCaseData class represents a set of arguments - and other parameter info to be used for a parameterized - test case. It provides a number of instance modifiers - for use in initializing the test case. - - Note: Instance modifiers are getters that return - the same instance after modifying it's state. - - - - - The argument list to be provided to the test - - - - - The expected result to be returned - - - - - Set to true if this has an expected result - - - - - The expected exception Type - - - - - The FullName of the expected exception - - - - - The name to be used for the test - - - - - The description of the test - - - - - A dictionary of properties, used to add information - to tests without requiring the class to change. - - - - - If true, indicates that the test case is to be ignored - - - - - If true, indicates that the test case is marked explicit - - - - - The reason for ignoring a test case - - - - - Initializes a new instance of the class. - - The arguments. - - - - Initializes a new instance of the class. - - The argument. - - - - Initializes a new instance of the class. - - The first argument. - The second argument. - - - - Initializes a new instance of the class. - - The first argument. - The second argument. - The third argument. - - - - Sets the expected result for the test - - The expected result - A modified TestCaseData - - - - Sets the expected exception type for the test - - Type of the expected exception. - The modified TestCaseData instance - - - - Sets the expected exception type for the test - - FullName of the expected exception. - The modified TestCaseData instance - - - - Sets the name of the test case - - The modified TestCaseData instance - - - - Sets the description for the test case - being constructed. - - The description. - The modified TestCaseData instance. - - - - Applies a category to the test - - - - - - - Applies a named property to the test - - - - - - - - Applies a named property to the test - - - - - - - - Applies a named property to the test - - - - - - - - Ignores this TestCase. - - - - - - Ignores this TestCase, specifying the reason. - - The reason. - - - - - Marks this TestCase as Explicit - - - - - - Marks this TestCase as Explicit, specifying the reason. - - The reason. - - - - - Gets the argument list to be provided to the test - - - - - Gets the expected result - - - - - Returns true if the result has been set - - - - - Gets the expected exception Type - - - - - Gets the FullName of the expected exception - - - - - Gets the name to be used for the test - - - - - Gets the description of the test - - - - - Gets a value indicating whether this is ignored. - - true if ignored; otherwise, false. - - - - Gets a value indicating whether this is explicit. - - true if explicit; otherwise, false. - - - - Gets the ignore reason. - - The ignore reason. - - - - Gets a list of categories associated with this test. - - - - - Gets the property dictionary for this test - - - - - Provide the context information of the current test - - - - - Constructs a TestContext using the provided context dictionary - - A context dictionary - - - - Get the current test context. This is created - as needed. The user may save the context for - use within a test, but it should not be used - outside the test for which it is created. - - - - - Gets a TestAdapter representing the currently executing test in this context. - - - - - Gets a ResultAdapter representing the current result for the test - executing in this context. - - - - - Gets the directory containing the current test assembly. - - - - - Gets the directory to be used for outputing files created - by this test run. - - - - - TestAdapter adapts a Test for consumption by - the user test code. - - - - - Constructs a TestAdapter for this context - - The context dictionary - - - - The name of the test. - - - - - The FullName of the test - - - - - The properties of the test. - - - - - ResultAdapter adapts a TestResult for consumption by - the user test code. - - - - - Construct a ResultAdapter for a context - - The context holding the result - - - - The TestState of current test. This maps to the ResultState - used in nunit.core and is subject to change in the future. - - - - - The TestStatus of current test. This enum will be used - in future versions of NUnit and so is to be preferred - to the TestState value. - - - - - Provides details about a test - - - - - Creates an instance of TestDetails - - The fixture that the test is a member of, if available. - The method that implements the test, if available. - The full name of the test. - A string representing the type of test, e.g. "Test Case". - Indicates if the test represents a suite of tests. - - - - The fixture that the test is a member of, if available. - - - - - The method that implements the test, if available. - - - - - The full name of the test. - - - - - A string representing the type of test, e.g. "Test Case". - - - - - Indicates if the test represents a suite of tests. - - - - - The ResultState enum indicates the result of running a test - - - - - The result is inconclusive - - - - - The test was not runnable. - - - - - The test has been skipped. - - - - - The test has been ignored. - - - - - The test succeeded - - - - - The test failed - - - - - The test encountered an unexpected exception - - - - - The test was cancelled by the user - - - - - The TestStatus enum indicates the result of running a test - - - - - The test was inconclusive - - - - - The test has skipped - - - - - The test succeeded - - - - - The test failed - - - - - Helper class with static methods used to supply constraints - that operate on strings. - - - - - Returns a constraint that succeeds if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that fails if the actual - value contains the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that fails if the actual - value starts with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that fails if the actual - value ends with the substring supplied as an argument. - - - - - Returns a constraint that succeeds if the actual - value matches the Regex pattern supplied as an argument. - - - - - Returns a constraint that fails if the actual - value matches the pattern supplied as an argument. - - - - - Returns a ConstraintExpression, which will apply - the following constraint to all members of a collection, - succeeding if all of them succeed. - - - - - TextMessageWriter writes constraint descriptions and messages - in displayable form as a text stream. It tailors the display - of individual message components to form the standard message - format of NUnit assertion failure messages. - - - - - Prefix used for the expected value line of a message - - - - - Prefix used for the actual value line of a message - - - - - Length of a message prefix - - - - - Construct a TextMessageWriter - - - - - Construct a TextMessageWriter, specifying a user message - and optional formatting arguments. - - - - - - - Method to write single line message with optional args, usually - written to precede the general failure message, at a givel - indentation level. - - The indentation level of the message - The message to be written - Any arguments used in formatting the message - - - - Display Expected and Actual lines for a constraint. This - is called by MessageWriter's default implementation of - WriteMessageTo and provides the generic two-line display. - - The constraint that failed - - - - Display Expected and Actual lines for given values. This - method may be called by constraints that need more control over - the display of actual and expected values than is provided - by the default implementation. - - The expected value - The actual value causing the failure - - - - Display Expected and Actual lines for given values, including - a tolerance value on the expected line. - - The expected value - The actual value causing the failure - The tolerance within which the test was made - - - - Display the expected and actual string values on separate lines. - If the mismatch parameter is >=0, an additional line is displayed - line containing a caret that points to the mismatch point. - - The expected string value - The actual string value - The point at which the strings don't match or -1 - If true, case is ignored in string comparisons - If true, clip the strings to fit the max line length - - - - Writes the text for a connector. - - The connector. - - - - Writes the text for a predicate. - - The predicate. - - - - Write the text for a modifier. - - The modifier. - - - - Writes the text for an expected value. - - The expected value. - - - - Writes the text for an actual value. - - The actual value. - - - - Writes the text for a generalized value. - - The value. - - - - Writes the text for a collection value, - starting at a particular point, to a max length - - The collection containing elements to write. - The starting point of the elements to write - The maximum number of elements to write - - - - Write the generic 'Expected' line for a constraint - - The constraint that failed - - - - Write the generic 'Expected' line for a given value - - The expected value - - - - Write the generic 'Expected' line for a given value - and tolerance. - - The expected value - The tolerance within which the test was made - - - - Write the generic 'Actual' line for a constraint - - The constraint for which the actual value is to be written - - - - Write the generic 'Actual' line for a given value - - The actual value causing a failure - - - - Gets or sets the maximum line length for this writer - - - - - Helper class with properties and methods that supply - constraints that operate on exceptions. - - - - - Creates a constraint specifying the exact type of exception expected - - - - - Creates a constraint specifying the exact type of exception expected - - - - - Creates a constraint specifying the type of exception expected - - - - - Creates a constraint specifying the type of exception expected - - - - - Creates a constraint specifying an expected exception - - - - - Creates a constraint specifying an exception with a given InnerException - - - - - Creates a constraint specifying an expected TargetInvocationException - - - - - Creates a constraint specifying an expected TargetInvocationException - - - - - Creates a constraint specifying an expected TargetInvocationException - - - - - Creates a constraint specifying that no exception is thrown - - - - diff --git a/lib/tests/nunit.util.dll b/lib/tests/nunit.util.dll deleted file mode 100644 index c837e9ecf06..00000000000 Binary files a/lib/tests/nunit.util.dll and /dev/null differ diff --git a/lib/tests/protobuf-net.dll b/lib/tests/protobuf-net.dll deleted file mode 100644 index 99bbb956f80..00000000000 Binary files a/lib/tests/protobuf-net.dll and /dev/null differ diff --git a/lib/tests/sqlite3.def b/lib/tests/sqlite3.def deleted file mode 100644 index 29ded5c73c3..00000000000 --- a/lib/tests/sqlite3.def +++ /dev/null @@ -1,179 +0,0 @@ -EXPORTS -sqlite3_aggregate_context -sqlite3_aggregate_count -sqlite3_auto_extension -sqlite3_backup_finish -sqlite3_backup_init -sqlite3_backup_pagecount -sqlite3_backup_remaining -sqlite3_backup_step -sqlite3_bind_blob -sqlite3_bind_double -sqlite3_bind_int -sqlite3_bind_int64 -sqlite3_bind_null -sqlite3_bind_parameter_count -sqlite3_bind_parameter_index -sqlite3_bind_parameter_name -sqlite3_bind_text -sqlite3_bind_text16 -sqlite3_bind_value -sqlite3_bind_zeroblob -sqlite3_blob_bytes -sqlite3_blob_close -sqlite3_blob_open -sqlite3_blob_read -sqlite3_blob_write -sqlite3_busy_handler -sqlite3_busy_timeout -sqlite3_changes -sqlite3_clear_bindings -sqlite3_close -sqlite3_collation_needed -sqlite3_collation_needed16 -sqlite3_column_blob -sqlite3_column_bytes -sqlite3_column_bytes16 -sqlite3_column_count -sqlite3_column_database_name -sqlite3_column_database_name16 -sqlite3_column_decltype -sqlite3_column_decltype16 -sqlite3_column_double -sqlite3_column_int -sqlite3_column_int64 -sqlite3_column_name -sqlite3_column_name16 -sqlite3_column_origin_name -sqlite3_column_origin_name16 -sqlite3_column_table_name -sqlite3_column_table_name16 -sqlite3_column_text -sqlite3_column_text16 -sqlite3_column_type -sqlite3_column_value -sqlite3_commit_hook -sqlite3_complete -sqlite3_complete16 -sqlite3_config -sqlite3_context_db_handle -sqlite3_create_collation -sqlite3_create_collation16 -sqlite3_create_collation_v2 -sqlite3_create_function -sqlite3_create_function16 -sqlite3_create_module -sqlite3_create_module_v2 -sqlite3_data_count -sqlite3_db_config -sqlite3_db_handle -sqlite3_db_mutex -sqlite3_db_status -sqlite3_declare_vtab -sqlite3_enable_load_extension -sqlite3_enable_shared_cache -sqlite3_errcode -sqlite3_errmsg -sqlite3_errmsg16 -sqlite3_exec -sqlite3_expired -sqlite3_extended_errcode -sqlite3_extended_result_codes -sqlite3_file_control -sqlite3_finalize -sqlite3_free -sqlite3_free_table -sqlite3_get_autocommit -sqlite3_get_auxdata -sqlite3_get_table -sqlite3_global_recover -sqlite3_initialize -sqlite3_interrupt -sqlite3_last_insert_rowid -sqlite3_libversion -sqlite3_libversion_number -sqlite3_limit -sqlite3_load_extension -sqlite3_malloc -sqlite3_memory_alarm -sqlite3_memory_highwater -sqlite3_memory_used -sqlite3_mprintf -sqlite3_mutex_alloc -sqlite3_mutex_enter -sqlite3_mutex_free -sqlite3_mutex_leave -sqlite3_mutex_try -sqlite3_next_stmt -sqlite3_open -sqlite3_open16 -sqlite3_open_v2 -sqlite3_os_end -sqlite3_os_init -sqlite3_overload_function -sqlite3_prepare -sqlite3_prepare16 -sqlite3_prepare16_v2 -sqlite3_prepare_v2 -sqlite3_profile -sqlite3_progress_handler -sqlite3_randomness -sqlite3_realloc -sqlite3_release_memory -sqlite3_reset -sqlite3_reset_auto_extension -sqlite3_result_blob -sqlite3_result_double -sqlite3_result_error -sqlite3_result_error16 -sqlite3_result_error_code -sqlite3_result_error_nomem -sqlite3_result_error_toobig -sqlite3_result_int -sqlite3_result_int64 -sqlite3_result_null -sqlite3_result_text -sqlite3_result_text16 -sqlite3_result_text16be -sqlite3_result_text16le -sqlite3_result_value -sqlite3_result_zeroblob -sqlite3_rollback_hook -sqlite3_set_authorizer -sqlite3_set_auxdata -sqlite3_shutdown -sqlite3_sleep -sqlite3_snprintf -sqlite3_soft_heap_limit -sqlite3_sql -sqlite3_status -sqlite3_step -sqlite3_stmt_status -sqlite3_strnicmp -sqlite3_table_column_metadata -sqlite3_test_control -sqlite3_thread_cleanup -sqlite3_threadsafe -sqlite3_total_changes -sqlite3_trace -sqlite3_transfer_bindings -sqlite3_update_hook -sqlite3_user_data -sqlite3_value_blob -sqlite3_value_bytes -sqlite3_value_bytes16 -sqlite3_value_double -sqlite3_value_int -sqlite3_value_int64 -sqlite3_value_numeric_type -sqlite3_value_text -sqlite3_value_text16 -sqlite3_value_text16be -sqlite3_value_text16le -sqlite3_value_type -sqlite3_version -sqlite3_vfs_find -sqlite3_vfs_register -sqlite3_vfs_unregister -sqlite3_vmprintf -sqlite3_win32_mbcs_to_utf8 diff --git a/lib/tests/sqlite3.dll b/lib/tests/sqlite3.dll deleted file mode 100644 index 321d48d31cf..00000000000 Binary files a/lib/tests/sqlite3.dll and /dev/null differ diff --git a/license.txt b/license.txt new file mode 100644 index 00000000000..ba621930133 --- /dev/null +++ b/license.txt @@ -0,0 +1,69 @@ +ServiceStack +Copyright (c) 2013-present, ServiceStack +=============================================================================== + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU Affero General Public License as published by the +Free Software Foundation, either version 3 of the License, see +http://www.gnu.org/licenses/agpl-3.0.html. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + +FOSS License Exception +=============================================================================== + +This Exception applies to open source applications built with ServiceStack and +ServiceStack extensions ("The Software"), and to open source Derivative Works of +the Software, that use the Software under the terms of GNU Affero General +Public License, version 3 ("AGPLv3"). The Exception extends AGPLv3 by providing +additional grants that allows developers of FOSS applications to include ServiceStack +with their FOSS applications in combination with other software licensed under +the licenses from the "Open Source License List" below, provided that: + +You obey the AGPLv3 terms for the Software and the Derivative Work, except for +the separate parts of the Derivative Work ("Additions") which constitute independent +work and are not dervied from the Software. + + - All Additions are distributed subject to one of the licenses listed below. + - Your software distribution provides complete source code for the Additions. + - The Derivative Work and its Additions are intended for use in end-user applications + and do not constitute software intended for use by software developers, such as + software libraries, components, and development kits. + - If you violate any of the terms in this Exception, you lose all rights granted + to you by the Exception and revert to the terms of AGPLv3. + +ServiceStack reserves all rights not expressly granted in these terms and conditions. + +Open Source License List + +Name Version +Academic Free License 2.0 +Apache Software License 2.0 +Apple Public Source License 2.0 +Artistic license From Perl 5.8.0 +BSD license July 22 1999 +Common Development and Distribution License (CDDL) 1.0 +Common Public License 1.0 +Eclipse Public License 1.0 +Educational Community License 2.0 +European Union Public License (EUPL) 1.1 +GNU General Public License (GPL) 2.0 +GNU Library or "Lesser" General Public License (LGPL) 3.0 +Jabber Open Source License 1.0 +MIT License (As listed in file MIT-License.txt) - +Mozilla Public License (MPL) 1.0/1.1 +Open Software License 2.0 +OpenSSL license (with original SSLeay license) 2003 (1998) +University of Illinois/NCSA Open Source License - +W3C License 2001 +X11 License 2001 +Zlib/libpng License - + + +Commercial License +=========================================================================== +In addition to this license, ServiceStack is offered under a commercial license. +see https://servicestack.net/pricing for details. diff --git a/release/copy.bat b/release/copy.bat deleted file mode 100644 index 3fc51546eff..00000000000 --- a/release/copy.bat +++ /dev/null @@ -1,31 +0,0 @@ -MD latest\ServiceStack -MD latest\ServiceStack.OrmLite - -COPY ..\NuGet\ServiceStack\lib\net35\* latest\ServiceStack -COPY ..\NuGet\ServiceStack\lib\net40\* latest\ServiceStack -COPY ..\NuGet\ServiceStack.Common\lib\net35\* latest\ServiceStack -COPY ..\NuGet\ServiceStack.Mvc\lib\net40\* latest\ServiceStack -COPY ..\NuGet\ServiceStack.Plugins.ProtoBuf\lib\net35\* latest\ServiceStack - -COPY ..\..\ServiceStack.Text\NuGet\lib\net35\* latest\ServiceStack -COPY ..\..\ServiceStack.Redis\NuGet\lib\net35\* latest\ServiceStack -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.SqlServer\lib\* latest\ServiceStack - -MD latest\ServiceStack.OrmLite\Firebird -MD latest\ServiceStack.OrmLite\MySql -MD latest\ServiceStack.OrmLite\PostgreSQL -MD latest\ServiceStack.OrmLite\Sqlite32 -MD latest\ServiceStack.OrmLite\Sqlite64 -MD latest\ServiceStack.OrmLite\SqlServer -MD latest\ServiceStack.OrmLite\Sqlite32.Mono - -COPY ..\..\ServiceStack.Text\NuGet\lib\net35\* latest\ServiceStack.OrmLite -COPY ..\NuGet\ServiceStack.Common\lib\net35\* latest\ServiceStack.OrmLite -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.Firebird\lib\* latest\ServiceStack.OrmLite\Firebird -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.MySql\lib\* latest\ServiceStack.OrmLite\MySql -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.PostgreSQL\lib\* latest\ServiceStack.OrmLite\PostgreSQL -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.Sqlite32\lib\* latest\ServiceStack.OrmLite\Sqlite32 -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.Sqlite64\lib\* latest\ServiceStack.OrmLite\Sqlite64 -COPY ..\..\ServiceStack.OrmLite\NuGet\ServiceStack.OrmLite.SqlServer\lib\* latest\ServiceStack.OrmLite\SqlServer -COPY ..\..\ServiceStack.OrmLite\src\ServiceStack.OrmLite.Sqlite\bin\Release\ServiceStack.OrmLite.* latest\ServiceStack.OrmLite\Sqlite32.Mono - diff --git a/release/latest/MonoDroid/Debug/placeholder.txt b/release/latest/MonoDroid/Debug/placeholder.txt deleted file mode 100644 index 00a6efd9a58..00000000000 --- a/release/latest/MonoDroid/Debug/placeholder.txt +++ /dev/null @@ -1 +0,0 @@ -this is a place holder for future builds diff --git a/release/latest/MonoDroid/Release/placeholder.txt b/release/latest/MonoDroid/Release/placeholder.txt deleted file mode 100644 index 00a6efd9a58..00000000000 --- a/release/latest/MonoDroid/Release/placeholder.txt +++ /dev/null @@ -1 +0,0 @@ -this is a place holder for future builds diff --git a/release/latest/MonoDroid/ServiceStack.Common.dll b/release/latest/MonoDroid/ServiceStack.Common.dll deleted file mode 100644 index 2c4bbfcea1a..00000000000 Binary files a/release/latest/MonoDroid/ServiceStack.Common.dll and /dev/null differ diff --git a/release/latest/MonoDroid/ServiceStack.Interfaces.dll b/release/latest/MonoDroid/ServiceStack.Interfaces.dll deleted file mode 100644 index 80b2f96287a..00000000000 Binary files a/release/latest/MonoDroid/ServiceStack.Interfaces.dll and /dev/null differ diff --git a/release/latest/MonoDroid/ServiceStack.Text.dll b/release/latest/MonoDroid/ServiceStack.Text.dll deleted file mode 100644 index 42c113ac632..00000000000 Binary files a/release/latest/MonoDroid/ServiceStack.Text.dll and /dev/null differ diff --git a/release/latest/MonoTouch/Debug/ServiceStack.Common.MonoTouch.dll b/release/latest/MonoTouch/Debug/ServiceStack.Common.MonoTouch.dll deleted file mode 100755 index f4a0884967b..00000000000 Binary files a/release/latest/MonoTouch/Debug/ServiceStack.Common.MonoTouch.dll and /dev/null differ diff --git a/release/latest/MonoTouch/Debug/ServiceStack.Common.MonoTouch.dll.mdb b/release/latest/MonoTouch/Debug/ServiceStack.Common.MonoTouch.dll.mdb deleted file mode 100644 index 539635bd712..00000000000 Binary files a/release/latest/MonoTouch/Debug/ServiceStack.Common.MonoTouch.dll.mdb and /dev/null differ diff --git a/release/latest/MonoTouch/Debug/ServiceStack.Interfaces.MonoTouch.dll b/release/latest/MonoTouch/Debug/ServiceStack.Interfaces.MonoTouch.dll deleted file mode 100755 index 35be8958626..00000000000 Binary files a/release/latest/MonoTouch/Debug/ServiceStack.Interfaces.MonoTouch.dll and /dev/null differ diff --git a/release/latest/MonoTouch/Debug/ServiceStack.Interfaces.MonoTouch.dll.mdb b/release/latest/MonoTouch/Debug/ServiceStack.Interfaces.MonoTouch.dll.mdb deleted file mode 100644 index f7658de41e4..00000000000 Binary files a/release/latest/MonoTouch/Debug/ServiceStack.Interfaces.MonoTouch.dll.mdb and /dev/null differ diff --git a/release/latest/MonoTouch/Debug/ServiceStack.Text.MonoTouch.dll b/release/latest/MonoTouch/Debug/ServiceStack.Text.MonoTouch.dll deleted file mode 100755 index b7908625216..00000000000 Binary files a/release/latest/MonoTouch/Debug/ServiceStack.Text.MonoTouch.dll and /dev/null differ diff --git a/release/latest/MonoTouch/Debug/ServiceStack.Text.MonoTouch.dll.mdb b/release/latest/MonoTouch/Debug/ServiceStack.Text.MonoTouch.dll.mdb deleted file mode 100644 index c067d96138b..00000000000 Binary files a/release/latest/MonoTouch/Debug/ServiceStack.Text.MonoTouch.dll.mdb and /dev/null differ diff --git a/release/latest/MonoTouch/Release/.DS_Store b/release/latest/MonoTouch/Release/.DS_Store deleted file mode 100644 index 5008ddfcf53..00000000000 Binary files a/release/latest/MonoTouch/Release/.DS_Store and /dev/null differ diff --git a/release/latest/MonoTouch/Release/ServiceStack.Common.MonoTouch.dll b/release/latest/MonoTouch/Release/ServiceStack.Common.MonoTouch.dll deleted file mode 100755 index 48ebeac93de..00000000000 Binary files a/release/latest/MonoTouch/Release/ServiceStack.Common.MonoTouch.dll and /dev/null differ diff --git a/release/latest/MonoTouch/Release/ServiceStack.Interfaces.MonoTouch.dll b/release/latest/MonoTouch/Release/ServiceStack.Interfaces.MonoTouch.dll deleted file mode 100755 index ec2fa535476..00000000000 Binary files a/release/latest/MonoTouch/Release/ServiceStack.Interfaces.MonoTouch.dll and /dev/null differ diff --git a/release/latest/MonoTouch/Release/ServiceStack.Text.MonoTouch.dll b/release/latest/MonoTouch/Release/ServiceStack.Text.MonoTouch.dll deleted file mode 100755 index 20576abe8a5..00000000000 Binary files a/release/latest/MonoTouch/Release/ServiceStack.Text.MonoTouch.dll and /dev/null differ diff --git a/release/latest/MonoTouch/ServiceStack.Client.MonoTouch-v3.85.zip b/release/latest/MonoTouch/ServiceStack.Client.MonoTouch-v3.85.zip deleted file mode 100644 index 63dda5485c1..00000000000 Binary files a/release/latest/MonoTouch/ServiceStack.Client.MonoTouch-v3.85.zip and /dev/null differ diff --git a/release/latest/ServiceStack.Client/ServiceStack.Client.dll b/release/latest/ServiceStack.Client/ServiceStack.Client.dll deleted file mode 100644 index b813c53c3c6..00000000000 Binary files a/release/latest/ServiceStack.Client/ServiceStack.Client.dll and /dev/null differ diff --git a/release/latest/ServiceStack.Client/ServiceStack.Client.pdb b/release/latest/ServiceStack.Client/ServiceStack.Client.pdb deleted file mode 100644 index 84a2ae38f7f..00000000000 Binary files a/release/latest/ServiceStack.Client/ServiceStack.Client.pdb and /dev/null differ diff --git a/release/latest/Silverlight/README.txt b/release/latest/Silverlight/README.txt deleted file mode 100644 index 28f7a814439..00000000000 --- a/release/latest/Silverlight/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -ServiceStack Client builds for Silverlight. - -Due to restrictions in Silverlight only the Async operations are supported. \ No newline at end of file diff --git a/release/latest/Silverlight/ServiceStack.Client.Silverlight-v3.42.zip b/release/latest/Silverlight/ServiceStack.Client.Silverlight-v3.42.zip deleted file mode 100644 index a6b2e43b915..00000000000 Binary files a/release/latest/Silverlight/ServiceStack.Client.Silverlight-v3.42.zip and /dev/null differ diff --git a/release/latest/Silverlight/ServiceStack.Common.dll b/release/latest/Silverlight/ServiceStack.Common.dll deleted file mode 100644 index 70884257c66..00000000000 Binary files a/release/latest/Silverlight/ServiceStack.Common.dll and /dev/null differ diff --git a/release/latest/Silverlight/ServiceStack.Interfaces.dll b/release/latest/Silverlight/ServiceStack.Interfaces.dll deleted file mode 100644 index 806b00e8249..00000000000 Binary files a/release/latest/Silverlight/ServiceStack.Interfaces.dll and /dev/null differ diff --git a/release/latest/Silverlight/ServiceStack.Text.dll b/release/latest/Silverlight/ServiceStack.Text.dll deleted file mode 100644 index 55664802be9..00000000000 Binary files a/release/latest/Silverlight/ServiceStack.Text.dll and /dev/null differ diff --git a/release/latest/js/JSV.js b/release/latest/js/JSV.js deleted file mode 100644 index 4177d55e14f..00000000000 --- a/release/latest/js/JSV.js +++ /dev/null @@ -1,588 +0,0 @@ -/** - * Created by IntelliJ IDEA. - * User: mythz - * Date: 16-Jun-2010 - * Time: 00:51:17 - * To change this template use File | Settings | File Templates. - */ - -var JSV = {}; -/** - * parses JSV text into a JavaScript type - * @param str - */ -JSV.parse = function(str) -{ - if (!str) return str; - if (str[0] == '{') - { - return JSV.parseObject_(str); - } - else if (str[0] == '[') - { - return JSV.parseArray_(str); - } - else - { - return JSV.parseString(str); - } -} - -JSV.ESCAPE_CHARS = ['"', ',', '{', '}', '[', ']']; - -JSV.parseArray_ = function(str) -{ - var to = [], value = JSV.stripList_(str); - if (!value) return to; - - if (value[0] == '{') - { - var ref = {i:0}; - do - { - var itemValue = JSV.eatMapValue_(value, ref); - to.push(JSV.parse(itemValue)); - } while (++ref.i < value.length); - } - else - { - for (var ref={i:0}; ref.i < value.length; ref.i++) - { - var elementValue = JSV.eatElementValue_(value, ref); - to.push(JSV.parse(elementValue)); - } - } - return to; -}; - -JSV.parseObject_ = function(str) -{ - if (str[0] != '{') - { - throw "Type definitions should start with a '{', got string starting with: " - + str.substr(0, str.length < 50 ? str.length : 50); - } - - var name, obj = {}; - - if (str == '{}') return null; - for (var ref={i:1}, strTypeLength = str.length; ref.i < strTypeLength; ref.i++) - { - name = JSV.eatMapKey_(str, ref); - ref.i++; - var value = JSV.eatMapValue_(str, ref); - obj[name]= JSV.parse(value); - } - return obj; -} - -JSV.eatElementValue_ = function(value, ref) -{ - return JSV.eatUntilCharFound_(value, ref, ','); -} - -JSV.containsAny_ = function(str, tests) -{ - if (!is.String(str)) return; - for (var i = 0, len = tests.length; i < len; i++) - { - if (str.indexOf(tests[i]) != -1) return true; - } - return false; -}; - -JSV.toCsvField = function(text) -{ - return !text || JSV.containsAny_(JSV.ESCAPE_CHARS) - ? text - : '"' + text.replace(/"/g, '""') + '"'; -} - -JSV.parseString = JSV.fromCsvField = function(text) -{ - return !text || text[0] != '"' - ? text - : text.substr(1, text.length - 2).replace(/""/g, '"'); -} - -JSV.stripList_ = function(value) -{ - if (!value) return null; - return value[0] == '[' - ? value.substr(1, value.length - 2) - : value; -}; - -/** - * @param value {string} - * @param ref {ref int} - * @param findChar {char} - */ -JSV.eatUntilCharFound_ = function(value, ref, findChar) -{ - var tokenStartPos = ref.i; - var valueLength = value.length; - if (value[tokenStartPos] != '"') - { - ref.i = value.indexOf(findChar, tokenStartPos); - if (ref.i == -1) ref.i = valueLength; - return value.substr(tokenStartPos, ref.i - tokenStartPos); - } - - while (++ref.i < valueLength) - { - if (value[ref.i] == '"') - { - if (ref.i + 1 >= valueLength) - { - return value.substr(tokenStartPos, ++ref.i - tokenStartPos); - } - if (value[ref.i + 1] == '"') - { - ref.i++; - } - else if (value[ref.i + 1] == findChar) - { - return value.substr(tokenStartPos, ++ref.i - tokenStartPos); - } - } - } - - throw "Could not find ending quote"; -} - -/** - * - * @param value {string} - * @param i {ref int} - */ -JSV.eatMapKey_ = function(value, ref) -{ - var tokenStartPos = ref.i; - while (value[++ref.i] != ':' && ref.i < value.length) { } - return value.substr(tokenStartPos, ref.i - tokenStartPos); -} - -/** - * - * @param value {string} - * @param ref {ref int} - */ -JSV.eatMapValue_ = function(value, ref) -{ - var tokenStartPos = ref.i; - var valueLength = value.length; - if (ref.i == valueLength) return null; - - var valueChar = value[ref.i]; - - //If we are at the end, return. - if (valueChar == ',' || valueChar == '}') - { - return null; - } - - //Is List, i.e. [...] - var withinQuotes = false; - if (valueChar == '[') - { - var endsToEat = 1; - while (++ref.i < valueLength && endsToEat > 0) - { - valueChar = value[ref.i]; - if (valueChar == '"') - withinQuotes = !withinQuotes; - if (withinQuotes) - continue; - if (valueChar == '[') - endsToEat++; - if (valueChar == ']') - endsToEat--; - } - return value.substr(tokenStartPos, ref.i - tokenStartPos); - } - - //Is Type/Map, i.e. {...} - if (valueChar == '{') - { - var endsToEat = 1; - while (++ref.i < valueLength && endsToEat > 0) - { - valueChar = value[ref.i]; - - if (valueChar == '"') - withinQuotes = !withinQuotes; - if (withinQuotes) - continue; - if (valueChar == '{') - endsToEat++; - if (valueChar == '}') - endsToEat--; - } - return value.substr(tokenStartPos, ref.i - tokenStartPos); - } - - //Is Within Quotes, i.e. "..." - if (valueChar == '"') - { - while (++ref.i < valueLength) - { - valueChar = value[ref.i]; - if (valueChar != '"') continue; - var isLiteralQuote = ref.i + 1 < valueLength && value[ref.i + 1] == '"'; - ref.i++; //skip quote - if (!isLiteralQuote) - break; - } - return value.substr(tokenStartPos, ref.i - tokenStartPos); - } - - //Is Value - while (++ref.i < valueLength) - { - valueChar = value[ref.i]; - if (valueChar == ',' || valueChar == '}') - break; - } - - return value.substr(tokenStartPos, ref.i - tokenStartPos); -} - -JSV.isEmpty_ = function(a) -{ - return (a === null || a === undefined || a === ""); -} -JSV.isFunction_ = function(a) -{ - return (typeof (a) === 'function') ? a.constructor.toString().match(/Function/) !== null : false; -}; -JSV.isString_ = function(a) -{ - if (a === null || a === undefined) return false; - return (typeof (a) === 'string') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/string/i) !== null : false; -}; -JSV.isDate_ = function(a) -{ - if (JSV.isEmpty_(a)) return false; - return (typeof (a) === 'date') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/date/i) !== null : false; -}; - -JSV.isArray_ = function(a) -{ - if (a === null || a === undefined || a === "") return false; - return (typeof (a) === 'object') ? a.constructor.toString().match(/array/i) !== null || a.length !== undefined : false; -}; -JSV.toXsdDateTime = function(date) -{ - function pad(n) { - var s = n.toString(); - return s.length < 2 ? '0'+s : s; - }; - var yyyy = date.getUTCFullYear(); - var MM = pad(date.getUTCMonth()+1); - var dd = pad(date.getUTCDate()); - var hh = pad(date.getUTCHours()); - var mm = pad(date.getUTCMinutes()); - var ss = pad(date.getUTCSeconds()); - var ms = pad(date.getUTCMilliseconds()); - - return yyyy +'-' + MM + '-' + dd + 'T' + hh + ':' + mm + ':' + ss + '.' + ms + 'Z'; -} -JSV.serialize = JSV.stringify = function(obj) -{ - if (obj === null || obj === undefined) return null; - - var typeOf = typeof(obj); - if (obj === 'function') return null; - - if (typeOf === 'object') - { - var ctorStr = obj.constructor.toString().toLowerCase(); - if (ctorStr.indexOf('string') != -1) - return JSV.escapeString(obj); - if (ctorStr.indexOf('boolean') != -1) - return obj ? "True" : "False"; - if (ctorStr.indexOf('number') != -1) - return obj; - if (ctorStr.indexOf('date') != -1) - return JSV.toXsdDateTime(obj); - if (ctorStr.indexOf('array') != -1) - return JSV.serializeArray(obj); - - return JSV.serializeObject(obj); - } - else - { - switch(typeOf) - { - case 'string': - return JSV.escapeString(obj); - break; - case 'boolean': - return obj ? "True" : "False"; - break; - case 'date': - return JSV.toXsdDateTime(obj); - break; - case 'array': - return JSV.serializeArray(obj); - break; - case 'number': - default: - return obj; - } - } -}; -JSV.serializeObject = function(obj) -{ - var value, sb = new StringBuffer(); - for (var key in obj) - { - value = obj[key]; - if (!obj.hasOwnProperty(key) || JSV.isEmpty_(value) || JSV.isFunction_(value)) continue; - - if (sb.length > 0) - sb.append(','); - - sb.append(JSV.escapeString(key)); - sb.append(':'); - sb.append(JSV.serialize(value)); - } - return '{' + sb.toString() + '}'; -}; -JSV.serializeArray = function(array) -{ - var value, sb = new StringBuffer(); - for (var i=0, len=array.length; i 0) - sb.append(','); - - sb.append(JSV.serialize(value)); - } - return '[' + sb.toString() + ']'; -}; -JSV.escapeString = function(str) -{ - if (str === undefined || str === null) return null; - if (str === '') return '""'; - - if (str.indexOf('"')) - { - str = str.replace(/"/g,'""'); - } - if (JSV.containsAny_(str, JSV.ESCAPE_CHARS)) - { - return '"' + str + '"'; - } - return str; -}; -JSV.containsAny_ = function(str, tests) -{ - if (!JSV.isString_(str)) return; - for (var i = 0, len = tests.length; i < len; i++) - { - if (str.indexOf(tests[i]) != -1) return true; - } - return false; -}; - -/* Closure Library StringBuffer for efficient string concatenation */ -var hasScriptEngine = 'ScriptEngine' in window; -var HAS_JSCRIPT = hasScriptEngine && window['ScriptEngine']() == 'JScript'; - -StringBuffer = function(opt_a1, var_args) { - this.buffer_ = HAS_JSCRIPT ? [] : ''; - - if (opt_a1 != null) { - this.append.apply(this, arguments); - } -}; -StringBuffer.prototype.set = function(s) { - this.clear(); - this.append(s); -}; -if (HAS_JSCRIPT) { - StringBuffer.prototype.bufferLength_ = 0; - StringBuffer.prototype.append = function(a1, opt_a2, var_args) { - // IE version. - if (opt_a2 == null) { // second argument is undefined (null == undefined) - // Array assignment is 2x faster than Array push. Also, use a1 - // directly to avoid arguments instantiation, another 2x improvement. - this.buffer_[this.bufferLength_++] = a1; - } else { - this.buffer_.push.apply(/** @type {Array} */ (this.buffer_), arguments); - this.bufferLength_ = this.buffer_.length; - } - return this; - }; -} else { - StringBuffer.prototype.append = function(a1, opt_a2, var_args) { - // W3 version. - this.buffer_ += a1; - if (opt_a2 != null) { // second argument is undefined (null == undefined) - for (var i = 1; i < arguments.length; i++) { - this.buffer_ += arguments[i]; - } - } - return this; - }; -} -StringBuffer.prototype.clear = function() { - if (HAS_JSCRIPT) { - this.buffer_.length = 0; // Reuse the array to avoid creating new object. - this.bufferLength_ = 0; - } else { - this.buffer_ = ''; - } -}; -StringBuffer.prototype.getLength = function() { - return this.toString().length; -}; -StringBuffer.prototype.toString = function() { - if (HAS_JSCRIPT) { - var str = this.buffer_.join(''); - this.clear(); - if (str) { - this.append(str); - } - return str; - } else { - return /** @type {string} */ (this.buffer_); - } -}; - - -/** - * Considering pulling this out - * @param baseUri - * @param type - */ -function JsvServiceClient(baseUri) -{ - this.baseSyncReplyUri = JsvServiceClient.combine_(baseUri, "Jsv/SyncReply"); - this.baseAsyncOneWayUri = JsvServiceClient.combine_(baseUri, "Jsv/AsyncOneWay"); -} -JsvServiceClient.prototype.send = function(webMethod, request, onSuccess, onError, ajaxOptions) { - var startCallTime = new Date(); - var requestUrl = JsvServiceClient.combine_(this.baseSyncReplyUri, webMethod); - var id = JsvServiceClient.id++; - - var options = { - type: "GET", - url: requestUrl, - data: request, - dataType: "text", - success: function(responseText) - { - var endCallTime = new Date(); - var callDuration = endCallTime.getTime() - startCallTime.getTime(); - - var response = JSV.parse(responseText); - if (!response) - { - if (onSuccess) onSuccess(null); - return; - } - - var status = JsvServiceClient.parseResponseStatus_(response.ResponseStatus); - if (status.isSuccess) - { - if (onSuccess) onSuccess(response); - JsvServiceClient.onSuccess({ id: id, webMethod: webMethod, request: request, - response: response, durationMs: callDuration - }); - } - else - { - if (onError) onError(status); - JsvServiceClient.onError({ id: id, webMethod: webMethod, request: request, - error: status, durationMs: callDuration - }); - } - }, - error: function(xhr, desc, exObj) - { - var endCallTime = new Date(); - var callDuration = endCallTime.getTime() - startCallTime.getTime(); - - try - { - if (onError) onError(xhr.responseText); - } - catch (e) {} - JsvServiceClient.onError({ id: id, webMethod: webMethod, request: request, - error: xhr.responseText, durationMs: callDuration - }); - } - }; - - for (var k in ajaxOptions) options[k] = ajaxOptions[k]; - - var ajax = $.ajax(options); -}; - -JsvServiceClient.combine_ = function() { - var paths = ""; - for (var i = 0, len = arguments.length; i < len; i++) { - if (paths.length > 0) - paths += "/"; - paths += arguments[i].replace(/[/]+$/g, ""); - } - return paths; -}; - -//Sends a HTTP 'GET' request on the QueryString -JsvServiceClient.prototype.getFromService = function(webMethod, request, onSuccess, onError) { - this.send(webMethod, request, onSuccess, onError); -}; - -//Sends a HTTP 'POST' request as key value pair formData -JsvServiceClient.prototype.postFormDataToService = function(webMethod, request, onSuccess, onError) { - this.send(webMethod, request, onSuccess, onError, { type: "POST" }); -}; - -//Sends a HTTP 'POST' request as JSV @requires jQuery -JsvServiceClient.prototype.postToService = function(webMethod, request, onSuccess, onError) { - var jsvRequest = JSV.serialize(request); - this.send(webMethod, jsvRequest, onSuccess, onError, { type: "POST", processData: false, contentType: "application/jsv; charset=utf-8" }); -}; - -JsvServiceClient.id = 0; -JsvServiceClient.onError = function() { }; -JsvServiceClient.onSuccess = function() { }; - -JsvServiceClient.parseResponseStatus_ = function(status) -{ - if (!status) return {isSuccess:true}; - - var result = - { - isSuccess: status.ErrorCode === undefined || status.ErrorCode === null, - errorCode: status.ErrorCode, - message: status.Message, - errorMessage: status.ErrorMessage, - stackTrace: status.StackTrace, - fieldErrors: [], - fieldErrorMap: {} - }; - - if (status.FieldErrors) - { - for (var i=0, len = status.FieldErrors.length; i 0) { - _s.state.useProperties = (_p.util.type(data[0]) == "object"); - } - - //Query evaluation - _s.query = { - cache:[], - str:[], - appendCmd:function(action) { - _s.query.cache.push(action); - - //set the true or false value - var not = _s.state.not ? "!" : ""; - - //clear up an existing - if (_s.query.cache.length == 0) { - _s.state.operator = ""; - } - - //undo any state changes - _s.state.or = false; - _s.state.not = false; - - //append the items - _s.query.str.push([_s.state.operator, "(", not, "(_s.query.cache[", (_s.query.cache.length - 1), "](record)))"].join("")); - - //update the operator as needed - _s.state.operator = "&&"; - - }, - select:function() { - - //if there hasn't been a command, return everything - if (_s.query.str.length == 0) { - return { - selected:_s.state.data, - remaining: [] - }; - } - - //get the query string - var query; - eval(["query = function(record) {" + " return (", _s.query.str.join(""), "); };" ].join("")); - - //eval and select each result - var selected = []; var remaining = []; - for(var i = 0; i < _s.state.data.length; i++) { - var item = _s.state.data[i]; - try { - if (query(item)) { - selected.push(item); - } - else { - remaining.push(item); - } - } - catch (e) { - - _s.state.debug.log("Exception when evaluating the query for selection: %0%. query: %1%", [e,query]); - remaining.push(item); - } - } - - //return the final results - return { - selected:selected, - remaining:remaining - }; - - }, - prepCmd:function(params, args) { - - //prepare this command - //set the known data - _s.state.lastCommand = params.command; - _s.state.paramCount = params.count; - _s.state.lastCommandName = params.name; - - //start by clearing any null data - var values = []; var found = false; - for (var i = args.length; i-- > 0;) { - if (!args[i] && !found) { continue; } - found = true; - values.push(args[i]); - } - values.reverse(); - - //detetmine if a field was set in this - //if the data list count is greater than - //the required parameters, then the first - //param should be the name of the field - if (_s.state.useProperties && values.length == params.count + 1) { - _s.state.lastField = values.shift(); - } - - //return an object to execute with - return { - arg: values, - field: _s.state.lastField - }; - }, - repeatCmd:function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - if (_s.helper.empty([v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25])) { return; } - _s.state.lastCommand(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }, - performSort:function(records, field, desc) { - records.sort(function(a,b) { - a = a[field]; - b = b[field]; - return (a < b) ? -1 : (a > b) ? 1 : 0; - }); - if (desc) { records.reverse(); } - } - }; - - //Helper methods - _s.helper = { - toRegex:function(val) { - if (val == null) { return ""; } - return val.toString().replace( - /\*|\(|\)|\\|\/|\?|\.|\*|\+|\<|\>|\[|\]|\=|\&|\$|\^/gi, - function(match) { return ("\\" + match); } - ); - - }, - getNumericValue:function(obj) { - if (obj.length) { return obj.length; } - return obj; - }, - trim:_p.util.trim, - match:function(val,exp) { - if (!(val && exp)) { return false; } - if (_s.helper.type(exp) == "regexp") { exp = exp.source; } - exp = new RegExp(exp, "g"+(_s.state.ignoreCase?"i":"")); - return (val.match(exp)); - }, - propsEqual:function(val1, val2) { - if (val1 == null && val2 == null) { return true; } - if (val1 == null || val2 == null) { return false; } - for(var name in val1) { - if (val2[name] == undefined) { return false; } - if (!_s.helper.equals(val1[name], val2[name])) { return false; } - } - return true; - }, - equals:function(val1,val2) { - try { - - //check for null values first - if (val1 == null && val2 == null) { return true; } - if ((val1 == null && val2) || (val1 && val2 == null)) { return false; } - - //if this is a string, check for case - var val1Type = _s.helper.type(val1); - var val2Type = _s.helper.type(val2); - if (val1Type != val2Type) { - return false; - } - if (val1Type == "string" && val2Type == "string") { - return _s.helper.match(val1, "^"+val2+"$"); - } - if (val1Type == "string" && val2Type == "regexp") { - return _s.helper.match(val1, val2); - } - if (val1Type == "number" || val1Type == "bool") { - return (val1 == val2); - } - else if (val1Type == "array" || val1Type == "object") { - if (val1.length != val2.length) { return false; } - for (var i = 0; i < val1.length; i++) { - if (!_s.helper.equals(val1[i], val2[i])) { return false; } - } - return true; - } - else { - return (val1 == val2); - } - } - catch (e) { - return false; - } - }, - allEqual:function(val1,val2) { - if (_p.helper.type(val1) != "array") { val1 = [val1]; } - for (var item in val1) { - if (!_p.helper.equals(val1[item], val2)) { return false; } - } - return true; - }, - anyEqual:function(val1,val2) { - if (_p.helper.type(val1) != "array") { val1 = [val1]; } - for (var item in val1) { - if (!_p.helper.equals(val1[item], val2)) { return true; } - } - return false; - }, - sort:function(records, sorting, desc) { - - //if no sorting was provided - if (sorting == null) { - records.sort(); - if (desc) { query.state.data.reverse(); } - return records; - } - - //recursively handle sorting - var index = 0; - var doSort = function(records) { - - //clone to fix a BIZZARE IE7 bug - records = _p.util.clone(records); - - var field = sorting[index].field; - var desc = sorting[index].desc; - - //if at the end, just sort it - if (index == sorting.length - 1) { - _s.query.performSort(records, field, desc); - return records; - }; - - //increment forward to the next command - _s.query.performSort(records, field, desc); - var dist = _s.helper.distinct(records, field); - index++; - - //sort and gather values - call _doSort again if - //to check for futher commands - var results = []; - for (var j = 0; j < dist.length; j++) { - var sorted = doSort(dist[j].items); - for (var k = 0; k < sorted.length; k++) { - results.push(sorted[k]); - } - }; - - //return the results for this section - return results; - - }; - return doSort(_s.state.data); - - - }, - distinct:function(records, field) { - var dist = []; - for (var i = 0; i < records.length; i++) { - var val = records[i]; - var key = (field != null) ? eval(["(val.", field, ")"].join("")) : val; - - //check if the value exists yet - var added = false; - for (var item in dist) { - if (dist[item].key === key) { - added = true; - dist[item].items.push(val); - break; - } - } - - //make sure it was added - if (!added) { dist.push({ key:key, items:[ val ]}); } - } - - //return the final object - return dist; - }, - empty:_p.util.empty, - type:_p.util.type, - when:_p.util.when, - each:_p.util.each, - format:_p.util.format, - clone:_p.util.clone, - all:_p.util.allValues, - as:_p.util.as - }; - - //apply each of the extended functions - for(var item in _p.extend.cmd) { - (function(params) { - - //make sure this works - if (!(params.type || params.name || params.method)) { return; } - - //source commands are not added to a query - if (params.type.match(/source/i)) { return; } - - //determine the correct source - if (params.namespace && !_query[params.namespace]) { _query[params.namespace] = {}; } - var target = params.namespace ? _query[params.namespace] : _query; - - //apply this command - var method = (function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - - //set the state of the command - _s.state.debug.log("Called command %0% '%1%()'.", [params.type, params.name]); - var state = { - add:function(cmd) { _s.query.str.push(cmd); }, - query:_query, - state:_s.state, - helper:_s.helper, - repeat:function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - _s.query.repeatCmd(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - } - }; - - //depending on the type, set how this acts - if (params.type.match(/^query$/i)) { - - //prepare this command for use - var cmd = _s.query.prepCmd({ - command:target[params.name], - count:params.count, - name:params.name - }, [v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25]); - - //prepare the command for use - _s.query.appendCmd(function(record) { - - //try and get the value - try { - state.value = _s.state.useProperties ? eval("record."+cmd.field) : record; - } - catch (e) { - _s.state.debug.log("Exception when calling '%0%()' : %1%.", [params.name, e]); - state.value = null; - } - - //prepare the command - state.record = record; - state.type = state.helper.type(state.value); - state.when = function(actions) { - return _s.helper.when(state.value, actions); - }; - - //query the method - return params.method(state, cmd.arg[0], cmd.arg[1], cmd.arg[2], cmd.arg[3], cmd.arg[4], - cmd.arg[5], cmd.arg[6], cmd.arg[7], cmd.arg[8], cmd.arg[9], cmd.arg[10], cmd.arg[11], cmd.arg[12], cmd.arg[13], cmd.arg[14], - cmd.arg[15], cmd.arg[16], cmd.arg[17], cmd.arg[18], cmd.arg[19], cmd.arg[20], cmd.arg[21], cmd.arg[22], cmd.arg[23], cmd.arg[24]); - }); - - //return the query object - return _query; - - } - - //if an action, do the action and return the query - else if (params.type.match(/^action$/i)) { - - //execute the method and return the query - try { - params.method(state, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - } - catch (e) { - _s.state.debug.log("Exception when calling '%0%()' : %1%.", [params.name, e]); - } - return _query; - } - - //if selecting, return whatever the method returns - else if (params.type.match(/^selection$/i)) { - - //if this query wants to manually select the results - state.results = params.manual ? [] : _s.query.select(); - state.select = _s.query.select; - - //execute the selection method - return params.method(state, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - - } - - //return the query - return _query; - - }); - - - //next, assign a regular version - target[params.name] = method; - - //next, query methods receive extra names - if (params.type.match(/^query$/i) && - (_p.settings.generate == null || _p.settings.generate) && - (params.generate == null || params.generate)) { - - //then assign a second "or" version - var altName = params.name.substr(0,1).toUpperCase() + params.name.substr(1, params.name.length - 1); - - //create an automatic OR version - target["or"+altName] = function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - _s.state.operator = "||"; - return method(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }; - - //create an automatic AND version - target["and"+altName] = function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - _s.state.operator = "&&"; - return method(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }; - - //create an automatic NOT version - target["not"+altName] = function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - _s.state.not = !_s.state.not; - return method(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }; - - //create an automatic NOT version - target["andNot"+altName] = function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - _s.state.not = !_s.state.not; - _s.state.operator = "&&"; - return method(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }; - - //create an automatic NOT version - target["orNot"+altName] = function(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - _s.state.not = !_s.state.not; - _s.state.operator = "||"; - return method(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }; - - } - - })(_p.extend.cmd[item]); - - } - - }; - - }; - - //creates a default jLinq library - var _defaultLibrary = function() { - return { - locked:true, - generate:true, - types:{ - array:function(val) { - return (val.push && val.pop && val.reverse && val.slice && val.splice); - }, - "function":function(val) { - return ((typeof(val)).toString().match(/^function$/i)); - }, - string:function(val) { - return ((typeof(val)).toString().match(/^string$/i)); - }, - number:function(val) { - return ((typeof(val)).toString().match(/^number$/i)); - }, - bool:function(val) { - return ((typeof(val)).toString().match(/^boolean$/i)); - }, - regexp:function(val) { - return (val.ignoreCase != null && val.global != null && val.exec); - }, - date:function(val) { - return (val.getTime && val.setTime && val.toDateString && val.toTimeString); - } - }, - extend:[ - - //Selection Methods - //============================================================ - - //default selection routine - selects from an array - {name:"from", type:"source", - method:function(query, source) { - return query.helper.when(source, { - "function":function() { return source(); }, - array:function() { return source; }, - other:function() { return [ source ]; } - }); - }}, - - //Action Methods - //============================================================ - - //enters into debug mode - options available - {name:"debug", type:"action", operators:false, - method:function(query, delegate) { - query.state.debug.onEvent = delegate; - }}, - - //makes comparisons ignore case - {name:"reverse", type:"action", - method:function(query) { - query.state.data.reverse(); - }}, - - //makes comparisons ignore case - {name:"ignoreCase", type:"action", - method:function(query) { - query.state.ignoreCase = true; - }}, - - //makes string comparisons case sensitive - {name:"useCase", type:"action", - method:function(query) { - query.state.ignoreCase = false; - }}, - - //flags the query for || - can be used to repeat a command - {name:"or", type:"action", - method:function(query, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - query.state.operator = "||"; - query.repeat(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }}, - - //flags the query for ! - can be used to repeat a command - {name:"not", type:"action", - method:function(query, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - query.state.not = !query.state.not; - query.repeat(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }}, - - //flags the query for && - can be used to repeat a command - {name:"and", type:"action", - method:function(query, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - query.state.operator = "&&"; - query.repeat(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }}, - - //flags the query for || and ! - can be used to repeat a command - {name:"orNot", type:"action", - method:function(query, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - query.state.or = true; - query.state.not = !query.state.not; - query.repeat(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }}, - - //flags the query for && and ! - can be used to repeat a command - {name:"andNot", type:"action", - method:function(query, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - query.state.or = false; - query.state.not = !query.state.not; - query.repeat(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25); - }}, - - //combines all query selections into an expression with && - {name:"combine", type:"action", - method:function(query, delegate) { - query.add(query.state.operator+"("+(query.state.not?"!":"")); - query.state.operator = ""; - delegate(query.query); - query.add(")"); - }}, - - //combines all query selections into an expression with || - {name:"orCombine", type:"action", - method:function(query, delegate) { - query.state.operator = "||"; - query.add(query.state.operator+"("+(query.state.not?"!":"")); - query.state.operator = ""; - delegate(query.query); - query.add(")"); - }}, - - - //Query Methods - //============================================================= - - //runs a delegate as a query, this method is definately cheating - //since -1 is telling it not to expect a field... - {name:"where", count:-1, type:"query", - method:function(query, delegate) { - return delegate(query.record, query.helper); - }}, - - //checks if two fields are equal or not - {name:"has", count:1, type:"query", - method:function(query, value) { - var use = parseInt(value.toString(), 16); - var compare = parseInt(query.value.toString(), 16); - return ((compare & use) == use); - }}, - - //checks if two fields are equal or not - {name:"equals", count:1, type:"query", - method:function(query, value) { - return query.helper.equals(query.value, value); - }}, - - //returns if a string starts with the phrase - //returns if the first element in array is equal - {name:"startsWith", count:1, type:"query", - method:function(query, value) { - - //allow arrays to be passed as comparisons - if (query.helper.type(value) != "array") { - value = [value]; - } - - //check for each value - for (var item in value) { - var match = value[item]; - if (query.when({ - array:function() { - return query.helper.equals(query.value[0], match) - }, - other:function() { - return query.helper.match(query.value.toString(), "^"+match.toString()); - } - })) { return true; }; - } - }}, - - //returns if a string ends with a phrase - //returns if the last element in array is equal - {name:"endsWith", count:1, type:"query", - method:function(query, value) { - - //allow arrays to be passed as comparisons - if (query.helper.type(value) != "array") { - value = [value]; - } - - //check for each value - for (var item in value) { - var match = value[item]; - if (query.when({ - array:function() { - return query.helper.equals(query.value[query.value.length - 1], match) - }, - other:function() { - return query.helper.match(query.value.toString(), match.toString()+"$"); - } - })) { return true; }; - } - }}, - - //returns if a string contains a phrase - //returns if any element in array is equal - {name:"contains", count:1, type:"query", - method:function(query, value) { - if (value == null) { return false; } - - //allow arrays to be passed as comparisons - if (query.helper.type(value) != "array") { - value = [value]; - } - - //check for each value - for (var item in value) { - var match = value[item]; - if (query.when({ - array:function() { - for (var i = 0; i < query.value.length; i++) { - if (query.helper.equals(query.value[i], match)) { return true; } - } - }, - other:function() { - return query.helper.match(query.value.toString(), "^.*" + query.helper.toRegex(match) + ".*$"); - } - })) { return true; }; - } - }}, - - //evaluates each item with a regular expression - {name:"match", count:1, type:"query", - method:function(query, value) { - - //allow arrays to be passed as comparisons - if (query.helper.type(value) != "array") { - value = [value]; - } - //TODO : Convert items into regular expressions - //array:(item1|item2|item3|item4) - - //check for each value - for (var item in value) { - var match = value[item]; - if (query.when({ - array:function() { - for (var i = 0; i < query.value.length; i++) { - if (query.helper.match(query.value[i], match)) { return true; } - } - }, - other:function() { - return query.helper.match(query.value.toString(), match); - } - })) { return true; }; - } - - }}, - - //returns if a number is less - //returns if a string has less characters - //returns if an array has less elements - {name:"less", count:1, type:"query", - method:function(query, value) { - - //get the value to use with this - value = query.helper.when(value, { - number:function() { return value; }, - date:function() { return value; }, - other:function() { return value.length; } - }); - - return query.when({ - string:function() { - return (query.value.length < value); - }, - array:function() { - return (query.value.length < value); - }, - other:function() { - return (query.value < value); - } - }); - }}, - - //returns if a number is more - //returns if a string has more characters - //returns if an array has more elements - {name:"greater", count:1, type:"query", - method:function(query, value) { - - //get the value to use with this - value = query.helper.when(value, { - number:function() { return value; }, - date:function() { return value; }, - other:function() { return value.length; } - }); - - return query.when({ - string:function() { - return (query.value.length > value); - }, - array:function() { - return (query.value.length > value); - }, - other:function() { - return (query.value > value); - } - }); - }}, - - //returns if a number is less - //returns if a string has less characters - //returns if an array has less elements - {name:"lessEquals", count:1, type:"query", - method:function(query, value) { - - //get the value to use with this - value = query.helper.when(value, { - number:function() { return value; }, - date:function() { return value; }, - other:function() { return value.length; } - }); - - return query.when({ - string:function() { - return (query.value.length <= value); - }, - array:function() { - return (query.value.length <= value); - }, - other:function() { - return (query.value <= value); - } - }); - }}, - - //returns if a number is more - //returns if a string has more characters - //returns if an array has more elements - {name:"greaterEquals", count:1, type:"query", - method:function(query, value) { - - //get the value to use with this - value = query.helper.when(value, { - number:function() { return value; }, - date:function() { return value; }, - other:function() { return value.length; } - }); - - return query.when({ - string:function() { - return (query.value.length >= value); - }, - array:function() { - return (query.value.length >= value); - }, - other:function() { - return (query.value >= value); - } - }); - }}, - - //returns if a number is more - //returns if a string has more characters - //returns if an array has more elements - {name:"between", count:2, type:"query", - method:function(query, low, high) { - - //get the value to use with this - low = query.helper.when(low, { - number:function() { return low; }, - date:function() { return value; }, - other:function() { return low.length; } - }); - - high = query.helper.when(high, { - number:function() { return high; }, - other:function() { return high.length; } - }); - - return query.when({ - string:function() { - return (query.value.length > low && query.value.length < high); - }, - array:function() { - return (query.value.length > low && query.value.length < high); - }, - other:function() { - return (query.value > low && query.value < high); - } - }); - }}, - - //returns if a number is more - //returns if a string has more characters - //returns if an array has more elements - {name:"betweenEquals", count:2, type:"query", - method:function(query, low, high) { - low = query.helper.when(low, { - number:function() { return low; }, - date:function() { return value; }, - other:function() { return low.length; } - }); - - high = query.helper.when(high, { - number:function() { return high; }, - date:function() { return value; }, - other:function() { return high.length; } - }); - - return query.when({ - string:function() { - return (query.value.length >= low && query.value.length <= high); - }, - array:function() { - return (query.value.length >= low && query.value.length <= high); - }, - other:function() { - return (query.value >= low && query.value <= high); - } - }); - }}, - - //returns if a field is null - //returns if an array is empty - //returns if a string is empty - {name:"empty", count:0, type:"query", - method:function(query) { - return query.when({ - array:function() { - return (query.value.length == 0); - }, - string:function() { - return (query.value == ""); - }, - empty:function() { - return true; - } - }); - }}, - - //returns if a boolean iss true - //returns if a record has a field - {name:"is", count:0, type:"query", - method:function(query) { - return query.when({ - bool:function() { - return query.value; - }, - empty:function() { - return false; - }, - other:function() { - return (query.value != null); - } - }); - }}, - - //returns if a boolean is false - //returns if a record is missing a field - {name:"isNot", count:0, type:"query", - method:function(query) { - return query.when({ - bool:function() { - return !query.value; - }, - empty:function() { - return true; - }, - other:function() { - return (query.value == null); - } - }); - }}, - - - //Selection Methods - //============================================================= - - //returns if any records match the query - {name:"any", type:"selection", - method:function(query) { - return (query.results.selected.length > 0); - }}, - - //returns if all records match the query - {name:"all", type:"selection", - method:function(query) { - return (query.results.selected.length == query.state.data.length); - }}, - - //returns none of the records match - {name:"none", type:"selection", - method:function(query) { - return !query.query.all(); - }}, - - //returns the total records found - {name:"count", type:"selection", - method:function(query, invert) { - return invert ? query.results.remaining.length : query.results.selected.length; - }}, - - //returns array of matching records - {name:"select", type:"selection", - method:function(query, selection, invert) { - - //select the records - var records = []; - var results = invert ? query.results.remaining : query.results.selected; - selection = query.helper.type(selection) == "function" ? selection : function(r) { return r; }; - for (var i = 0; i < results.length; i++) { - records.push(selection(results[i])); - } - - //return the final records - return records; - - }}, - - //returns HTML string for a table - {name:"toTable", type:"selection", manual:true, - method:function(query, params, selection, invert) { - - params = params ? params : {}; - var results = query.query.select(selection, invert); - - //create the table structure - if (results.count == 0) { return "No results for this query"; } - - //getting a string - var getString = function(raw) { - query.helper.when(raw, { - date:function() { - raw = query.helper.format("%0%/%1%/%2% at %3%:%4% %5%", - [raw.getMonth()+1, raw.getDate(), raw.getFullYear(), (raw.getHours() > 12 ? raw.getHours() - 12 : raw.getHours()), raw.getMinutes(), (raw.getHours() > 12 ? "PM" : "AM")] - ); - }, - empty:function() { - raw = "null"; - }, - other:function() { - raw = raw.toString(); - } - }); - return raw; - }; - - //otherwise, start the table - var output = [""]; - - //create the header - if (query.state.useProperties) { - var columns = []; - output.push(""); - for(var item in results[0]) { - columns.push(item); - output.push(""); - } - output.push(""); - } - - //do each item - var alt = true; - for (var i = 0; i < results.length; i++) { - alt = !alt; - var record = results[i]; - output.push(""); - - //create the row - if (query.state.useProperties) { - for(var col in columns) { - - //get a formatted string - var item = columns[col]; - var val = record[item]; - var msg = getString(val); - - //add the information - output.push(""); - } - } - else { - //no properties - output.push(""); - } - - //close the row - output.push(""); - - } - - //close the table and return the output - output.push("
      "); - output.push(escape(item)); - output.push("
      "); - output.push(msg); - output.push(""); - output.push(getString(record)); - output.push("
      "); - return output.join(""); - - }}, - - //Executes the action to each match then returns the query - technically a selection - {name:"each", type:"selection", manual:true, - method:function(query, action, selection, invert) { - - //select the correct records and perform the action - var results = query.query.select(selection, invert); - for(var i = 0; i < results.length; i++) { - action(results[i], i); - } - - //return the query again - return query.query; - - }}, - - //Orders the records then returns the query - technically a selection - {name:"orderBy", type:"selection", manual:true, - method:function(query, v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25) { - var order = query.helper.all([v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25]); - if (order.length == 0) { order = [""]; } - - //sort depending on if there are properties or not - if (!query.state.useProperties) { - var desc = (order.length > 0) ? (order[0]+"").match(/^\-/g) : false; - query.state.data = query.helper.sort(query.state.data, null, desc); - return query.query; - } - - //since this is more complicated, build the sorting order - var sorting = []; - for (var i = 0; i < order.length; i++) { - sorting.push({ - desc: (order[i].substr(0,1) == "-"), - field: order[i].replace(/^\-/g, "") - }); - } - query.state.data = query.helper.sort(query.state.data, sorting); - - //return a new query - return query.query; - - }}, - - //returns all distinct values based on the field - {name:"distinct", type:"selection", - method:function(query, field, invert) { - var sel = invert ? query.results.remaining : query.results.selected; - var results = query.helper.distinct(sel, field); - - //return just the names of the fields - var dist = []; - for (var item in results) { - dist.push(results[item].key); - } - - //sort it to be helpful - return query.helper.sort(dist, null, false); - - }}, - - //groups the records and returns - {name:"groupBy", type:"selection", - method:function(query, field, invert) { - var sel = invert ? query.results.remaining : query.results.selected; - var results = query.helper.distinct(sel, field); - return jLinq.from(results); - }}, - - //Joins a second array to the current query - {name:"join", type:"selection", - method:function(query, source, alias, pk, fk) { - - //clone the source array - source = query.helper.clone(source); - - //create a second query for this item - var gen = []; - for (var i = 0; i < query.state.data.length; i++) { - var record = query.helper.clone(query.state.data[i]); - var results = jLinq.from(source).equals(fk, record[pk]).select(); - if (results.length == 1) { - record[alias] = results[0]; - } - else { - record[i][alias] = results; - } - - //add the new record - gen.push(record); - } - - //return a new query - return jLinq.from(gen); - - }}, - - //attaches a property to each record - {name:"attach", type:"selection", - method:function(query, alias, delegate) { - for(var i = 0; i < query.state.data.length; i++) { - query.state.data[i][alias] = delegate(query.state.data[i]); - } - }}, - - //skips and takes the correct set of records - {name:"skipTake", type:"selection", manual:true, - method:function(query, skip, take, selection, invert) { - skip = Math.max(query.helper.type(skip) == "number" ? skip : 0, 0); - take = Math.max(query.helper.type(take) == "number" ? take : 0, 0); - - //take the correct number of records - var results = query.query.select(selection, invert); - return results.slice(skip, (skip + take)); - - }}, - - //skips and takes the correct set of records - {name:"take", type:"selection", manual:true, - method:function(query, take, selection, invert) { - take = Math.max(query.helper.type(take) == "number" ? take : 0, 0); - - //take the correct number of records - var results = query.query.select(selection, invert); - return results.slice(0, take ); - - }}, - - //the first match of the set -- allows a default match if nothing is found - {name:"first", type:"selection", manual:true, - method:function(query, defType, selection, invert) { - var results = query.query.select(selection, invert); - return results.length > 0 ? results[0] : defType ? defType : null; - }}, - - //the last match of the set -- allows a default match if nothing is found - {name:"last", type:"selection", manual:true, - method:function(query, defType, selection, invert) { - var results = query.query.select(selection, invert); - return results.length > 0 ? results[results.length - 1] : defType ? defType : null; - }}, - - //the element at the specified index -- allows a default match if nothing is found - {name:"at", type:"selection", manual:true, - method:function(query, index, defType, selection, invert) { - var results = query.query.select(selection, invert); - return index < results.length || index >= 0 ? results[index] : defType ? defType : null; - }}, - - //returns the sum of all fields of a type - {name:"sum", type:"selection", - method:function(query, field, invert) { - if (!query.state.useProperties) { invert = field; } - var sel = invert ? query.results.remaining : query.results.selected; - var result = 0; - query.helper.each(sel, function(rec) { - if (query.state.useProperties) { - if (result == null) { - result = rec[field]; - } - else { - query.helper.when(rec[field], { - array:function() { - result += rec[field].length; - }, - string:function() { - result += rec[field].length; - }, - other:function() { - result += rec[field]; - }}); - } - } - else { - query.helper.when(rec, { - array:function() { - result += rec.length; - }, - string:function() { - result += rec.length; - }, - other:function() { - result += rec; - }}); - } - }); - return { - count:sel.length, - result:result, - records:sel - }; - }}, - - //returns the average of a sum selection - {name:"average", type:"selection", - method:function(query, field, invert) { - var sel = invert ? query.results.remaining : query.results.selected; - var sum = jLinq.from(sel).sum(field).result; - return { - total:sum, - count:sel.length, - result:(sum / sel.length), - records:sel - }; - }}, - - //returns the maximum value - {name:"max", type:"selection", - method:function(query, field, invert) { - var list = jLinq.from(invert ? query.results.remaining : query.results.selected) - .select(function(r) { - r = query.state.useProperties ? r[field] : r; - return { - value:r, - count:query.helper.getNumericValue(r) - } - }); - return jLinq.from(list).orderBy("count", "value").last()["value"]; - }}, - - //returns the minimum value - {name:"min", type:"selection", - method:function(query, field, invert) { - var list = jLinq.from(invert ? query.results.remaining : query.results.selected) - .select(function(r) { - r = query.state.useProperties ? r[field] : r; - return { - value:r, - count:query.helper.getNumericValue(r) - } - }); - return jLinq.from(list).orderBy("count", "value").first()["value"]; - }}, - - //contains any values not found in comparison each array - {name:"except", type:"selection", - method:function(query, compare, invert) { - var selection = invert ? query.results.remaining : query.results.selected; - if (!(compare && compare.length && compare.length > 0)) { return jLinq.from(selection); } - - //return only results that don't match - var result = jLinq.from(selection) - .notWhere(function(val) { - for (var i = 0; i < compare.length; i++) { - if (query.state.useProperties) { - if (query.helper.propsEqual(compare[i], val)) { return true; } - } - else { - if (query.helper.equals(compare[i], val)) { return true; } - } - } - return false; - }) - .select(); - return jLinq.from(result); - }}, - - //returns unique values from two arrays - {name:"intersect", type:"selection", - method:function(query, compare, invert) { - var selection = invert ? query.results.remaining : query.results.selected; - if (!(compare && compare.length && compare.length > 0)) { return jLinq.from(selection); } - - //return only results that don't match - var result = jLinq.from(selection) - .where(function(val) { - for (var i = 0; i < compare.length; i++) { - if (query.state.useProperties) { - if (query.helper.propsEqual(compare[i], val)) { return true; } - } - else { - if (query.helper.equals(compare[i], val)) { return true; } - } - } - return false; - }) - .select(); - return jLinq.from(result); - }}, - - //merges two arrays together - {name:"union", type:"selection", - method:function(query, compare, invert) { - var selection = invert ? query.results.remaining : query.results.selected; - if (!(compare && compare.length && compare.length > 0)) { return jLinq.from(selection); } - - //return the results to make a single list - return jLinq.from(compare.concat( - jLinq.from(selection) - .where(function(val) { - for (var i = 0; i < compare.length; i++) { - if (query.state.useProperties) { - if (query.helper.propsEqual(compare[i], val)) { return false; } - } - else { - if (query.helper.equals(compare[i], val)) { return false; } - } - } - return true; - }) - .select() - )); - }}, - - //skips records until the first condition is met - {name:"skipWhile", type:"selection", - method:function(query, delegate, invert) { - var selection = invert ? query.results.remaining : query.results.selected; - - //return the results to make a single list - var skip = true; - return jLinq.from(selection) - .where(function(rec, helper) { - if (skip) { skip = delegate(rec, helper); } - return !skip; - }) - .select(); - }}, - - //takes records till the first condition is met - {name:"takeWhile", type:"selection", - method:function(query, delegate, invert) { - var selection = invert ? query.results.remaining : query.results.selected; - - //return the results to make a single list - var take = true; - return jLinq.from(selection) - .where(function(rec, helper) { - if (take) { take = delegate(rec, query.helper); } - return take; - }) - .select(); - }}, - - //merges two arrays together - {name:"selectMany", type:"selection", - method:function(query, collection, delegate, select, invert) { - var selection = invert ? query.results.remaining : query.results.selected; - - //return the results to make a single list - select = select ? select : function(r,s) { return { source:r, compare:s }; }; - var results = []; - query.helper.each(selection, function(rec) { - query.helper.each(collection, function(sub) { - if (delegate(rec, sub)) { results.push(select(rec,sub)); } - }); - }); - return results; - }} - - ] - - }; - - }; //default library - - //create the base library - jLinq = new library(_defaultLibrary()); - jLinq.finish(true); - - //Create entirely new libraries - jLinq.library = function(settings, imp) { - if (imp == null) { imp = true; } - - //if no defaults, return it as is - var lib = new library(_defaultLibrary()); - - //clear out the info if not importing - if (!imp) { - lib.types = {}; - lib.extend = []; - } - - //import any settings, if any - var lock = false; - if (settings) { - - //extend the methods - if (settings.extend) { - for (var ext in settings.extend) { - lib.extend(settings.extend[ext]) - } - } - - //extend the types - if (settings.types) { - for (var type in settings.types) { - lib.addType(settings.types[type]);; - } - } - - //if there is a lock setting - if (settings.locked) { lock = settings.locked; } - - }; - - //set the lock and return - lib.finish(lock); - return lib; - - }; - -})(); \ No newline at end of file diff --git a/release/latest/js/jquery-1.4.2.min.js b/release/latest/js/jquery-1.4.2.min.js deleted file mode 100644 index 7c243080233..00000000000 --- a/release/latest/js/jquery-1.4.2.min.js +++ /dev/null @@ -1,154 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(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(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
      a"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

      ";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="
      ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
      ","
      "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
      ").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
      "; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/release/latest/js/jquery.json-2.2.js b/release/latest/js/jquery.json-2.2.js deleted file mode 100644 index 87f5d0157c8..00000000000 --- a/release/latest/js/jquery.json-2.2.js +++ /dev/null @@ -1,178 +0,0 @@ -/* - * jQuery JSON Plugin - * version: 2.1 (2009-08-14) - * - * This document is licensed as free software under the terms of the - * MIT License: http://www.opensource.org/licenses/mit-license.php - * - * Brantley Harris wrote this plugin. It is based somewhat on the JSON.org - * website's http://www.json.org/json2.js, which proclaims: - * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that - * I uphold. - * - * It is also influenced heavily by MochiKit's serializeJSON, which is - * copyrighted 2005 by Bob Ippolito. - */ - -(function($) { - /** jQuery.toJSON( json-serializble ) - Converts the given argument into a JSON respresentation. - - If an object has a "toJSON" function, that will be used to get the representation. - Non-integer/string keys are skipped in the object, as are keys that point to a function. - - json-serializble: - The *thing* to be converted. - **/ - $.toJSON = function(o) - { - if (typeof(JSON) == 'object' && JSON.stringify) - return JSON.stringify(o); - - var type = typeof(o); - - if (o === null) - return "null"; - - if (type == "undefined") - return undefined; - - if (type == "number" || type == "boolean") - return o + ""; - - if (type == "string") - return $.quoteString(o); - - if (type == 'object') - { - if (typeof o.toJSON == "function") - return $.toJSON( o.toJSON() ); - - if (o.constructor === Date) - { - var month = o.getUTCMonth() + 1; - if (month < 10) month = '0' + month; - - var day = o.getUTCDate(); - if (day < 10) day = '0' + day; - - var year = o.getUTCFullYear(); - - var hours = o.getUTCHours(); - if (hours < 10) hours = '0' + hours; - - var minutes = o.getUTCMinutes(); - if (minutes < 10) minutes = '0' + minutes; - - var seconds = o.getUTCSeconds(); - if (seconds < 10) seconds = '0' + seconds; - - var milli = o.getUTCMilliseconds(); - if (milli < 100) milli = '0' + milli; - if (milli < 10) milli = '0' + milli; - - return '"' + year + '-' + month + '-' + day + 'T' + - hours + ':' + minutes + ':' + seconds + - '.' + milli + 'Z"'; - } - - if (o.constructor === Array) - { - var ret = []; - for (var i = 0; i < o.length; i++) - ret.push( $.toJSON(o[i]) || "null" ); - - return "[" + ret.join(",") + "]"; - } - - var pairs = []; - for (var k in o) { - var name; - var type = typeof k; - - if (type == "number") - name = '"' + k + '"'; - else if (type == "string") - name = $.quoteString(k); - else - continue; //skip non-string or number keys - - if (typeof o[k] == "function") - continue; //skip pairs where the value is a function. - - var val = $.toJSON(o[k]); - - pairs.push(name + ":" + val); - } - - return "{" + pairs.join(", ") + "}"; - } - }; - - /** jQuery.evalJSON(src) - Evaluates a given piece of json source. - **/ - $.evalJSON = function(src) - { - if (typeof(JSON) == 'object' && JSON.parse) - return JSON.parse(src); - return eval("(" + src + ")"); - }; - - /** jQuery.secureEvalJSON(src) - Evals JSON in a way that is *more* secure. - **/ - $.secureEvalJSON = function(src) - { - if (typeof(JSON) == 'object' && JSON.parse) - return JSON.parse(src); - - var filtered = src; - filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@'); - filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); - filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); - - if (/^[\],:{}\s]*$/.test(filtered)) - return eval("(" + src + ")"); - else - throw new SyntaxError("Error parsing JSON, source is not valid."); - }; - - /** jQuery.quoteString(string) - Returns a string-repr of a string, escaping quotes intelligently. - Mostly a support function for toJSON. - - Examples: - >>> jQuery.quoteString("apple") - "apple" - - >>> jQuery.quoteString('"Where are we going?", she asked.') - "\"Where are we going?\", she asked." - **/ - $.quoteString = function(string) - { - if (string.match(_escapeable)) - { - return '"' + string.replace(_escapeable, function (a) - { - var c = _meta[a]; - if (typeof c === 'string') return c; - c = a.charCodeAt(); - return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); - }) + '"'; - } - return '"' + string + '"'; - }; - - var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g; - - var _meta = { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }; -})(jQuery); diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index 26e4edee4a8..00000000000 Binary files a/src/.DS_Store and /dev/null differ diff --git a/src/.nuget/NuGet.config b/src/.nuget/NuGet.config new file mode 100644 index 00000000000..fe6a62c920d --- /dev/null +++ b/src/.nuget/NuGet.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/.nuget/NuGet.exe b/src/.nuget/NuGet.exe new file mode 100755 index 00000000000..856263ded82 Binary files /dev/null and b/src/.nuget/NuGet.exe differ diff --git a/src/.nuget/NuGet.targets b/src/.nuget/NuGet.targets new file mode 100644 index 00000000000..f2d0eb36fb0 --- /dev/null +++ b/src/.nuget/NuGet.targets @@ -0,0 +1,77 @@ + + + + $(MSBuildProjectDirectory)\..\ + + + + + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) + $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) + $([System.IO.Path]::Combine($(SolutionDir), "packages")) + + + + + $(SolutionDir).nuget + packages.config + $(SolutionDir)packages + + + + + $(NuGetToolsPath)\NuGet.exe + "$(NuGetExePath)" + mono --runtime=v4.0.30319 $(NuGetExePath) + + $(TargetDir.Trim('\\')) + + + "" + + + false + + + false + + + $(NuGetCommand) install "$(PackagesConfig)" -source $(PackageSources) -o "$(PackagesDir)" + $(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols + + + + RestorePackages; + $(BuildDependsOn); + + + + + $(BuildDependsOn); + BuildPackage; + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000000..8dbe4f1bbe0 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,55 @@ + + + + 6.0.3 + ServiceStack + ServiceStack, Inc. + © 2008-2022 ServiceStack, Inc + true + https://github.com/ServiceStack/ServiceStack + https://servicestack.net/terms + https://servicestack.net/img/logo-64.png + https://docs.servicestack.net/release-notes-history + git + https://github.com/ServiceStack/ServiceStack.git + embedded + latest + true + true + false + $(NoWarn);1591;CS3001;CS3002;CS3003;CS3005;CS3009;CS3015;CS3024;CS3027 + + + + true + true + + + + $(DefineConstants);NETFX;NET45;NET472 + True + False + ../servicestack.snk + + + + $(DefineConstants);NETSTANDARD;NETSTANDARD2_0 + + + + $(DefineConstants);NET6_0;NET6_0_OR_GREATER + + + + $(DefineConstants);NETCORE;NETCORE_SUPPORT + + + + + + + + DEBUG + + + diff --git a/src/GlobalAssemblyInfo.cs b/src/GlobalAssemblyInfo.cs new file mode 100644 index 00000000000..8c260e93578 --- /dev/null +++ b/src/GlobalAssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Reflection; + +[assembly: AssemblyVersion("3.9.60.0")] diff --git a/src/ServiceStack.Android.sln b/src/ServiceStack.Android.sln deleted file mode 100644 index 7f7162bdfa9..00000000000 --- a/src/ServiceStack.Android.sln +++ /dev/null @@ -1,32 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.Common.Android", "ServiceStack.Common.Android\ServiceStack.Common.Android.csproj", "{BEA92E9F-00B1-4923-BD81-7F3A9CA24408}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.Interfaces.Android", "ServiceStack.Interfaces.Android\ServiceStack.Interfaces.Android.csproj", "{05A5DDBF-A1A2-4B28-9FF0-C07060A8AEFC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.Text.Android", "..\..\ServiceStack.Text\src\ServiceStack.Text.Android\ServiceStack.Text.Android\ServiceStack.Text.Android.csproj", "{56838CD4-8EBC-4860-A3E1-1697875BBC61}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BEA92E9F-00B1-4923-BD81-7F3A9CA24408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BEA92E9F-00B1-4923-BD81-7F3A9CA24408}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BEA92E9F-00B1-4923-BD81-7F3A9CA24408}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BEA92E9F-00B1-4923-BD81-7F3A9CA24408}.Release|Any CPU.Build.0 = Release|Any CPU - {05A5DDBF-A1A2-4B28-9FF0-C07060A8AEFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {05A5DDBF-A1A2-4B28-9FF0-C07060A8AEFC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {05A5DDBF-A1A2-4B28-9FF0-C07060A8AEFC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {05A5DDBF-A1A2-4B28-9FF0-C07060A8AEFC}.Release|Any CPU.Build.0 = Release|Any CPU - {56838CD4-8EBC-4860-A3E1-1697875BBC61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56838CD4-8EBC-4860-A3E1-1697875BBC61}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56838CD4-8EBC-4860-A3E1-1697875BBC61}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56838CD4-8EBC-4860-A3E1-1697875BBC61}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/ServiceStack.Api.OpenApi/OpenApiFeature.cs b/src/ServiceStack.Api.OpenApi/OpenApiFeature.cs new file mode 100644 index 00000000000..813e7d0d127 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/OpenApiFeature.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using ServiceStack.Host.Handlers; +using ServiceStack.IO; +using ServiceStack.Api.OpenApi.Specification; +using ServiceStack.Auth; + +namespace ServiceStack.Api.OpenApi +{ + public class OpenApiFeature : IPlugin, IPreInitPlugin, Model.IHasStringId + { + public string Id { get; set; } = Plugins.OpenApi; + /// + /// Gets or sets pattern to filter available resources. + /// + public string ResourceFilterPattern { get; set; } + + public bool UseCamelCaseSchemaPropertyNames { get; set; } + + public bool UseLowercaseUnderscoreSchemaPropertyNames { get; set; } + + public bool DisableAutoDtoInBodyParam { get; set; } + + public string LogoUrl { get; set; } + + public string LogoHref { get; set; } + + public Action ApiDeclarationFilter { get; set; } + + /// + /// Operation filter. Action takes a verb and operation as parameters + /// + public Action OperationFilter { get; set; } + + public Action SchemaFilter { get; set; } + + public Action SchemaPropertyFilter { get; set; } + + public List Tags { get; set; } + + public List AnyRouteVerbs { get; set; } + + public List InlineSchemaTypesInNamespaces { get; set; } + + public bool DisableSwaggerUI { get; set; } + + public Dictionary SecurityDefinitions { get; set; } + + public Dictionary> OperationSecurity { get; set; } + + public bool UseBearerSecurity + { + set + { + SecurityDefinitions = new Dictionary { + { "Bearer", new OpenApiSecuritySchema { + Type = "apiKey", + Name = "Authorization", + In = "header", + } } + }; + OperationSecurity = new Dictionary> { + { "Bearer", new List() } + }; + } + } + + public bool UseBasicSecurity + { + set + { + SecurityDefinitions = new Dictionary { + { "basic", new OpenApiSecuritySchema { Type = "basic" } } + }; + OperationSecurity = new Dictionary> { + { "basic", new List() } + }; + } + } + + public OpenApiFeature() + { + Tags = new List(); + AnyRouteVerbs = new List { HttpMethods.Get, HttpMethods.Post, HttpMethods.Put, HttpMethods.Delete }; + InlineSchemaTypesInNamespaces = new List(); + } + + public void BeforePluginsLoaded(IAppHost appHost) + { + appHost.Config.EmbeddedResourceSources.Add(typeof(OpenApiFeature).Assembly); + } + + public void Register(IAppHost appHost) + { + if (ResourceFilterPattern != null) + OpenApiService.resourceFilterRegex = new Regex(ResourceFilterPattern, RegexOptions.Compiled); + + if (SecurityDefinitions == null && OperationSecurity == null) + { + var useBasicAuth = appHost.GetPlugin()?.AuthProviders + ?.Any(x => x.Provider == AuthenticateService.BasicProvider) == true; + if (!useBasicAuth) + UseBearerSecurity = true; + else + UseBasicSecurity = true; + } + + OpenApiService.UseCamelCaseSchemaPropertyNames = UseCamelCaseSchemaPropertyNames; + OpenApiService.UseLowercaseUnderscoreSchemaPropertyNames = UseLowercaseUnderscoreSchemaPropertyNames; + OpenApiService.DisableAutoDtoInBodyParam = DisableAutoDtoInBodyParam; + OpenApiService.ApiDeclarationFilter = ApiDeclarationFilter; + OpenApiService.OperationFilter = OperationFilter; + OpenApiService.SchemaFilter = SchemaFilter; + OpenApiService.SchemaPropertyFilter = SchemaPropertyFilter; + OpenApiService.AnyRouteVerbs = AnyRouteVerbs.ToArray(); + OpenApiService.InlineSchemaTypesInNamespaces = InlineSchemaTypesInNamespaces.ToArray(); + OpenApiService.SecurityDefinitions = SecurityDefinitions; + OpenApiService.OperationSecurity = OperationSecurity; + + appHost.RegisterService(typeof(OpenApiService), "/openapi"); + + if (!DisableSwaggerUI) + { + var swaggerUrl = "swagger-ui/"; + + appHost.ConfigurePlugin( + feature => feature.AddPluginLink(swaggerUrl, "Swagger UI")); + + appHost.CatchAllHandlers.Add((httpMethod, pathInfo, filePath) => + { + IVirtualFile indexFile; + IVirtualFile patchFile = null; + IVirtualFile patchPreLoadFile = null; + pathInfo = pathInfo.TrimStart('/'); + switch (pathInfo) + { + case "swagger-ui/": + case "swagger-ui/default.html": + indexFile = appHost.VirtualFileSources.GetFile("/swagger-ui/index.html"); + patchFile = appHost.VirtualFileSources.GetFile("/swagger-ui/patch.js"); + patchPreLoadFile = appHost.VirtualFileSources.GetFile("/swagger-ui/patch-preload.js"); + break; + default: + indexFile = null; + break; + } + if (indexFile != null) + { + var html = indexFile.ReadAllText(); + var injectJs = patchFile?.ReadAllText(); + var injectPreloadJs = patchPreLoadFile?.ReadAllText(); + + return new CustomResponseHandler((req, res) => + { + res.ContentType = MimeTypes.HtmlUtf8; //use alt HTML ContentType so it's not overridden when Feature.Html is removed + var resourcesUrl = req.ResolveAbsoluteUrl("~/openapi"); + html = html.Replace("http://petstore.swagger.io/v2/swagger.json", resourcesUrl) + .Replace("ApiDocs", HostContext.ServiceName) + .Replace("swagger", $"{HostContext.ServiceName}") + .Replace("http://swagger.io", LogoHref ?? "./"); + + if (LogoUrl != null) + html = html.Replace("images/logo_small.png", LogoUrl); + + if (injectPreloadJs != null) + { + html = html.Replace("window.swaggerUi.load();", injectPreloadJs + "\n\n window.swaggerUi.load();"); + } + + if (injectJs != null) + { + html = html.Replace("", + ""); + } + + return html; + }); + } + return pathInfo.StartsWith("/swagger-ui/") + ? new StaticFileHandler() + : null; + }); + } + } + + public static bool IsEnabled => HostContext.HasPlugin(); + } +} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/OpenApiService.cs b/src/ServiceStack.Api.OpenApi/OpenApiService.cs new file mode 100644 index 00000000000..9b72548621e --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/OpenApiService.cs @@ -0,0 +1,1075 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text.RegularExpressions; +using ServiceStack.DataAnnotations; +using ServiceStack.Host; +using ServiceStack.NativeTypes; +using ServiceStack.Text; +using ServiceStack.Web; +using ServiceStack.Api.OpenApi.Support; +using ServiceStack.Api.OpenApi.Specification; + +namespace ServiceStack.Api.OpenApi +{ + [DataContract] + [ExcludeMetadata] + public class OpenApiSpecification : IReturn + { + [DataMember(Name = "apiKey")] + public string ApiKey { get; set; } + } + + [AddHeader(DefaultContentType = MimeTypes.Json)] + [DefaultRequest(typeof(OpenApiSpecification))] + [Restrict(VisibilityTo = RequestAttributes.None)] + public class OpenApiService : Service + { + internal static bool UseCamelCaseSchemaPropertyNames { get; set; } + internal static bool UseLowercaseUnderscoreSchemaPropertyNames { get; set; } + internal static bool DisableAutoDtoInBodyParam { get; set; } + + internal static Regex resourceFilterRegex; + + internal static Action ApiDeclarationFilter { get; set; } + internal static Action OperationFilter { get; set; } + internal static Action SchemaFilter { get; set; } + internal static Action SchemaPropertyFilter { get; set; } + internal static string[] AnyRouteVerbs { get; set; } + internal static string[] InlineSchemaTypesInNamespaces { get; set; } + + public static Dictionary SecurityDefinitions { get; set; } + public static Dictionary> OperationSecurity { get; set; } + + public object Get(OpenApiSpecification request) + { + var map = HostContext.ServiceController.RestPathMap; + var paths = new List(); + + var basePath = new Uri(base.Request.GetBaseUrl()); + + var meta = HostContext.Metadata; + + foreach (var key in map.Keys) + { + var restPaths = map[key]; + var visiblePaths = restPaths.Where(x => meta.IsVisible(Request, Format.Json, x.RequestType.Name)); + paths.AddRange(visiblePaths); + } + + var definitions = new Dictionary + { + { "Object", new OpenApiSchema { Description = "Object", Type = OpenApiType.Object, Properties = new OrderedDictionary() } }, + }; + + foreach (var restPath in paths.SelectMany(x => x.Verbs.Select(y => new { Value = x, Verb = y }))) + { + ParseDefinitions(definitions, restPath.Value.RequestType, restPath.Value.Path, restPath.Verb); + } + + var tags = new Dictionary(); + var apiPaths = ParseOperations(paths, definitions, tags); + + var result = new OpenApiDeclaration + { + Info = new OpenApiInfo + { + Title = HostContext.ServiceName, + Version = HostContext.Config.ApiVersion, + }, + Paths = apiPaths, + BasePath = basePath.AbsolutePath, + Schemes = new List { basePath.Scheme }, //TODO: get https from config + Host = basePath.Authority, + Consumes = new List { "application/json" }, + Produces = new List { "application/json" }, + Definitions = definitions.Where(x => !SchemaIdToClrType.ContainsKey(x.Key) || !IsInlineSchema(SchemaIdToClrType[x.Key])).ToDictionary(x => x.Key, x => x.Value), + Tags = tags.Values.OrderBy(x => x.Name).ToList(), + Parameters = new Dictionary { { "Accept", GetAcceptHeaderParameter() } }, + SecurityDefinitions = SecurityDefinitions, + }; + + if (SchemaFilter != null) + { + result.Parameters.Each(x => { + if (x.Value.Schema != null) + SchemaFilter(x.Value.Schema); + }); + result.Definitions.Each(x => { + if (x.Value.AllOf != null) + SchemaFilter(x.Value.AllOf); + SchemaFilter(x.Value); + }); + result.Responses.Each(x => { + if (x.Value.Schema != null) + SchemaFilter(x.Value.Schema); + }); + } + + if (OperationFilter != null) + apiPaths.Each(x => GetOperations(x.Value).Each(o => OperationFilter(o.Item1, o.Item2))); + + ApiDeclarationFilter?.Invoke(result); + + return new HttpResult(result) + { + ResultScope = () => JsConfig.With(new Config + { + IncludeNullValues = false, + IncludeNullValuesInDictionaries = false, + IncludeTypeInfo = false, + ExcludeTypeInfo = true, + }) + }; + } + + private IEnumerable> GetOperations(OpenApiPath value) + { + if (value.Get != null) yield return new Tuple("GET", value.Get); + if (value.Post != null) yield return new Tuple("POST", value.Post); + if (value.Put != null) yield return new Tuple("PUT", value.Put); + if (value.Patch != null) yield return new Tuple("PATCH", value.Patch); + if (value.Delete != null) yield return new Tuple("DELETE", value.Delete); + if (value.Head != null) yield return new Tuple("HEAD", value.Head); + if (value.Options != null) yield return new Tuple("OPTIONS", value.Options); + } + + private static readonly Dictionary ClrTypesToSwaggerScalarTypes = new Dictionary { + {typeof(byte[]), OpenApiType.String}, + {typeof(sbyte[]), OpenApiType.String}, + {typeof(byte), OpenApiType.Integer}, + {typeof(sbyte), OpenApiType.Integer}, + {typeof(bool), OpenApiType.Boolean}, + {typeof(short), OpenApiType.Integer}, + {typeof(ushort), OpenApiType.Integer}, + {typeof(int), OpenApiType.Integer}, + {typeof(uint), OpenApiType.Integer}, + {typeof(long), OpenApiType.Integer}, + {typeof(ulong), OpenApiType.Integer}, + {typeof(float), OpenApiType.Number}, + {typeof(double), OpenApiType.Number}, + {typeof(decimal), OpenApiType.Number}, + {typeof(string), OpenApiType.String}, + {typeof(DateTime), OpenApiType.String}, + {typeof(DateTimeOffset), OpenApiType.String}, + }; + + private static readonly Dictionary ClrTypesToSwaggerScalarFormats = new Dictionary { + {typeof(byte[]), OpenApiTypeFormat.Byte}, + {typeof(sbyte[]), OpenApiTypeFormat.Byte}, + {typeof(byte), OpenApiTypeFormat.Int}, + {typeof(sbyte), OpenApiTypeFormat.Int}, + {typeof(short), OpenApiTypeFormat.Int}, + {typeof(ushort), OpenApiTypeFormat.Int}, + {typeof(int), OpenApiTypeFormat.Int}, + {typeof(uint), OpenApiTypeFormat.Int}, + {typeof(long), OpenApiTypeFormat.Long}, + {typeof(ulong), OpenApiTypeFormat.Long}, + {typeof(float), OpenApiTypeFormat.Float}, + {typeof(double), OpenApiTypeFormat.Double}, + {typeof(decimal), OpenApiTypeFormat.Double}, + {typeof(DateTime), OpenApiTypeFormat.DateTime}, + {typeof(DateTimeOffset), OpenApiTypeFormat.DateTime}, + }; + + private static bool IsSwaggerScalarType(Type type) + { + return ClrTypesToSwaggerScalarTypes.ContainsKey(type) + || (Nullable.GetUnderlyingType(type) ?? type).IsEnum + || (type.IsValueType && !IsKeyValuePairType(type)) + || type.IsNullableType(); + } + + private static string GetSwaggerTypeName(Type type) + { + var lookupType = Nullable.GetUnderlyingType(type) ?? type; + + return ClrTypesToSwaggerScalarTypes.ContainsKey(lookupType) + ? ClrTypesToSwaggerScalarTypes[lookupType] + : GetSchemaTypeName(lookupType); + } + + private static string GetSwaggerTypeFormat(Type type, string route = null, string verb = null) + { + var lookupType = Nullable.GetUnderlyingType(type) ?? type; + + //special case for response types byte[]. If byte[] is in response + //then we should use `binary` swagger type, because it's octet-encoded + //otherwise we use `byte` swagger type for base64-encoded input + if (route == null && verb == null && type == typeof(byte[])) + return OpenApiTypeFormat.Binary; + + return ClrTypesToSwaggerScalarFormats.TryGetValue(lookupType, out var format) ? format : null; + } + + private static Type GetListElementType(Type type) + { + if (type.IsArray) return type.GetElementType(); + + if (!type.IsGenericType) return null; + var genericType = type.GetGenericTypeDefinition(); + if (genericType == typeof(List<>) || genericType == typeof(IList<>) || genericType == typeof(IEnumerable<>)) + return type.GetGenericArguments()[0]; + return null; + } + + private static bool IsListType(Type type) + { + //Swagger2 specification has a special data format for type byte[] ('byte', 'binary' or 'file'), so it's not a list + if (type == typeof(byte[])) + return false; + + return GetListElementType(type) != null; + } + + private Dictionary GetOpenApiListItems(Type listItemType, string route, string verb, + string[] enumValues = null) + { + var items = new Dictionary(); + + if (IsSwaggerScalarType(listItemType)) + { + items.Add("type", GetSwaggerTypeName(listItemType)); + items.Add("format", GetSwaggerTypeFormat(listItemType, route, verb)); + if (IsRequiredType(listItemType)) + { + items.Add("x-nullable", false); + } + if (enumValues?.Length > 0) + { + items.Add("enum", enumValues); + } + } + else + { + items.Add("$ref", "#/definitions/" + GetSchemaTypeName(listItemType)); + } + + return items; + } + + private OpenApiSchema GetListSchema(IDictionary schemas, Type schemaType, string route, string verb) + { + if (!IsListType(schemaType)) + return null; + + var listItemType = GetListElementType(schemaType); + ParseDefinitions(schemas, listItemType, route, verb); + + return new OpenApiSchema + { + Title = GetSchemaTypeName(schemaType), + Type = OpenApiType.Array, + Items = GetOpenApiListItems(listItemType, route, verb) + }; + } + + private static bool IsDictionaryType(Type type) + { + if (!type.IsGenericType) return false; + + var genericType = type.GetGenericTypeDefinition(); + if (genericType == typeof(Dictionary<,>) + || genericType == typeof(IDictionary<,>) + || genericType == typeof(IReadOnlyDictionary<,>) + || genericType == typeof(SortedDictionary<,>)) + { + return true; + } + + return false; + } + + private OpenApiSchema GetDictionarySchema(IDictionary schemas, Type schemaType, string route, string verb) + { + if (!IsDictionaryType(schemaType)) + return null; + + var valueType = schemaType.GetGenericArguments()[1]; + + ParseDefinitions(schemas, valueType, route, verb); + + return new OpenApiSchema + { + Title = GetSchemaTypeName(schemaType), + Type = OpenApiType.Object, + Description = schemaType.GetDescription() ?? GetSchemaTypeName(schemaType), + AdditionalProperties = GetOpenApiProperty(schemas, valueType, route, verb) + }; + } + + private static bool IsKeyValuePairType(Type type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>); + } + + private OpenApiSchema GetKeyValuePairSchema(IDictionary schemas, Type schemaType, string route, string verb) + { + if (!IsKeyValuePairType(schemaType)) + return null; + + var keyType = schemaType.GetGenericArguments()[0]; + var valueType = schemaType.GetGenericArguments()[1]; + + return new OpenApiSchema + { + Type = OpenApiType.Object, + Title = GetSchemaTypeName(schemaType), + Description = schemaType.GetDescription() ?? GetSchemaTypeName(schemaType), + Properties = new OrderedDictionary + { + { "Key", GetOpenApiProperty(schemas, keyType, route, verb) }, + { "Value", GetOpenApiProperty(schemas, valueType, route, verb) } + } + }; + } + + private static bool IsRequiredType(Type type) + { + return !type.IsNullableType() && type != typeof(string); + } + + private static string GetSchemaTypeName(Type schemaType) + { + if ((!IsKeyValuePairType(schemaType) && schemaType.IsValueType) || schemaType.IsNullableType()) + return OpenApiType.String; + + if (!schemaType.IsGenericType) + return schemaType.Name; + + var typeName = schemaType.ToPrettyName(); + return typeName; + } + + private static string GetSchemaDefinitionRef(Type schemaType) => + swaggerRefRegex.Replace(GetSchemaTypeName(schemaType), "_"); + + private static readonly Regex swaggerRefRegex = new Regex("[^A-Za-z0-9\\.\\-_]", RegexOptions.Compiled); + + private OpenApiProperty GetOpenApiProperty(IDictionary schemas, PropertyInfo pi, string route, string verb) + { + var ret = GetOpenApiProperty(schemas, pi.PropertyType, route, verb); + ret.PropertyInfo = pi; + return ret; + } + + private OpenApiProperty GetOpenApiProperty(IDictionary schemas, Type propertyType, string route, string verb) + { + var schemaProp = new OpenApiProperty { + PropertyType = propertyType, + }; + + if (IsKeyValuePairType(propertyType)) + { + if (IsInlineSchema(propertyType)) + { + ParseDefinitions(schemas, propertyType, route, verb); + InlineSchema(schemas[GetSchemaTypeName(propertyType)], schemaProp); + } + else + { + ParseDefinitions(schemas, propertyType, route, verb); + schemaProp.Ref = "#/definitions/" + GetSchemaDefinitionRef(propertyType); + } + } + else if (IsListType(propertyType)) + { + schemaProp.Type = OpenApiType.Array; + var listItemType = GetListElementType(propertyType); + if (IsSwaggerScalarType(listItemType)) + { + schemaProp.Items = new Dictionary + { + { "type", GetSwaggerTypeName(listItemType) }, + { "format", GetSwaggerTypeFormat(listItemType, route, verb) } + }; + if (IsRequiredType(listItemType)) + { + schemaProp.Items.Add("x-nullable", false); + //schemaProp.Items.Add("required", "true"); + } + ParseDefinitions(schemas, listItemType, route, verb); + } + else if (IsInlineSchema(listItemType)) + { + ParseDefinitions(schemas, listItemType, route, verb); + InlineSchema(schemas[GetSchemaTypeName(listItemType)], schemaProp); + } + else + { + schemaProp.Items = new Dictionary { { "$ref", "#/definitions/" + GetSchemaDefinitionRef(listItemType) } }; + ParseDefinitions(schemas, listItemType, route, verb); + } + } + else if ((Nullable.GetUnderlyingType(propertyType) ?? propertyType).IsEnum) + { + var enumType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; + if (enumType.IsNumericType()) + { + var underlyingType = Enum.GetUnderlyingType(enumType); + schemaProp.Type = GetSwaggerTypeName(underlyingType); + schemaProp.Format = GetSwaggerTypeFormat(underlyingType, route, verb); + schemaProp.Enum = GetNumericValues(enumType, underlyingType).ToArray(); + } + else + { + schemaProp.Type = OpenApiType.String; + schemaProp.Enum = Enum.GetNames(enumType).ToArray(); + } + } + else if (IsSwaggerScalarType(propertyType)) + { + schemaProp.Type = GetSwaggerTypeName(propertyType); + schemaProp.Format = GetSwaggerTypeFormat(propertyType, route, verb); + schemaProp.Nullable = IsRequiredType(propertyType) ? false : (bool?)null; + //schemaProp.Required = IsRequiredType(propertyType) ? true : (bool?)null; + } + else if (IsInlineSchema(propertyType)) + { + ParseDefinitions(schemas, propertyType, route, verb); + InlineSchema(schemas[GetSchemaTypeName(propertyType)], schemaProp); + } + else + { + ParseDefinitions(schemas, propertyType, route, verb); + schemaProp.Ref = "#/definitions/" + GetSchemaDefinitionRef(propertyType); + } + + return schemaProp; + } + + private static void InlineSchema(OpenApiSchema schema, OpenApiProperty schemaProp) + { + schemaProp.Items = new Dictionary + { + {"title", schema.Title}, + {"discriminator", schema.Discriminator}, + {"readOnly", schema.ReadOnly}, + {"xml", schema.Xml}, + {"externalDocs", schema.ExternalDocs}, + {"example", schema.Example}, + {"required", schema.Required}, + {"allOf", schema.AllOf}, + {"properties", schema.Properties}, + {"additionalProperties", schema.AdditionalProperties}, + {"description", schema.Description}, + {"type", schema.Type}, + {"format", schema.Format}, + {"items", schema.Items}, + {"collectionFormat", schema.CollectionFormat}, + {"default", schema.Default}, + {"maximum", schema.Maximum}, + {"exclusiveMaximum", schema.ExclusiveMaximum}, + {"exclusiveMinimum", schema.ExclusiveMinimum}, + {"maxLength", schema.MaxLength}, + {"minLength", schema.MinLength}, + {"pattern", schema.Pattern}, + {"maxItems", schema.MaxItems}, + {"minItems", schema.MinItems}, + {"uniqueItems", schema.UniqueItems}, + {"maxProperties", schema.MaxProperties}, + {"minProperties", schema.MinProperties}, + {"enum", schema.Enum}, + {"multipleOf", schema.MultipleOf}, + {"x-nullable", schema.Nullable} + }; + } + + protected bool IsInlineSchema(Type schemaType) + { + return InlineSchemaTypesInNamespaces.Contains(schemaType.Namespace); + } + + public Dictionary SchemaIdToClrType { get; } = new Dictionary(); + + private void ParseDefinitions(IDictionary schemas, Type schemaType, string route, string verb) + { + if (IsSwaggerScalarType(schemaType) || schemaType.ExcludesFeature(Feature.Metadata)) return; + + var schemaId = GetSchemaDefinitionRef(schemaType); + if (schemas.ContainsKey(schemaId)) return; + + var schema = GetDictionarySchema(schemas, schemaType, route, verb) + ?? GetKeyValuePairSchema(schemas, schemaType, route, verb) + ?? GetListSchema(schemas, schemaType, route, verb); + + bool parseProperties = false; + + if (schema == null) + { + schema = new OpenApiSchema + { + Type = OpenApiType.Object, + Title = schemaType.Name, + Description = schemaType.GetDescription() ?? GetSchemaTypeName(schemaType), + Properties = new OrderedDictionary() + }; + parseProperties = schemaType.IsUserType(); + } + schemas[schemaId] = schema; + SchemaIdToClrType[schemaId] = schemaType; + + var properties = schemaType.GetProperties(); + + // Order schema properties by DataMember.Order if [DataContract] and [DataMember](s) defined + // Ordering defined by: http://msdn.microsoft.com/en-us/library/ms729813.aspx + var dataContractAttr = schemaType.FirstAttribute(); + if (dataContractAttr != null && properties.Any(prop => prop.IsDefined(typeof(DataMemberAttribute), true))) + { + var typeOrder = new List { schemaType }; + var baseType = schemaType.BaseType; + while (baseType != null) + { + typeOrder.Add(baseType); + baseType = baseType.BaseType; + } + + var propsWithDataMember = properties.Where(prop => prop.IsDefined(typeof(DataMemberAttribute), true)); + var propDataMemberAttrs = properties.ToDictionary(prop => prop, prop => prop.FirstAttribute()); + + properties = propsWithDataMember + .OrderBy(prop => propDataMemberAttrs[prop].Order) // Order by DataMember.Order + .ThenByDescending(prop => typeOrder.IndexOf(prop.DeclaringType)) // Then by BaseTypes First + .ThenBy(prop => // Then by [DataMember].Name / prop.Name + { + var name = propDataMemberAttrs[prop].Name; + return name.IsNullOrEmpty() ? prop.Name : name; + }).ToArray(); + } + + if (parseProperties) + { + foreach (var prop in properties) + { + if (prop.HasAttribute()) + continue; + + var apiMembers = prop + .AllAttributes() + .OrderByDescending(attr => attr.Route) + .ToList(); + var apiDoc = apiMembers + .Where(attr => string.IsNullOrEmpty(verb) || string.IsNullOrEmpty(attr.Verb) || (verb ?? "").Equals(attr.Verb)) + .Where(attr => string.IsNullOrEmpty(route) || string.IsNullOrEmpty(attr.Route) || (route ?? "").StartsWith(attr.Route)) + .FirstOrDefault(attr => attr.ParameterType == "body" || attr.ParameterType == "model"); + + if (apiMembers.Any(x => x.ExcludeInSchema)) + continue; + var schemaProperty = GetOpenApiProperty(schemas, prop, route, verb); + var schemaPropertyName = GetSchemaPropertyName(prop); + + schemaProperty.Description = prop.GetDescription() ?? apiDoc?.Description; + + var propAttr = prop.FirstAttribute(); + if (propAttr != null) + { + if (propAttr.DataType != null) + schemaProperty.Type = propAttr.DataType; + + if (propAttr.Format != null) + schemaProperty.Format = propAttr.Format; + + if (propAttr.IsRequired) + { + if (schema.Required == null) + schema.Required = new List(); + schema.Required.Add(schemaPropertyName); + } + } + + schemaProperty.Enum = GetEnumValues(prop.FirstAttribute()); + + SchemaPropertyFilter?.Invoke(schemaProperty); + + schema.Properties[schemaPropertyName] = schemaProperty; + } + } + } + + private static string GetSchemaPropertyName(PropertyInfo prop) + { + var dataMemberAttr = prop.FirstAttribute(); + if (dataMemberAttr != null && !dataMemberAttr.Name.IsNullOrEmpty()) + return dataMemberAttr.Name; + + return UseCamelCaseSchemaPropertyNames + ? (UseLowercaseUnderscoreSchemaPropertyNames ? prop.Name.ToLowercaseUnderscore() : prop.Name.ToCamelCase()) + : prop.Name; + } + + private static IEnumerable GetNumericValues(Type propertyType, Type underlyingType) + { + var values = Enum.GetValues(propertyType) + .Map(x => $"{Convert.ChangeType(x, underlyingType)} ({x})"); + + return values; + } + + private OpenApiSchema GetResponseSchema(IRestPath restPath, IDictionary schemas, out string schemaDescription) + { + schemaDescription = string.Empty; + + // Given: class MyDto : IReturn. Determine the type X. + foreach (var i in restPath.RequestType.GetInterfaces()) + { + if (i == typeof(IReturnVoid)) + return GetSchemaForResponseType(typeof(void), schemas, out schemaDescription); + + if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IReturn<>)) + { + var schemaType = i.GetGenericArguments()[0]; + return GetSchemaForResponseType(schemaType, schemas, out schemaDescription); + } + } + + return new OpenApiSchema { Ref = "#/definitions/Object" }; + } + + private OpenApiSchema GetSchemaForResponseType(Type schemaType, IDictionary schemas, out string schemaDescription) + { + if (schemaType == typeof(IReturnVoid) || schemaType == typeof(void)) + { + schemaDescription = "No Content"; + return null; + } + + ParseDefinitions(schemas, schemaType, null, null); + + var schema = GetDictionarySchema(schemas, schemaType, null, null) + ?? GetKeyValuePairSchema(schemas, schemaType, null, null) + ?? GetListSchema(schemas, schemaType, null, null) + ?? (IsSwaggerScalarType(schemaType) + ? new OpenApiSchema + { + Title = GetSchemaTypeName(schemaType), + Type = GetSwaggerTypeName(schemaType), + Format = GetSwaggerTypeFormat(schemaType) + } + : IsInlineSchema(schemaType) + ? schemas[GetSchemaTypeName(schemaType)] + : new OpenApiSchema { Ref = "#/definitions/" + GetSchemaDefinitionRef(schemaType) }); + + schemaDescription = schema.Description ?? schemaType.GetDescription() ?? string.Empty; + + return schema; + } + + private OrderedDictionary GetMethodResponseCodes(IRestPath restPath, IDictionary schemas, Type requestType) + { + var responses = new OrderedDictionary(); + + var responseSchema = GetResponseSchema(restPath, schemas, out string schemaDescription); + //schema is null when return type is IReturnVoid + var statusCode = responseSchema == null && HostConfig.Instance.Return204NoContentForEmptyResponse + ? ((int)HttpStatusCode.NoContent).ToString() + : ((int)HttpStatusCode.OK).ToString(); + + responses.Add(statusCode, new OpenApiResponse + { + Schema = responseSchema, + Description = !string.IsNullOrEmpty(schemaDescription) ? schemaDescription : "Success" + }); + + foreach (var attr in requestType.AllAttributes()) + { + string apiSchemaDescription = string.Empty; + + var response = new OpenApiResponse + { + Schema = attr.ResponseType != null + ? GetSchemaForResponseType(attr.ResponseType, schemas, out apiSchemaDescription) + : responseSchema, + Description = attr.Description ?? apiSchemaDescription + }; + + statusCode = attr.IsDefaultResponse ? "default" : attr.StatusCode.ToString(); + if (!responses.ContainsKey(statusCode)) + responses.Add(statusCode, response); + else + responses[statusCode] = response; + } + + return responses; + } + + private OrderedDictionary ParseOperations(List restPaths, Dictionary schemas, Dictionary tags) + { + var feature = HostContext.GetPlugin(); + var apiPaths = new OrderedDictionary(); + + foreach (var restPath in restPaths) + { + var verbs = new List(); + var summary = restPath.Summary ?? restPath.RequestType.GetDescription(); + + verbs.AddRange(restPath.AllowsAllVerbs + ? AnyRouteVerbs + : restPath.Verbs); + + var routePath = restPath.Path.Replace("*", ""); + var requestType = restPath.RequestType; + + if (!apiPaths.TryGetValue(restPath.Path, out var curPath)) + { + curPath = new OpenApiPath + { + Parameters = new List + { + new OpenApiParameter { Ref = "#/parameters/Accept" } + } + }; + apiPaths.Add(restPath.Path, curPath); + } + + var op = HostContext.Metadata.OperationsMap[requestType]; + + var annotatingTagAttributes = requestType.AllAttributes(); + + foreach (var verb in verbs) + { + var needAuth = op.RequiresAuthentication; + + var userTags = new List(); + if (ApplyToUtils.VerbsApplyTo.TryGetValue(verb, out var applyToVerb)) + { + userTags = annotatingTagAttributes.Where(x => x.ApplyTo.HasFlag(applyToVerb)).Select(x => x.Name).ToList(); + } + + var operation = new OpenApiOperation + { + RequestType = requestType.Name, + Summary = summary, + Description = restPath.Notes ?? summary, + OperationId = GetOperationName(requestType.Name, routePath, verb), + Parameters = ParseParameters(schemas, requestType, routePath, verb), + Responses = GetMethodResponseCodes(restPath, schemas, requestType), + Consumes = new List { "application/json" }, + Produces = new List { "application/json" }, + Tags = userTags.Count > 0 ? userTags : GetTags(restPath.Path), + Deprecated = requestType.HasAttribute(), + Security = needAuth ? new List>> { + OperationSecurity + } : null + }; + + if (HasFormData(verb, operation.Parameters)) + operation.Consumes = new List { "application/x-www-form-urlencoded" }; + + foreach (var tag in operation.Tags) + { + if (!tags.ContainsKey(tag)) + { + var tagObject = feature.Tags.FirstOrDefault(x => x.Name == tag) + ?? new OpenApiTag { Name = tag }; + + tags.Add(tag, tagObject); + } + } + + switch (verb) + { + case HttpMethods.Get: curPath.Get = operation; break; + case HttpMethods.Post: curPath.Post = operation; break; + case HttpMethods.Put: curPath.Put = operation; break; + case HttpMethods.Delete: curPath.Delete = operation; break; + case HttpMethods.Patch: curPath.Patch = operation; break; + case HttpMethods.Head: curPath.Head = operation; break; + case HttpMethods.Options: curPath.Options = operation; break; + } + } + } + + return apiPaths; + } + + private bool IsFormData(string verb, ApiAttribute apiAttr) + { + if (verb != HttpMethods.Post && verb != HttpMethods.Put) + return false; + + if (apiAttr?.BodyParameter == GenerateBodyParameter.Always + || (!DisableAutoDtoInBodyParam && apiAttr?.BodyParameter != GenerateBodyParameter.Never)) + return false; + + return true; + } + + private bool HasFormData(string verb, List parameters) + { + return (verb == HttpMethods.Post || verb == HttpMethods.Put) && parameters.Any(p => p.In == "formData"); + } + + static readonly Dictionary postfixes = new Dictionary() + { + { HttpMethods.Get, "_Get" }, //'Get' or 'List' to pass Autorest validation + { HttpMethods.Put, "_Create" }, //'Create' to pass Autorest validation + { HttpMethods.Post, "_Post" }, + { HttpMethods.Patch, "_Update" }, //'Update' to pass Autorest validation + { HttpMethods.Delete, "_Delete" } //'Delete' to pass Autorest validation + }; + + + HashSet operationIds = new(); + + /// Returns operation postfix to make operationId unique and swagger json be validable + private string GetOperationName(string name, string route, string verb) + { + string pathPostfix = string.Empty; + + var entries = route.Replace("{", string.Empty) + .Replace("}", string.Empty) + .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + if (entries.Length > 1) + pathPostfix = string.Join(string.Empty, entries, 1, entries.Length - 1); + + postfixes.TryGetValue(verb, out var verbPostfix); + verbPostfix ??= string.Empty; + + var operationId = name + pathPostfix + verbPostfix; + + int num = 2; + while (operationIds.Contains(operationId)) + { + operationId = name + pathPostfix + num + verbPostfix; + num++; + } + + operationIds.Add(operationId); + + return operationId; + } + + private static string[] GetEnumValues(ApiAllowableValuesAttribute attr) + { + return attr?.Values?.ToArray(); + } + + private List ParseParameters(IDictionary schemas, Type operationType, string route, string verb) + { + var hasDataContract = operationType.HasAttribute(); + var apiAttr = operationType.FirstAttribute(); + + var properties = operationType.GetProperties(); + var paramAttrs = new Dictionary(); + var propertyTypes = new Dictionary(); + var allowableParams = new List(); + var defaultOperationParameters = new List(); + + var hasApiMembers = false; + + foreach (var property in properties) + { + if (property.HasAttribute()) + continue; + + var attr = hasDataContract + ? property.FirstAttribute() + : null; + + var propertyName = attr?.Name ?? property.Name; + + var apiMembers = property.AllAttributes(); + if (apiMembers.Length > 0) + hasApiMembers = true; + + paramAttrs[propertyName] = apiMembers; + propertyTypes[propertyName] = property.PropertyType; + var allowableValuesAttr = property.FirstAttribute(); + + if (hasDataContract && attr == null) + continue; + + var inPath = (route ?? "").ToLowerInvariant().Contains("{" + propertyName.ToLowerInvariant() + "}"); + var paramType = inPath + ? "path" + : IsFormData(verb, apiAttr) ? "formData" : "query"; + + + var parameter = GetParameter(schemas, property.PropertyType, + route, verb, + propertyName, paramType, + enumValues: allowableValuesAttr != null + ? GetEnumValues(allowableValuesAttr) + : Html.Input.GetEnumValues(property.PropertyType)); + + defaultOperationParameters.Add(parameter); + } + + var methodOperationParameters = defaultOperationParameters; + if (hasApiMembers) + { + methodOperationParameters = new List(); + foreach (var key in paramAttrs.Keys) + { + var apiMembers = paramAttrs[key]; + foreach (var member in apiMembers) + { + if ((member.Verb == null || string.Compare(member.Verb, verb, StringComparison.OrdinalIgnoreCase) == 0) + && (member.Route == null || (route ?? "").StartsWith(member.Route)) + && !string.Equals(member.ParameterType, "model") + && methodOperationParameters.All(x => x.Name != (member.Name ?? key))) + { + var allowableValuesAttr = allowableParams.FirstOrDefault(attr => attr.Name == (member.Name ?? key)); + var p = GetParameter(schemas, propertyTypes[key], route, verb, + member.Name ?? key, + member.GetParamType(operationType, member.Verb ?? verb), + enumValues: allowableValuesAttr != null + ? GetEnumValues(allowableValuesAttr) + : Html.Input.GetEnumValues(propertyTypes[key]), + true + ); + p.Type = member.DataType ?? p.Type; + p.Format = member.Format ?? p.Format; + p.Required = p.In =="path" || member.IsRequired; + p.Description = member.Description ?? p.Description; + + //Fix old Swagger 1.2 parameter type + if (p.In == "form") + p.In = "formData"; + + methodOperationParameters.Add(p); + } + } + } + } + + if (apiAttr?.BodyParameter == GenerateBodyParameter.Always + || (!DisableAutoDtoInBodyParam && apiAttr?.BodyParameter != GenerateBodyParameter.Never)) + { + if (!HttpMethods.Get.EqualsIgnoreCase(verb) && !HttpMethods.Delete.EqualsIgnoreCase(verb) + && !methodOperationParameters.Any(p => "body".EqualsIgnoreCase(p.In))) + { + ParseDefinitions(schemas, operationType, route, verb); + + var parameter = GetParameter(schemas, operationType, route, verb, "body", "body"); + + if (apiAttr?.IsRequired == true) + parameter.Required = true; + + methodOperationParameters.Add(parameter); + } + } + + return methodOperationParameters; + } + + private OpenApiParameter GetParameter(IDictionary schemas, Type schemaType, string route, string verb, string paramName, string paramIn, + string[] enumValues = null, + bool isApiMember = false) + { + //Compatibility: replace old Swagger ParamType to new Open API + if (paramIn == "form") paramIn = "formData"; + + if (IsSwaggerScalarType(schemaType)) + { + return new OpenApiParameter + { + In = paramIn, + Name = paramName, + Type = GetSwaggerTypeName(schemaType), + Format = GetSwaggerTypeFormat(schemaType, route, verb), + Enum = enumValues, + Nullable = IsRequiredType(schemaType) ? false : (bool?)null, + Required = paramIn == "path" ? true : (bool?)null + }; + } + + if (paramIn != "body" && !isApiMember) + { + return new OpenApiParameter + { + In = paramIn, + Name = paramName, + Type = OpenApiType.String, + Required = paramIn == "path" ? true : (bool?)null + }; + } + + if (IsDictionaryType(schemaType)) + { + return new OpenApiParameter + { + In = paramIn, + Name = paramName, + Schema = GetDictionarySchema(schemas, schemaType, route, verb) + }; + } + + if (IsListType(schemaType)) + { + return GetListParameter(schemas, schemaType, route, verb, paramName, paramIn, enumValues:enumValues); + } + + OpenApiSchema openApiSchema; + + if (IsInlineSchema(schemaType)) + { + openApiSchema = schemas[GetSchemaTypeName(schemaType)]; + } + else + { + openApiSchema = new OpenApiSchema {Ref = "#/definitions/" + GetSchemaTypeName(schemaType)}; + } + + return new OpenApiParameter + { + In = paramIn, + Name = paramName, + Schema = openApiSchema + }; + } + + private List GetTags(string path) + { + var tagName = GetTagName(path); + return tagName != null ? new List { tagName } : null; + } + + private string GetTagName(string path) + { + var tags = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + return tags.Length > 0 ? tags[0] : null; + } + + private OpenApiParameter GetListParameter(IDictionary schemas, Type listType, string route, string verb, string paramName, string paramIn, + string[] enumValues = null) + { + if (!IsListType(listType)) + return null; + + var parameter = new OpenApiParameter + { + Type = OpenApiType.Array, + CollectionFormat = "multi", + Description = listType.GetDescription(), + Name = paramName, + In = paramIn, + Required = paramIn == "path" + }; + + var listItemType = GetListElementType(listType); + ParseDefinitions(schemas, listItemType, route, verb); + parameter.Items = GetOpenApiListItems(listItemType, route, verb, enumValues: enumValues); + + return parameter; + } + + private OpenApiParameter GetAcceptHeaderParameter() + { + return new OpenApiParameter + { + Type = OpenApiType.String, + Name = "Accept", + Description = "Accept Header", + Enum = new [] { "application/json" }, + In = "header", + Required = true, + }; + } + } +} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/Properties/AssemblyInfo.cs b/src/ServiceStack.Api.OpenApi/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..35fb1bf4708 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +[assembly: System.Runtime.InteropServices.ComVisible(false)] +[assembly: System.Runtime.InteropServices.Guid("1dfebd7c-72e5-423e-8e0b-6da176ba34b8")] +[assembly: System.Reflection.AssemblyVersion("6.0.0.0")] + +[assembly: System.Runtime.Serialization.ContractNamespace("http://schemas.servicestack.net/types", + ClrNamespace = "ServiceStack.Api.OpenApi")] diff --git a/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.Core.csproj b/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.Core.csproj new file mode 100644 index 00000000000..d91d088e68d --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.Core.csproj @@ -0,0 +1,37 @@ + + + + ServiceStack.Api.OpenApi.Core + ServiceStack.Api.OpenApi + ServiceStack.Api.OpenApi + netstandard2.0;net6.0 + ServiceStack.Api.OpenApi .NET Standard 2.0 + + Implements v2.0 of the Open API Specification (https://www.openapis.org). + Open API is a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services. + + OpenAPI;metadata;Swagger;API;REST;Metadata;Docs;ServiceStack + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.Source.csproj b/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.Source.csproj new file mode 100644 index 00000000000..a430e1d4a47 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.Source.csproj @@ -0,0 +1,38 @@ + + + + ServiceStack.Api.OpenApi + ServiceStack.Api.OpenApi + ServiceStack.Api.OpenApi + netstandard2.0;net6.0 + ServiceStack support for Open API v2.0 and integrated Swagger UI + + Implements v2.0 of the Open API Specification (https://www.openapis.org). + Open API is a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services. + + OpenAPI;metadata;Swagger;API;REST;Metadata;Docs;ServiceStack + false + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.csproj b/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.csproj new file mode 100644 index 00000000000..7eaaed349f7 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/ServiceStack.Api.OpenApi.csproj @@ -0,0 +1,41 @@ + + + + ServiceStack.Api.OpenApi + ServiceStack.Api.OpenApi + net472;netstandard2.0;net6.0 + ServiceStack support for Open API v2.0 and integrated Swagger UI + + Implements v2.0 of the Open API Specification (https://www.openapis.org). + Open API is a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services. + + OpenAPI;metadata;Swagger;API;REST;Metadata;Docs;ServiceStack + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiContact.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiContact.cs new file mode 100644 index 00000000000..c0f4709154b --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiContact.cs @@ -0,0 +1,15 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiContact + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "url")] + public string Url { get; set; } + [DataMember(Name = "email")] + public string Email { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiDataTypeSchema.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiDataTypeSchema.cs new file mode 100644 index 00000000000..7d51e87337e --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiDataTypeSchema.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + //from https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-parameterMaximum + [DataContract] + public abstract class OpenApiDataTypeSchema + { + [DataMember(Name = "$ref")] + public string Ref { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "type")] + public string Type { get; set; } + [DataMember(Name = "format")] + public string Format { get; set; } + [DataMember(Name = "items")] + public Dictionary Items { get; set; } + [DataMember(Name = "collectionFormat")] + public string CollectionFormat { get; set; } + [DataMember(Name = "default")] + public string Default { get; set; } + [DataMember(Name = "maximum")] + public double? Maximum { get; set; } + [DataMember(Name = "exclusiveMaximum")] + public bool? ExclusiveMaximum { get; set; } + [DataMember(Name = "minimum")] + public double? Minimum { get; set; } + [DataMember(Name = "exclusiveMinimum")] + public bool? ExclusiveMinimum { get; set; } + [DataMember(Name = "maxLength")] + public int? MaxLength { get; set; } + [DataMember(Name = "minLength")] + public int? MinLength { get; set; } + [DataMember(Name = "pattern")] + public string Pattern { get; set; } + [DataMember(Name = "maxItems")] + public int? MaxItems { get; set; } + [DataMember(Name = "minItems")] + public int? MinItems { get; set; } + [DataMember(Name = "uniqueItems")] + public bool? UniqueItems { get; set; } + [DataMember(Name = "maxProperties")] + public string MaxProperties { get; set; } + [DataMember(Name = "minProperties")] + public string MinProperties { get; set; } + [DataMember(Name = "required")] + public bool? Required { get; set; } + [DataMember(Name = "enum")] + public string[] Enum { get; set; } + [DataMember(Name = "multipleOf")] + public double? MultipleOf { get; set; } + [DataMember(Name = "x-nullable")] + public bool? Nullable { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiDeclaration.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiDeclaration.cs new file mode 100644 index 00000000000..8083a9fba5d --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiDeclaration.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack.Api.OpenApi.Support; +using ServiceStack.DataAnnotations; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + [ExcludeMetadata] + public class OpenApiDeclaration + { + [DataMember(Name = "swagger")] + public string Swagger => "2.0"; + + [DataMember(Name = "info")] + public OpenApiInfo Info { get; set; } + + [DataMember(Name = "host")] + public string Host { get; set; } + + [DataMember(Name = "basePath")] + public string BasePath { get; set; } + + [DataMember(Name = "schemes")] + public List Schemes { get; set; } + + [DataMember(Name = "consumes")] + public List Consumes { get; set; } + + [DataMember(Name = "produces")] + public List Produces { get; set; } + + [DataMember(Name = "paths")] + public OrderedDictionary Paths { get; set; } + + [DataMember(Name = "definitions")] + public Dictionary Definitions { get; set; } + + [DataMember(Name = "parameters")] + public Dictionary Parameters { get; set; } + + [DataMember(Name = "responses")] + public OrderedDictionary Responses { get; set; } + + [DataMember(Name = "securityDefinitions")] + public Dictionary SecurityDefinitions { get; set; } + + [DataMember(Name = "security")] + public List>> Security { get; set; } + + [DataMember(Name = "tags")] + public List Tags { get; set; } + + [DataMember(Name = "externalDocs")] + public OpenApiExternalDocumentation ExternalDocs { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiExternalDocumentation.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiExternalDocumentation.cs new file mode 100644 index 00000000000..2ea7854ce05 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiExternalDocumentation.cs @@ -0,0 +1,13 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiExternalDocumentation + { + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "url")] + public string Url { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiInfo.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiInfo.cs new file mode 100644 index 00000000000..a688a559878 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiInfo.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiInfo + { + [DataMember(Name = "title")] + public string Title { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "termsOfServiceUrl")] + public string TermsOfServiceUrl { get; set; } + [DataMember(Name = "contact")] + public OpenApiContact Contact { get; set; } + [DataMember(Name = "license")] + public OpenApiLicense License { get; set; } + [DataMember(Name = "version")] + public string Version { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiLicense.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiLicense.cs new file mode 100644 index 00000000000..811de391ac6 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiLicense.cs @@ -0,0 +1,13 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiLicense + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "url")] + public string Url { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiOperation.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiOperation.cs new file mode 100644 index 00000000000..0dcbdc0f6f8 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiOperation.cs @@ -0,0 +1,40 @@ +using ServiceStack.Api.OpenApi.Support; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiOperation + { + //Custom: Request DTO Name to help with custom filtering + [IgnoreDataMember] + public string RequestType { get; set; } + + [DataMember(Name = "tags")] + public List Tags { get; set; } + [DataMember(Name = "summary")] + public string Summary { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "externalDocs")] + public OpenApiExternalDocumentation ExternalDocs { get; set; } + [DataMember(Name = "operationId")] + public string OperationId { get; set; } + [DataMember(Name = "consumes")] + public List Consumes { get; set; } + [DataMember(Name = "produces")] + public List Produces { get; set; } + [DataMember(Name = "parameters")] + public List Parameters { get; set; } + [DataMember(Name = "responses")] + public OrderedDictionary Responses { get; set; } + [DataMember(Name = "schemes")] + public List Schemes { get; set; } + [DataMember(Name = "deprecated")] + public bool Deprecated { get; set; } + [DataMember(Name = "security")] + public List>> Security { get; set; } + } + +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiParameter.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiParameter.cs new file mode 100644 index 00000000000..7b004e51267 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiParameter.cs @@ -0,0 +1,17 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiParameter : OpenApiDataTypeSchema + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "in")] + public string In { get; set; } + [DataMember(Name = "schema")] + public OpenApiSchema Schema { get; set; } + [DataMember(Name = "allowEmptyValue")] + public bool? AllowEmptyValue { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiPath.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiPath.cs new file mode 100644 index 00000000000..675d9a5dd87 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiPath.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiPath + { + [DataMember(Name = "$ref")] + public string Ref { get; set; } + [DataMember(Name = "get")] + public OpenApiOperation Get { get; set; } + [DataMember(Name = "put")] + public OpenApiOperation Put { get; set; } + [DataMember(Name = "post")] + public OpenApiOperation Post { get; set; } + [DataMember(Name = "delete")] + public OpenApiOperation Delete { get; set; } + [DataMember(Name = "options")] + public OpenApiOperation Options { get; set; } + [DataMember(Name = "head")] + public OpenApiOperation Head { get; set; } + [DataMember(Name = "patch")] + public OpenApiOperation Patch { get; set; } + [DataMember(Name = "parameters")] + public List Parameters { get; set; } + } + +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiProperty.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiProperty.cs new file mode 100644 index 00000000000..2eef9d4e561 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiProperty.cs @@ -0,0 +1,15 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiProperty : OpenApiDataTypeSchema + { + [IgnoreDataMember] + public PropertyInfo PropertyInfo { get; set; } + [IgnoreDataMember] + public Type PropertyType { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiResponse.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiResponse.cs new file mode 100644 index 00000000000..0e0578b8f0b --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiResponse.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiResponse + { + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "schema")] + public OpenApiSchema Schema { get; set; } + [DataMember(Name = "headers")] + public Dictionary Headers { get; set; } + [DataMember(Name = "examples")] + public Dictionary Examples { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiSchema.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiSchema.cs new file mode 100644 index 00000000000..3ffa870e02f --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiSchema.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using ServiceStack.Api.OpenApi.Support; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiSchema : OpenApiDataTypeSchema + { + [DataMember(Name = "title")] + public string Title { get; set; } + [DataMember(Name = "discriminator")] + public string Discriminator { get; set; } + [DataMember(Name = "readOnly")] + public bool? ReadOnly { get; set; } + [DataMember(Name = "xml")] + public OpenApiXmlObject Xml { get; set; } + [DataMember(Name = "externalDocs")] + public OpenApiExternalDocumentation ExternalDocs { get; set; } + [DataMember(Name = "example")] + public string Example { get; set; } + + [DataMember(Name = "required")] + public new List Required { get; set; } + + [DataMember(Name = "allOf")] + public OpenApiSchema AllOf { get; set; } + [DataMember(Name = "properties")] + public OrderedDictionary Properties { get; set; } + [DataMember(Name = "additionalProperties")] + public OpenApiProperty AdditionalProperties { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiSecurity.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiSecurity.cs new file mode 100644 index 00000000000..931a89078ae --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiSecurity.cs @@ -0,0 +1,15 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiSecurity + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "externalDocs")] + public OpenApiExternalDocumentation ExternalDocs { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiSecuritySchema.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiSecuritySchema.cs new file mode 100644 index 00000000000..2b83208f06a --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiSecuritySchema.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiSecuritySchema + { + [DataMember(Name = "type")] + public string Type { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "in")] + public string In { get; set; } + [DataMember(Name = "flow")] + public string Flow { get; set; } + [DataMember(Name = "authorizationUrl")] + public string AuthorizationUrl { get; set; } + [DataMember(Name = "tokenUrl")] + public string TokenUrl { get; set; } + [DataMember(Name = "scopes")] + public Dictionary Scopes { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiTag.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiTag.cs new file mode 100644 index 00000000000..bfa7433c02d --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiTag.cs @@ -0,0 +1,17 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiTag + { + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "description")] + public string Description { get; set; } + + [DataMember(Name = "externalDocs")] + public OpenApiExternalDocumentation ExternalDocs { get; set; } + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiType.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiType.cs new file mode 100644 index 00000000000..cd02aabf0d9 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiType.cs @@ -0,0 +1,26 @@ +namespace ServiceStack.Api.OpenApi.Specification +{ + public static class OpenApiType + { + public const string Array = "array"; + public const string Boolean = "boolean"; + public const string Number = "number"; + public const string Integer = "integer"; + public const string String = "string"; + public const string Object = "object"; + } + + public static class OpenApiTypeFormat + { + public const string Array = "int32"; + public const string Byte = "byte"; + public const string Binary = "binary"; + public const string Date = "date"; + public const string DateTime = "date-time"; + public const string Double = "double"; + public const string Float = "float"; + public const string Int = "int32"; + public const string Long = "int64"; + public const string Password = "password"; + } +} diff --git a/src/ServiceStack.Api.OpenApi/Specification/OpenApiXmlObject.cs b/src/ServiceStack.Api.OpenApi/Specification/OpenApiXmlObject.cs new file mode 100644 index 00000000000..a01f72efe3b --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Specification/OpenApiXmlObject.cs @@ -0,0 +1,20 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Api.OpenApi.Specification +{ + [DataContract] + public class OpenApiXmlObject + { + [DataMember(Name = "name")] + public string Name { get; set; } + [DataMember(Name = "namespace")] + public string Namespace { get; set; } + [DataMember(Name = "prefix")] + public string Prefix { get; set; } + [DataMember(Name = "attribute")] + public bool Attribute { get; set; } + [DataMember(Name = "wrapped")] + public bool Wrapped { get; set; } + } + +} diff --git a/src/ServiceStack.Api.OpenApi/Support/IOrderedDictionary.cs b/src/ServiceStack.Api.OpenApi/Support/IOrderedDictionary.cs new file mode 100644 index 00000000000..23703a0073e --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Support/IOrderedDictionary.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace ServiceStack.Api.OpenApi.Support +{ + /// + /// Represents a generic collection of key/value pairs that are ordered independently of the key and value. + /// + /// The type of the keys in the dictionary + /// The type of the values in the dictionary + public interface IOrderedDictionary + : IOrderedDictionary, IDictionary + { + /// + /// Adds an entry with the specified key and value into the IOrderedDictionary<TKey,TValue> collection with the lowest available index. + /// + /// The key of the entry to add. + /// The value of the entry to add. + /// The index of the newly added entry + /// + /// You can also use the property to add new elements by setting the value of a key that does not exist in the IOrderedDictionary<TKey,TValue> collection; however, if the specified key already exists in the IOrderedDictionary<TKey,TValue>, setting the property overwrites the old value. In contrast, the method does not modify existing elements. + /// An element with the same key already exists in the IOrderedDictionary<TKey,TValue> + /// The IOrderedDictionary<TKey,TValue> is read-only.
      + /// -or-
      + /// The IOrderedDictionary<TKey,TValue> has a fized size.
      + new int Add(TKey key, TValue value); + + /// + /// Inserts a new entry into the IOrderedDictionary<TKey,TValue> collection with the specified key and value at the specified index. + /// + /// The zero-based index at which the element should be inserted. + /// The key of the entry to add. + /// The value of the entry to add. The value can be if the type of the values in the dictionary is a reference type. + /// is less than 0.
      + /// -or-
      + /// is greater than .
      + /// An element with the same key already exists in the IOrderedDictionary<TKey,TValue>. + /// The IOrderedDictionary<TKey,TValue> is read-only.
      + /// -or-
      + /// The IOrderedDictionary<TKey,TValue> has a fized size.
      + void Insert(int index, TKey key, TValue value); + + /// + /// Gets or sets the value at the specified index. + /// + /// The zero-based index of the value to get or set. + /// The value of the item at the specified index. + /// is less than 0.
      + /// -or-
      + /// is equal to or greater than .
      + new TValue this[int index] + { + get; + set; + } + } +} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/Support/OrderedDictionary.cs b/src/ServiceStack.Api.OpenApi/Support/OrderedDictionary.cs new file mode 100644 index 00000000000..3b68772d1c5 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/Support/OrderedDictionary.cs @@ -0,0 +1,642 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace ServiceStack.Api.OpenApi.Support +{ + /// + /// Represents a generic collection of key/value pairs that are ordered independently of the key and value. + /// + /// The type of the keys in the dictionary + /// The type of the values in the dictionary + public class OrderedDictionary : IOrderedDictionary + { + private const int DefaultInitialCapacity = 0; + + private static readonly string KeyTypeName = typeof(TKey).FullName; + private static readonly string ValueTypeName = typeof(TValue).FullName; + private static readonly bool ValueTypeIsReferenceType = !typeof(ValueType).IsAssignableFrom(typeof(TValue)); + + private Dictionary dictionary; + private List> list; + private readonly IEqualityComparer comparer; + private object syncRoot; + private readonly int initialCapacity; + + /// + /// Initializes a new instance of the OrderedDictionary<TKey,TValue> class. + /// + public OrderedDictionary() + : this(DefaultInitialCapacity, null) + { + } + + /// + /// Initializes a new instance of the OrderedDictionary<TKey,TValue> class using the specified initial capacity. + /// + /// The initial number of elements that the OrderedDictionary<TKey,TValue> can contain. + /// is less than 0 + public OrderedDictionary(int capacity) + : this(capacity, null) + { + } + + /// + /// Initializes a new instance of the OrderedDictionary<TKey,TValue> class using the specified comparer. + /// + /// The IEqualityComparer<TKey> to use when comparing keys, or to use the default EqualityComparer<TKey> for the type of the key. + public OrderedDictionary(IEqualityComparer comparer) + : this(DefaultInitialCapacity, comparer) + { + } + + /// + /// Initializes a new instance of the OrderedDictionary<TKey,TValue> class using the specified initial capacity and comparer. + /// + /// The initial number of elements that the OrderedDictionary<TKey,TValue> collection can contain. + /// The IEqualityComparer<TKey> to use when comparing keys, or to use the default EqualityComparer<TKey> for the type of the key. + /// is less than 0 + public OrderedDictionary(int capacity, IEqualityComparer comparer) + { + if (0 > capacity) + throw new ArgumentOutOfRangeException("capacity", "'capacity' must be non-negative"); + + initialCapacity = capacity; + this.comparer = comparer; + } + + /// + /// Converts the object passed as a key to the key type of the dictionary + /// + /// The key object to check + /// The key object, cast as the key type of the dictionary + /// is . + /// The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . + private static TKey ConvertToKeyType(object keyObject) + { + if (null == keyObject) + { + throw new ArgumentNullException("key"); + } + else + { + if (keyObject is TKey) + return (TKey)keyObject; + } + throw new ArgumentException("'key' must be of type " + KeyTypeName, "key"); + } + + /// + /// Converts the object passed as a value to the value type of the dictionary + /// + /// The object to convert to the value type of the dictionary + /// The value object, converted to the value type of the dictionary + /// is , and the value type of the OrderedDictionary<TKey,TValue> is a value type. + /// The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . + private static TValue ConvertToValueType(object value) + { + if (null == value) + { + if (ValueTypeIsReferenceType) + return default(TValue); + else + throw new ArgumentNullException("value"); + } + else + { + if (value is TValue) + return (TValue)value; + } + throw new ArgumentException("'value' must be of type " + ValueTypeName, "value"); + } + + /// + /// Gets the dictionary object that stores the keys and values + /// + /// The dictionary object that stores the keys and values for the OrderedDictionary<TKey,TValue> + /// Accessing this property will create the dictionary object if necessary + private Dictionary Dictionary + { + get + { + if (null == dictionary) + { + dictionary = new Dictionary(initialCapacity, comparer); + } + return dictionary; + } + } + + /// + /// Gets the list object that stores the key/value pairs. + /// + /// The list object that stores the key/value pairs for the OrderedDictionary<TKey,TValue> + /// Accessing this property will create the list object if necessary. + private List> List + { + get + { + if (null == list) + { + list = new List>(initialCapacity); + } + return list; + } + } + + IDictionaryEnumerator IOrderedDictionary.GetEnumerator() + { + return Dictionary.GetEnumerator(); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return Dictionary.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return List.GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return List.GetEnumerator(); + } + + /// + /// Inserts a new entry into the OrderedDictionary<TKey,TValue> collection with the specified key and value at the specified index. + /// + /// The zero-based index at which the element should be inserted. + /// The key of the entry to add. + /// The value of the entry to add. The value can be if the type of the values in the dictionary is a reference type. + /// is less than 0.
      + /// -or-
      + /// is greater than .
      + /// is . + /// An element with the same key already exists in the OrderedDictionary<TKey,TValue>. + public void Insert(int index, TKey key, TValue value) + { + if (index > Count || index < 0) + throw new ArgumentOutOfRangeException("index"); + + Dictionary.Add(key, value); + List.Insert(index, new KeyValuePair(key, value)); + } + + /// + /// Inserts a new entry into the OrderedDictionary<TKey,TValue> collection with the specified key and value at the specified index. + /// + /// The zero-based index at which the element should be inserted. + /// The key of the entry to add. + /// The value of the entry to add. The value can be if the type of the values in the dictionary is a reference type. + /// is less than 0.
      + /// -or-
      + /// is greater than .
      + /// is .
      + /// -or-
      + /// is , and the value type of the OrderedDictionary<TKey,TValue> is a value type.
      + /// The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      + /// -or-
      + /// The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      + /// -or-
      + /// An element with the same key already exists in the OrderedDictionary<TKey,TValue>.
      + void IOrderedDictionary.Insert(int index, object key, object value) + { + Insert(index, ConvertToKeyType(key), ConvertToValueType(value)); + } + + /// + /// Removes the entry at the specified index from the OrderedDictionary<TKey,TValue> collection. + /// + /// The zero-based index of the entry to remove. + /// is less than 0.
      + /// -or-
      + /// index is equal to or greater than .
      + public void RemoveAt(int index) + { + if (index >= Count || index < 0) + throw new ArgumentOutOfRangeException("index", "'index' must be non-negative and less than the size of the collection"); + + TKey key = List[index].Key; + + List.RemoveAt(index); + Dictionary.Remove(key); + } + + /// + /// Gets or sets the value at the specified index. + /// + /// The zero-based index of the value to get or set. + /// The value of the item at the specified index. + /// is less than 0.
      + /// -or-
      + /// index is equal to or greater than .
      + public TValue this[int index] + { + get + { + return List[index].Value; + } + + set + { + if (index >= Count || index < 0) + throw new ArgumentOutOfRangeException("index", "'index' must be non-negative and less than the size of the collection"); + + TKey key = List[index].Key; + + List[index] = new KeyValuePair(key, value); + Dictionary[key] = value; + } + } + + /// + /// Gets or sets the value at the specified index. + /// + /// The zero-based index of the value to get or set. + /// The value of the item at the specified index. + /// is less than 0.
      + /// -or-
      + /// index is equal to or greater than .
      + /// is a null reference, and the value type of the OrderedDictionary<TKey,TValue> is a value type. + /// The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . + object IOrderedDictionary.this[int index] + { + get + { + return this[index]; + } + + set + { + this[index] = ConvertToValueType(value); + } + } + + /// + /// Adds an entry with the specified key and value into the OrderedDictionary<TKey,TValue> collection with the lowest available index. + /// + /// The key of the entry to add. + /// The value of the entry to add. This value can be . + /// A key cannot be , but a value can be. + /// You can also use the property to add new elements by setting the value of a key that does not exist in the OrderedDictionary<TKey,TValue> collection; however, if the specified key already exists in the OrderedDictionary<TKey,TValue>, setting the property overwrites the old value. In contrast, the method does not modify existing elements. + /// is + /// An element with the same key already exists in the OrderedDictionary<TKey,TValue> + void IDictionary.Add(TKey key, TValue value) + { + Add(key, value); + } + + /// + /// Adds an entry with the specified key and value into the OrderedDictionary<TKey,TValue> collection with the lowest available index. + /// + /// The key of the entry to add. + /// The value of the entry to add. This value can be . + /// The index of the newly added entry + /// A key cannot be , but a value can be. + /// You can also use the property to add new elements by setting the value of a key that does not exist in the OrderedDictionary<TKey,TValue> collection; however, if the specified key already exists in the OrderedDictionary<TKey,TValue>, setting the property overwrites the old value. In contrast, the method does not modify existing elements. + /// is + /// An element with the same key already exists in the OrderedDictionary<TKey,TValue> + public int Add(TKey key, TValue value) + { + Dictionary.Add(key, value); + List.Add(new KeyValuePair(key, value)); + return Count - 1; + } + + /// + /// Adds an entry with the specified key and value into the OrderedDictionary<TKey,TValue> collection with the lowest available index. + /// + /// The key of the entry to add. + /// The value of the entry to add. This value can be . + /// is .
      + /// -or-
      + /// is , and the value type of the OrderedDictionary<TKey,TValue> is a value type.
      + /// The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      + /// -or-
      + /// The value type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of .
      + void IDictionary.Add(object key, object value) + { + Add(ConvertToKeyType(key), ConvertToValueType(value)); + } + + /// + /// Removes all elements from the OrderedDictionary<TKey,TValue> collection. + /// + /// The capacity is not changed as a result of calling this method. + public void Clear() + { + Dictionary.Clear(); + List.Clear(); + } + + /// + /// Determines whether the OrderedDictionary<TKey,TValue> collection contains a specific key. + /// + /// The key to locate in the OrderedDictionary<TKey,TValue> collection. + /// if the OrderedDictionary<TKey,TValue> collection contains an element with the specified key; otherwise, . + /// is + public bool ContainsKey(TKey key) + { + return Dictionary.ContainsKey(key); + } + /// + /// Determines whether the OrderedDictionary<TKey,TValue> collection contains a specific key. + /// + /// The key to locate in the OrderedDictionary<TKey,TValue> collection. + /// if the OrderedDictionary<TKey,TValue> collection contains an element with the specified key; otherwise, . + /// is + /// The key type of the OrderedDictionary<TKey,TValue> is not in the inheritance hierarchy of . + bool IDictionary.Contains(object key) + { + return ContainsKey(ConvertToKeyType(key)); + } + + /// + /// Gets a value indicating whether the OrderedDictionary<TKey,TValue> has a fixed size. + /// + /// if the OrderedDictionary<TKey,TValue> has a fixed size; otherwise, . The default is . + bool IDictionary.IsFixedSize + { + get + { + return false; + } + } + + /// + /// Gets a value indicating whether the OrderedDictionary<TKey,TValue> collection is read-only. + /// + /// if the OrderedDictionary<TKey,TValue> is read-only; otherwise, . The default is . + /// + /// A collection that is read-only does not allow the addition, removal, or modification of elements after the collection is created. + /// A collection that is read-only is simply a collection with a wrapper that prevents modification of the collection; therefore, if changes are made to the underlying collection, the read-only collection reflects those changes. + /// + public bool IsReadOnly + { + get + { + return false; + } + } + + /// + /// Gets an object containing the keys in the OrderedDictionary<TKey,TValue>. + /// + /// An object containing the keys in the OrderedDictionary<TKey,TValue>. + /// The returned object is not a static copy; instead, the collection refers back to the keys in the original OrderedDictionary<TKey,TValue>. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the key collection. + ICollection IDictionary.Keys + { + get + { + return (ICollection)Keys; + } + } + + /// + /// Returns the zero-based index of the specified key in the OrderedDictionary<TKey,TValue> + /// + /// The key to locate in the OrderedDictionary<TKey,TValue> + /// The zero-based index of , if is found in the OrderedDictionary<TKey,TValue>; otherwise, -1 + /// This method performs a linear search; therefore it has a cost of O(n) at worst. + public int IndexOfKey(TKey key) + { + if (null == key) + throw new ArgumentNullException("key"); + + for (int index = 0; index < List.Count; index++) + { + KeyValuePair entry = List[index]; + TKey next = entry.Key; + if (null != comparer) + { + if (comparer.Equals(next, key)) + { + return index; + } + } + else if (next.Equals(key)) + { + return index; + } + } + + return -1; + } + + /// + /// Removes the entry with the specified key from the OrderedDictionary<TKey,TValue> collection. + /// + /// The key of the entry to remove + /// if the key was found and the corresponding element was removed; otherwise, + public bool Remove(TKey key) + { + if (null == key) + throw new ArgumentNullException("key"); + + int index = IndexOfKey(key); + if (index >= 0) + { + if (Dictionary.Remove(key)) + { + List.RemoveAt(index); + return true; + } + } + return false; + } + + /// + /// Removes the entry with the specified key from the OrderedDictionary<TKey,TValue> collection. + /// + /// The key of the entry to remove + void IDictionary.Remove(object key) + { + Remove(ConvertToKeyType(key)); + } + + /// + /// Gets an object containing the values in the OrderedDictionary<TKey,TValue> collection. + /// + /// An object containing the values in the OrderedDictionary<TKey,TValue> collection. + /// The returned object is not a static copy; instead, the refers back to the values in the original OrderedDictionary<TKey,TValue> collection. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the . + ICollection IDictionary.Values + { + get + { + return (ICollection)Values; + } + } + + /// + /// Gets or sets the value with the specified key. + /// + /// The key of the value to get or set. + /// The value associated with the specified key. If the specified key is not found, attempting to get it returns , and attempting to set it creates a new element using the specified key. + public TValue this[TKey key] + { + get + { + return Dictionary[key]; + } + set + { + if (Dictionary.ContainsKey(key)) + { + Dictionary[key] = value; + List[IndexOfKey(key)] = new KeyValuePair(key, value); + } + else + { + Add(key, value); + } + } + } + + /// + /// Gets or sets the value with the specified key. + /// + /// The key of the value to get or set. + /// The value associated with the specified key. If the specified key is not found, attempting to get it returns , and attempting to set it creates a new element using the specified key. + object IDictionary.this[object key] + { + get + { + return this[ConvertToKeyType(key)]; + } + set + { + this[ConvertToKeyType(key)] = ConvertToValueType(value); + } + } + + /// + /// Copies the elements of the OrderedDictionary<TKey,TValue> elements to a one-dimensional Array object at the specified index. + /// + /// The one-dimensional object that is the destination of the objects copied from the OrderedDictionary<TKey,TValue>. The must have zero-based indexing. + /// The zero-based index in at which copying begins. + /// The method preserves the order of the elements in the OrderedDictionary<TKey,TValue> + void ICollection.CopyTo(Array array, int index) + { + ((ICollection)List).CopyTo(array, index); + } + + /// + /// Gets the number of key/values pairs contained in the OrderedDictionary<TKey,TValue> collection. + /// + /// The number of key/value pairs contained in the OrderedDictionary<TKey,TValue> collection. + public int Count + { + get + { + return List.Count; + } + } + + /// + /// Gets a value indicating whether access to the OrderedDictionary<TKey,TValue> object is synchronized (thread-safe). + /// + /// This method always returns false. + bool ICollection.IsSynchronized + { + get + { + return false; + } + } + + /// + /// Gets an object that can be used to synchronize access to the OrderedDictionary<TKey,TValue> object. + /// + /// An object that can be used to synchronize access to the OrderedDictionary<TKey,TValue> object. + object ICollection.SyncRoot + { + get + { + if (this.syncRoot == null) + { + System.Threading.Interlocked.CompareExchange(ref this.syncRoot, new object(), null); + } + return this.syncRoot; + } + } + + /// + /// Gets an ICollection<TKey> object containing the keys in the OrderedDictionary<TKey,TValue>. + /// + /// An ICollection<TKey> object containing the keys in the OrderedDictionary<TKey,TValue>. + /// The returned ICollection<TKey> object is not a static copy; instead, the collection refers back to the keys in the original OrderedDictionary<TKey,TValue>. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the key collection. + public ICollection Keys + { + get + { + return Dictionary.Keys; + } + } + + /// + /// Gets the value associated with the specified key. + /// + /// The key of the value to get. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of . This parameter can be passed uninitialized. + /// if the OrderedDictionary<TKey,TValue> contains an element with the specified key; otherwise, . + public bool TryGetValue(TKey key, out TValue value) + { + return Dictionary.TryGetValue(key, out value); + } + + /// + /// Gets an ICollection<TValue> object containing the values in the OrderedDictionary<TKey,TValue>. + /// + /// An ICollection<TValue> object containing the values in the OrderedDictionary<TKey,TValue>. + /// The returned ICollection<TKey> object is not a static copy; instead, the collection refers back to the values in the original OrderedDictionary<TKey,TValue>. Therefore, changes to the OrderedDictionary<TKey,TValue> continue to be reflected in the value collection. + public ICollection Values + { + get + { + return Dictionary.Values; + } + } + + /// + /// Adds the specified value to the OrderedDictionary<TKey,TValue> with the specified key. + /// + /// The KeyValuePair<TKey,TValue> structure representing the key and value to add to the OrderedDictionary<TKey,TValue>. + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + /// + /// Determines whether the OrderedDictionary<TKey,TValue> contains a specific key and value. + /// + /// The KeyValuePair<TKey,TValue> structure to locate in the OrderedDictionary<TKey,TValue>. + /// if is found in the OrderedDictionary<TKey,TValue>; otherwise, . + bool ICollection>.Contains(KeyValuePair item) + { + return ((ICollection>)Dictionary).Contains(item); + } + + /// + /// Copies the elements of the OrderedDictionary<TKey,TValue> to an array of type , starting at the specified index. + /// + /// The one-dimensional array of type KeyValuePair<TKey,TValue> that is the destination of the KeyValuePair<TKey,TValue> elements copied from the OrderedDictionary<TKey,TValue>. The array must have zero-based indexing. + /// The zero-based index in at which copying begins. + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((ICollection>)Dictionary).CopyTo(array, arrayIndex); + } + + /// + /// Removes a key and value from the dictionary. + /// + /// The KeyValuePair<TKey,TValue> structure representing the key and value to remove from the OrderedDictionary<TKey,TValue>. + /// if the key and value represented by is successfully found and removed; otherwise, . This method returns if is not found in the OrderedDictionary<TKey,TValue>. + bool ICollection>.Remove(KeyValuePair item) + { + return Remove(item.Key); + } + } +} diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/css/print.css b/src/ServiceStack.Api.OpenApi/swagger-ui/css/print.css new file mode 100644 index 00000000000..f2e8446445c --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/css/print.css @@ -0,0 +1 @@ +.swagger-section pre code{display:block;padding:.5em;background:#f0f0f0}.swagger-section pre .clojure .built_in,.swagger-section pre .lisp .title,.swagger-section pre .nginx .title,.swagger-section pre .subst,.swagger-section pre .tag .title,.swagger-section pre code{color:#000}.swagger-section pre .addition,.swagger-section pre .aggregate,.swagger-section pre .apache .cbracket,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .constant,.swagger-section pre .django .variable,.swagger-section pre .erlang_repl .function_or_atom,.swagger-section pre .flow,.swagger-section pre .markdown .header,.swagger-section pre .parent,.swagger-section pre .preprocessor,.swagger-section pre .ruby .symbol,.swagger-section pre .ruby .symbol .string,.swagger-section pre .rules .value,.swagger-section pre .rules .value .number,.swagger-section pre .smalltalk .class,.swagger-section pre .stream,.swagger-section pre .string,.swagger-section pre .tag .value,.swagger-section pre .template_tag,.swagger-section pre .tex .command,.swagger-section pre .tex .special,.swagger-section pre .title{color:#800}.swagger-section pre .annotation,.swagger-section pre .chunk,.swagger-section pre .comment,.swagger-section pre .diff .header,.swagger-section pre .markdown .blockquote,.swagger-section pre .template_comment{color:#888}.swagger-section pre .change,.swagger-section pre .date,.swagger-section pre .go .constant,.swagger-section pre .literal,.swagger-section pre .markdown .bullet,.swagger-section pre .markdown .link_url,.swagger-section pre .number,.swagger-section pre .regexp,.swagger-section pre .smalltalk .char,.swagger-section pre .smalltalk .symbol{color:#080}.swagger-section pre .apache .sqbracket,.swagger-section pre .array,.swagger-section pre .attr_selector,.swagger-section pre .clojure .attribute,.swagger-section pre .coffeescript .property,.swagger-section pre .decorator,.swagger-section pre .deletion,.swagger-section pre .doctype,.swagger-section pre .envvar,.swagger-section pre .erlang_repl .reserved,.swagger-section pre .filter .argument,.swagger-section pre .important,.swagger-section pre .javadoc,.swagger-section pre .label,.swagger-section pre .localvars,.swagger-section pre .markdown .link_label,.swagger-section pre .nginx .built_in,.swagger-section pre .pi,.swagger-section pre .prompt,.swagger-section pre .pseudo,.swagger-section pre .ruby .string,.swagger-section pre .shebang,.swagger-section pre .tex .formula,.swagger-section pre .vhdl .attribute{color:#88f}.swagger-section pre .aggregate,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .built_in,.swagger-section pre .css .tag,.swagger-section pre .go .typename,.swagger-section pre .id,.swagger-section pre .javadoctag,.swagger-section pre .keyword,.swagger-section pre .markdown .strong,.swagger-section pre .phpdoc,.swagger-section pre .request,.swagger-section pre .smalltalk .class,.swagger-section pre .status,.swagger-section pre .tex .command,.swagger-section pre .title,.swagger-section pre .winutils,.swagger-section pre .yardoctag{font-weight:700}.swagger-section pre .markdown .emphasis{font-style:italic}.swagger-section pre .nginx .built_in{font-weight:400}.swagger-section pre .coffeescript .javascript,.swagger-section pre .javascript .xml,.swagger-section pre .tex .formula,.swagger-section pre .xml .cdata,.swagger-section pre .xml .css,.swagger-section pre .xml .javascript,.swagger-section pre .xml .vbscript{opacity:.5}.swagger-section .hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0}.swagger-section .hljs,.swagger-section .hljs-subst{color:#444}.swagger-section .hljs-attribute,.swagger-section .hljs-doctag,.swagger-section .hljs-keyword,.swagger-section .hljs-meta-keyword,.swagger-section .hljs-name,.swagger-section .hljs-selector-tag{font-weight:700}.swagger-section .hljs-addition,.swagger-section .hljs-built_in,.swagger-section .hljs-bullet,.swagger-section .hljs-code,.swagger-section .hljs-literal{color:#1f811f}.swagger-section .hljs-link,.swagger-section .hljs-regexp,.swagger-section .hljs-selector-attr,.swagger-section .hljs-selector-pseudo,.swagger-section .hljs-symbol,.swagger-section .hljs-template-variable,.swagger-section .hljs-variable{color:#bc6060}.swagger-section .hljs-deletion,.swagger-section .hljs-number,.swagger-section .hljs-quote,.swagger-section .hljs-selector-class,.swagger-section .hljs-selector-id,.swagger-section .hljs-string,.swagger-section .hljs-template-tag,.swagger-section .hljs-type{color:#800}.swagger-section .hljs-section,.swagger-section .hljs-title{color:#800;font-weight:700}.swagger-section .hljs-comment{color:#888}.swagger-section .hljs-meta{color:#2b6ea1}.swagger-section .hljs-emphasis{font-style:italic}.swagger-section .hljs-strong{font-weight:700}.swagger-section .swagger-ui-wrap{line-height:1;font-family:Droid Sans,sans-serif;min-width:760px;max-width:960px;margin-left:auto;margin-right:auto}.swagger-section .swagger-ui-wrap b,.swagger-section .swagger-ui-wrap strong{font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap blockquote,.swagger-section .swagger-ui-wrap q{quotes:none}.swagger-section .swagger-ui-wrap p{line-height:1.4em;padding:0 0 10px;color:#333}.swagger-section .swagger-ui-wrap blockquote:after,.swagger-section .swagger-ui-wrap blockquote:before,.swagger-section .swagger-ui-wrap q:after,.swagger-section .swagger-ui-wrap q:before{content:none}.swagger-section .swagger-ui-wrap .heading_with_menu h1,.swagger-section .swagger-ui-wrap .heading_with_menu h2,.swagger-section .swagger-ui-wrap .heading_with_menu h3,.swagger-section .swagger-ui-wrap .heading_with_menu h4,.swagger-section .swagger-ui-wrap .heading_with_menu h5,.swagger-section .swagger-ui-wrap .heading_with_menu h6{display:block;clear:none;float:left;-ms-box-sizing:border-box;box-sizing:border-box;width:60%}.swagger-section .swagger-ui-wrap table{border-collapse:collapse;border-spacing:0}.swagger-section .swagger-ui-wrap table thead tr th{padding:5px;font-size:.9em;color:#666;border-bottom:1px solid #999}.swagger-section .swagger-ui-wrap table tbody tr:last-child td{border-bottom:none}.swagger-section .swagger-ui-wrap table tbody tr.offset{background-color:#f0f0f0}.swagger-section .swagger-ui-wrap table tbody tr td{padding:6px;font-size:.9em;border-bottom:1px solid #ccc;vertical-align:top;line-height:1.3em}.swagger-section .swagger-ui-wrap ol{margin:0 0 10px;padding:0 0 0 18px;list-style-type:decimal}.swagger-section .swagger-ui-wrap ol li{padding:5px 0;font-size:.9em;color:#333}.swagger-section .swagger-ui-wrap ol,.swagger-section .swagger-ui-wrap ul{list-style:none}.swagger-section .swagger-ui-wrap h1 a,.swagger-section .swagger-ui-wrap h2 a,.swagger-section .swagger-ui-wrap h3 a,.swagger-section .swagger-ui-wrap h4 a,.swagger-section .swagger-ui-wrap h5 a,.swagger-section .swagger-ui-wrap h6 a{text-decoration:none}.swagger-section .swagger-ui-wrap h1 a:hover,.swagger-section .swagger-ui-wrap h2 a:hover,.swagger-section .swagger-ui-wrap h3 a:hover,.swagger-section .swagger-ui-wrap h4 a:hover,.swagger-section .swagger-ui-wrap h5 a:hover,.swagger-section .swagger-ui-wrap h6 a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap h1 span.divider,.swagger-section .swagger-ui-wrap h2 span.divider,.swagger-section .swagger-ui-wrap h3 span.divider,.swagger-section .swagger-ui-wrap h4 span.divider,.swagger-section .swagger-ui-wrap h5 span.divider,.swagger-section .swagger-ui-wrap h6 span.divider{color:#aaa}.swagger-section .swagger-ui-wrap a{color:#547f00}.swagger-section .swagger-ui-wrap a img{border:none}.swagger-section .swagger-ui-wrap article,.swagger-section .swagger-ui-wrap aside,.swagger-section .swagger-ui-wrap details,.swagger-section .swagger-ui-wrap figcaption,.swagger-section .swagger-ui-wrap figure,.swagger-section .swagger-ui-wrap footer,.swagger-section .swagger-ui-wrap header,.swagger-section .swagger-ui-wrap hgroup,.swagger-section .swagger-ui-wrap menu,.swagger-section .swagger-ui-wrap nav,.swagger-section .swagger-ui-wrap section,.swagger-section .swagger-ui-wrap summary{display:block}.swagger-section .swagger-ui-wrap pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#fcf6db;border:1px solid #e5e0c6;padding:10px}.swagger-section .swagger-ui-wrap pre code{line-height:1.6em;background:none}.swagger-section .swagger-ui-wrap .content>.content-type>div>label{clear:both;display:block;color:#0f6ab4;font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap .content pre{font-size:12px;margin-top:5px;padding:5px}.swagger-section .swagger-ui-wrap .icon-btn{cursor:pointer}.swagger-section .swagger-ui-wrap .info_title{padding-bottom:10px;font-weight:700;font-size:25px}.swagger-section .swagger-ui-wrap .footer{margin-top:20px}.swagger-section .swagger-ui-wrap div.big p,.swagger-section .swagger-ui-wrap p.big{font-size:1em;margin-bottom:10px}.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea,.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input{width:500px!important}.swagger-section .swagger-ui-wrap .info_license,.swagger-section .swagger-ui-wrap .info_tos{padding-bottom:5px}.swagger-section .swagger-ui-wrap .message-fail{color:#c00}.swagger-section .swagger-ui-wrap .info_email,.swagger-section .swagger-ui-wrap .info_name,.swagger-section .swagger-ui-wrap .info_url{padding-bottom:5px}.swagger-section .swagger-ui-wrap .info_description{padding-bottom:10px;font-size:15px}.swagger-section .swagger-ui-wrap .markdown ol li,.swagger-section .swagger-ui-wrap .markdown ul li{padding:3px 0;line-height:1.4em;color:#333}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input{display:block;padding:4px;width:auto;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title{font-size:1.3em}.swagger-section .swagger-ui-wrap table.fullwidth{width:100%}.swagger-section .swagger-ui-wrap .model-signature{font-family:Droid Sans,sans-serif;font-size:1em;line-height:1.5em}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a{text-decoration:none;color:#aaa}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap .model-signature .propType{color:#55a}.swagger-section .swagger-ui-wrap .model-signature pre:hover{background-color:#ffd}.swagger-section .swagger-ui-wrap .model-signature pre{font-size:.85em;line-height:1.2em;overflow:auto;height:200px;resize:vertical;cursor:pointer}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav{display:block;min-width:230px;margin:0;padding:0}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li{float:left;margin:0 5px 5px 0;padding:2px 5px 2px 0;border-right:1px solid #ddd}.swagger-section .swagger-ui-wrap .model-signature .propOpt{color:#555}.swagger-section .swagger-ui-wrap .model-signature .snippet small{font-size:.75em}.swagger-section .swagger-ui-wrap .model-signature .propOptKey{font-style:italic}.swagger-section .swagger-ui-wrap .model-signature .description .strong{font-weight:700;color:#000;font-size:.9em}.swagger-section .swagger-ui-wrap .model-signature .description div{font-size:.9em;line-height:1.5em;margin-left:1em}.swagger-section .swagger-ui-wrap .model-signature .description .stronger{font-weight:700;color:#000}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper{border-spacing:0;position:absolute;background-color:#fff;border:1px solid #bbb;display:none;font-size:11px;max-width:400px;line-height:30px;color:#000;padding:5px;margin-left:10px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th{text-align:center;background-color:#eee;border:1px solid #bbb;font-size:11px;color:#666;font-weight:700;padding:5px;line-height:15px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:first-child,.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:last-child{display:inline}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:not(:first-child):before{display:block;content:''}.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown>p:only-child{margin-right:-3px}.swagger-section .swagger-ui-wrap .model-signature .propName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .signature-container{clear:both}.swagger-section .swagger-ui-wrap .body-textarea{width:300px;height:100px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap .markdown li code,.swagger-section .swagger-ui-wrap .markdown p code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#f0f0f0;color:#000;padding:1px 3px}.swagger-section .swagger-ui-wrap .required{font-weight:700}.swagger-section .swagger-ui-wrap .editor_holder{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em}.swagger-section .swagger-ui-wrap .editor_holder label{font-weight:400!important}.swagger-section .swagger-ui-wrap .editor_holder label.required{font-weight:700!important}.swagger-section .swagger-ui-wrap input.parameter{width:300px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap h1{color:#000;font-size:1.5em;line-height:1.3em;padding:10px 0;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap .heading_with_menu{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap .heading_with_menu ul{display:block;clear:none;float:right;-ms-box-sizing:border-box;box-sizing:border-box;margin-top:10px}.swagger-section .swagger-ui-wrap h2{color:#000;font-size:1.3em;padding:10px 0}.swagger-section .swagger-ui-wrap h2 a{color:#000}.swagger-section .swagger-ui-wrap h2 span.sub{font-size:.7em;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap h2 span.sub a{color:#777}.swagger-section .swagger-ui-wrap span.weak{color:#666}.swagger-section .swagger-ui-wrap .message-success{color:#89bf04}.swagger-section .swagger-ui-wrap caption,.swagger-section .swagger-ui-wrap td,.swagger-section .swagger-ui-wrap th{text-align:left;font-weight:400;vertical-align:middle}.swagger-section .swagger-ui-wrap .code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea{font-family:Droid Sans,sans-serif;height:250px;padding:4px;display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select{display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label{display:block;float:left;clear:none;margin:0;padding:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input{display:block;float:left;clear:none;margin:0 5px 0 0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label{color:#000}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label{display:block;clear:both;width:auto;padding:0 0 3px;color:#666}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr{padding-left:3px;color:#888}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints{margin-left:0;font-style:italic;font-size:.9em;margin:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons{margin:0;padding:0}.swagger-section .swagger-ui-wrap span.blank,.swagger-section .swagger-ui-wrap span.empty{color:#888;font-style:italic}.swagger-section .swagger-ui-wrap .markdown h3{color:#547f00}.swagger-section .swagger-ui-wrap .markdown h4{color:#666}.swagger-section .swagger-ui-wrap .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}.swagger-section .swagger-ui-wrap .markdown pre code{line-height:1.6em;overflow:auto}.swagger-section .swagger-ui-wrap div.gist{margin:20px 0 25px!important}.swagger-section .swagger-ui-wrap ul#resources{font-family:Droid Sans,sans-serif;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource{border-bottom:1px solid #ddd}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a{color:#555}.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child{border-bottom:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading{border:1px solid transparent;float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:14px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;border-right:1px solid #ddd;color:#666;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a{color:#aaa;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#999;padding-left:0;display:block;clear:none;float:left;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#999}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation{float:none;clear:both;overflow:hidden;display:block;margin:0 0 10px;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading{float:none;clear:both;overflow:hidden;display:block;margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3{display:block;clear:none;float:left;width:auto;margin:0;padding:0;line-height:1.1em;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path{padding-left:10px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a.toggleOperation.deprecated{text-decoration:line-through}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a{text-transform:uppercase;text-decoration:none;color:#fff;display:inline-block;width:50px;font-size:.7em;text-align:center;padding:7px 0 4px;border-radius:2px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span{margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:6px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a{text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .markdown p{color:inherit;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .nickname{color:#aaa;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content{border-top:none;padding:10px;border-bottom-left-radius:6px;border-bottom-right-radius:6px;margin:0 0 20px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4{font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a{padding:4px 0 0 10px;display:inline-block;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit{display:block;clear:none;float:left;padding:6px 8px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber{background-image:url(../images/throbber.gif);width:128px;height:16px;display:block;clear:none;float:right}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type=text].error{outline:2px solid #000;outline-color:#c00}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name=parameterContentType]{max-width:300px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;padding:10px;font-size:.9em;max-height:400px;overflow-y:auto}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading{background-color:#f9f2e9;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a{background-color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0e0ca;color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{background-color:#faf5ee;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap 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}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#ffd20f;color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading{background-color:#f5e8e8;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap 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}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#e8c6c7;color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content{background-color:#f7eded;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a{color:#c8787a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading{background-color:#e7f6ec;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a{background-color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3e8d1;color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content{background-color:#ebf7f0;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading{background-color:#fce9e3;border:1px solid #f5d5c3}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a{background-color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0cecb;color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content{background-color:#faf0ef;border:1px solid #f0cecb}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{border-top:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap p#colophon{margin:0 15px 40px;padding:10px 0;font-size:.8em;border-top:1px solid #ddd;font-family:Droid Sans,sans-serif;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap p#colophon a{text-decoration:none;color:#547f00}.swagger-section .swagger-ui-wrap h3{color:#000;font-size:1.1em;padding:10px 0}.swagger-section .swagger-ui-wrap .markdown ol,.swagger-section .swagger-ui-wrap .markdown ul{font-family:Droid Sans,sans-serif;margin:5px 0 10px;padding:0 0 0 18px;list-style-type:disc}.swagger-section .swagger-ui-wrap form.form_box{background-color:#ebf3f9;border:1px solid #c3d9ec;padding:10px}.swagger-section .swagger-ui-wrap form.form_box label{color:#0f6ab4!important}.swagger-section .swagger-ui-wrap form.form_box input[type=submit]{display:block;padding:10px}.swagger-section .swagger-ui-wrap form.form_box p.weak{font-size:.8em}.swagger-section .swagger-ui-wrap form.form_box p{font-size:.9em;padding:0 0 15px;color:#7e7b6d}.swagger-section .swagger-ui-wrap form.form_box p a{color:#646257}.swagger-section .swagger-ui-wrap form.form_box p strong{color:#000}.swagger-section .swagger-ui-wrap .operation-status td.markdown>p:last-child{padding-bottom:0}.swagger-section .title{font-style:bold}.swagger-section .secondary_form{display:none}.swagger-section .main_image{display:block;margin-left:auto;margin-right:auto}.swagger-section .oauth_body{margin-left:100px;margin-right:100px}.swagger-section .oauth_submit{text-align:center;display:inline-block}.swagger-section .authorize-wrapper{margin:15px 0 10px}.swagger-section .authorize-wrapper_operation{float:right}.swagger-section .authorize__btn:hover{text-decoration:underline;cursor:pointer}.swagger-section .authorize__btn_operation:hover .authorize-scopes{display:block}.swagger-section .authorize-scopes{position:absolute;margin-top:20px;background:#fff;border:1px solid #ccc;border-radius:5px;display:none;font-size:13px;max-width:300px;line-height:30px;color:#000;padding:5px}.swagger-section .authorize-scopes .authorize__scope{text-decoration:none}.swagger-section .authorize__btn_operation{height:18px;vertical-align:middle;display:inline-block;background:url(../images/explorer_icons.png) no-repeat}.swagger-section .authorize__btn_operation_login{background-position:0 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .authorize__btn_operation_logout{background-position:-30px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section #auth_container{color:#fff;display:inline-block;border:none;padding:5px;width:87px;height:13px}.swagger-section #auth_container .authorize__btn{color:#fff}.swagger-section .auth_container{padding:0 0 10px;margin-bottom:5px;border-bottom:1px solid #ccc;font-size:.9em}.swagger-section .auth_container .auth__title{color:#547f00;font-size:1.2em}.swagger-section .auth_container .basic_auth__label{display:inline-block;width:60px}.swagger-section .auth_container .auth__description{color:#999;margin-bottom:5px}.swagger-section .auth_container .auth__button{margin-top:10px;height:30px}.swagger-section .auth_container .key_auth__field{margin:5px 0}.swagger-section .auth_container .key_auth__label{display:inline-block;width:60px}.swagger-section .api-popup-dialog{position:absolute;display:none}.swagger-section .api-popup-dialog-wrapper{z-index:2;width:500px;background:#fff;padding:20px;border:1px solid #ccc;border-radius:5px;font-size:13px;color:#777;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.swagger-section .api-popup-dialog-shadow{position:fixed;top:0;left:0;width:100%;height:100%;opacity:.2;background-color:gray;z-index:1}.swagger-section .api-popup-dialog .api-popup-title{font-size:24px;padding:10px 0}.swagger-section .api-popup-dialog .error-msg{padding-left:5px;padding-bottom:5px}.swagger-section .api-popup-dialog .api-popup-content{max-height:500px;overflow-y:auto}.swagger-section .api-popup-dialog .api-popup-authbtn,.swagger-section .api-popup-dialog .api-popup-cancel{height:30px}.swagger-section .api-popup-scopes{padding:10px 20px}.swagger-section .api-popup-scopes li{padding:5px 0;line-height:20px}.swagger-section .api-popup-scopes li input{position:relative;top:2px}.swagger-section .api-popup-scopes .api-scope-desc{padding-left:20px;font-style:italic}.swagger-section .api-popup-actions{padding-top:10px}.swagger-section fieldset{padding-bottom:10px;padding-left:20px}#header{display:none}.swagger-section .swagger-ui-wrap .model-signature pre{max-height:none}.swagger-section .swagger-ui-wrap .body-textarea,.swagger-section .swagger-ui-wrap input.parameter{width:100px}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options{display:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content{display:block!important} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/css/reset.css b/src/ServiceStack.Api.OpenApi/swagger-ui/css/reset.css new file mode 100644 index 00000000000..40dc8301c57 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/css/reset.css @@ -0,0 +1 @@ +a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}table{border-collapse:collapse;border-spacing:0} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/css/screen.css b/src/ServiceStack.Api.OpenApi/swagger-ui/css/screen.css new file mode 100644 index 00000000000..1f069f6abe3 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/css/screen.css @@ -0,0 +1 @@ +.swagger-section pre code{display:block;padding:.5em;background:#f0f0f0}.swagger-section pre .clojure .built_in,.swagger-section pre .lisp .title,.swagger-section pre .nginx .title,.swagger-section pre .subst,.swagger-section pre .tag .title,.swagger-section pre code{color:#000}.swagger-section pre .addition,.swagger-section pre .aggregate,.swagger-section pre .apache .cbracket,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .constant,.swagger-section pre .django .variable,.swagger-section pre .erlang_repl .function_or_atom,.swagger-section pre .flow,.swagger-section pre .markdown .header,.swagger-section pre .parent,.swagger-section pre .preprocessor,.swagger-section pre .ruby .symbol,.swagger-section pre .ruby .symbol .string,.swagger-section pre .rules .value,.swagger-section pre .rules .value .number,.swagger-section pre .smalltalk .class,.swagger-section pre .stream,.swagger-section pre .string,.swagger-section pre .tag .value,.swagger-section pre .template_tag,.swagger-section pre .tex .command,.swagger-section pre .tex .special,.swagger-section pre .title{color:#800}.swagger-section pre .annotation,.swagger-section pre .chunk,.swagger-section pre .comment,.swagger-section pre .diff .header,.swagger-section pre .markdown .blockquote,.swagger-section pre .template_comment{color:#888}.swagger-section pre .change,.swagger-section pre .date,.swagger-section pre .go .constant,.swagger-section pre .literal,.swagger-section pre .markdown .bullet,.swagger-section pre .markdown .link_url,.swagger-section pre .number,.swagger-section pre .regexp,.swagger-section pre .smalltalk .char,.swagger-section pre .smalltalk .symbol{color:#080}.swagger-section pre .apache .sqbracket,.swagger-section pre .array,.swagger-section pre .attr_selector,.swagger-section pre .clojure .attribute,.swagger-section pre .coffeescript .property,.swagger-section pre .decorator,.swagger-section pre .deletion,.swagger-section pre .doctype,.swagger-section pre .envvar,.swagger-section pre .erlang_repl .reserved,.swagger-section pre .filter .argument,.swagger-section pre .important,.swagger-section pre .javadoc,.swagger-section pre .label,.swagger-section pre .localvars,.swagger-section pre .markdown .link_label,.swagger-section pre .nginx .built_in,.swagger-section pre .pi,.swagger-section pre .prompt,.swagger-section pre .pseudo,.swagger-section pre .ruby .string,.swagger-section pre .shebang,.swagger-section pre .tex .formula,.swagger-section pre .vhdl .attribute{color:#88f}.swagger-section pre .aggregate,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .built_in,.swagger-section pre .css .tag,.swagger-section pre .go .typename,.swagger-section pre .id,.swagger-section pre .javadoctag,.swagger-section pre .keyword,.swagger-section pre .markdown .strong,.swagger-section pre .phpdoc,.swagger-section pre .request,.swagger-section pre .smalltalk .class,.swagger-section pre .status,.swagger-section pre .tex .command,.swagger-section pre .title,.swagger-section pre .winutils,.swagger-section pre .yardoctag{font-weight:700}.swagger-section pre .markdown .emphasis{font-style:italic}.swagger-section pre .nginx .built_in{font-weight:400}.swagger-section pre .coffeescript .javascript,.swagger-section pre .javascript .xml,.swagger-section pre .tex .formula,.swagger-section pre .xml .cdata,.swagger-section pre .xml .css,.swagger-section pre .xml .javascript,.swagger-section pre .xml .vbscript{opacity:.5}.swagger-section .hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0}.swagger-section .hljs,.swagger-section .hljs-subst{color:#444}.swagger-section .hljs-attribute,.swagger-section .hljs-doctag,.swagger-section .hljs-keyword,.swagger-section .hljs-meta-keyword,.swagger-section .hljs-name,.swagger-section .hljs-selector-tag{font-weight:700}.swagger-section .hljs-addition,.swagger-section .hljs-built_in,.swagger-section .hljs-bullet,.swagger-section .hljs-code,.swagger-section .hljs-literal{color:#1f811f}.swagger-section .hljs-link,.swagger-section .hljs-regexp,.swagger-section .hljs-selector-attr,.swagger-section .hljs-selector-pseudo,.swagger-section .hljs-symbol,.swagger-section .hljs-template-variable,.swagger-section .hljs-variable{color:#bc6060}.swagger-section .hljs-deletion,.swagger-section .hljs-number,.swagger-section .hljs-quote,.swagger-section .hljs-selector-class,.swagger-section .hljs-selector-id,.swagger-section .hljs-string,.swagger-section .hljs-template-tag,.swagger-section .hljs-type{color:#800}.swagger-section .hljs-section,.swagger-section .hljs-title{color:#800;font-weight:700}.swagger-section .hljs-comment{color:#888}.swagger-section .hljs-meta{color:#2b6ea1}.swagger-section .hljs-emphasis{font-style:italic}.swagger-section .hljs-strong{font-weight:700}.swagger-section .swagger-ui-wrap{line-height:1;font-family:Droid Sans,sans-serif;min-width:760px;max-width:960px;margin-left:auto;margin-right:auto}.swagger-section .swagger-ui-wrap b,.swagger-section .swagger-ui-wrap strong{font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap blockquote,.swagger-section .swagger-ui-wrap q{quotes:none}.swagger-section .swagger-ui-wrap p{line-height:1.4em;padding:0 0 10px;color:#333}.swagger-section .swagger-ui-wrap blockquote:after,.swagger-section .swagger-ui-wrap blockquote:before,.swagger-section .swagger-ui-wrap q:after,.swagger-section .swagger-ui-wrap q:before{content:none}.swagger-section .swagger-ui-wrap .heading_with_menu h1,.swagger-section .swagger-ui-wrap .heading_with_menu h2,.swagger-section .swagger-ui-wrap .heading_with_menu h3,.swagger-section .swagger-ui-wrap .heading_with_menu h4,.swagger-section .swagger-ui-wrap .heading_with_menu h5,.swagger-section .swagger-ui-wrap .heading_with_menu h6{display:block;clear:none;float:left;-ms-box-sizing:border-box;box-sizing:border-box;width:60%}.swagger-section .swagger-ui-wrap table{border-collapse:collapse;border-spacing:0}.swagger-section .swagger-ui-wrap table thead tr th{padding:5px;font-size:.9em;color:#666;border-bottom:1px solid #999}.swagger-section .swagger-ui-wrap table tbody tr:last-child td{border-bottom:none}.swagger-section .swagger-ui-wrap table tbody tr.offset{background-color:#f0f0f0}.swagger-section .swagger-ui-wrap table tbody tr td{padding:6px;font-size:.9em;border-bottom:1px solid #ccc;vertical-align:top;line-height:1.3em}.swagger-section .swagger-ui-wrap ol{margin:0 0 10px;padding:0 0 0 18px;list-style-type:decimal}.swagger-section .swagger-ui-wrap ol li{padding:5px 0;font-size:.9em;color:#333}.swagger-section .swagger-ui-wrap ol,.swagger-section .swagger-ui-wrap ul{list-style:none}.swagger-section .swagger-ui-wrap h1 a,.swagger-section .swagger-ui-wrap h2 a,.swagger-section .swagger-ui-wrap h3 a,.swagger-section .swagger-ui-wrap h4 a,.swagger-section .swagger-ui-wrap h5 a,.swagger-section .swagger-ui-wrap h6 a{text-decoration:none}.swagger-section .swagger-ui-wrap h1 a:hover,.swagger-section .swagger-ui-wrap h2 a:hover,.swagger-section .swagger-ui-wrap h3 a:hover,.swagger-section .swagger-ui-wrap h4 a:hover,.swagger-section .swagger-ui-wrap h5 a:hover,.swagger-section .swagger-ui-wrap h6 a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap h1 span.divider,.swagger-section .swagger-ui-wrap h2 span.divider,.swagger-section .swagger-ui-wrap h3 span.divider,.swagger-section .swagger-ui-wrap h4 span.divider,.swagger-section .swagger-ui-wrap h5 span.divider,.swagger-section .swagger-ui-wrap h6 span.divider{color:#aaa}.swagger-section .swagger-ui-wrap a{color:#547f00}.swagger-section .swagger-ui-wrap a img{border:none}.swagger-section .swagger-ui-wrap article,.swagger-section .swagger-ui-wrap aside,.swagger-section .swagger-ui-wrap details,.swagger-section .swagger-ui-wrap figcaption,.swagger-section .swagger-ui-wrap figure,.swagger-section .swagger-ui-wrap footer,.swagger-section .swagger-ui-wrap header,.swagger-section .swagger-ui-wrap hgroup,.swagger-section .swagger-ui-wrap menu,.swagger-section .swagger-ui-wrap nav,.swagger-section .swagger-ui-wrap section,.swagger-section .swagger-ui-wrap summary{display:block}.swagger-section .swagger-ui-wrap pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#fcf6db;border:1px solid #e5e0c6;padding:10px}.swagger-section .swagger-ui-wrap pre code{line-height:1.6em;background:none}.swagger-section .swagger-ui-wrap .content>.content-type>div>label{clear:both;display:block;color:#0f6ab4;font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap .content pre{font-size:12px;margin-top:5px;padding:5px}.swagger-section .swagger-ui-wrap .icon-btn{cursor:pointer}.swagger-section .swagger-ui-wrap .info_title{padding-bottom:10px;font-weight:700;font-size:25px}.swagger-section .swagger-ui-wrap .footer{margin-top:20px}.swagger-section .swagger-ui-wrap div.big p,.swagger-section .swagger-ui-wrap p.big{font-size:1em;margin-bottom:10px}.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea,.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input{width:500px!important}.swagger-section .swagger-ui-wrap .info_license,.swagger-section .swagger-ui-wrap .info_tos{padding-bottom:5px}.swagger-section .swagger-ui-wrap .message-fail{color:#c00}.swagger-section .swagger-ui-wrap .info_email,.swagger-section .swagger-ui-wrap .info_name,.swagger-section .swagger-ui-wrap .info_url{padding-bottom:5px}.swagger-section .swagger-ui-wrap .info_description{padding-bottom:10px;font-size:15px}.swagger-section .swagger-ui-wrap .markdown ol li,.swagger-section .swagger-ui-wrap .markdown ul li{padding:3px 0;line-height:1.4em;color:#333}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input{display:block;padding:4px;width:auto;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title{font-size:1.3em}.swagger-section .swagger-ui-wrap table.fullwidth{width:100%}.swagger-section .swagger-ui-wrap .model-signature{font-family:Droid Sans,sans-serif;font-size:1em;line-height:1.5em}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a{text-decoration:none;color:#aaa}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap .model-signature .propType{color:#55a}.swagger-section .swagger-ui-wrap .model-signature pre:hover{background-color:#ffd}.swagger-section .swagger-ui-wrap .model-signature pre{font-size:.85em;line-height:1.2em;overflow:auto;height:200px;resize:vertical;cursor:pointer}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav{display:block;min-width:230px;margin:0;padding:0}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li{float:left;margin:0 5px 5px 0;padding:2px 5px 2px 0;border-right:1px solid #ddd}.swagger-section .swagger-ui-wrap .model-signature .propOpt{color:#555}.swagger-section .swagger-ui-wrap .model-signature .snippet small{font-size:.75em}.swagger-section .swagger-ui-wrap .model-signature .propOptKey{font-style:italic}.swagger-section .swagger-ui-wrap .model-signature .description .strong{font-weight:700;color:#000;font-size:.9em}.swagger-section .swagger-ui-wrap .model-signature .description div{font-size:.9em;line-height:1.5em;margin-left:1em}.swagger-section .swagger-ui-wrap .model-signature .description .stronger{font-weight:700;color:#000}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper{border-spacing:0;position:absolute;background-color:#fff;border:1px solid #bbb;display:none;font-size:11px;max-width:400px;line-height:30px;color:#000;padding:5px;margin-left:10px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th{text-align:center;background-color:#eee;border:1px solid #bbb;font-size:11px;color:#666;font-weight:700;padding:5px;line-height:15px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:first-child,.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:last-child{display:inline}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:not(:first-child):before{display:block;content:''}.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown>p:only-child{margin-right:-3px}.swagger-section .swagger-ui-wrap .model-signature .propName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .signature-container{clear:both}.swagger-section .swagger-ui-wrap .body-textarea{width:300px;height:100px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap .markdown li code,.swagger-section .swagger-ui-wrap .markdown p code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#f0f0f0;color:#000;padding:1px 3px}.swagger-section .swagger-ui-wrap .required{font-weight:700}.swagger-section .swagger-ui-wrap .editor_holder{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em}.swagger-section .swagger-ui-wrap .editor_holder label{font-weight:400!important}.swagger-section .swagger-ui-wrap .editor_holder label.required{font-weight:700!important}.swagger-section .swagger-ui-wrap input.parameter{width:300px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap h1{color:#000;font-size:1.5em;line-height:1.3em;padding:10px 0;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap .heading_with_menu{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap .heading_with_menu ul{display:block;clear:none;float:right;-ms-box-sizing:border-box;box-sizing:border-box;margin-top:10px}.swagger-section .swagger-ui-wrap h2{color:#000;font-size:1.3em;padding:10px 0}.swagger-section .swagger-ui-wrap h2 a{color:#000}.swagger-section .swagger-ui-wrap h2 span.sub{font-size:.7em;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap h2 span.sub a{color:#777}.swagger-section .swagger-ui-wrap span.weak{color:#666}.swagger-section .swagger-ui-wrap .message-success{color:#89bf04}.swagger-section .swagger-ui-wrap caption,.swagger-section .swagger-ui-wrap td,.swagger-section .swagger-ui-wrap th{text-align:left;font-weight:400;vertical-align:middle}.swagger-section .swagger-ui-wrap .code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea{font-family:Droid Sans,sans-serif;height:250px;padding:4px;display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select{display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label{display:block;float:left;clear:none;margin:0;padding:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input{display:block;float:left;clear:none;margin:0 5px 0 0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label{color:#000}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label{display:block;clear:both;width:auto;padding:0 0 3px;color:#666}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr{padding-left:3px;color:#888}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints{margin-left:0;font-style:italic;font-size:.9em;margin:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons{margin:0;padding:0}.swagger-section .swagger-ui-wrap span.blank,.swagger-section .swagger-ui-wrap span.empty{color:#888;font-style:italic}.swagger-section .swagger-ui-wrap .markdown h3{color:#547f00}.swagger-section .swagger-ui-wrap .markdown h4{color:#666}.swagger-section .swagger-ui-wrap .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}.swagger-section .swagger-ui-wrap .markdown pre code{line-height:1.6em;overflow:auto}.swagger-section .swagger-ui-wrap div.gist{margin:20px 0 25px!important}.swagger-section .swagger-ui-wrap ul#resources{font-family:Droid Sans,sans-serif;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource{border-bottom:1px solid #ddd}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a{color:#555}.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child{border-bottom:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading{border:1px solid transparent;float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:14px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;border-right:1px solid #ddd;color:#666;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a{color:#aaa;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#999;padding-left:0;display:block;clear:none;float:left;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#999}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation{float:none;clear:both;overflow:hidden;display:block;margin:0 0 10px;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading{float:none;clear:both;overflow:hidden;display:block;margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3{display:block;clear:none;float:left;width:auto;margin:0;padding:0;line-height:1.1em;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path{padding-left:10px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a.toggleOperation.deprecated{text-decoration:line-through}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a{text-transform:uppercase;text-decoration:none;color:#fff;display:inline-block;width:50px;font-size:.7em;text-align:center;padding:7px 0 4px;border-radius:2px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span{margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:6px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a{text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .markdown p{color:inherit;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .nickname{color:#aaa;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content{border-top:none;padding:10px;border-bottom-left-radius:6px;border-bottom-right-radius:6px;margin:0 0 20px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4{font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a{padding:4px 0 0 10px;display:inline-block;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit{display:block;clear:none;float:left;padding:6px 8px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber{background-image:url(../images/throbber.gif);width:128px;height:16px;display:block;clear:none;float:right}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type=text].error{outline:2px solid #000;outline-color:#c00}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name=parameterContentType]{max-width:300px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;padding:10px;font-size:.9em;max-height:400px;overflow-y:auto}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading{background-color:#f9f2e9;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a{background-color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0e0ca;color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{background-color:#faf5ee;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap 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}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#ffd20f;color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading{background-color:#f5e8e8;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap 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}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#e8c6c7;color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content{background-color:#f7eded;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a{color:#c8787a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading{background-color:#e7f6ec;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a{background-color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3e8d1;color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content{background-color:#ebf7f0;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading{background-color:#fce9e3;border:1px solid #f5d5c3}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a{background-color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0cecb;color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content{background-color:#faf0ef;border:1px solid #f0cecb}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{border-top:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap p#colophon{margin:0 15px 40px;padding:10px 0;font-size:.8em;border-top:1px solid #ddd;font-family:Droid Sans,sans-serif;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap p#colophon a{text-decoration:none;color:#547f00}.swagger-section .swagger-ui-wrap h3{color:#000;font-size:1.1em;padding:10px 0}.swagger-section .swagger-ui-wrap .markdown ol,.swagger-section .swagger-ui-wrap .markdown ul{font-family:Droid Sans,sans-serif;margin:5px 0 10px;padding:0 0 0 18px;list-style-type:disc}.swagger-section .swagger-ui-wrap form.form_box{background-color:#ebf3f9;border:1px solid #c3d9ec;padding:10px}.swagger-section .swagger-ui-wrap form.form_box label{color:#0f6ab4!important}.swagger-section .swagger-ui-wrap form.form_box input[type=submit]{display:block;padding:10px}.swagger-section .swagger-ui-wrap form.form_box p.weak{font-size:.8em}.swagger-section .swagger-ui-wrap form.form_box p{font-size:.9em;padding:0 0 15px;color:#7e7b6d}.swagger-section .swagger-ui-wrap form.form_box p a{color:#646257}.swagger-section .swagger-ui-wrap form.form_box p strong{color:#000}.swagger-section .swagger-ui-wrap .operation-status td.markdown>p:last-child{padding-bottom:0}.swagger-section .title{font-style:bold}.swagger-section .secondary_form{display:none}.swagger-section .main_image{display:block;margin-left:auto;margin-right:auto}.swagger-section .oauth_body{margin-left:100px;margin-right:100px}.swagger-section .oauth_submit{text-align:center;display:inline-block}.swagger-section .authorize-wrapper{margin:15px 0 10px}.swagger-section .authorize-wrapper_operation{float:right}.swagger-section .authorize__btn:hover{text-decoration:underline;cursor:pointer}.swagger-section .authorize__btn_operation:hover .authorize-scopes{display:block}.swagger-section .authorize-scopes{position:absolute;margin-top:20px;background:#fff;border:1px solid #ccc;border-radius:5px;display:none;font-size:13px;max-width:300px;line-height:30px;color:#000;padding:5px}.swagger-section .authorize-scopes .authorize__scope{text-decoration:none}.swagger-section .authorize__btn_operation{height:18px;vertical-align:middle;display:inline-block;background:url(../images/explorer_icons.png) no-repeat}.swagger-section .authorize__btn_operation_login{background-position:0 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .authorize__btn_operation_logout{background-position:-30px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section #auth_container{color:#fff;display:inline-block;border:none;padding:5px;width:87px;height:13px}.swagger-section #auth_container .authorize__btn{color:#fff}.swagger-section .auth_container{padding:0 0 10px;margin-bottom:5px;border-bottom:1px solid #ccc;font-size:.9em}.swagger-section .auth_container .auth__title{color:#547f00;font-size:1.2em}.swagger-section .auth_container .basic_auth__label{display:inline-block;width:60px}.swagger-section .auth_container .auth__description{color:#999;margin-bottom:5px}.swagger-section .auth_container .auth__button{margin-top:10px;height:30px}.swagger-section .auth_container .key_auth__field{margin:5px 0}.swagger-section .auth_container .key_auth__label{display:inline-block;width:60px}.swagger-section .api-popup-dialog{position:absolute;display:none}.swagger-section .api-popup-dialog-wrapper{z-index:2;width:500px;background:#fff;padding:20px;border:1px solid #ccc;border-radius:5px;font-size:13px;color:#777;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.swagger-section .api-popup-dialog-shadow{position:fixed;top:0;left:0;width:100%;height:100%;opacity:.2;background-color:gray;z-index:1}.swagger-section .api-popup-dialog .api-popup-title{font-size:24px;padding:10px 0}.swagger-section .api-popup-dialog .error-msg{padding-left:5px;padding-bottom:5px}.swagger-section .api-popup-dialog .api-popup-content{max-height:500px;overflow-y:auto}.swagger-section .api-popup-dialog .api-popup-authbtn,.swagger-section .api-popup-dialog .api-popup-cancel{height:30px}.swagger-section .api-popup-scopes{padding:10px 20px}.swagger-section .api-popup-scopes li{padding:5px 0;line-height:20px}.swagger-section .api-popup-scopes li input{position:relative;top:2px}.swagger-section .api-popup-scopes .api-scope-desc{padding-left:20px;font-style:italic}.swagger-section .api-popup-actions{padding-top:10px}.swagger-section fieldset{padding-bottom:10px;padding-left:20px}.swagger-section .access,.swagger-section .auth{float:right}.swagger-section .api-ic{height:18px;vertical-align:middle;display:inline-block;background:url(../images/explorer_icons.png) no-repeat}.swagger-section .api-ic .api_information_panel{position:relative;margin-top:20px;margin-left:-5px;background:#fff;border:1px solid #ccc;border-radius:5px;display:none;font-size:13px;max-width:300px;line-height:30px;color:#000;padding:5px}.swagger-section .api-ic .api_information_panel p .api-msg-enabled{color:green}.swagger-section .api-ic .api_information_panel p .api-msg-disabled{color:red}.swagger-section .api-ic:hover .api_information_panel{position:absolute;display:block}.swagger-section .ic-info{background-position:0 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .ic-warning{background-position:-60px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .ic-error{background-position:-30px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .ic-off{background-position:-90px 0;width:58px;margin-top:-4px;cursor:pointer}.swagger-section .ic-on{background-position:-160px 0;width:58px;margin-top:-4px;cursor:pointer}.swagger-section #header{background-color:#89bf04;padding:9px 14px 19px;height:23px;min-width:775px}.swagger-section #input_baseUrl{width:400px}.swagger-section #api_selector{display:block;clear:none;float:right}.swagger-section #api_selector .input{display:inline-block;clear:none;margin:0 10px 0 0}.swagger-section #api_selector input{font-size:.9em;padding:3px;margin:0}.swagger-section #input_apiKey{width:200px}.swagger-section #auth_container .authorize__btn,.swagger-section #explore{display:block;text-decoration:none;font-weight:700;padding:6px 8px;font-size:.9em;color:#fff;background-color:#547f00;border-radius:4px}.swagger-section #auth_container .authorize__btn:hover,.swagger-section #explore:hover{background-color:#547f00}.swagger-section #header #logo{font-size:1.5em;font-weight:700;text-decoration:none;color:#fff}.swagger-section #header #logo .logo__img{display:block;float:left;margin-top:2px}.swagger-section #header #logo .logo__title{display:inline-block;padding:5px 0 0 10px}.swagger-section #content_message{margin:10px 15px;font-style:italic;color:#999}.swagger-section #message-bar{min-height:30px;text-align:center;padding-top:10px}.swagger-section .swagger-collapse:before{content:"-"}.swagger-section .swagger-expand:before{content:"+"}.swagger-section .error{outline-color:#c00;background-color:#f2dede} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/css/style.css b/src/ServiceStack.Api.OpenApi/swagger-ui/css/style.css new file mode 100644 index 00000000000..52907e46365 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/css/style.css @@ -0,0 +1 @@ +.swagger-section #header a#logo{font-size:1.5em;font-weight:700;text-decoration:none;padding:20px 0 20px 40px}#text-head{font-size:80px;font-family:Roboto,sans-serif;color:#fff;float:right;margin-right:20%}.navbar-fixed-top .navbar-brand,.navbar-fixed-top .navbar-nav,.navbar-header{height:auto}.navbar-inverse{background-color:#000;border-color:#000}#navbar-brand{margin-left:20%}.navtext{font-size:10px}.h1,h1{font-size:60px}.navbar-default .navbar-header .navbar-brand{color:#a2dfee}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#393939;font-family:Arvo,serif;font-size:1.5em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#525252;padding-left:0;display:block;clear:none;float:left;font-family:Arvo,serif;font-weight:700}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#0a0a0a}.container1{width:1500px;margin:auto;margin-top:0;background-repeat:no-repeat;background-position:-40px -20px;margin-bottom:210px}.container-inner{width:1200px;margin:auto;background-color:hsla(192,8%,88%,.75);padding-bottom:40px;padding-top:40px;border-radius:15px}.header-content{padding:0;width:1000px}.title1{font-size:80px;font-family:Vollkorn,serif;color:#404040;text-align:center;padding-top:40px;padding-bottom:100px}#icon{margin-top:-18px}.subtext{font-size:25px;font-style:italic;color:#08b;text-align:right;padding-right:250px}.bg-primary{background-color:#00468b}.navbar-default .nav>li>a,.navbar-default .nav>li>a:focus,.navbar-default .nav>li>a:focus:hover,.navbar-default .nav>li>a:hover{color:#08b}.text-faded{font-size:25px;font-family:Vollkorn,serif}.section-heading{font-family:Vollkorn,serif;font-size:45px;padding-bottom:10px}hr{border-color:#00468b;padding-bottom:10px}.description{margin-top:20px;padding-bottom:200px}.description li{font-family:Vollkorn,serif;font-size:25px;color:#525252;margin-left:28%;padding-top:5px}.gap{margin-top:200px}.troubleshootingtext{color:hsla(0,0%,100%,.7);padding-left:30%}.troubleshootingtext li{list-style-type:circle;font-size:25px;padding-bottom:5px}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.block.response_body.json:hover{cursor:pointer}.backdrop{color:blue}#myModal{height:100%}.modal-backdrop{bottom:0;position:fixed}.curl{padding:10px;font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em;max-height:400px;margin-top:5px;overflow-y:auto;background-color:#fcf6db;border:1px solid #e5e0c6;border-radius:4px}.curl_title{font-size:1.1em;margin:0;padding:15px 0 5px;font-family:Open Sans,Helvetica Neue,Arial,sans-serif;font-weight:500;line-height:1.1}.footer{display:none}.swagger-section .swagger-ui-wrap h2{padding:0}h2{margin:0;margin-bottom:5px}.markdown p,.swagger-section .swagger-ui-wrap .code{font-size:15px;font-family:Arvo,serif}.swagger-section .swagger-ui-wrap b{font-family:Arvo,serif}#signin:hover{cursor:pointer}.dropdown-menu{padding:15px}.navbar-right .dropdown-menu{left:0;right:auto}#signinbutton{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b}.navbar-default .nav>li .details{color:#000;text-transform:none;font-size:15px;font-weight:400;font-family:Open Sans,sans-serif;font-style:italic;line-height:20px;top:-2px}.navbar-default .nav>li .details:hover{color:#000}#signout{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b} \ No newline at end of file diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/css/typography.css b/src/ServiceStack.Api.OpenApi/swagger-ui/css/typography.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/fonts/DroidSans-Bold.ttf b/src/ServiceStack.Api.OpenApi/swagger-ui/fonts/DroidSans-Bold.ttf new file mode 100644 index 00000000000..036c4d135bf Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/fonts/DroidSans-Bold.ttf differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/fonts/DroidSans.ttf b/src/ServiceStack.Api.OpenApi/swagger-ui/fonts/DroidSans.ttf new file mode 100644 index 00000000000..e517a0c5b9d Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/fonts/DroidSans.ttf differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/collapse.gif b/src/ServiceStack.Api.OpenApi/swagger-ui/images/collapse.gif new file mode 100644 index 00000000000..8843e8ce5a4 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/collapse.gif differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/expand.gif b/src/ServiceStack.Api.OpenApi/swagger-ui/images/expand.gif new file mode 100644 index 00000000000..477bf13718d Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/expand.gif differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/explorer_icons.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/explorer_icons.png new file mode 100644 index 00000000000..be43b273940 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/explorer_icons.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon-16x16.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon-16x16.png new file mode 100644 index 00000000000..0f7e13b0d99 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon-16x16.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon-32x32.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon-32x32.png new file mode 100644 index 00000000000..b0a3352ffd3 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon-32x32.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon.ico b/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon.ico new file mode 100644 index 00000000000..8b60bcf06a7 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/favicon.ico differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/logo_small.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/logo_small.png new file mode 100644 index 00000000000..0e071cd228e Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/logo_small.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/logo_small_swagger.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/logo_small_swagger.png new file mode 100644 index 00000000000..ce3908e3f27 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/logo_small_swagger.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/pet_store_api.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/pet_store_api.png new file mode 100644 index 00000000000..1192ad8cd6a Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/pet_store_api.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/throbber.gif b/src/ServiceStack.Api.OpenApi/swagger-ui/images/throbber.gif new file mode 100644 index 00000000000..06393889242 Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/throbber.gif differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/images/wordnik_api.png b/src/ServiceStack.Api.OpenApi/swagger-ui/images/wordnik_api.png new file mode 100644 index 00000000000..dc0ddab138f Binary files /dev/null and b/src/ServiceStack.Api.OpenApi/swagger-ui/images/wordnik_api.png differ diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/index.html b/src/ServiceStack.Api.OpenApi/swagger-ui/index.html new file mode 100644 index 00000000000..14232f9f4e7 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/index.html @@ -0,0 +1,108 @@ + + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
       
      +
      + + diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ca.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ca.js new file mode 100644 index 00000000000..f8c815aa92c --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ca.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Advertència: Obsolet", + "Implementation Notes":"Notes d'implementació", + "Response Class":"Classe de la Resposta", + "Status":"Estatus", + "Parameters":"Paràmetres", + "Parameter":"Paràmetre", + "Value":"Valor", + "Description":"Descripció", + "Parameter Type":"Tipus del Paràmetre", + "Data Type":"Tipus de la Dada", + "Response Messages":"Missatges de la Resposta", + "HTTP Status Code":"Codi d'Estatus HTTP", + "Reason":"Raó", + "Response Model":"Model de la Resposta", + "Request URL":"URL de la Sol·licitud", + "Response Body":"Cos de la Resposta", + "Response Code":"Codi de la Resposta", + "Response Headers":"Capçaleres de la Resposta", + "Hide Response":"Amagar Resposta", + "Try it out!":"Prova-ho!", + "Show/Hide":"Mostrar/Amagar", + "List Operations":"Llista Operacions", + "Expand Operations":"Expandir Operacions", + "Raw":"Cru", + "can't parse JSON. Raw result":"no puc analitzar el JSON. Resultat cru", + "Example Value":"Valor d'Exemple", + "Model Schema":"Esquema del Model", + "Model":"Model", + "apply":"aplicar", + "Username":"Nom d'usuari", + "Password":"Contrasenya", + "Terms of service":"Termes del servei", + "Created by":"Creat per", + "See more at":"Veure més en", + "Contact the developer":"Contactar amb el desenvolupador", + "api version":"versió de la api", + "Response Content Type":"Tipus de Contingut de la Resposta", + "fetching resource":"recollint recurs", + "fetching resource list":"recollins llista de recursos", + "Explore":"Explorant", + "Show Swagger Petstore Example Apis":"Mostrar API d'Exemple Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"No es pot llegir del servidor. Potser no teniu la configuració de control d'accés apropiada.", + "Please specify the protocol for":"Si us plau, especifiqueu el protocol per a", + "Can't read swagger JSON from":"No es pot llegir el JSON de swagger des de", + "Finished Loading Resource Information. Rendering Swagger UI":"Finalitzada la càrrega del recurs informatiu. Renderitzant Swagger UI", + "Unable to read api":"No es pot llegir l'api", + "from path":"des de la ruta", + "server returned":"el servidor ha retornat" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/el.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/el.js new file mode 100644 index 00000000000..fcd1ffdd5a9 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/el.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Προειδοποίηση: Έχει αποσυρθεί", + "Implementation Notes":"Σημειώσεις Υλοποίησης", + "Response Class":"Απόκριση", + "Status":"Κατάσταση", + "Parameters":"Παράμετροι", + "Parameter":"Παράμετρος", + "Value":"Τιμή", + "Description":"Περιγραφή", + "Parameter Type":"Τύπος Παραμέτρου", + "Data Type":"Τύπος Δεδομένων", + "Response Messages":"Μηνύματα Απόκρισης", + "HTTP Status Code":"Κωδικός Κατάστασης HTTP", + "Reason":"Αιτιολογία", + "Response Model":"Μοντέλο Απόκρισης", + "Request URL":"URL Αιτήματος", + "Response Body":"Σώμα Απόκρισης", + "Response Code":"Κωδικός Απόκρισης", + "Response Headers":"Επικεφαλίδες Απόκρισης", + "Hide Response":"Απόκρυψη Απόκρισης", + "Headers":"Επικεφαλίδες", + "Try it out!":"Δοκιμάστε το!", + "Show/Hide":"Εμφάνιση/Απόκρυψη", + "List Operations":"Λίστα Λειτουργιών", + "Expand Operations":"Ανάπτυξη Λειτουργιών", + "Raw":"Ακατέργαστο", + "can't parse JSON. Raw result":"αδυναμία ανάλυσης JSON. Ακατέργαστο αποτέλεσμα", + "Example Value":"Παράδειγμα Τιμής", + "Model Schema":"Σχήμα Μοντέλου", + "Model":"Μοντέλο", + "Click to set as parameter value":"Πατήστε για να θέσετε τιμή παραμέτρου", + "apply":"εφαρμογή", + "Username":"Όνομα χρήση", + "Password":"Κωδικός πρόσβασης", + "Terms of service":"Όροι χρήσης", + "Created by":"Δημιουργήθηκε από", + "See more at":"Δείτε περισσότερα στο", + "Contact the developer":"Επικοινωνήστε με τον προγραμματιστή", + "api version":"έκδοση api", + "Response Content Type":"Τύπος Περιεχομένου Απόκρισης", + "Parameter content type:":"Τύπος περιεχομένου παραμέτρου:", + "fetching resource":"παραλαβή πόρου", + "fetching resource list":"παραλαβή λίστας πόρων", + "Explore":"Εξερεύνηση", + "Show Swagger Petstore Example Apis":"Εμφάνιση Api Δειγμάτων Petstore του Swagger", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Αδυναμία ανάγνωσης από τον εξυπηρετητή. Μπορεί να μην έχει κατάλληλες ρυθμίσεις για access-control-origin.", + "Please specify the protocol for":"Παρακαλώ προσδιορίστε το πρωτόκολλο για", + "Can't read swagger JSON from":"Αδυναμία ανάγνωσης swagger JSON από", + "Finished Loading Resource Information. Rendering Swagger UI":"Ολοκλήρωση Φόρτωσης Πληροφορικών Πόρου. Παρουσίαση Swagger UI", + "Unable to read api":"Αδυναμία ανάγνωσης api", + "from path":"από το μονοπάτι", + "server returned":"ο εξυπηρετηρής επέστρεψε" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/en.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/en.js new file mode 100644 index 00000000000..918313665db --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/en.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Warning: Deprecated", + "Implementation Notes":"Implementation Notes", + "Response Class":"Response Class", + "Status":"Status", + "Parameters":"Parameters", + "Parameter":"Parameter", + "Value":"Value", + "Description":"Description", + "Parameter Type":"Parameter Type", + "Data Type":"Data Type", + "Response Messages":"Response Messages", + "HTTP Status Code":"HTTP Status Code", + "Reason":"Reason", + "Response Model":"Response Model", + "Request URL":"Request URL", + "Response Body":"Response Body", + "Response Code":"Response Code", + "Response Headers":"Response Headers", + "Hide Response":"Hide Response", + "Headers":"Headers", + "Try it out!":"Try it out!", + "Show/Hide":"Show/Hide", + "List Operations":"List Operations", + "Expand Operations":"Expand Operations", + "Raw":"Raw", + "can't parse JSON. Raw result":"can't parse JSON. Raw result", + "Example Value":"Example Value", + "Model Schema":"Model Schema", + "Model":"Model", + "Click to set as parameter value":"Click to set as parameter value", + "apply":"apply", + "Username":"Username", + "Password":"Password", + "Terms of service":"Terms of service", + "Created by":"Created by", + "See more at":"See more at", + "Contact the developer":"Contact the developer", + "api version":"api version", + "Response Content Type":"Response Content Type", + "Parameter content type:":"Parameter content type:", + "fetching resource":"fetching resource", + "fetching resource list":"fetching resource list", + "Explore":"Explore", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.", + "Please specify the protocol for":"Please specify the protocol for", + "Can't read swagger JSON from":"Can't read swagger JSON from", + "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI", + "Unable to read api":"Unable to read api", + "from path":"from path", + "server returned":"server returned" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/es.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/es.js new file mode 100644 index 00000000000..13fa015e6df --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/es.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Advertencia: Obsoleto", + "Implementation Notes":"Notas de implementación", + "Response Class":"Clase de la Respuesta", + "Status":"Status", + "Parameters":"Parámetros", + "Parameter":"Parámetro", + "Value":"Valor", + "Description":"Descripción", + "Parameter Type":"Tipo del Parámetro", + "Data Type":"Tipo del Dato", + "Response Messages":"Mensajes de la Respuesta", + "HTTP Status Code":"Código de Status HTTP", + "Reason":"Razón", + "Response Model":"Modelo de la Respuesta", + "Request URL":"URL de la Solicitud", + "Response Body":"Cuerpo de la Respuesta", + "Response Code":"Código de la Respuesta", + "Response Headers":"Encabezados de la Respuesta", + "Hide Response":"Ocultar Respuesta", + "Try it out!":"Pruébalo!", + "Show/Hide":"Mostrar/Ocultar", + "List Operations":"Listar Operaciones", + "Expand Operations":"Expandir Operaciones", + "Raw":"Crudo", + "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo", + "Example Value":"Valor de Ejemplo", + "Model Schema":"Esquema del Modelo", + "Model":"Modelo", + "apply":"aplicar", + "Username":"Nombre de usuario", + "Password":"Contraseña", + "Terms of service":"Términos de Servicio", + "Created by":"Creado por", + "See more at":"Ver más en", + "Contact the developer":"Contactar al desarrollador", + "api version":"versión de la api", + "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta", + "fetching resource":"buscando recurso", + "fetching resource list":"buscando lista del recurso", + "Explore":"Explorar", + "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.", + "Please specify the protocol for":"Por favor, especificar el protocola para", + "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde", + "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI", + "Unable to read api":"No se puede leer la api", + "from path":"desde ruta", + "server returned":"el servidor retornó" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/fr.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/fr.js new file mode 100644 index 00000000000..388dff14bac --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/fr.js @@ -0,0 +1,54 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Avertissement : Obsolète", + "Implementation Notes":"Notes d'implémentation", + "Response Class":"Classe de la réponse", + "Status":"Statut", + "Parameters":"Paramètres", + "Parameter":"Paramètre", + "Value":"Valeur", + "Description":"Description", + "Parameter Type":"Type du paramètre", + "Data Type":"Type de données", + "Response Messages":"Messages de la réponse", + "HTTP Status Code":"Code de statut HTTP", + "Reason":"Raison", + "Response Model":"Modèle de réponse", + "Request URL":"URL appelée", + "Response Body":"Corps de la réponse", + "Response Code":"Code de la réponse", + "Response Headers":"En-têtes de la réponse", + "Hide Response":"Cacher la réponse", + "Headers":"En-têtes", + "Try it out!":"Testez !", + "Show/Hide":"Afficher/Masquer", + "List Operations":"Liste des opérations", + "Expand Operations":"Développer les opérations", + "Raw":"Brut", + "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut", + "Example Value":"Exemple la valeur", + "Model Schema":"Définition du modèle", + "Model":"Modèle", + "apply":"appliquer", + "Username":"Nom d'utilisateur", + "Password":"Mot de passe", + "Terms of service":"Conditions de service", + "Created by":"Créé par", + "See more at":"Voir plus sur", + "Contact the developer":"Contacter le développeur", + "api version":"version de l'api", + "Response Content Type":"Content Type de la réponse", + "fetching resource":"récupération de la ressource", + "fetching resource list":"récupération de la liste de ressources", + "Explore":"Explorer", + "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.", + "Please specify the protocol for":"Veuillez spécifier un protocole pour", + "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de", + "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI", + "Unable to read api":"Impossible de lire l'api", + "from path":"à partir du chemin", + "server returned":"réponse du serveur" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/geo.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/geo.js new file mode 100644 index 00000000000..609c20d9c86 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/geo.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"ყურადღება: აღარ გამოიყენება", + "Implementation Notes":"იმპლემენტაციის აღწერა", + "Response Class":"რესპონს კლასი", + "Status":"სტატუსი", + "Parameters":"პარამეტრები", + "Parameter":"პარამეტრი", + "Value":"მნიშვნელობა", + "Description":"აღწერა", + "Parameter Type":"პარამეტრის ტიპი", + "Data Type":"მონაცემის ტიპი", + "Response Messages":"პასუხი", + "HTTP Status Code":"HTTP სტატუსი", + "Reason":"მიზეზი", + "Response Model":"რესპონს მოდელი", + "Request URL":"მოთხოვნის URL", + "Response Body":"პასუხის სხეული", + "Response Code":"პასუხის კოდი", + "Response Headers":"პასუხის ჰედერები", + "Hide Response":"დამალე პასუხი", + "Headers":"ჰედერები", + "Try it out!":"ცადე !", + "Show/Hide":"გამოჩენა/დამალვა", + "List Operations":"ოპერაციების სია", + "Expand Operations":"ოპერაციები ვრცლად", + "Raw":"ნედლი", + "can't parse JSON. Raw result":"JSON-ის დამუშავება ვერ მოხერხდა. ნედლი პასუხი", + "Example Value":"მაგალითი", + "Model Schema":"მოდელის სტრუქტურა", + "Model":"მოდელი", + "Click to set as parameter value":"პარამეტრისთვის მნიშვნელობის მისანიჭებლად, დააკლიკე", + "apply":"გამოყენება", + "Username":"მოხმარებელი", + "Password":"პაროლი", + "Terms of service":"მომსახურების პირობები", + "Created by":"შექმნა", + "See more at":"ნახე ვრცლად", + "Contact the developer":"დაუკავშირდი დეველოპერს", + "api version":"api ვერსია", + "Response Content Type":"პასუხის კონტენტის ტიპი", + "Parameter content type:":"პარამეტრის კონტენტის ტიპი:", + "fetching resource":"რესურსების მიღება", + "fetching resource list":"რესურსების სიის მიღება", + "Explore":"ნახვა", + "Show Swagger Petstore Example Apis":"ნახე Swagger Petstore სამაგალითო Api", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"სერვერთან დაკავშირება ვერ ხერხდება. შეამოწმეთ access-control-origin.", + "Please specify the protocol for":"მიუთითეთ პროტოკოლი", + "Can't read swagger JSON from":"swagger JSON წაკითხვა ვერ მოხერხდა", + "Finished Loading Resource Information. Rendering Swagger UI":"რესურსების ჩატვირთვა სრულდება. Swagger UI რენდერდება", + "Unable to read api":"api წაკითხვა ვერ მოხერხდა", + "from path":"მისამართიდან", + "server returned":"სერვერმა დააბრუნა" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/it.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/it.js new file mode 100644 index 00000000000..8529c2a90bc --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/it.js @@ -0,0 +1,52 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Attenzione: Deprecato", + "Implementation Notes":"Note di implementazione", + "Response Class":"Classe della risposta", + "Status":"Stato", + "Parameters":"Parametri", + "Parameter":"Parametro", + "Value":"Valore", + "Description":"Descrizione", + "Parameter Type":"Tipo di parametro", + "Data Type":"Tipo di dato", + "Response Messages":"Messaggi della risposta", + "HTTP Status Code":"Codice stato HTTP", + "Reason":"Motivo", + "Response Model":"Modello di risposta", + "Request URL":"URL della richiesta", + "Response Body":"Corpo della risposta", + "Response Code":"Oggetto della risposta", + "Response Headers":"Intestazioni della risposta", + "Hide Response":"Nascondi risposta", + "Try it out!":"Provalo!", + "Show/Hide":"Mostra/Nascondi", + "List Operations":"Mostra operazioni", + "Expand Operations":"Espandi operazioni", + "Raw":"Grezzo (raw)", + "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).", + "Model Schema":"Schema del modello", + "Model":"Modello", + "apply":"applica", + "Username":"Nome utente", + "Password":"Password", + "Terms of service":"Condizioni del servizio", + "Created by":"Creato da", + "See more at":"Informazioni aggiuntive:", + "Contact the developer":"Contatta lo sviluppatore", + "api version":"versione api", + "Response Content Type":"Tipo di contenuto (content type) della risposta", + "fetching resource":"recuperando la risorsa", + "fetching resource list":"recuperando lista risorse", + "Explore":"Esplora", + "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.", + "Please specify the protocol for":"Si prega di specificare il protocollo per", + "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:", + "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata", + "Unable to read api":"Impossibile leggere la api", + "from path":"da cartella", + "server returned":"il server ha restituito" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ja.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ja.js new file mode 100644 index 00000000000..1cbeb374ac1 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ja.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告: 廃止予定", + "Implementation Notes":"実装メモ", + "Response Class":"レスポンスクラス", + "Status":"ステータス", + "Parameters":"パラメータ群", + "Parameter":"パラメータ", + "Value":"値", + "Description":"説明", + "Parameter Type":"パラメータタイプ", + "Data Type":"データタイプ", + "Response Messages":"レスポンスメッセージ", + "HTTP Status Code":"HTTPステータスコード", + "Reason":"理由", + "Response Model":"レスポンスモデル", + "Request URL":"リクエストURL", + "Response Body":"レスポンスボディ", + "Response Code":"レスポンスコード", + "Response Headers":"レスポンスヘッダ", + "Hide Response":"レスポンスを隠す", + "Headers":"ヘッダ", + "Try it out!":"実際に実行!", + "Show/Hide":"表示/非表示", + "List Operations":"操作一覧", + "Expand Operations":"操作の展開", + "Raw":"未加工", + "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果", + "Example Value":"値の例", + "Model Schema":"モデルスキーマ", + "Model":"モデル", + "Click to set as parameter value":"パラメータ値と設定するにはクリック", + "apply":"実行", + "Username":"ユーザ名", + "Password":"パスワード", + "Terms of service":"サービス利用規約", + "Created by":"Created by", + "See more at":"詳細を見る", + "Contact the developer":"開発者に連絡", + "api version":"APIバージョン", + "Response Content Type":"レスポンス コンテンツタイプ", + "Parameter content type:":"パラメータコンテンツタイプ:", + "fetching resource":"リソースの取得", + "fetching resource list":"リソース一覧の取得", + "Explore":"調査", + "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.", + "Please specify the protocol for":"プロトコルを指定してください", + "Can't read swagger JSON from":"次からswagger JSONを読み込めません", + "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています", + "Unable to read api":"APIを読み込めません", + "from path":"次のパスから", + "server returned":"サーバからの返答" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ko-kr.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ko-kr.js new file mode 100644 index 00000000000..03c7626d7f9 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ko-kr.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"경고:폐기예정됨", + "Implementation Notes":"구현 노트", + "Response Class":"응답 클래스", + "Status":"상태", + "Parameters":"매개변수들", + "Parameter":"매개변수", + "Value":"값", + "Description":"설명", + "Parameter Type":"매개변수 타입", + "Data Type":"데이터 타입", + "Response Messages":"응답 메세지", + "HTTP Status Code":"HTTP 상태 코드", + "Reason":"원인", + "Response Model":"응답 모델", + "Request URL":"요청 URL", + "Response Body":"응답 본문", + "Response Code":"응답 코드", + "Response Headers":"응답 헤더", + "Hide Response":"응답 숨기기", + "Headers":"헤더", + "Try it out!":"써보기!", + "Show/Hide":"보이기/숨기기", + "List Operations":"목록 작업", + "Expand Operations":"전개 작업", + "Raw":"원본", + "can't parse JSON. Raw result":"JSON을 파싱할수 없음. 원본결과:", + "Model Schema":"모델 스키마", + "Model":"모델", + "apply":"적용", + "Username":"사용자 이름", + "Password":"암호", + "Terms of service":"이용약관", + "Created by":"작성자", + "See more at":"추가정보:", + "Contact the developer":"개발자에게 문의", + "api version":"api버전", + "Response Content Type":"응답Content Type", + "fetching resource":"리소스 가져오기", + "fetching resource list":"리소스 목록 가져오기", + "Explore":"탐색", + "Show Swagger Petstore Example Apis":"Swagger Petstore 예제 보기", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"서버로부터 읽어들일수 없습니다. access-control-origin 설정이 올바르지 않을수 있습니다.", + "Please specify the protocol for":"다음을 위한 프로토콜을 정하세요", + "Can't read swagger JSON from":"swagger JSON 을 다음으로 부터 읽을수 없습니다", + "Finished Loading Resource Information. Rendering Swagger UI":"리소스 정보 불러오기 완료. Swagger UI 랜더링", + "Unable to read api":"api를 읽을 수 없습니다.", + "from path":"다음 경로로 부터", + "server returned":"서버 응답함." +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/pl.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/pl.js new file mode 100644 index 00000000000..ce41e91799d --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/pl.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Uwaga: Wycofane", + "Implementation Notes":"Uwagi Implementacji", + "Response Class":"Klasa Odpowiedzi", + "Status":"Status", + "Parameters":"Parametry", + "Parameter":"Parametr", + "Value":"Wartość", + "Description":"Opis", + "Parameter Type":"Typ Parametru", + "Data Type":"Typ Danych", + "Response Messages":"Wiadomości Odpowiedzi", + "HTTP Status Code":"Kod Statusu HTTP", + "Reason":"Przyczyna", + "Response Model":"Model Odpowiedzi", + "Request URL":"URL Wywołania", + "Response Body":"Treść Odpowiedzi", + "Response Code":"Kod Odpowiedzi", + "Response Headers":"Nagłówki Odpowiedzi", + "Hide Response":"Ukryj Odpowiedź", + "Headers":"Nagłówki", + "Try it out!":"Wypróbuj!", + "Show/Hide":"Pokaż/Ukryj", + "List Operations":"Lista Operacji", + "Expand Operations":"Rozwiń Operacje", + "Raw":"Nieprzetworzone", + "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane", + "Model Schema":"Schemat Modelu", + "Model":"Model", + "apply":"użyj", + "Username":"Nazwa użytkownika", + "Password":"Hasło", + "Terms of service":"Warunki używania", + "Created by":"Utworzone przez", + "See more at":"Zobacz więcej na", + "Contact the developer":"Kontakt z deweloperem", + "api version":"wersja api", + "Response Content Type":"Typ Zasobu Odpowiedzi", + "fetching resource":"ładowanie zasobu", + "fetching resource list":"ładowanie listy zasobów", + "Explore":"Eksploruj", + "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.", + "Please specify the protocol for":"Proszę podać protokół dla", + "Can't read swagger JSON from":"Nie można odczytać swagger JSON z", + "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI", + "Unable to read api":"Nie można odczytać api", + "from path":"ze ścieżki", + "server returned":"serwer zwrócił" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/pt.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/pt.js new file mode 100644 index 00000000000..f2e7c13d413 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/pt.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Aviso: Depreciado", + "Implementation Notes":"Notas de Implementação", + "Response Class":"Classe de resposta", + "Status":"Status", + "Parameters":"Parâmetros", + "Parameter":"Parâmetro", + "Value":"Valor", + "Description":"Descrição", + "Parameter Type":"Tipo de parâmetro", + "Data Type":"Tipo de dados", + "Response Messages":"Mensagens de resposta", + "HTTP Status Code":"Código de status HTTP", + "Reason":"Razão", + "Response Model":"Modelo resposta", + "Request URL":"URL requisição", + "Response Body":"Corpo da resposta", + "Response Code":"Código da resposta", + "Response Headers":"Cabeçalho da resposta", + "Headers":"Cabeçalhos", + "Hide Response":"Esconder resposta", + "Try it out!":"Tente agora!", + "Show/Hide":"Mostrar/Esconder", + "List Operations":"Listar operações", + "Expand Operations":"Expandir operações", + "Raw":"Cru", + "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru", + "Model Schema":"Modelo esquema", + "Model":"Modelo", + "apply":"Aplicar", + "Username":"Usuário", + "Password":"Senha", + "Terms of service":"Termos do serviço", + "Created by":"Criado por", + "See more at":"Veja mais em", + "Contact the developer":"Contate o desenvolvedor", + "api version":"Versão api", + "Response Content Type":"Tipo de conteúdo da resposta", + "fetching resource":"busca recurso", + "fetching resource list":"buscando lista de recursos", + "Explore":"Explorar", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin", + "Please specify the protocol for":"Por favor especifique o protocolo", + "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de", + "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI", + "Unable to read api":"Não foi possível ler api", + "from path":"do caminho", + "server returned":"servidor retornou" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ru.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ru.js new file mode 100644 index 00000000000..592744e957f --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/ru.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Предупреждение: Устарело", + "Implementation Notes":"Заметки", + "Response Class":"Пример ответа", + "Status":"Статус", + "Parameters":"Параметры", + "Parameter":"Параметр", + "Value":"Значение", + "Description":"Описание", + "Parameter Type":"Тип параметра", + "Data Type":"Тип данных", + "HTTP Status Code":"HTTP код", + "Reason":"Причина", + "Response Model":"Структура ответа", + "Request URL":"URL запроса", + "Response Body":"Тело ответа", + "Response Code":"HTTP код ответа", + "Response Headers":"Заголовки ответа", + "Hide Response":"Спрятать ответ", + "Headers":"Заголовки", + "Response Messages":"Что может прийти в ответ", + "Try it out!":"Попробовать!", + "Show/Hide":"Показать/Скрыть", + "List Operations":"Операции кратко", + "Expand Operations":"Операции подробно", + "Raw":"В сыром виде", + "can't parse JSON. Raw result":"Не удается распарсить ответ:", + "Example Value":"Пример", + "Model Schema":"Структура", + "Model":"Описание", + "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра", + "apply":"применить", + "Username":"Имя пользователя", + "Password":"Пароль", + "Terms of service":"Условия использования", + "Created by":"Разработано", + "See more at":"Еще тут", + "Contact the developer":"Связаться с разработчиком", + "api version":"Версия API", + "Response Content Type":"Content Type ответа", + "Parameter content type:":"Content Type параметра:", + "fetching resource":"Получение ресурса", + "fetching resource list":"Получение ресурсов", + "Explore":"Показать", + "Show Swagger Petstore Example Apis":"Показать примеры АПИ", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа", + "Please specify the protocol for":"Пожалуйста, укажите протокол для", + "Can't read swagger JSON from":"Не получается прочитать swagger json из", + "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим", + "Unable to read api":"Не удалось прочитать api", + "from path":"по адресу", + "server returned":"сервер сказал" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/tr.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/tr.js new file mode 100644 index 00000000000..16426a9c34b --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/tr.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Uyarı: Deprecated", + "Implementation Notes":"Gerçekleştirim Notları", + "Response Class":"Dönen Sınıf", + "Status":"Statü", + "Parameters":"Parametreler", + "Parameter":"Parametre", + "Value":"Değer", + "Description":"Açıklama", + "Parameter Type":"Parametre Tipi", + "Data Type":"Veri Tipi", + "Response Messages":"Dönüş Mesajı", + "HTTP Status Code":"HTTP Statü Kodu", + "Reason":"Gerekçe", + "Response Model":"Dönüş Modeli", + "Request URL":"İstek URL", + "Response Body":"Dönüş İçeriği", + "Response Code":"Dönüş Kodu", + "Response Headers":"Dönüş Üst Bilgileri", + "Hide Response":"Dönüşü Gizle", + "Headers":"Üst Bilgiler", + "Try it out!":"Dene!", + "Show/Hide":"Göster/Gizle", + "List Operations":"Operasyonları Listele", + "Expand Operations":"Operasyonları Aç", + "Raw":"Ham", + "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç", + "Model Schema":"Model Şema", + "Model":"Model", + "apply":"uygula", + "Username":"Kullanıcı Adı", + "Password":"Parola", + "Terms of service":"Servis şartları", + "Created by":"Oluşturan", + "See more at":"Daha fazlası için", + "Contact the developer":"Geliştirici ile İletişime Geçin", + "api version":"api versiyon", + "Response Content Type":"Dönüş İçerik Tipi", + "fetching resource":"kaynak getiriliyor", + "fetching resource list":"kaynak listesi getiriliyor", + "Explore":"Keşfet", + "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.", + "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz", + "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor", + "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor", + "Unable to read api":"api okunamadı", + "from path":"yoldan", + "server returned":"sunucuya dönüldü" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/translator.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/translator.js new file mode 100644 index 00000000000..ffb879f9a27 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/translator.js @@ -0,0 +1,39 @@ +'use strict'; + +/** + * Translator for documentation pages. + * + * To enable translation you should include one of language-files in your index.html + * after . + * For example - + * + * If you wish to translate some new texts you should do two things: + * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. + * 2. Mark that text it templates this way New Phrase or . + * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate. + * + */ +window.SwaggerTranslator = { + + _words:[], + + translate: function(sel) { + var $this = this; + sel = sel || '[data-sw-translate]'; + + $(sel).each(function() { + $(this).html($this._tryTranslate($(this).html())); + + $(this).val($this._tryTranslate($(this).val())); + $(this).attr('title', $this._tryTranslate($(this).attr('title'))); + }); + }, + + _tryTranslate: function(word) { + return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; + }, + + learn: function(wordsMap) { + this._words = wordsMap; + } +}; diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lang/zh-cn.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/zh-cn.js new file mode 100644 index 00000000000..3af61ad6e4c --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lang/zh-cn.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告:已过时", + "Implementation Notes":"实现备注", + "Response Class":"响应类", + "Status":"状态", + "Parameters":"参数", + "Parameter":"参数", + "Value":"值", + "Description":"描述", + "Parameter Type":"参数类型", + "Data Type":"数据类型", + "Response Messages":"响应消息", + "HTTP Status Code":"HTTP状态码", + "Reason":"原因", + "Response Model":"响应模型", + "Request URL":"请求URL", + "Response Body":"响应体", + "Response Code":"响应码", + "Response Headers":"响应头", + "Hide Response":"隐藏响应", + "Headers":"头", + "Try it out!":"试一下!", + "Show/Hide":"显示/隐藏", + "List Operations":"显示操作", + "Expand Operations":"展开操作", + "Raw":"原始", + "can't parse JSON. Raw result":"无法解析JSON. 原始结果", + "Example Value":"示例", + "Click to set as parameter value":"点击设置参数", + "Model Schema":"模型架构", + "Model":"模型", + "apply":"应用", + "Username":"用户名", + "Password":"密码", + "Terms of service":"服务条款", + "Created by":"创建者", + "See more at":"查看更多:", + "Contact the developer":"联系开发者", + "api version":"api版本", + "Response Content Type":"响应Content Type", + "Parameter content type:":"参数类型:", + "fetching resource":"正在获取资源", + "fetching resource list":"正在获取资源列表", + "Explore":"浏览", + "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。", + "Please specify the protocol for":"请指定协议:", + "Can't read swagger JSON from":"无法读取swagger JSON于", + "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI", + "Unable to read api":"无法读取api", + "from path":"从路径", + "server returned":"服务器返回" +}); diff --git a/src/ServiceStack.Api.OpenApi/swagger-ui/lib/backbone-min.js b/src/ServiceStack.Api.OpenApi/swagger-ui/lib/backbone-min.js new file mode 100644 index 00000000000..8eff02e9842 --- /dev/null +++ b/src/ServiceStack.Api.OpenApi/swagger-ui/lib/backbone-min.js @@ -0,0 +1 @@ +!function(t,e){if("function"==typeof define&&define.amd)define(["underscore","jquery","exports"],function(i,n,s){t.Backbone=e(t,s,i,n)});else if("undefined"!=typeof exports){var i=require("underscore");e(t,exports,i)}else t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}(this,function(t,e,i,n){var s=t.Backbone,r=[],a=(r.push,r.slice);r.splice;e.VERSION="1.1.2",e.$=n,e.noConflict=function(){return t.Backbone=s,this},e.emulateHTTP=!1,e.emulateJSON=!1;var o=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var n=this._events[t]||(this._events[t]=[]);return n.push({callback:e,context:i,ctx:i||this}),this},once:function(t,e,n){if(!c(this,"once",t,[e,n])||!e)return this;var s=this,r=i.once(function(){s.off(t,r),e.apply(this,arguments)});return r._callback=e,this.on(t,r,n)},off:function(t,e,n){var s,r,a,o,h,u,l,d;if(!this._events||!c(this,"off",t,[e,n]))return this;if(!t&&!e&&!n)return this._events=void 0,this;for(o=t?[t]:i.keys(this._events),h=0,u=o.length;h").attr(t);this.setElement(n,!1)}}}),e.sync=function(t,n,s){var r=E[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:r,dataType:"json"};if(s.url||(a.url=i.result(n,"url")||j()),null!=s.data||!n||"create"!==t&&"update"!==t&&"patch"!==t||(a.contentType="application/json",a.data=JSON.stringify(s.attrs||n.toJSON(s))),s.emulateJSON&&(a.contentType="application/x-www-form-urlencoded",a.data=a.data?{model:a.data}:{}),s.emulateHTTP&&("PUT"===r||"DELETE"===r||"PATCH"===r)){a.type="POST",s.emulateJSON&&(a.data._method=r);var o=s.beforeSend;s.beforeSend=function(t){if(t.setRequestHeader("X-HTTP-Method-Override",r),o)return o.apply(this,arguments)}}"GET"===a.type||s.emulateJSON||(a.processData=!1),"PATCH"===a.type&&x&&(a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")});var h=s.xhr=e.ajax(i.extend(a,s));return n.trigger("request",n,h,s),h};var x=!("undefined"==typeof window||!window.ActiveXObject||window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent),E={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var k=e.Router=function(t){t||(t={}),t.routes&&(this.routes=t.routes),this._bindRoutes(),this.initialize.apply(this,arguments)},T=/\((.*?)\)/g,$=/(\(\?)?:\w+/g,S=/\*\w+/g,H=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend(k.prototype,o,{initialize:function(){},route:function(t,n,s){i.isRegExp(t)||(t=this._routeToRegExp(t)),i.isFunction(n)&&(s=n,n=""),s||(s=this[n]);var r=this;return e.history.route(t,function(i){var a=r._extractParameters(t,i);r.execute(s,a),r.trigger.apply(r,["route:"+n].concat(a)),r.trigger("route",n,a),e.history.trigger("route",r,n,a)}),this},execute:function(t,e){t&&t.apply(this,e)},navigate:function(t,i){return e.history.navigate(t,i),this},_bindRoutes:function(){if(this.routes){this.routes=i.result(this,"routes");for(var t,e=i.keys(this.routes);null!=(t=e.pop());)this.route(t,this.routes[t])}},_routeToRegExp:function(t){return t=t.replace(H,"\\$&").replace(T,"(?:$1)?").replace($,function(t,e){return e?t:"([^/?]+)"}).replace(S,"([^?]*?)"),new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var n=t.exec(e).slice(1);return i.map(n,function(t,e){return e===n.length-1?t||null:t?decodeURIComponent(t):null})}});var A=e.History=function(){this.handlers=[],i.bindAll(this,"checkUrl"),"undefined"!=typeof window&&(this.location=window.location,this.history=window.history)},I=/^[#\/]|\s+$/g,N=/^\/+|\/+$/g,R=/msie [\w.]+/,O=/\/$/,P=/#.*$/;A.started=!1,i.extend(A.prototype,o,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(null==t)if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(O,"");t.indexOf(i)||(t=t.slice(i.length))}else t=this.getHash();return t.replace(I,"")},start:function(t){if(A.started)throw new Error("Backbone.history has already been started");A.started=!0,this.options=i.extend({root:"/"},this.options,t),this.root=this.options.root,this._wantsHashChange=this.options.hashChange!==!1,this._wantsPushState=!!this.options.pushState,this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var n=this.getFragment(),s=document.documentMode,r=R.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);if(this.root=("/"+this.root+"/").replace(N,"/"),r&&this._wantsHashChange){var a=e.$(' + +
      + +
      +
      + +
      + + + 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/repositories.config b/src/packages/repositories.config deleted file mode 100644 index 97f1736b2fa..00000000000 --- a/src/packages/repositories.config +++ /dev/null @@ -1,4 +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/CheckWeb/Web.Debug.config b/tests/CheckWeb/Web.Debug.config new file mode 100644 index 00000000000..2e302f9f954 --- /dev/null +++ b/tests/CheckWeb/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file 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 08c14982675..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 4efe33e13df..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 5cc68b713c5..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 c99a8658718..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 7b1b664ffcb..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 2774e8b51a2..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 1898c82a4a8..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 de2db3c8e1f..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 27f592aaccd..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 c59ad15cb8a..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 527d87ba199..1071046c5fc 100644 --- a/tests/RazorRockstars.Console.Files/AppHost.cs +++ b/tests/RazorRockstars.Console.Files/AppHost.cs @@ -1,56 +1,115 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; -using Funq; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.DataAnnotations; -using ServiceStack.OrmLite; -using ServiceStack.Razor; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints; - +using System; +using System.Collections.Generic; +using System.Data; +using System.Net; +using System.Runtime.Serialization; +using System.Security.Cryptography; +using Funq; +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.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) - { - Plugins.Add(new RazorFormat()); + { + Use?.Invoke(container); - container.Register( - new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider)); + 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()); - using (var db = container.Resolve().OpenDbConnection()) + Plugins.Add(new ValidationFeature()); + container.RegisterValidators(typeof(AutoValidationValidator).Assembly); + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + + dbFactory.RegisterConnection("testdb", "~/App_Data/test.sqlite".MapAbsolutePath(), SqliteDialect.Provider); + + using (var db = dbFactory.OpenDbConnection()) { - db.CreateTable(overwrite: false); //Create table if not exists + 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] @@ -58,6 +117,7 @@ public class Rockstar 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) @@ -68,75 +128,267 @@ public Rockstar(int id, string firstName, string lastName, int age) Age = age; } } - - [RestService("/rockstars")] - [RestService("/rockstars/aged/{Age}")] - [RestService("/rockstars/delete/{Delete}")] - [RestService("/rockstars/{Id}")] - public class Rockstars + + [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 string Delete { get; set; } - public string View { 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; } + [DataMember] + public int Total { get; set; } + [DataMember] + public int? Aged { get; set; } + [DataMember] + public List Results { get; set; } } - public class RockstarsService : RestServiceBase + [Route("/ilist1/{View}")] + public class IList1 { - public IDbConnectionFactory DbFactory { get; set; } + public string View { get; set; } + } - public override object OnGet(Rockstars request) + [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) { - using (var db = DbFactory.OpenDbConnection()) + 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()) { - if (request.Delete == "reset") + 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) { - db.DeleteAll(); - db.Insert(Rockstar.SeedData); - } - else if (request.Delete.IsInt()) + 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 { - db.DeleteById(request.Delete.ToInt()); - } - - var response = new RockstarsResponse { - Aged = request.Age, - Total = db.GetScalar("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; + 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; } + } - public override object OnPost(Rockstars request) + + [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) { - using (var db = DbFactory.OpenDbConnection()) + 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 { - db.Insert(request.TranslateTo()); - return OnGet(new Rockstars()); + ServerEvents.NotifyChannel(request.Channel, request.Selector, request.Message); } } } -} \ No newline at end of file + + [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/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 new file mode 100644 index 00000000000..211069bb4b0 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/DynamicJsonTests.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Text; + +namespace RazorRockstars.Console.Files +{ + [TestFixture] + public class DynamicJsonTests + { + [Test] + public void Can_serialize_dynamic_instance() + { + var dog = new { Name = "Spot" }; + var json = DynamicJson.Serialize(dog); + + Assert.IsNotNull(json); + json.Print(); + } + + [Test] + public void Can_deserialize_dynamic_instance() + { + var dog = new { Name = "Spot" }; + var json = DynamicJson.Serialize(dog); + var deserialized = DynamicJson.Deserialize(json); + + Assert.IsNotNull(deserialized); + Assert.AreEqual(dog.Name, deserialized.Name); + } + } +} 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 new file mode 100644 index 00000000000..8f64c007e46 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/MsgPackServiceTests.cs @@ -0,0 +1,157 @@ +using System.IO; +using System.Text; +using MsgPack; +using MsgPack.Serialization; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Logging; +using ServiceStack.MsgPack; +using ServiceStack.Text; + +namespace RazorRockstars.Console.Files +{ + public class MsgPackEmail + { + public string ToAddress { get; set; } + public string FromAddress { get; set; } + public string Subject { get; set; } + public string Body { get; set; } + public byte[] AttachmentData { get; set; } + + public bool Equals(MsgPackEmail 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(MsgPackEmail)) return false; + return Equals((MsgPackEmail)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; + } + } + } + + public class MsgPackEmailResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class MsgPackEmailService : Service + { + public object Any(MsgPackEmail request) + { + return request; + } + } + + + [TestFixture] + public class MsgPackServiceTests + { + protected const string ListeningOn = "http://localhost:3337/"; + + AppHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + + appHost = new AppHost { EnableRazor = false }; + appHost.Plugins.Add(new MsgPackFormat()); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + Dispose(); + } + + public void Dispose() + { + if (appHost == null) return; + appHost.Dispose(); + } + + MsgPackEmail request = new MsgPackEmail { + ToAddress = "to@email.com", + FromAddress = "from@email.com", + Subject = "Subject", + Body = "Body", + AttachmentData = Encoding.UTF8.GetBytes("AttachmentData"), + }; + + [Test] + public void Can_Send_MsgPack_request() + { + var client = new MsgPackServiceClient(ListeningOn); + + try + { + var response = client.Send(request); + + Assert.That(response.Equals(request)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void Can_serialize_email_dto() + { + using (var ms = new MemoryStream()) + { + var serializer = MessagePackSerializer.Get(request.GetType()); + serializer.PackTo(Packer.Create(ms), request); + + ms.Position = 0; + + var unpacker = Unpacker.Create(ms); + unpacker.Read(); + var response = serializer.UnpackFrom(unpacker); + + Assert.That(response.Equals(request)); + } + } + + [Test] + public void Can_serialize_email_dto_generic() + { + using (var ms = new MemoryStream()) + { + var serializer = MessagePackSerializer.Get(); + serializer.Pack(ms, request); + + ms.Position = 0; + + var response = serializer.Unpack(ms); + + Assert.That(response.Equals(request)); + } + } + } +} diff --git a/tests/RazorRockstars.Console.Files/Pages/Dir2/Page4.cshtml b/tests/RazorRockstars.Console.Files/Pages/Dir2/Page4.cshtml index 923161988ba..f64cce4b9d3 100644 --- a/tests/RazorRockstars.Console.Files/Pages/Dir2/Page4.cshtml +++ b/tests/RazorRockstars.Console.Files/Pages/Dir2/Page4.cshtml @@ -25,8 +25,10 @@

      Show all Rockstars

      Razor View

      - - + - \ No newline at end of file +@Html.Partial("MPage3") + + + 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 87cc74a318b..77fa27caddd 100644 --- a/tests/RazorRockstars.Console.Files/RazorRockstars.Console.Files.csproj +++ b/tests/RazorRockstars.Console.Files/RazorRockstars.Console.Files.csproj @@ -1,216 +1,393 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {1A5796C5-8AB6-4676-AC20-83594AED1798} - Exe - Properties - RazorRockstars.Console.Files - RazorRockstars.Console.Files - 512 - - - x86 - True - full - False - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - - - AnyCPU - pdbonly - True - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\lib\tests\Mono.Data.Sqlite.dll - - - - - - - - - - - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - - - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.Text.dll - - - - ..\..\lib\tests\nunit.framework.dll - - - - - - - - - - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - PreserveNewest - - - - PreserveNewest - - - sqlite3.dll - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - + + + + Debug + x86 + 8.0.30703 + 2.0 + {1A5796C5-8AB6-4676-AC20-83594AED1798} + Exe + Properties + RazorRockstars.Console.Files + RazorRockstars.Console.Files + 512 + ..\..\src\ + true + v4.7.2 + + + + + + x86 + True + full + False + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + false + + + x86 + pdbonly + True + bin\Release\ + TRACE + prompt + 4 + false + + + bin\x86\Signed\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + - - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {672F2DFE-4EE8-498B-B449-23E9E7F6961C} - ServiceStack.FluentValidation.Mvc3 - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - {64128C85-B9AF-4B4C-BE83-04983EF7F8C9} - ServiceStack.Razor - - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface - - - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} - ServiceStack - - - + --> + + + + + + {5e258282-86a6-4780-ab25-5e458f2e6f70} + ServiceStack.Api.OpenApi + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416db-c143-4028-a0c3-cf41892d18d3} + ServiceStack.Common + + + {c05de4a1-84c5-481b-8bd4-c837a1303b01} + ServiceStack.HttpClient + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {6b751a07-75d4-4a9d-b3a0-eea27808e64c} + ServiceStack.MsgPack + + + {d73274ae-006b-4cee-ba60-0ecf5873048d} + ServiceStack.Razor + + + {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} + ServiceStack.Server + + + {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 15a1df56b39..306fcb851e2 100644 --- a/tests/RazorRockstars.Console.Files/RazorRockstars_FilesTests.cs +++ b/tests/RazorRockstars.Console.Files/RazorRockstars_FilesTests.cs @@ -1,188 +1,505 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Text; - +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Threading; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Logging; +using ServiceStack.Razor; +using ServiceStack.Testing; +using ServiceStack.Text; + namespace RazorRockstars.Console.Files { - [TestFixture] - public class RazorRockstars_FilesTests - { - AppHost appHost; - - Stopwatch startedAt; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - startedAt = Stopwatch.StartNew(); - appHost = new AppHost(); - appHost.Init(); - appHost.Start("http://*:1337/"); - } - - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - "Time Taken {0}ms".Fmt(startedAt.ElapsedMilliseconds).Print(); - appHost.Dispose(); - } - - [Ignore("Debug Run")][Test] - public void RunFor10Mins() - { - Thread.Sleep(TimeSpan.FromMinutes(10)); - } - - public static string AcceptContentType = "*/*"; - public void Assert200(string url, params string[] containsItems) - { + [TestFixture] + public class RazorRockstars_FilesTests + { + public const string ListeningOn = "http://*:2337/"; + public const string Host = "http://localhost:2337"; + + private const string BaseUri = Host + "/"; + + AppHost appHost; + + Stopwatch startedAt; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + startedAt = Stopwatch.StartNew(); + appHost = new AppHost + { + EnableMarkdown = true, + }; + 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); + Thread.Sleep(TimeSpan.FromMinutes(10)); + } + + [Test] + public void Does_not_use_same_razor_page_instance() + { + var html = GetRazorInstanceHtml(); + Assert.That(html, Does.Contain("
        Counter: 1
        ")); + + html = GetRazorInstanceHtml(); + 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(mockReq); + var dto = new RockstarsResponse { Results = Rockstar.SeedData.ToList() }; + razorFormat.ProcessRequest(mockReq, mockRes, dto); + var html = mockRes.ReadAsString(); + return html; + } + + public static string AcceptContentType = "*/*"; + public void Assert200(string url, params string[] containsItems) + { + 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 containsItems) + { + if (!text.Contains(item)) + { + Assert.Fail(item + " was not found in " + url); + } + } + } + + 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(); - var text = url.GetStringFromUrl(AcceptContentType, r => { - if (r.StatusCode != HttpStatusCode.OK) - Assert.Fail(url + " did not return 200 OK"); - }); - foreach (var item in containsItems) - { - if (!text.Contains(item)) - { - Assert.Fail(item + " was not found in " + url); - } - } - } - - public void Assert200UrlContentType(string url, string contentType) - { - url.Print(); - url.GetStringFromUrl(AcceptContentType, r => { - if (r.StatusCode != HttpStatusCode.OK) - Assert.Fail(url + " did not return 200 OK: " + r.StatusCode); - if (!r.ContentType.StartsWith(contentType)) - Assert.Fail(url + " did not return contentType " + contentType); - }); - } - - public static string Host = "http://localhost:1337"; - - static string ViewRockstars = ""; - static string ViewRockstars2 = ""; + url.GetStringFromUrl(AcceptContentType, responseFilter: r => + { + if (r.StatusCode != HttpStatusCode.OK) + Assert.Fail(url + " did not return 200 OK: " + r.StatusCode); + if (!r.ContentType.StartsWith(contentType)) + Assert.Fail(url + " did not return contentType " + contentType); + }); + } + + public void AssertStatus(string url, HttpStatusCode statusCode, params string[] containsItems) + { + url.Print(); + try + { + var text = url.GetStringFromUrl(AcceptContentType, responseFilter: r => + { + if (r.StatusCode != statusCode) + Assert.Fail("'{0}' returned {1} expected {2}".Fmt(url, r.StatusCode, statusCode)); + }); + } + catch (WebException webEx) + { + if (webEx != null && webEx.Status == WebExceptionStatus.ProtocolError) + { + var errorResponse = ((HttpWebResponse)webEx.Response); + if (errorResponse.StatusCode != statusCode) + Assert.Fail("'{0}' returned {1} expected {2}".Fmt(url, errorResponse.StatusCode, statusCode)); + var errorBody = webEx.GetResponseBody(); + errorBody.Print(); + + foreach (var item in containsItems) + { + if (!errorBody.Contains(item)) + { + Assert.Fail(item + " was not found in " + url); + } + } + return; + } + + throw; + } + } + + static string ViewRockstars = ""; + static string ViewRockstars2 = ""; static string ViewRockstars3 = ""; - static string ViewRockstarsMark = ""; - static string ViewNoModelNoController = ""; - static string ViewTypedModelNoController = ""; - static string ViewPage1 = ""; - static string ViewPage2 = ""; - static string ViewPage3 = ""; - static string ViewPage4 = ""; - static string ViewMarkdownRootPage = ""; - static string ViewMPage1 = ""; - static string ViewMPage2 = ""; - static string ViewMPage3 = ""; - static string ViewMPage4 = ""; - static string ViewRazorPartial = ""; - static string ViewMarkdownPartial = ""; - static string ViewRazorPartialModel = ""; - - static string View_Default = ""; - static string View_Pages_Default = ""; - static string View_Pages_Dir_Default = ""; - static string ViewM_Pages_Dir2_Default = ""; - - static string Template_Layout = ""; - static string Template_Pages_Layout = ""; - static string Template_Pages_Dir_Layout = ""; - static string Template_SimpleLayout = ""; - static string Template_SimpleLayout2 = ""; - static string Template_HtmlReport = ""; - - static string TemplateM_Layout = ""; - static string TemplateM_Pages_Layout = ""; - static string TemplateM_Pages_Dir_Layout = ""; + static string ViewRockstarsMark = ""; + static string ViewNoModelNoController = ""; + static string ViewTypedModelNoController = ""; + static string ViewCachedAllReqstars = ""; + static string ViewIList = ""; + static string ViewList = ""; + static string ViewPage1 = ""; + static string ViewPage2 = ""; + static string ViewPage3 = ""; + static string ViewPage4 = ""; + static string ViewMarkdownRootPage = ""; + static string ViewMPage1 = ""; + static string ViewMPage2 = ""; + static string ViewMPage3 = ""; + static string ViewMPage4 = ""; + static string ViewRazorPartial = ""; + 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 = ""; + static string Template_Pages_Dir_Layout = ""; + static string Template_SimpleLayout = ""; + static string Template_SimpleLayout2 = ""; + static string Template_HtmlReport = ""; + static string Template_PartialModel = ""; + + static string TemplateM_Layout = ""; + static string TemplateM_Pages_Layout = ""; + static string TemplateM_Pages_Dir_Layout = ""; static string TemplateM_HtmlReport = ""; - [Test] - public void Can_get_page_with_default_view_and_template() - { - Assert200(Host + "/rockstars", ViewRockstars, Template_HtmlReport); - } + [Test] + public void Can_get_metadata_page() + { + Assert200(BaseUri.CombineWith("metadata")); + } + + [Test] + public void Can_get_Rockstars_service() + { + var client = new JsonServiceClient(BaseUri); + var response = client.Get("rockstars"); + Assert.That(response.Results.Count, Is.EqualTo(Rockstar.SeedData.Length)); + } + + [Test] + public void Can_get_page_with_default_view_and_template() + { + Assert200(Host + "/rockstars", ViewRockstars, Template_HtmlReport); + } - [Test] - public void Can_get_page_with_alt_view_and_default_template() - { + [Test] + public void Can_get_page_with_alt_view_and_default_template() + { Assert200(Host + "/rockstars?View=Rockstars2", ViewRockstars2, Template_Layout); - } - - [Test] - public void Can_get_page_with_alt_viewengine_view_and_default_template() - { + } + + [Test] + public void Can_get_page_with_alt_viewengine_view_and_default_template() + { Assert200(Host + "/rockstars?View=RockstarsMark", ViewRockstarsMark, TemplateM_HtmlReport); - } - - [Test] - public void Can_get_page_with_default_view_and_alt_template() - { - Assert200(Host + "/rockstars?Template=SimpleLayout", ViewRockstars, Template_SimpleLayout); - } - - [Test] - public void Can_get_page_with_alt_viewengine_view_and_alt_razor_template() - { - Assert200(Host + "/rockstars?View=Rockstars2&Template=SimpleLayout2", ViewRockstars2, Template_SimpleLayout2); - } - - [Test] - public void Can_get_razor_content_pages() - { - Assert200(Host + "/TypedModelNoController", - ViewTypedModelNoController, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); - Assert200(Host + "/nomodelnocontroller", - ViewNoModelNoController, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial); - Assert200(Host + "/pages/page1", - ViewPage1, Template_Pages_Layout, ViewRazorPartialModel, ViewMarkdownPartial); - Assert200(Host + "/pages/dir/Page2", - ViewPage2, Template_Pages_Dir_Layout, ViewRazorPartial, ViewMarkdownPartial); - Assert200(Host + "/pages/dir2/Page3", - ViewPage3, Template_Pages_Layout, ViewRazorPartial, ViewMarkdownPartial); - Assert200(Host + "/pages/dir2/Page4", - ViewPage4, Template_HtmlReport, ViewRazorPartial, ViewMarkdownPartial); - } - - [Test] - public void Can_get_markdown_content_pages() - { - Assert200(Host + "/MRootPage", - ViewMarkdownRootPage, TemplateM_Layout); - Assert200(Host + "/pages/mpage1", - ViewMPage1, TemplateM_Pages_Layout); - Assert200(Host + "/pages/dir/mPage2", - ViewMPage2, TemplateM_Pages_Dir_Layout); - } - - [Test] - public void Can_get_default_razor_pages() - { - Assert200(Host + "/", - View_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); - Assert200(Host + "/Pages/", - View_Pages_Default, Template_Pages_Layout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); - Assert200(Host + "/Pages/Dir/", - View_Pages_Dir_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); - } - - [Test] - public void Can_get_default_markdown_pages() - { - Assert200(Host + "/Pages/Dir2/", - ViewM_Pages_Dir2_Default, TemplateM_Pages_Layout); - } - - [Test] //Good for testing adhoc compilation - public void Can_get_last_view_template_compiled() - { - Assert200(Host + "/rockstars?View=Rockstars3", ViewRockstars3, Template_SimpleLayout2); - } + } + + [Test] + public void Can_get_page_with_default_view_and_alt_template() + { + Assert200(Host + "/rockstars?Template=SimpleLayout", ViewRockstars, Template_SimpleLayout); + } + + [Test] + public void Can_get_page_with_alt_viewengine_view_and_alt_razor_template() + { + Assert200(Host + "/rockstars?View=Rockstars2&Template=SimpleLayout2", ViewRockstars2, Template_SimpleLayout2); + } + + [Test] + public void Can_get_razor_content_pages() + { + Assert200(Host + "/TypedModelNoController", + ViewTypedModelNoController, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); + Assert200(Host + "/nomodelnocontroller", + ViewNoModelNoController, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial); + Assert200(Host + "/pages/page1", + ViewPage1, Template_Pages_Layout, ViewRazorPartialModel, ViewMarkdownPartial); + Assert200(Host + "/pages/dir/Page2", + ViewPage2, Template_Pages_Dir_Layout, ViewRazorPartial, ViewMarkdownPartial); + Assert200(Host + "/pages/dir2/Page3", + ViewPage3, Template_Pages_Layout, ViewRazorPartial, ViewMarkdownPartial); + Assert200(Host + "/pages/dir2/Page4", + ViewPage4, Template_HtmlReport, ViewRazorPartial, ViewMarkdownPartial); + } + + [Test] + public void Can_get_razor_content_pages_with_partials() + { + Assert200(Host + "/pages/dir2/Page4", + ViewPage4, Template_HtmlReport, ViewRazorPartial, ViewMarkdownPartial, ViewMPage3); + } + + [Test] + public void Can_get_markdown_content_pages() + { + Assert200(Host + "/MRootPage", + ViewMarkdownRootPage, TemplateM_Layout); + Assert200(Host + "/pages/mpage1", + ViewMPage1, TemplateM_Pages_Layout); + Assert200(Host + "/pages/dir/mPage2", + ViewMPage2, TemplateM_Pages_Dir_Layout); + } + + [Test] + public void Redirects_when_trying_to_get_razor_page_with_extension() + { + Assert200(Host + "/pages/dir2/Page4.cshtml", + ViewPage4, Template_HtmlReport, ViewRazorPartial, ViewMarkdownPartial, ViewMPage3); + } + + [Test] + public void Redirects_when_trying_to_get_markdown_page_with_extension() + { + Assert200(Host + "/pages/mpage1.md", + ViewMPage1, TemplateM_Pages_Layout); + } + + [Test] + public void Can_get_default_razor_pages() + { + Assert200(Host + "/", + View_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel, ViewContentPartialModel, ViewPagesPartialModel); + Assert200(Host + "/Pages/", + 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() + { + Assert200(Host + "/Pages/Dir2/", + ViewM_Pages_Dir2_Default, TemplateM_Pages_Layout); + } + + [Test] //Good for testing adhoc compilation + public void Can_get_last_view_template_compiled() + { + Assert200(Host + "/rockstars?View=Rockstars3", ViewRockstars3, Template_SimpleLayout2); + } + + [Test] + public void Can_get_razor_view_with_interface_response() + { + Assert200(Host + "/ilist1/IList", ViewIList, Template_HtmlReport); + Assert200(Host + "/ilist2/IList", ViewIList, Template_HtmlReport); + Assert200(Host + "/ilist3/IList", ViewIList, Template_HtmlReport); + + Assert200(Host + "/ilist1/List", ViewList, Template_HtmlReport); + Assert200(Host + "/ilist2/List", ViewList, Template_HtmlReport); + Assert200(Host + "/ilist3/List", ViewList, Template_HtmlReport); + } + + [Test] + public void Can_get_PartialModel() + { + var containsItems = new List + { + Template_PartialModel, + ViewPartialChildModel, + }; + + 5.Times(x => containsItems.Add("")); + + Assert200(Host + "/partialmodel", containsItems.ToArray()); + } + + [Test] + 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() + { + AssertStatus(Host + "/modelerror?message=Custom_Error_Message", HttpStatusCode.BadRequest, + Template_HtmlReport, + "", + "

        ResponseStatus: ArgumentException

        ", + "

        ResponseStatus: Custom_Error_Message was triggered by client

        "); + } + + [Test] + public void Does_return_populated_error_page_with_custom_status() + { + AssertStatus(Host + "/modelerror/417?message=Custom_Error_Message_Only", HttpStatusCode.ExpectationFailed, + Template_HtmlReport, + "", + "

        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 new file mode 100644 index 00000000000..6b6b71a1800 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/ReqStarsService.cs @@ -0,0 +1,1021 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; +using System.Threading; +using System.Web.ModelBinding; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.Host; +using ServiceStack.Logging; +using ServiceStack.MsgPack; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace RazorRockstars.Console.Files +{ + /// New Proposal, keeping ServiceStack's message-based semantics: + /// Inspired by Ivan's proposal: http://korneliuk.blogspot.com/2012/08/servicestack-reusing-dtos.html + /// + /// To align with ServiceStack's message-based design, an "Action": + /// - is public and only supports a single argument the typed Request DTO + /// - method name matches a HTTP Method or "Any" which is used as a fallback (for all methods) if it exists + /// - only returns object or void + /// + /// Notes: + /// Content Negotiation built-in, i.e. by default each method/route is automatically available in every registered Content-Type (HTTP Only). + /// 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 + { + public int? Age { get; set; } + } + + [Route("/reqstars", "GET")] + public class AllReqstars : IReturn> { } + + [Route("/reqstars/cached/{Aged}", "GET")] + public class CachedAllReqstars : IReturn + { + public int Aged { get; set; } + } + + public class ReqstarsResponse + { + public int Total { get; set; } + public int? Aged { get; set; } + public List Results { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/reqstars/reset")] + public class ResetReqstar : IReturnVoid { } + + [Route("/reqstars/{Id}", "GET")] + 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 + { + public int Id { get; set; } + } + + [Route("/reqstars")] + public class Reqstar : 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 Reqstar() { } + public Reqstar(int id, string firstName, string lastName, int age) + { + Id = id; + FirstName = firstName; + LastName = lastName; + Age = age; + } + } + + [Route("/reqstars/{Id}", "PATCH")] + public class UpdateReqstar : IReturn + { + public int Id { get; set; } + public int Age { get; set; } + + public UpdateReqstar() { } + public UpdateReqstar(int id, int age) + { + Id = id; + Age = age; + } + } + + [Route("/modelerror")] + [Route("/modelerror/{StatusCode}")] + [Route("/modelerror/{StatusCode}/{Message}")] + public class ModelError : IReturn + { + public int? StatusCode { get; set; } + public string Message { get; set; } + } + + public class ModelErrorResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class RoutelessReqstar : IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + } + + public class ReqstarsByNames : List { } + + [Route("/richrequest")] + public class RichRequest : IReturn + { + public List StringList { get; set; } + public HashSet StringSet { get; set; } + public string[] StringArray { get; set; } + } + + public class ReqstarsService : Service + { + public static Reqstar[] SeedData = new[] { + new Reqstar(1, "Foo", "Bar", 20), + new Reqstar(2, "Something", "Else", 30), + new Reqstar(3, "Foo2", "Bar2", 20), + }; + + public object Any(ACodeGenTest request) + { + return new ACodeGenTestResponse { FirstResult = request.FirstField }; + } + + [EnableCors] + public void Options(Reqstar reqstar) { } + + public void Any(ResetReqstar request) + { + Db.DeleteAll(); + Db.Insert(SeedData); + } + + public ReqstarsResponse Get(SearchReqstars request) + { + if (request.Age.HasValue && request.Age <= 0) + throw new ArgumentException("Invalid Age"); + + return new ReqstarsResponse //matches ReqstarsResponse.cshtml razor view + { + Aged = request.Age, + Total = Db.Scalar("select count(*) from Reqstar"), + Results = request.Age.HasValue + ? Db.Select(q => q.Age == request.Age.Value) + : Db.Select() + }; + } + + public List Any(AllReqstars request) + { + return Db.Select(); + } + + public object Any(CachedAllReqstars request) + { + if (request.Aged <= 0) + throw new ArgumentException("Invalid Age"); + + var cacheKey = typeof(CachedAllReqstars).Name; + return base.Request.ToOptimizedResultUsingCache(base.Cache, cacheKey, () => + new ReqstarsResponse { + Aged = request.Aged, + Total = Db.Scalar("select count(*) from Reqstar"), + Results = Db.Select(q => q.Age == request.Aged) + }); + } + + [ClientCanSwapTemplates] //allow action-level filters + public Reqstar Get(GetReqstar request) + { + 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) + { + if (!request.Age.HasValue) + throw new ArgumentException("Age is required"); + + Db.Insert(request.ConvertTo()); + return Db.Select(); + } + + public Reqstar Patch(UpdateReqstar request) + { + Db.Update(request, x => x.Id == request.Id); + return Db.SingleById(request.Id); + } + + public void Any(DeleteReqstar request) + { + Db.DeleteById(request.Id); + } + + public RoutelessReqstar Any(RoutelessReqstar request) + { + return request; + } + + public List Any(ReqstarsByNames request) + { + return Db.Select(q => Sql.In(q.FirstName, request.ToArray())); + } + + public MixedDataContractResponse Any(MixedDataContract request) + { + return new MixedDataContractResponse(); + } + + public InheritsResponse Any(Inherits request) + { + return new InheritsResponse(); + } + + public RichRequest Get(RichRequest request) + { + return request; + } + + public object Any(ModelError request) + { + if (request.StatusCode.HasValue) + { + throw new HttpError( + request.StatusCode.Value, + typeof(ArgumentException).Name, + request.Message); + } + throw new ArgumentException(request.Message + " was triggered by client"); + } + } + + + [Route("/ignore/{ignore}")] + public class IgnoreRoute1 + { + public string Name { get; set; } + } + [Route("/ignore/{ignore}/between")] + public class IgnoreRoute2 + { + public string Name { get; set; } + } + [Route("/ignore/{ignore}/and/{ignore}")] + [Route("/ignore/{ignore}/with/{name}")] + public class IgnoreRoute3 + { + public string Name { get; set; } + } + [Route("/ignorewildcard/{ignore*}")] + public class IgnoreWildcardRoute + { + public string Name { get; set; } + } + + public class IgnoreService : Service + { + public object Get(IgnoreRoute1 request) + { + return request; + } + + public object Get(IgnoreRoute2 request) + { + return request; + } + + public object Get(IgnoreRoute3 request) + { + return request; + } + + public object Get(IgnoreWildcardRoute request) + { + return request; + } + } + + [DataContract(Name = "MixName", Namespace = "http://mix.namespace.com")] + public class MixedDataContract : IReturn + { + [DataMember(Name = "MixId", Order = 1, EmitDefaultValue = false, IsRequired = true)] + public int Id { get; set; } + } + + [DataContract(Name = "MixedDCResponse")] + public class MixedDataContractResponse + { + [DataMember(Name = "MixTotal")] + public int Total { get; set; } + [DataMember(Order = 2)] + public int? Aged { get; set; } + [DataMember(EmitDefaultValue = false)] + public List Results { get; set; } + [DataMember(IsRequired = true)] + public string Required { get; set; } + + [DataMember] + public MixDataType MixDataType { get; set; } + } + + public class MixDataType + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class Inherits : InheritsBase + { + public string Name { get; set; } + } + + public class InheritsBase + { + public int Id { get; set; } + } + + public class InheritsResponse + { + public string Result { get; set; } + } + + [Route("/filterattributes")] + public class RequestDto : IReturn { } + public class ResponseDto + { + public string Foo { get; set; } + } + + [MyResponseFilter] + [MyRequestFilter] + public class MyService : Service + { + public object Get(RequestDto request) + { + return new ResponseDto { Foo = "Bar" }; + } + } + + public class MyResponseFilterAttribute : ResponseFilterAttribute + { + public static int Called = 0; + public override void Execute(IRequest req, IResponse res, object responseDto) + { + Called++; + var x = responseDto; + } + } + + public class MyRequestFilterAttribute : RequestFilterAttribute + { + public static int Called = 0; + public override void Execute(IRequest req, IResponse res, object responseDto) + { + Called++; + var x = responseDto; + } + } + + [TestFixture] + public class ReqStarsServiceTests + { + private const string ListeningOn = "http://*:2337/"; + public const string Host = "http://localhost:2337"; + + private const string BaseUri = Host + "/"; + + private AppHost appHost; + + private Stopwatch startedAt; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + startedAt = Stopwatch.StartNew(); + appHost = new AppHost { + EnableRazor = true, //Uncomment for faster tests! + }; + appHost.Plugins.Add(new MsgPackFormat()); + //appHost.Plugins.Add(new NetSerializerFormat()); + //Fast + appHost.Init(); + HostContext.Config.DebugMode = true; + appHost.Start(ListeningOn); + } + + private IDbConnection db; + + [SetUp] + public void SetUp() + { + db = appHost.TryResolve().OpenDbConnection(); + db.DropAndCreateTable(); + db.Insert(ReqstarsService.SeedData); + } + + [TearDown] + public void TearDown() + { + db.Dispose(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + "Time Taken {0}ms".Fmt(startedAt.ElapsedMilliseconds).Print(); + appHost.Dispose(); + } + + [Ignore("Debug Run")] + [Test] + public void RunFor10Mins() + { + Thread.Sleep(TimeSpan.FromMinutes(10)); + } + + [Ignore("Concurrent Run")] + [Test] + public void Concurrent_GetReqstar_JSON() + { + const int NoOfThreads = 100; + + var client = new JsonServiceClient(BaseUri); + + int completed = 0; + Exception lastEx = null; + NoOfThreads.TimesAsync(i => { + try + { + var response = client.Get(new GetReqstar { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + } + catch (Exception ex) + { + lastEx = ex; + } + finally + { + Interlocked.Increment(ref completed); + } + }); + + while (completed < NoOfThreads) + Thread.Sleep(100); + + if (lastEx != null) + throw lastEx; + } + + + [Ignore("Concurrent Run")] + [Test] + public void Concurrent_GetReqstar_Razor() + { + const int NoOfThreads = 100; + + int completed = 0; + Exception lastEx = null; + string lastText = null; + NoOfThreads.TimesAsync(i => { + try + { + lastText = "{0}/reqstars/1".Fmt(Host).GetStringFromUrl(); + } + catch (Exception ex) + { + lastEx = ex; + } + finally + { + Interlocked.Increment(ref completed); + } + }); + + while (completed < NoOfThreads) + Thread.Sleep(100); + + lastText.Print(); + + if (lastEx != null) + throw lastEx; + } + + protected static IRestClient[] RestClients = + { + new JsonServiceClient(BaseUri), + new XmlServiceClient(BaseUri), + new JsvServiceClient(BaseUri), + new MsgPackServiceClient(BaseUri), + //new NetSerializerServiceClient(BaseUri), + }; + + protected static IServiceClient[] ServiceClients = + RestClients.OfType().ToArray(); + + + + [Test, TestCaseSource("RestClients")] + public void Does_allow_sending_collections(IServiceClient client) + { + var results = client.Send>(new ReqstarsByNames { "Foo", "Foo2" }); + } + + [Test, TestCaseSource("RestClients")] + public void Does_execute_request_and_response_filter_attributes(IRestClient client) + { + MyRequestFilterAttribute.Called = MyResponseFilterAttribute.Called = 0; + var response = client.Get(new RequestDto()); + Assert.That(response.Foo, Is.EqualTo("Bar")); + Assert.That(MyRequestFilterAttribute.Called, Is.EqualTo(1)); + Assert.That(MyResponseFilterAttribute.Called, Is.EqualTo(1)); + } + + [Test] + public void Can_Process_OPTIONS_request_with_Cors_ActionFilter() + { + var webReq = WebRequest.CreateHttp(Host + "/reqstars"); + webReq.Method = "OPTIONS"; + using (var r = webReq.GetResponse()) + { + 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 = r.GetResponseStream().ReadFully(); + Assert.That(response.Length, Is.EqualTo(0)); + } + } + + + [Test, TestCaseSource("RestClients")] + public void Can_GET_AllReqstars(IRestClient client) + { + var allReqstars = client.Get>("/reqstars"); + Assert.That(allReqstars.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("ServiceClients")] + public void Can_SEND_AllReqstars_PrettyTypedApi(IServiceClient client) + { + var allReqstars = client.Send(new AllReqstars()); + Assert.That(allReqstars.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_AllReqstars_PrettyRestApi(IRestClient client) + { + var request = new AllReqstars(); + var response = client.Get(request); + + Assert.That(request.ToUrl("GET"), Is.EqualTo("/reqstars")); + Assert.That(response.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test] + public void Can_GET_AllReqstars_View() + { + var html = "{0}/reqstars".Fmt(Host).GetStringFromUrl(accept: "text/html"); + html.Print(); + Assert.That(html, Does.Contain("")); + Assert.That(html, Does.Contain("")); + } + + + [Test, TestCaseSource("RestClients")] + public void Can_GET_SearchReqstars(IRestClient client) + { + var response = client.Get("/reqstars/search"); + Assert.That(response.Results.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("ServiceClients")] + public void Disallows_SEND_SearchReqstars_PrettyTypedApi(IServiceClient client) + { + try + { + var response = client.Send(new SearchReqstars()); + Assert.Fail("POST's to SearchReqstars should not be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(405)); + Assert.That(webEx.StatusDescription, Is.EqualTo("Method Not Allowed")); + } + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_SearchReqstars_PrettyRestApi(IRestClient client) + { + var request = new SearchReqstars(); + var response = client.Get(request); + + Assert.That(request.ToUrl("GET"), Is.EqualTo("/reqstars/search")); + Assert.That(response.Results.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("RestClients")] + public void Invalid_GET_SearchReqstars_throws_typed_Response_PrettyRestApi(IRestClient client) + { + try + { + var response = client.Get(new SearchReqstars { Age = -1 }); + Assert.Fail("POST's to SearchReqstars should not be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(400)); + Assert.That(webEx.StatusDescription, Is.EqualTo("ArgumentException")); + + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo("ArgumentException")); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("Invalid Age")); + + Assert.That(webEx.ResponseDto as ReqstarsResponse, Is.Not.Null); + } + } + + + [Test, TestCaseSource("RestClients")] + public void Can_GET_SearchReqstars_aged_20(IRestClient client) + { + var response = client.Get("/reqstars/aged/20"); + Assert.That(response.Results.Count, + Is.EqualTo(ReqstarsService.SeedData.Count(x => x.Age == 20))); + } + + [Test, TestCaseSource("ServiceClients")] + public void Disallows_SEND_SearchReqstars_aged_20_PrettyTypedApi(IServiceClient client) + { + try + { + var response = client.Send(new SearchReqstars { Age = 20 }); + Assert.Fail("POST's to SearchReqstars should not be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(405)); + Assert.That(webEx.StatusDescription, Is.EqualTo("Method Not Allowed")); + } + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_SearchReqstars_aged_20_PrettyRestApi(IRestClient client) + { + var request = new SearchReqstars { Age = 20 }; + var response = client.Get(request); + + Assert.That(request.ToUrl("GET"), Is.EqualTo("/reqstars/aged/20")); + Assert.That(response.Results.Count, + Is.EqualTo(ReqstarsService.SeedData.Count(x => x.Age == 20))); + } + + + [Test, TestCaseSource("RestClients")] + public void Can_GET_GetReqstar(IRestClient client) + { + var response = client.Get("/reqstars/1"); + Assert.That(response.FirstName, + Is.EqualTo(ReqstarsService.SeedData[0].FirstName)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_GetReqstar_PrettyRestApi(IRestClient client) + { + var request = new GetReqstar { Id = 1 }; + var response = client.Get(request); + + Assert.That(request.ToUrl("GET"), Is.EqualTo("/reqstars/1")); + Assert.That(response.FirstName, + Is.EqualTo(ReqstarsService.SeedData[0].FirstName)); + } + + [Test, TestCaseSource("ServiceClients")] + public void Disallows_SEND_GetReqstar_PrettyTypedApi(IServiceClient client) + { + try + { + var response = client.Send(new GetReqstar { Id = 1 }); + Assert.Fail("POST's to GetReqstar should not be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(405)); + Assert.That(webEx.StatusDescription, Is.EqualTo("Method Not Allowed")); + } + } + + [Test] + public void Can_GET_GetReqstar_View() + { + var html = "{0}/reqstars/1".Fmt(Host).GetStringFromUrl(accept: "text/html"); + html.Print(); + Assert.That(html, Does.Contain("")); + Assert.That(html, Does.Contain("")); + } + + + public class EmptyResponse { } + + [Test, TestCaseSource("RestClients")] + public void Can_DELETE_Reqstar(IRestClient client) + { + var response = client.Delete("/reqstars/1/delete"); + + var reqstarsLeft = db.Select(); + + Assert.That(reqstarsLeft.Count, + Is.EqualTo(ReqstarsService.SeedData.Length - 1)); + } + + [Test, TestCaseSource("ServiceClients")] + public void Can_DELETE_Reqstar_PrettyTypedApi(IServiceClient client) + { + client.Send(new DeleteReqstar { Id = 1 }); + + var reqstarsLeft = db.Select(); + + Assert.That(reqstarsLeft.Count, + Is.EqualTo(ReqstarsService.SeedData.Length - 1)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_DELETE_Reqstar_PrettyRestApi(IRestClient client) + { + client.Delete(new DeleteReqstar { Id = 1 }); + + var reqstarsLeft = db.Select(); + + Assert.That(reqstarsLeft.Count, + Is.EqualTo(ReqstarsService.SeedData.Length - 1)); + } + + + [Test, TestCaseSource("RestClients")] + public void Can_PATCH_UpdateReqstar(IRestClient client) + { + var response = client.Patch("/reqstars/1", new UpdateReqstar(1, 18)); + Assert.That(response.Age, Is.EqualTo(18)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_PATCH_UpdateReqstar_PrettyRestApi(IRestClient client) + { + var response = client.Patch(new UpdateReqstar(1, 18)); + Assert.That(response.Age, Is.EqualTo(18)); + } + + + [Test, TestCaseSource("RestClients")] + public void Can_CREATE_Reqstar(IRestClient client) + { + var response = client.Post>("/reqstars", new Reqstar(4, "Just", "Created", 25)); + + Assert.That(response.Count, + Is.EqualTo(ReqstarsService.SeedData.Length + 1)); + } + + [Test, TestCaseSource("ServiceClients")] + public void Can_CREATE_Reqstar_PrettyTypedApi(IServiceClient client) + { + var response = client.Send(new Reqstar(4, "Just", "Created", 25)); + + Assert.That(response.Count, + Is.EqualTo(ReqstarsService.SeedData.Length + 1)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_CREATE_Reqstar_PrettyRestApi(IRestClient client) + { + var response = client.Post(new Reqstar(4, "Just", "Created", 25)); + + Assert.That(response.Count, + Is.EqualTo(ReqstarsService.SeedData.Length + 1)); + } + + [Test, TestCaseSource("RestClients")] + public void Fails_to_CREATE_Empty_Reqstar_PrettyRestApi(IRestClient client) + { + try + { + var response = client.Post(new Reqstar()); + Assert.Fail("Should've thrown 400 Bad Request Error"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(400)); + Assert.That(webEx.StatusDescription, Is.EqualTo("ArgumentException")); + + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo("ArgumentException")); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("Age is required")); + + Assert.That(webEx.ResponseDto as ErrorResponse, Is.Not.Null); + } + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_ResetReqstars(IRestClient client) + { + db.DeleteAll(); + + var response = client.Get("/reqstars/reset"); + + var reqstarsLeft = db.Select(); + + Assert.That(reqstarsLeft.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("ServiceClients")] + public void Can_SEND_ResetReqstars_PrettyTypedApi(IServiceClient client) + { + db.DeleteAll(); + + client.Send(new ResetReqstar()); + + var reqstarsLeft = db.Select(); + + Assert.That(reqstarsLeft.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_ResetReqstars_PrettyRestApi(IRestClient client) + { + db.DeleteAll(); + + client.Get(new ResetReqstar()); + + var reqstarsLeft = db.Select(); + + Assert.That(reqstarsLeft.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_RoutelessReqstar_PrettyRestApi(IRestClient client) + { + var request = new RoutelessReqstar { + Id = 1, + FirstName = "Foo", + LastName = "Bar", + }; + + var response = client.Get(request); + + var format = ((ServiceClientBase)client).Format; + Assert.That(request.ToUrl("GET", format), Is.EqualTo( + "/{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)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_POST_RoutelessReqstar_PrettyRestApi(IRestClient client) + { + var request = new RoutelessReqstar { + Id = 1, + FirstName = "Foo", + LastName = "Bar", + }; + + var response = client.Post(request); + + var format = ((ServiceClientBase)client).Format; + Assert.That(request.ToUrl("POST", format), Is.EqualTo( + "/{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)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_GET_RichRequest_PrettyRestApi(IRestClient client) + { + var request = new RichRequest { + StringArray = new[] { "a", "b", "c" }, + StringList = new List { "d", "e", "f" }, + StringSet = new HashSet { "g", "h", "i" }, + }; + + Assert.That(request.ToUrl("GET"), Is.EqualTo("/richrequest?stringList=d,e,f&stringSet=g,h,i&stringArray=a,b,c".Replace(",","%2C"))); + + var response = client.Get(request); + + Assert.That(response.StringArray, Is.EquivalentTo(request.StringArray)); + Assert.That(response.StringList, Is.EquivalentTo(request.StringList)); + Assert.That(response.StringSet, Is.EquivalentTo(request.StringSet)); + } + + [Test] + public void Does_Cache_RazorPage() + { + var html = "{0}/reqstars/cached/10".Fmt(Host).GetStringFromUrl(); + Assert.That(html, Does.Contain("

        Counter:10

        ")); + html = "{0}/reqstars/cached/20".Fmt(Host).GetStringFromUrl(); + Assert.That(html, Does.Contain("

        Counter:10

        ")); + } + + [Test] + public void Does_ignore_all_types_of_routes() + { + var response1 = "{0}/ignore/AnyThing?Name=foo".Fmt(Host).GetJsonFromUrl().FromJson(); + Assert.That(response1.Name, Is.EqualTo("foo")); + + var response2 = "{0}/ignore/AnyThing/between?Name=foo".Fmt(Host).GetJsonFromUrl().FromJson(); + Assert.That(response2.Name, Is.EqualTo("foo")); + + var response3 = "{0}/ignore/AnyThing/and/everything?Name=foo".Fmt(Host).GetJsonFromUrl().FromJson(); + Assert.That(response3.Name, Is.EqualTo("foo")); + response3 = "{0}/ignore/AnyThing/with/foo".Fmt(Host).GetJsonFromUrl().FromJson(); + Assert.That(response3.Name, Is.EqualTo("foo")); + + var response4 = "{0}/ignorewildcard?Name=foo".Fmt(Host).GetJsonFromUrl().FromJson(); + Assert.That(response4.Name, Is.EqualTo("foo")); + response4 = "{0}/ignorewildcard/a?Name=foo".Fmt(Host).GetJsonFromUrl().FromJson(); + Assert.That(response4.Name, Is.EqualTo("foo")); + 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/AllReqstars.cshtml b/tests/RazorRockstars.Console.Files/Views/AllReqstars.cshtml new file mode 100644 index 00000000000..8a1e2932a21 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/AllReqstars.cshtml @@ -0,0 +1,34 @@ +@inherits ViewPage> + +@{ + ViewBag.Title = "All Reqstars"; + Layout = "HtmlReport"; +} + +

        We have @Model.Count Reqstars

        + + + + + + + + + + + + + + @foreach (var rockstar in Model) + { + + + + + } + +
        NameAge
        +

        Show all @Model.Count Reqstars

        +
        @rockstar.FirstName @rockstar.LastName @rockstar.Age
        + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/CachedAllReqstars.cshtml b/tests/RazorRockstars.Console.Files/Views/CachedAllReqstars.cshtml new file mode 100644 index 00000000000..56c39e90283 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/CachedAllReqstars.cshtml @@ -0,0 +1,35 @@ +@inherits ViewPage + +@{ + ViewBag.Title = "All Reqstars"; + Layout = "HtmlReport"; +} + +

        Counter:@Model.Aged

        +

        We have @Model.Results.Count Reqstars

        + + + + + + + + + + + + + + @foreach (var rockstar in Model.Results) + { + + + + + } + +
        NameAge
        +

        Show all @Model.Results.Count Reqstars

        +
        @rockstar.FirstName @rockstar.LastName @rockstar.Age
        + + \ 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/GetReqstar.cshtml b/tests/RazorRockstars.Console.Files/Views/GetReqstar.cshtml new file mode 100644 index 00000000000..103e96d0ef8 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/GetReqstar.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/IList.cshtml b/tests/RazorRockstars.Console.Files/Views/IList.cshtml new file mode 100644 index 00000000000..0ae742a6ced --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/IList.cshtml @@ -0,0 +1,34 @@ +@inherits ViewPage> + +@{ + ViewBag.Title = "IList"; + Layout = "HtmlReport"; +} + +

        We have @Model.Count Reqstars

        + + + + + + + + + + + + + + @foreach (var rockstar in Model) + { + + + + + } + +
        NameAge
        +

        Show all @Model.Count Reqstars

        +
        @rockstar.FirstName @rockstar.LastName @rockstar.Age
        + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/List.cshtml b/tests/RazorRockstars.Console.Files/Views/List.cshtml new file mode 100644 index 00000000000..a98450b73df --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/List.cshtml @@ -0,0 +1,34 @@ +@inherits ViewPage> + +@{ + ViewBag.Title = "List"; + Layout = "HtmlReport"; +} + +

        We have @Model.Count Reqstars

        + + + + + + + + + + + + + + @foreach (var rockstar in Model) + { + + + + + } + +
        NameAge
        +

        Show all @Model.Count Reqstars

        +
        @rockstar.FirstName @rockstar.LastName @rockstar.Age
        + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml b/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml new file mode 100644 index 00000000000..907bbe923b9 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml @@ -0,0 +1,9 @@ +@layout HtmlReport +@model ModelErrorResponse + +
        ModelError: @ModelError.AsRawJson()
        +

        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 new file mode 100644 index 00000000000..6d2cbdf957b --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/PartialChildModel.cshtml @@ -0,0 +1,9 @@ +@model PartialChildModel + +

        Inside PartialChildModel

        + +@Html.TextBoxFor(x => x.SomeProperty) + +PathInfo: @base.Request.PathInfo + + \ No newline at end of file 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 new file mode 100644 index 00000000000..07d03341105 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/PartialModel.cshtml @@ -0,0 +1,30 @@ +@model PartialModel +@{ + Layout = "Empty"; +} + +@section PartialHeaderSection { +

        Partial Header Section in PartialModel

        + +} + + + + + Partial Model + + + +

        @Html.Raw("bái sè")

        + + @foreach (var item in Model.Items) + { +
        @Html.Partial("PartialChildModel", item)
        + } + + @Html.Partial("PartialHeader") + + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/RazorInstance.cshtml b/tests/RazorRockstars.Console.Files/Views/RazorInstance.cshtml new file mode 100644 index 00000000000..c4a7d89bc31 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/RazorInstance.cshtml @@ -0,0 +1,11 @@ +@inherits ViewPage + +@{ + ViewBag.Title = Model.Aged.HasValue ? "{0} year old rockstars".Fmt(Model.Aged) : "All Rockstars"; + Layout = "HtmlReport"; + Counter++; +} + +
        Counter: @Counter
        + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/Rockstars.cshtml b/tests/RazorRockstars.Console.Files/Views/Rockstars.cshtml index f244250fd78..74c2c357ff0 100644 --- a/tests/RazorRockstars.Console.Files/Views/Rockstars.cshtml +++ b/tests/RazorRockstars.Console.Files/Views/Rockstars.cshtml @@ -16,6 +16,7 @@
        @Html.Label("FirstName") @Html.TextBox("FirstName","Amy")
        @Html.Label("LastName") @Html.TextBox("LastName","Winehouse")
        @Html.Label("Age") @Html.TextBox("Age","27")
        +
        @Html.Label("Alive") @Html.CheckBox("Alive", true)

        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/Empty.cshtml b/tests/RazorRockstars.Console.Files/Views/Shared/Empty.cshtml new file mode 100644 index 00000000000..603b12341f4 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/Shared/Empty.cshtml @@ -0,0 +1 @@ +@RenderBody() diff --git a/tests/RazorRockstars.Console.Files/Views/Shared/RazorPartialModel.cshtml b/tests/RazorRockstars.Console.Files/Views/Shared/RazorPartialModel.cshtml index e0dd86a6170..7158bfc8f4f 100644 --- a/tests/RazorRockstars.Console.Files/Views/Shared/RazorPartialModel.cshtml +++ b/tests/RazorRockstars.Console.Files/Views/Shared/RazorPartialModel.cshtml @@ -1,10 +1,10 @@ -@inherits ViewPage> - - - +@model List + + + \ 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 0226e6b4763..49d8c1f98fd 100644 --- a/tests/RazorRockstars.Console.Files/Web.config +++ b/tests/RazorRockstars.Console.Files/Web.config @@ -1,48 +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 80f18bf9334..3b06d6c642c 100644 --- a/tests/RazorRockstars.Console.Files/default.cshtml +++ b/tests/RazorRockstars.Console.Files/default.cshtml @@ -1,32 +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) - -
        @title
        -
          - @foreach (var rockstar in rockstars) { -
        • @rockstar.FirstName - @rockstar.LastName (@rockstar.Age)
        • - } -
        - -

        Show all Rockstars

        - -

        Razor View

        - - -
        - +@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/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 new file mode 100644 index 00000000000..252d4177023 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Configuration/AppSettingsTests.cs @@ -0,0 +1,548 @@ +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 +{ +#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 + { + [Test] + public void Can_get_environment_variable() + { + 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()) + { + 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] + public void GetNullable_String_Returns_Null() + { + var appSettings = GetAppSettings(); + var value = appSettings.GetNullableString("NullableKey"); + + Assert.That(value, Is.Null); + } + + [Test] + public void GetString_Returns_Value() + { + var appSettings = GetAppSettings(); + var value = appSettings.GetString("RealKey"); + + Assert.That(value, Is.EqualTo("This is a real value")); + } + + [Test] + public void Get_Returns_Default_Value_On_Null_Key() + { + var appSettings = GetAppSettings(); + var value = appSettings.Get("NullableKey", "default"); + + Assert.That(value, Is.EqualTo("default")); + } + + [Test] + public void Get_Casts_To_Specified_Type() + { + var appSettings = GetAppSettings(); + var value = appSettings.Get("IntKey", 1); + + Assert.That(value, Is.EqualTo(42)); + } + + [Test] + public void Get_Throws_Exception_On_Bad_Value() + { + var appSettings = GetAppSettings(); + + try + { + appSettings.Get("BadIntegerKey", 1); + Assert.Fail("Get did not throw a ConfigurationErrorsException"); + } + catch (ConfigurationErrorsException ex) + { + Assert.That(ex.Message.Contains("BadIntegerKey")); + } + } + + [Test] + public void Can_Get_List_From_Setting_using_generics() + { + var appSettings = GetAppSettings(); + 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() + { + var appSettings = GetAppSettings(); + var value = appSettings.GetList("ListKey"); + + Assert.That(value, Has.Count.EqualTo(5)); + Assert.That(value, Is.EqualTo(new List { "A", "B", "C", "D", "E" })); + } + + [Test] + public void GetDictionary_Parses_Dictionary_From_Setting() + { + var appSettings = GetAppSettings(); + var value = appSettings.GetDictionary("DictionaryKey"); + + Assert.That(value, Has.Count.EqualTo(5)); + 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() + { + var appSettings = GetAppSettings(); + + try + { + appSettings.GetDictionary("GarbageKey"); + Assert.Fail("GetDictionary did not throw a ConfigurationErrorsException"); + } + catch (ConfigurationErrorsException ex) + { + Assert.That(ex.Message.Contains("GarbageKey")); + } + } + + [Test] + public void GetDictionary_Throws_Exception_On_Bad_Value() + { + var appSettings = GetAppSettings(); + + try + { + appSettings.GetDictionary("BadDictionaryKey"); + Assert.Fail("GetDictionary did not throw a ConfigurationErrorsException"); + } + catch (ConfigurationErrorsException ex) + { + 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 new file mode 100644 index 00000000000..efc1bc8b6ff --- /dev/null +++ b/tests/ServiceStack.Common.Tests/CryptUtilTest.cs @@ -0,0 +1,49 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ServiceStack.Common; +using NUnit.Framework; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class CryptUtilsTest + { + [TestCase] + public void CanEncryptWithStringExtension() + { + RsaUtils.KeyLength = RsaKeyLengths.Bit1024; + RsaUtils.DefaultKeyPair = RsaUtils.CreatePublicAndPrivateKeyPair(); + + string TestStart = "Mr. Watson--come here--I want to see you."; + string Encrypted; + string Decrypted; + + Encrypted = TestStart.Encrypt(); + Assert.AreNotEqual(Encrypted, TestStart); + + Decrypted = Encrypted.Decrypt(); + Assert.AreEqual(Decrypted, TestStart); + + } + + [Test] + public void Can_sign_data_with_RSA() + { + var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + var publicKey = privateKey.ToPublicRsaParameters(); + + 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); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs b/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs index 611d1f528d4..1c431c15184 100644 --- a/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs +++ b/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs @@ -1,10 +1,12 @@ -using System.Web; +#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.Text; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Host; +using ServiceStack.IO; +using ServiceStack.Testing; +using ServiceStack.Web; namespace ServiceStack.Common.Tests { @@ -13,8 +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; @@ -23,12 +25,81 @@ public IHttpRequest CreateRequest(string userHostAddress) [Test] public void Can_parse_Ips() { - var handler = new RestHandler(); - var result = handler.GetEndpointAttributes(CreateRequest("204.2.145.235")); + 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] + enum A : int { B = 0, C = 2, D = 4 } + + [Test] + public void Can_parse_int_enums() + { + var result = A.B | A.C; + 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 76460ca0a15..298d34a2b27 100644 --- a/tests/ServiceStack.Common.Tests/Expressions/ExpressionTests.cs +++ b/tests/ServiceStack.Common.Tests/Expressions/ExpressionTests.cs @@ -2,63 +2,93 @@ using System.Linq.Expressions; using System.Reflection; using NUnit.Framework; +using System.Diagnostics; namespace ServiceStack.Common.Tests.Expressions { - [TestFixture] - public class ExpressionTests - { + [TestFixture] + public class ExpressionTests + { - public int AddMethod(int a) - { - return a + 4; - } + public int AddMethod(int a) + { + return a + 4; + } - [Test] - public void Simple_func_and_equivalent_expression_tests() - { - Func add = x => x + x; + [Test] + public void Simple_func_and_equivalent_expression_tests() + { + Func add = x => x + x; - Assert.That(add(4), Is.EqualTo(4 + 4)); + Assert.That(add(4), Is.EqualTo(4 + 4)); - Expression> addExpr = x => x + 4; + Expression> addExpr = x => x + 4; - Func addFromExpr = addExpr.Compile(); + Func addFromExpr = addExpr.Compile(); - Assert.That(addFromExpr(4), Is.EqualTo(add(4))); + Assert.That(addFromExpr(4), Is.EqualTo(add(4))); - Func addMethod = AddMethod; + Func addMethod = AddMethod; - Assert.That(addMethod(4), Is.EqualTo(add(4))); + 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")); - } + Expression> callAddMethodExpr = x => AddMethod(x); + var addMethodCall = (MethodCallExpression)callAddMethodExpr.Body; + Assert.That(addMethodCall.Method.Name, Is.EqualTo("AddMethod")); + } - public static int StaticAdd(int a) - { - return a + 4; - } + [Test] + public void Simple_func_timing_tests() + { + // 1/5 as expensive as expression + var stopWatch = new Stopwatch(); + stopWatch.Start(); + Func add = x => x + x; - [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 }); + Assert.That(add(4), Is.EqualTo(4 + 4)); + stopWatch.Stop(); + Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); + } - Expression> callAddMethodExpr = x => StaticAdd(x); - var addMethodCall = (MethodCallExpression)callAddMethodExpr.Body; - Assert.That(addMethodCall.Method.Name, Is.EqualTo("StaticAdd")); - } + [Test] + public void Simple_expression_timing_tests() + { + //5 times more expensive than Func + var stopWatch = new Stopwatch(); + stopWatch.Start(); + Expression> addExpr = x => x + 4; - [Test] - public void Dynamic_MethodCallExpression_to_call_a_static_method() - { + Func addFromExpr = addExpr.Compile(); - //MethodCallExpression.Call(Expression.Call(GetType().GetMethod("StaticAdd", BindingFlags.Static | BindingFlags.Public)); - - //Assert.That(addMethodCall.Method.Name, Is.EqualTo("StaticAdd")); - } - } -} \ No newline at end of file + 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 new file mode 100644 index 00000000000..d332e771ebc --- /dev/null +++ b/tests/ServiceStack.Common.Tests/FunqTests.cs @@ -0,0 +1,34 @@ +using Funq; +using NUnit.Framework; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class FunqTests + { + interface IBar { } + class Bar : IBar { } + class TestFoo { public IBar Bar { get; set; } } + + [Test] + public void Test1() + { + var container = new Container(); + var m = new TestFoo(); + container.Register(new Bar()); + Assert.NotNull(container.Resolve(), "Resolve"); + container.AutoWire(m); + Assert.NotNull(m.Bar, "Autowire"); + } + + [Test] + public void Test2() + { + var container = new Container(); + var m = new TestFoo(); + container.AutoWire(m); + Assert.Throws(() => container.Resolve()); + Assert.IsNull(m.Bar); // FAILS HERE + } + } +} diff --git a/tests/ServiceStack.Common.Tests/IdUtilsTests.cs b/tests/ServiceStack.Common.Tests/IdUtilsTests.cs index ebe396fdf46..db232e235e7 100644 --- a/tests/ServiceStack.Common.Tests/IdUtilsTests.cs +++ b/tests/ServiceStack.Common.Tests/IdUtilsTests.cs @@ -1,118 +1,170 @@ -using System; -using NUnit.Framework; -using ServiceStack.Common.Tests.Models; -using ServiceStack.Common.Utils; -using ServiceStack.DesignPatterns.Model; - -namespace ServiceStack.Common.Tests -{ - [TestFixture] - public class IdUtilsTests - { - private const int IntValue = 1; - private const string StringValue = "A"; - - public class HasIntId : IHasIntId - { - public int Id - { - get { return IntValue; } - } - } - - public class HasGenericIdInt : IHasId - { - public int Id - { - get { return IntValue; } - } - } - - public class HasGenericIdString : IHasId - { - public string Id - { - get { return StringValue; } - } - } - - public class HasIdProperty - { - public int Id - { - get { return IntValue; } - } - } - - public class HasIdStringProperty - { - public string Id - { - get { return StringValue; } - } - } - - public class HasIdCustomStringProperty - { - public string CustomId - { - get { return StringValue; } - } - } - - public class HasIdCustomIntProperty - { - public int CustomId - { - get { return IntValue; } - } - } - - [Test] - public void Can_get_if_HasIntId() - { - Assert.That(new HasIntId().GetId(), Is.EqualTo(IntValue)); - } - - [Test] - public void Can_get_if_HasGenericIdInt() - { - Assert.That(new HasGenericIdInt().GetId(), Is.EqualTo(IntValue)); - } - - [Test] - public void Can_get_if_HasGenericIdString() - { - Assert.That(new HasGenericIdString().GetId(), Is.EqualTo(StringValue)); - } - - [Test] - public void Can_get_if_HasIdProperty() - { - Assert.That(new HasIdProperty().GetId(), Is.EqualTo(IntValue)); - } - - [Test] - public void Can_get_if_HasIdStringProperty() - { - Assert.That(new HasIdStringProperty().GetId(), Is.EqualTo(StringValue)); - } - - [Test] - public void Can_get_if_HasIdCustomStringProperty() - { - ModelConfig.Id(x => x.CustomId); - - Assert.That(new HasIdCustomStringProperty().GetId(), Is.EqualTo(StringValue)); - } - - [Test] - public void Can_get_if_HasIdCustomIntProperty() - { - ModelConfig.Id(x => x.CustomId); - - Assert.That(new HasIdCustomIntProperty().GetId(), Is.EqualTo(IntValue)); - } - - } +using System; +using NUnit.Framework; +using ServiceStack.Common.Tests.Models; +using ServiceStack.DataAnnotations; +using ServiceStack.Model; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class IdUtilsTests + { + private const int IntValue = 1; + private const string StringValue = "A"; + + public class HasIntId : IHasIntId + { + public int Id + { + get { return IntValue; } + } + } + + public class HasGenericIdInt : IHasId + { + public int Id + { + get { return IntValue; } + } + } + + public class HasGenericIdString : IHasId + { + public string Id + { + get { return StringValue; } + } + } + + public class HasIdProperty + { + public int Id + { + get { return IntValue; } + } + } + + public class HasIdStringProperty + { + public string Id + { + get { return StringValue; } + } + } + + public class HasIdCustomStringProperty + { + public string CustomId + { + get { return StringValue; } + } + } + + public class HasIdCustomIntProperty + { + public int CustomId + { + get { return IntValue; } + } + } + + public class HasPrimaryKeyAttribute + { + [PrimaryKey] + public int CustomId + { + get { return IntValue; } + } + } + + 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() + { + Assert.That(new HasIntId().GetId(), Is.EqualTo(IntValue)); + } + + [Test] + public void Can_get_if_HasGenericIdInt() + { + Assert.That(new HasGenericIdInt().GetId(), Is.EqualTo(IntValue)); + } + + [Test] + public void Can_get_if_HasGenericIdString() + { + Assert.That(new HasGenericIdString().GetId(), Is.EqualTo(StringValue)); + } + + [Test] + public void Can_get_if_HasIdProperty() + { + Assert.That(new HasIdProperty().GetId(), Is.EqualTo(IntValue)); + } + + [Test] + public void Can_get_if_HasIdStringProperty() + { + Assert.That(new HasIdStringProperty().GetId(), Is.EqualTo(StringValue)); + } + + [Test] + public void Can_get_if_HasIdCustomStringProperty() + { + ModelConfig.Id(x => x.CustomId); + + Assert.That(new HasIdCustomStringProperty().GetId(), Is.EqualTo(StringValue)); + } + + [Test] + public void Can_get_if_HasIdCustomIntProperty() + { + ModelConfig.Id(x => x.CustomId); + + Assert.That(new HasIdCustomIntProperty().GetId(), Is.EqualTo(IntValue)); + } + + [Test] + 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 d3279b8b6bf..00000000000 --- a/tests/ServiceStack.Common.Tests/MappingTests.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; - -namespace ServiceStack.Common.Tests -{ - public class User - { - public string FirstName { get; set; } - public string LastName { get; set; } - public Car Car { get; set; } - } - - 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 class IntNullableIDObj - { - public int? Id { get; set; } - } - - public class IntIDObj - { - public int Id { get; set; } - } - - public class NullableConversion - { - public decimal Amount { get; set; } - } - - public class NullableConversionDto - { - public decimal? Amount { get; set; } - } - - public class EnumConversion - { - public Color 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_translate_nullableInt_to_and_from() - { - var nullable = new IntNullableIDObj(); - - var nonNullable = nullable.TranslateTo(); - - nonNullable.Id = 10; - - var expectedNullable = nonNullable.TranslateTo(); - - Assert.That(expectedNullable.Id.Value, Is.EqualTo(nonNullable.Id)); - } - } -} 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/MessagingTests.cs b/tests/ServiceStack.Common.Tests/MessagingTests.cs index 2951b42e3a1..c909555cc72 100644 --- a/tests/ServiceStack.Common.Tests/MessagingTests.cs +++ b/tests/ServiceStack.Common.Tests/MessagingTests.cs @@ -1,61 +1,63 @@ -using NUnit.Framework; -using ServiceStack.Messaging; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests -{ - 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() - { - 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 +#if !NETCORE +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Messaging; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + 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() + { + 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); + } + } +} +#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 725a1a2401f..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.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))); - } - } - } +using System; +using NUnit.Framework; +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))); + } + } + } } \ 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 84ca12e53c6..ec04f3a4c7f 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithIdAndName.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithIdAndName.cs @@ -4,60 +4,61 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithIdAndName - { - public ModelWithIdAndName() - { - } - - public ModelWithIdAndName(int id) - { - Id = id; - Name = "Name" + id; - } - - public int Id { get; set; } - - public string Name { get; set; } - - 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; - } - - 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 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 class ModelWithIdAndName + { + public ModelWithIdAndName() + { + } + + public ModelWithIdAndName(int id) + { + Id = id; + Name = "Name" + id; + } + + [AutoIncrement] + public int Id { get; set; } + + public string Name { get; set; } + + 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; + } + + 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 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); + } + } + } } \ 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 new file mode 100644 index 00000000000..28670876b8e --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithNamedCompositeIndex.cs @@ -0,0 +1,22 @@ +using ServiceStack.DataAnnotations; + +namespace ServiceStack.Common.Tests.Models +{ + [CompositeIndex(true, "Composite1", "Composite2", Name = "custom_index_name")] + public class ModelWithNamedCompositeIndex + { + public string Id { get; set; } + + [Index] + public string Name { get; set; } + + public string AlbumId { get; set; } + + [Index(true)] + public string UniqueName { get; set; } + + public string Composite1 { 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 new file mode 100644 index 00000000000..27d1a489f99 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Models/Poco.cs @@ -0,0 +1,9 @@ +namespace ServiceStack.Common.Tests.Models +{ + public class Poco + { + 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 be9deeda384..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, - DateCreated = new DateTime(i + 1 % 3000, (i % 11) + 1, (i % 27) + 1), - ShipperType = (ShipperType)(i % 3), - UniqueRef = new Guid(hex + "D148A5-E5F1-4E5A-8C60-52E5A80ACCC6"), - }; - } + 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"), + }; + } - 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 704ca266736..8cc5dc0f4f0 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/CredentialsServiceTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/CredentialsServiceTests.cs @@ -1,59 +1,82 @@ -using Moq; -using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; - -namespace ServiceStack.Common.Tests.OAuth -{ - [TestFixture] - public class CredentialsServiceTests - { - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - AuthService.Init(() => new AuthUserSession(), - new CredentialsAuthProvider()); - } - - public AuthService GetAuthService() - { - return new AuthService { - RequestContext = new MockRequestContext() - }; - } - - [Test] - public void Empty_request_invalidates_all_fields() - { - var authService = GetAuthService(); - - var response = (HttpError)authService.Get(new Auth()); - 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")); - } - - [Test] - public void Requires_UserName_and_Password() - { - var authService = GetAuthService(); - - var response = (HttpError)authService.Get( - new Auth { provider = AuthService.CredentialsProvider }); - - 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 +#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 + { + public class CredentialsTestAppHost : BasicAppHost + { + public CredentialsTestAppHost() : base(typeof(CredentialsServiceTests).Assembly) {} + + public override void Configure(Container container) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(), + })); + } + + public override IServiceRunner CreateServiceRunner(ActionContext actionContext) + { + return new ValidateServiceRunner(this, actionContext); + } + } + + class ValidateServiceRunner : ServiceRunner + { + public ValidateServiceRunner(IAppHost appHost, ActionContext actionContext) + : base(appHost, actionContext) { } + + 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() + { + using (var appHost = new CredentialsTestAppHost().Init()) + { + var response = (HttpError)appHost.ExecuteService( + new Authenticate { provider = CredentialsAuthProvider.Name }); + + 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")); + } + } + + [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(); + + 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 4adaea350fc..acc165f30c5 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/MockAuthHttpGateway.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/MockAuthHttpGateway.cs @@ -1,58 +1,238 @@ -using ServiceStack.ServiceInterface.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 = @"{{ - ""id"": ""{0}"", - ""name"": ""{1}"", - ""first_name"": ""{2}"", - ""last_name"": ""{3}"", - ""link"": ""http://www.facebook.com/newmovie"", - ""username"": ""newmovie"", - ""location"": {{ - ""id"": ""106078429431815"", - ""name"": ""London, United Kingdom"" - }}, - ""bio"": ""I am man."", - ""quotes"": ""100\u0025 of the shots you don't take don't go in.\n --Wayne Gretzky\n"", - ""gender"": ""male"", - ""email"": ""{4}"", - ""timezone"": -4, - ""locale"": ""en_GB"", - ""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""}}]"; - - public string DownloadTwitterUserInfo(string twitterUserId) - { - twitterUserId.ThrowIfNullOrEmpty("twitterUserId"); - - return JsonTwitter.Fmt(Tokens.DisplayName); - } - - public string DownloadFacebookUserInfo(string facebookCode) - { - facebookCode.ThrowIfNullOrEmpty("facebookCode"); - - return JsonFacebook.Fmt(Tokens.UserId, Tokens.DisplayName, - Tokens.FirstName, Tokens.LastName, Tokens.Email); - } - } -} \ No newline at end of file +#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 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}"", + ""last_name"": ""{3}"", + ""link"": ""http://www.facebook.com/newmovie"", + ""username"": ""newmovie"", + ""location"": {{ + ""id"": ""106078429431815"", + ""name"": ""London, United Kingdom"" + }}, + ""bio"": ""I am man."", + ""quotes"": ""100\u0025 of the shots you don't take don't go in.\n --Wayne Gretzky\n"", + ""gender"": ""male"", + ""email"": ""{4}"", + ""timezone"": -4, + ""locale"": ""en_GB"", + ""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 JsonYammer = @"{ + ""job_title"":""Developer"", + ""summary"":""I am a developer at XYZ Corp."", + ""activated_at"":""2012/12/21 12:21:12 +0000"", + ""schools"":[{ + ""start_year"":2000, + ""degree"":""Code Master"", + ""end_year"":2001, + ""description"":"""", + ""school"":""Code School"" + }], + ""admin"":""false"", + ""interests"":""Coding"", + ""network_id"":12345, + ""timezone"":""Perth"", + ""state"":""active"", + ""stats"":{ + ""updates"":212, + ""following"":8, + ""followers"":88 + }, + ""can_broadcast"":""false"", + ""name"":""{2}{3}"", + ""show_ask_for_photo"":false, + ""settings"":{ + ""xdr_proxy"":""https://xdrproxy.yammer.com"" + }, + ""mugshot_url_template"":""https://mug0.assets-yammer.com/mugshot/images/{width}x{height}/someblah"", + ""guid"":null, + ""mugshot_url"":""https://mug0.assets-yammer.com/mugshot/images/48x48/someblah"", + ""contact"":{ + ""has_fake_email"":false, + ""phone_numbers"":[{ + ""number"":""+61888888888 x88888"", + ""type"":""work"" + },{ + ""number"":""+61400123456"", + ""type"":""mobile"" + }], + ""im"":{ + ""provider"":""aim"",""username"":"""" + }, + ""email_addresses"":[{ + ""address"":""{4}"",""type"":""primary"" + }] + }, + ""previous_companies"":[{ + ""position"":""Junior Developer"", + ""start_year"":2001, + ""end_year"":2002, + ""description"":"""", + ""employer"":""UVW Corp""}], + ""network_name"":""ServiceStack"", + ""network_domains"":[""servicestack.net""], + ""verified_admin"":""false"", + ""first_name"":""{2}"", + ""significant_other"":"""", + ""birth_date"":"""", + ""id"":{0}, + ""url"":""https://www.yammer.com/api/v1/users/{0}"", + ""type"":""user"", + ""expertise"":""ServiceStack."", + ""last_name"":""{3}"", + ""location"":""Perth, WA, Australia"", + ""web_url"":""https://www.yammer.com/servicestack.net/users/{2}{3}"", + ""kids_names"":"""", + ""hire_date"":null, + ""department"":""IT"", + ""external_urls"":[ + ""http://servicestack.net"", + ""https://github.com/ServiceStack/ServiceStack"" + ], + ""full_name"":""{1}"" +}"; + + 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(); + } + + public Task DownloadGithubUserEmailsInfoAsync(string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + public string DownloadGoogleUserInfo(string accessToken) + { + throw new System.NotImplementedException(); + } + + public Task DownloadGoogleUserInfoAsync(string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + 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); + } + + 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 a41f0dfbe90..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(serviceTokensTw.DisplayName)); - Assert.That(userAuth.FirstName, Is.EqualTo(serviceTokensFb.FirstName)); - Assert.That(userAuth.LastName, Is.EqualTo(serviceTokensFb.LastName)); - Assert.That(userAuth.PrimaryEmail, Is.EqualTo(serviceTokensFb.Email)); - - 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 a323ad7f1e7..00000000000 --- a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTestsBase.cs +++ /dev/null @@ -1,242 +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.Common.Web; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.Redis; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; - -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); - - mockAppHost.Register(new AuthService { - RequestContext = requestContext, - }.SetAppHost(mockAppHost) as 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 b6df77de909..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 97fc1f04f58..699b2c415af 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthTests.cs @@ -1,54 +1,51 @@ -using System; -using System.IO; -using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests.OAuth -{ - [TestFixture] - public class OrmLiteUserAuthTests - { - [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()) - { - 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); - - var rows = db.Select(q => q.UserName == "UserName"); - - Console.WriteLine(rows[0].Dump()); - - Assert.That(rows[0].UserName, Is.EqualTo(userAuth.UserName)); - } - } - } -} \ No newline at end of file +#if !NETCORE +using System.Data; +using System.IO; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests.OAuth +{ + [TestFixture] + public class OrmLiteUserAuthTests + { + 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() + { + using (var db = OpenDbConnection()) + { + db.DropAndCreateTable(); + + var userAuth = GetUserAuth(); + + db.Insert(userAuth); + + var rows = db.Select(q => q.UserName == "UserName"); + + Assert.That(rows[0].UserName, Is.EqualTo(userAuth.UserName)); + } + } + + } +} +#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 bac5aa13864..81ca59b3c1f 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/RegistrationServiceTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/RegistrationServiceTests.cs @@ -1,140 +1,230 @@ -using Moq; -using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.FluentValidation; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; - -namespace ServiceStack.Common.Tests.OAuth -{ - [TestFixture] - public class RegistrationServiceTests - { - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - AuthService.Init(() => new 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) - { - var requestContext = new MockRequestContext(); - var service = new RegistrationService { - RegistrationValidator = validator ?? new RegistrationValidator { UserAuthRepo = GetStubRepo() }, - UserAuthRepo = authRepo ?? GetStubRepo(), - RequestContext = requestContext - }; - return service; - } - - [Test] - public void Empty_Registration_is_invalid() - { - var service = GetRegistrationService(); - - var response = (HttpError)service.Post(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")); - } - - [Test] - public void Empty_Registration_is_invalid_with_FullRegistrationValidator() - { - var service = GetRegistrationService(new FullRegistrationValidator()); - - var response = (HttpError)service.Post(new Registration()); - 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 - }; - - var request = new Registration { - DisplayName = "DisplayName", - Email = "my@email.com", - FirstName = "FirstName", - LastName = "LastName", - Password = "Password", - UserName = "UserName", - }; - - var response = (HttpError)service.Post(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")); - } - - - } -} \ No newline at end of file +#if !NETCORE +using System.Collections.Generic; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.FluentValidation; +using ServiceStack.Host; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests.OAuth +{ + [TestFixture] + public class RegistrationServiceTests + { + static AuthUserSession authUserSession = new AuthUserSession(); + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost + { + 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; + } + + 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 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 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; + } + + [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")); + } + + private void ClearSession() + { + authUserSession = new AuthUserSession(); + appHost.Container.Register(c => null); + } + + [Test] + public async Task Registration_with_Html_ContentType_And_Continue_returns_302_with_Location() + { + var service = GetRegistrationService(null, null, MimeTypes.Html); + + var request = GetValidRegistration(); + + 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")); + } + + [Test] + public async Task Registration_with_EmptyString_Continue_returns_RegistrationResponse() + { + var service = GetRegistrationService(null, null, MimeTypes.Html); + + var request = GetValidRegistration(); + service.Request.QueryString[Keywords.Continue] = string.Empty; + + var response = await service.PostAsync(request); + + Assert.That(response as HttpResult, Is.Null); + Assert.That(response as RegisterResponse, Is.Not.Null); + } + + [Test] + public async Task Registration_with_Json_ContentType_And_Continue_returns_RegistrationResponse_with_ReferrerUrl() + { + var service = GetRegistrationService(null, null, MimeTypes.Json); + + var request = GetValidRegistration(); + service.Request.QueryString[Keywords.Continue] = "http://localhost/home"; + + var response = await service.PostAsync(request); + + 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 576d871c2db..a0b4902f9df 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/RequiredRolesTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/RequiredRolesTests.cs @@ -1,83 +1,119 @@ -using System.Linq; -using Moq; -using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; - -namespace ServiceStack.Common.Tests.OAuth -{ - [TestFixture] - public class RequiredRolesTests - { - Mock userAuthMock; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - AuthService.Init(() => new AuthUserSession(), new CredentialsAuthProvider()); - } - - [SetUp] - public void SetUp() - { - userAuthMock = new Mock(); - - userAuthMock.Expect(x => x.GetUserAuthByUserName(It.IsAny())) - .Returns((UserAuth)null); - - userAuthMock.Expect(x => x.CreateUserAuth(It.IsAny(), It.IsAny())) - .Returns(new UserAuth { Id = 1 }); - } - - private RegistrationService GetRegistrationService() - { - var registrationService = RegistrationServiceTests.GetRegistrationService(authRepo: userAuthMock.Object); - var request = RegistrationServiceTests.GetValidRegistration(autoLogin: true); - registrationService.Execute(request); - return registrationService; - } - - [Test] - public void Does_validate_RequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() - { - var userWithAdminRole = new UserAuth { Id = 1, Roles = new[] { RoleNames.Admin }.ToList() }; - userAuthMock.Expect(x => x.GetUserAuth(It.IsAny(), It.IsAny())) - .Returns(userWithAdminRole); - - var registrationService = GetRegistrationService(); - - var requiredRole = new RequiredRoleAttribute(RoleNames.Admin); - - var requestContext = (MockRequestContext)registrationService.RequestContext; - requestContext.Container.Register(userAuthMock.Object); - var httpRes = requestContext.Get(); - - requiredRole.Execute( - requestContext.Get(), - httpRes, - null); - - Assert.That(!httpRes.IsClosed); - } - - [Test] - public void Does_validate_AssertRequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() - { - var userWithAdminRole = new UserAuth { Id = 1, Roles = new[] { RoleNames.Admin }.ToList() }; - userAuthMock.Expect(x => x.GetUserAuth(It.IsAny(), It.IsAny())) - .Returns(userWithAdminRole); - - var registrationService = GetRegistrationService(); - - var requestContext = (MockRequestContext)registrationService.RequestContext; - requestContext.Container.Register(userAuthMock.Object); - var httpRes = requestContext.Get(); - - RequiredRoleAttribute.AssertRequiredRoles(requestContext, RoleNames.Admin); - - Assert.That(!httpRes.IsClosed); - } - } -} \ No newline at end of file +#if !NETCORE +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests.OAuth +{ + [TestFixture] + public class RequiredRolesTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + 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 + { + private UserAuth userAuth; + public MockUserAuthRepository(UserAuth userAuth) + { + this.userAuth = userAuth; + } + + public override IUserAuth GetUserAuthByUserName(string userNameOrEmail) => null; + + public override async Task GetUserAuthByUserNameAsync(string userNameOrEmail, CancellationToken token = default) + => GetUserAuthByUserName(userNameOrEmail); + + 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 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; + + [SetUp] + public void SetUp() + { + var userWithAdminRole = new UserAuth { Id = 1, Roles = new[] { RoleNames.Admin }.ToList() }; + userAuth = new MockUserAuthRepository(userWithAdminRole); + } + + private RegisterService GetRegistrationService() + { + var registrationService = RegistrationServiceTests.GetRegistrationService(authRepo: userAuth); + var request = RegistrationServiceTests.GetValidRegistration(autoLogin: true); + + registrationService.PostAsync(request); + return registrationService; + } + + [Test] + public async Task Does_validate_RequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() + { + var registrationService = GetRegistrationService(); + + var requiredRole = new RequiredRoleAttribute(RoleNames.Admin); + + var request = registrationService.Request; + HostContext.Container.Register(userAuth); + var httpRes = request.Response; + + await requiredRole.ExecuteAsync(request, request.Response, request.OperationName); + + Assert.That(!httpRes.IsClosed); + } + + [Test] + public async Task Does_validate_AssertRequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() + { + var registrationService = GetRegistrationService(); + + var request = registrationService.Request; + HostContext.Container.Register(userAuth); + + await RequiredRoleAttribute.AssertRequiredRoleAsync(request, RoleNames.Admin); + + Assert.That(!request.Response.IsClosed); + } + } +} +#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 b3e771b5178..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 a93641cbdd1..b8722b53380 100644 --- a/tests/ServiceStack.Common.Tests/PerfTestBase.cs +++ b/tests/ServiceStack.Common.Tests/PerfTestBase.cs @@ -1,110 +1,110 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -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); - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +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); + } + } } \ 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 2c08f612000..8f514207da8 100644 --- a/tests/ServiceStack.Common.Tests/Properties/Settings.Designer.cs +++ b/tests/ServiceStack.Common.Tests/Properties/Settings.Designer.cs @@ -1,37 +1,39 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.239 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ServiceStack.Common.Tests.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.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 { - get { - return defaultInstance; - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)] - [global::System.Configuration.DefaultSettingValueAttribute("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\auth.mdf;Integrated Sec" + - "urity=True;Connect Timeout=30;User Instance=True")] - public string authConnectionString { - get { - return ((string)(this["authConnectionString"])); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// 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", "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 { + get { + return defaultInstance; + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)] + [global::System.Configuration.DefaultSettingValueAttribute("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\auth.mdf;Integrated Sec" + + "urity=True;Connect Timeout=30;User Instance=True")] + public string authConnectionString { + get { + return ((string)(this["authConnectionString"])); + } + } + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs b/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs new file mode 100644 index 00000000000..16e385c4717 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs @@ -0,0 +1,69 @@ +#if !NETCORE +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Web; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class QueryStringSerializerTests + { + [Test] + public void Can_deserialize_TestRequest_QueryStringSerializer_output() + { + // Setup + 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 MockHttpRequest("service", "GET", "application/json", "service", queryString, new MemoryStream(), new NameValueCollection()); + + 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)); + } + } + + [Test] + public void QueryStringSerializer_TestRequest_output() + { + var testRequest = new TestRequest { ListOfA = new List { new A { ListOfB = new List { new B { Property = "prop1" }, new B { Property = "prop2" } } } } }; + var str = QueryStringSerializer.SerializeToString(testRequest); + Assert.That(str, Is.EqualTo("ListOfA={ListOfB:[{Property:prop1},{Property:prop2}]}")); + } + + public class TestService : Service + { + public object Get(TestRequest request) + { + return "OK"; + } + } + + public class TestRequest + { + public List ListOfA { get; set; } + } + + public class A + { + public List ListOfB { get; set; } + } + + public class B + { + public string Property { get; set; } + } + } +} +#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 1e0fea5966d..1e6b73fb559 100644 --- a/tests/ServiceStack.Common.Tests/ReflectionExtensionsTests.cs +++ b/tests/ServiceStack.Common.Tests/ReflectionExtensionsTests.cs @@ -1,82 +1,156 @@ -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceInterface.ServiceModel; - -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; } - } - - [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); - } - - 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()))); - } - } +using System; +using System.Collections.Generic; +using NUnit.Framework; +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 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 + { + 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() + { + var values = new[] { "A", "B", "C" }; + var testA = new TestClassA + { + ToStringList = new List(values), + }; + + 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()))); + } + + [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 503bc1901c3..b2cd82cd62b 100644 --- a/tests/ServiceStack.Common.Tests/ReflectionUtilTests.cs +++ b/tests/ServiceStack.Common.Tests/ReflectionUtilTests.cs @@ -1,264 +1,305 @@ -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 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; } - } - - public class DtoWithStringArray - { - public string[] Data { get; set; } - } - - public class DtoWithEnumArray - { - public TestClassType[] Data { get; set; } - } - - public class RecursiveDto - { - public string Name { get; set; } - public RecursiveDto Child { get; set; } - } - - public class DtoWithRecursiveArray - { - public RecursiveDto[] Paths { get; set; } - } - - public class RecursiveArrayDto - { - public string Name { get; set; } - public RecursiveArrayDto[] Nodes { get; set; } - } - - public class MindTwister - { - public string Name { get; set; } - public RecursiveArrayDto[] Arrays { get; set; } - public Vortex Vortex { get; set; } - } - - public class Vortex - { - public int Id { get; set; } - public RecursiveArrayDto Arrays { get; set; } - public MindTwister[] Twisters { get; set; } - } - - [Test] - public void Can_PopulateRecursiveDto() - { - var obj = (RecursiveDto)ReflectionUtils.PopulateObject(new RecursiveDto()); - Assert.IsNotNullOrEmpty(obj.Name); - Assert.IsNotNull(obj.Child); - Assert.IsNotNullOrEmpty(obj.Child.Name); - } - - [Test] - public void Can_PopulateArrayOfRecursiveDto() - { - var obj = (DtoWithRecursiveArray)ReflectionUtils.PopulateObject(new DtoWithRecursiveArray()); - Assert.IsNotNull(obj.Paths); - Assert.Greater(obj.Paths.Length, 0); - Assert.IsNotNull(obj.Paths[0]); - Assert.IsNotNullOrEmpty(obj.Paths[0].Name); - Assert.IsNotNull(obj.Paths[0].Child); - Assert.IsNotNullOrEmpty(obj.Paths[0].Child.Name); - } - - [Test] - public void Can_PopulateRecursiveArrayDto() - { - var obj = (RecursiveArrayDto)ReflectionUtils.PopulateObject(new RecursiveArrayDto()); - Assert.IsNotNullOrEmpty(obj.Name); - Assert.IsNotNull(obj.Nodes[0]); - Assert.IsNotNullOrEmpty(obj.Nodes[0].Name); - Assert.IsNotNull(obj.Nodes[0].Nodes); - Assert.IsNotNullOrEmpty(obj.Nodes[0].Nodes[0].Name); - } - - [Test] - public void Can_PopulateTheVortex() - { - var obj = (MindTwister)ReflectionUtils.PopulateObject(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); - Assert.IsNotNull(obj.Arrays); - Assert.IsNotNull(obj.Vortex); - } - - [Test] - public void Can_PopulateObjectWithStringArray() - { - var obj = (DtoWithStringArray)ReflectionUtils.PopulateObject(new DtoWithStringArray()); - Assert.IsNotNull(obj.Data); - Assert.Greater(obj.Data.Length, 0); - Assert.IsNotNull(obj.Data[0]); - } - - [Test] - public void Can_PopulateObjectWithNonZeroEnumArray() - { - var obj = (DtoWithEnumArray)ReflectionUtils.PopulateObject(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 Translate_Between_Models_of_differrent_types_and_nullables() - { - var fromObj = ModelWithFieldsOfDifferentTypes.CreateConstant(1); - - var toObj = fromObj.TranslateTo(); - - Console.WriteLine(toObj.Dump()); - - ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(fromObj, toObj); - } - - [Test] - public void Translate_Between_Models_of_nullables_and_differrent_types() - { - var fromObj = ModelWithFieldsOfDifferentTypesAsNullables.CreateConstant(1); - - var toObj = fromObj.TranslateTo(); - - Console.WriteLine(toObj.Dump()); - - ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(toObj, fromObj); - } - } -} +using System; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Common.Tests.Models; +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; } + } + + public class DtoWithStringArray + { + public string[] Data { get; set; } + } + + public class DtoWithEnumArray + { + public TestClassType[] Data { get; set; } + } + + public class RecursiveDto + { + public string Name { get; set; } + public RecursiveDto Child { get; set; } + } + + public class DtoWithRecursiveArray + { + public RecursiveDto[] Paths { get; set; } + } + + public class RecursiveArrayDto + { + public string Name { get; set; } + public RecursiveArrayDto[] Nodes { get; set; } + } + + public class MindTwister + { + public string Name { get; set; } + public RecursiveArrayDto[] Arrays { get; set; } + public Vortex Vortex { get; set; } + } + + public class Vortex + { + public int Id { get; set; } + public RecursiveArrayDto Arrays { get; set; } + public MindTwister[] Twisters { get; set; } + } + + [Test] + public void Can_PopulateRecursiveDto() + { + var obj = (RecursiveDto)AutoMappingUtils.PopulateWith(new RecursiveDto()); + Assert.That(obj.Name, Is.Not.Null); + Assert.IsNotNull(obj.Child); + Assert.That(obj.Child.Name, Is.Not.Null); + } + + [Test] + public void Can_PopulateArrayOfRecursiveDto() + { + var obj = (DtoWithRecursiveArray)AutoMappingUtils.PopulateWith(new DtoWithRecursiveArray()); + Assert.IsNotNull(obj.Paths); + Assert.Greater(obj.Paths.Length, 0); + Assert.IsNotNull(obj.Paths[0]); + Assert.That(obj.Paths[0].Name, Is.Not.Null); + Assert.IsNotNull(obj.Paths[0].Child); + Assert.That(obj.Paths[0].Child.Name, Is.Not.Null); + } + + [Test] + public void Can_PopulateRecursiveArrayDto() + { + var obj = (RecursiveArrayDto)AutoMappingUtils.PopulateWith(new RecursiveArrayDto()); + Assert.That(obj.Name, Is.Not.Null); + Assert.IsNotNull(obj.Nodes[0]); + Assert.That(obj.Nodes[0].Name, Is.Not.Null); + Assert.IsNotNull(obj.Nodes[0].Nodes); + Assert.That(obj.Nodes[0].Nodes[0].Name, Is.Not.Null); + } + + [Test] + public void Can_PopulateTheVortex() + { + 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); + Assert.IsNotNull(obj.Arrays); + Assert.IsNotNull(obj.Vortex); + } + + [Test] + public void Can_PopulateObjectWithStringArray() + { + var obj = (DtoWithStringArray)AutoMappingUtils.PopulateWith(new DtoWithStringArray()); + Assert.IsNotNull(obj.Data); + Assert.Greater(obj.Data.Length, 0); + Assert.IsNotNull(obj.Data[0]); + } + + [Test] + public void Can_PopulateObjectWithNonZeroEnumArray() + { + 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)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() + { + var toObj = ModelWithFieldsOfDifferentTypes.Create(1); + var fromObj = ModelWithFieldsOfDifferentTypesAsNullables.Create(2); + + var originalToObj = ModelWithFieldsOfDifferentTypes.Create(1); + + fromObj.Name = null; + fromObj.Double = default(double); + fromObj.Guid = default(Guid); + fromObj.Bool = default(bool); + + toObj.PopulateWithNonDefaultValues(fromObj); + + Assert.That(toObj.Name, Is.EqualTo(originalToObj.Name)); + + Assert.That(toObj.Double, Is.EqualTo(fromObj.Double)); + Assert.That(toObj.Guid, Is.EqualTo(fromObj.Guid)); + Assert.That(toObj.Bool, Is.EqualTo(fromObj.Bool)); + Assert.That(toObj.Id, Is.EqualTo(fromObj.Id)); + Assert.That(toObj.LongId, Is.EqualTo(fromObj.LongId)); + Assert.That(toObj.DateTime, Is.EqualTo(fromObj.DateTime)); + } + + [Test] + public void Translate_Between_Models_of_different_types_and_nullables() + { + var fromObj = ModelWithFieldsOfDifferentTypes.CreateConstant(1); + + var toObj = fromObj.ConvertTo(); + + Console.WriteLine(toObj.Dump()); + + ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(fromObj, toObj); + } + + [Test] + public void Translate_Between_Models_of_nullables_and_different_types() + { + var fromObj = ModelWithFieldsOfDifferentTypesAsNullables.CreateConstant(1); + + var toObj = fromObj.ConvertTo(); + + Console.WriteLine(toObj.Dump()); + + 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 new file mode 100644 index 00000000000..2aacd365ad0 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ServiceClient.Web/HtmlServiceClient.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using ServiceStack.Web; + +namespace ServiceStack.Common.Tests.ServiceClient.Web +{ + public class HtmlServiceClient: ServiceClientBase + { + public HtmlServiceClient() + { + } + + public HtmlServiceClient(string baseUri) + // Can't call SetBaseUri as that appends the format specific suffixes. + :base(baseUri, baseUri) + { + } + + public override string Format + { + // Don't return a format as we are not using a ServiceStack format specific endpoint, but + // rather the general purpose endpoint (just like a html
      POST would use). + get { return null; } + } + + public override string Accept + { + get { return MimeTypes.Html; } + } + + public override string ContentType + { + // Only used by the base class when POST-ing. + get { return MimeTypes.FormUrlEncoded; } + } + + public override void SerializeToStream(IRequest req, object request, Stream stream) + { + var queryString = QueryStringSerializer.SerializeToString(request); + stream.Write(queryString); + } + + public override T DeserializeFromStream(Stream stream) + { + return (T) DeserializeDtoFromHtml(typeof (T), stream); + } + + public override StreamDeserializerDelegate StreamDeserializer + { + get { return DeserializeDtoFromHtml; } + } + + private object DeserializeDtoFromHtml(Type type, Stream fromStream) + { + // TODO: No tests currently use the response, but this could be something that will come in handy later. + // It isn't trivial though, will have to parse the HTML content. + return Activator.CreateInstance(type); + } + } +} 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 new file mode 100644 index 00000000000..283f47bf15e --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ServiceClient.Web/UrlExtensionsTests.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Common.Tests.Models; +using ServiceStack.NativeTypes; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests.ServiceClient.Web +{ + [TestFixture] + public class UrlExtensionsTests + { + [Test] + public void FormatVariable_DateTimeOffsetValue_ValueIsUrlEncoded() + { + var dateTimeOffset = DateTimeOffset.Now; + var formattedVariable = RestRoute.FormatVariable(dateTimeOffset); + var jsv = dateTimeOffset.ToJsv(); + Assert.AreEqual(Uri.EscapeDataString(jsv), formattedVariable); + } + + [Test] + public void FormatQueryParameterValue_DateTimeOffsetValue_ValueIsUrlEncoded() + { + var dateTimeOffset = DateTimeOffset.Now; + var formattedVariable = RestRoute.FormatQueryParameterValue(dateTimeOffset); + 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 9ff6dc4d16b..3dcfa62e6a3 100644 --- a/tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj +++ b/tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj @@ -1,264 +1,63 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {3FA9197A-462D-44CC-9AB3-61AF414D0B45} - Library - Properties - ServiceStack.Common.Tests - ServiceStack.Common.Tests - v3.5 - 512 - - - 3.5 - - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - True - full - False - bin\Debug\ - TRACE;DEBUG;MONO - prompt - 4 - AllRules.ruleset - True - AnyCPU - - - pdbonly - True - bin\Release\ - TRACE - prompt - 4 - AnyCPU - 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {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 - SQL Server 2008 Express - true - - - False - Windows Installer 3.1 - true - - - False - Windows Installer 4.5 - true - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - sqlite3.dll - PreserveNewest - - - - + + + net472;net6.0 + portable + ServiceStack.Common.Tests + ServiceStack.Common.Tests + false + false + false + false + false + false + false + false + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + $(DefineConstants);NET45 + + + + + + + + + + + $(DefineConstants);NETCORE + + + + + + + + SettingsSingleFileGenerator + + \ 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 225d10ee309..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; - -namespace ServiceStack.Common.Tests -{ - [TestFixture] - public class StreamExtensionsTests - { - [DataContract] - public class SimpleDto - { - [DataMember] - public int Id { get; set; } - - [DataMember] - public string Name { get; set; } - - public SimpleDto(int id, string name) - { - Id = id; - Name = name; - } - } - - [Test] - public void Can_compress_and_decompress_SimpleDto() - { - var simpleDto = new SimpleDto(1, "name"); - - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); - - var simpleDtoZip = simpleDtoXml.Deflate(); - - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - - var deserializedSimpleDtoXml = simpleDtoZip.Inflate(); - - Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( - deserializedSimpleDtoXml); - - Assert.That(deserializedSimpleDto, Is.Not.Null); - - 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"); - - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); - - var simpleDtoZip = simpleDtoXml.GZip(); - - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - - var deserializedSimpleDtoXml = simpleDtoZip.GUnzip(); - - Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( - deserializedSimpleDtoXml); - - Assert.That(deserializedSimpleDto, Is.Not.Null); - - Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); - Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); - } - } +using System.Runtime.Serialization; +using NUnit.Framework; +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; } + + [DataMember] + public string Name { get; set; } + + public SimpleDto(int id, string name) + { + Id = id; + Name = name; + } + } + + [Test] + public void Can_compress_and_decompress_SimpleDto() + { + var simpleDto = new SimpleDto(1, "name"); + + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); + + var simpleDtoZip = simpleDtoXml.Deflate(); + + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + + var deserializedSimpleDtoXml = simpleDtoZip.Inflate(); + + Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); + + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( + deserializedSimpleDtoXml); + + Assert.That(deserializedSimpleDto, Is.Not.Null); + + 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"); + + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); + + var simpleDtoZip = simpleDtoXml.GZip(); + + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + + var deserializedSimpleDtoXml = simpleDtoZip.GUnzip(); + + Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); + + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( + deserializedSimpleDtoXml); + + Assert.That(deserializedSimpleDto, Is.Not.Null); + + 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 13615c73a41..fe9f16ff5f1 100644 --- a/tests/ServiceStack.Common.Tests/StringExtensionTests.cs +++ b/tests/ServiceStack.Common.Tests/StringExtensionTests.cs @@ -3,116 +3,288 @@ using System.Linq; using System.Web; using NUnit.Framework; -using ServiceStack.Common.Extensions; 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() - { - var input = new[] { "Foo", "Boo", "Hoo", "Baz" }.ToList(); - var expected = input.Where(s => s.EndsWith("oo")).ToList(); - - var actual = input.Where(s => s.Glob("*oo")).ToList(); - + { + var input = new[] { "Foo", "Boo", "Hoo", "Baz" }.ToList(); + 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() + { + 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")); + 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("/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/")); + } + + [Test] + public void ToHttps_is_idempotent() + { + Assert.That("https://host.example.com/path".ToHttps().ToHttps(), Is.EqualTo("https://host.example.com/path")); + } + + [Test] + public void ToHttps_replaces_http_with_https() + { + Assert.That("http://host.example.com/path".ToHttps(), Is.EqualTo("https://host.example.com/path")); + } + + [Test] + public void ToHttps_only_replaces_http_at_beginning_of_string() + { + Assert.That("http://host.example.com/http/path".ToHttps(), Is.EqualTo("https://host.example.com/http/path")); + } + + [Test] + public void ToHttps_ignores_whitespace_at_beginning_of_string() + { + Assert.That(" http://host.example.com".ToHttps(), Is.EqualTo("https://host.example.com")); + } + + [Test] + 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 d85f7f68b15..b09362202f4 100644 --- a/tests/ServiceStack.Common.Tests/Text/AdhocJsTests.cs +++ b/tests/ServiceStack.Common.Tests/Text/AdhocJsTests.cs @@ -1,77 +1,78 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests.Text -{ - public enum EnumValues - { - Enum1, - Enum2, - Enum3, - } - - [TestFixture] - public class AdhocJsTests - { - [Test] - public void Can_Deserialize() - { - var items = TypeSerializer.DeserializeFromString>( - "/CustomPath35/api,/CustomPath40/api,/RootPath35,/RootPath40,:82,:83,:5001/api,:5002/api,:5003,:5004"); - - Console.WriteLine(items.Dump()); - } - - [Test] - public void Can_Serialize_Array_of_enums() - { - var enumArr = new[] { EnumValues.Enum1, EnumValues.Enum2, EnumValues.Enum3, }; - var json = JsonSerializer.SerializeToString(enumArr); - Assert.That(json, Is.EqualTo("[\"Enum1\",\"Enum2\",\"Enum3\"]")); - } - - [Test] - public void Can_Serialize_Array_of_chars() - { - var enumArr = new[] { 'A', 'B', 'C', }; - var json = JsonSerializer.SerializeToString(enumArr); - Assert.That(json, Is.EqualTo("[\"A\",\"B\",\"C\"]")); - } - - [Test] - public void Can_Serialize_Array_with_nulls() - { - var t = new { - Name = "MyName", - Number = (int?)null, - Data = new object[] { 5, null, "text" } - }; - - ServiceStack.Text.JsConfig.IncludeNullValues = true; - var json = ServiceStack.Text.JsonSerializer.SerializeToString(t); - Assert.That(json, Is.EqualTo("{\"Name\":\"MyName\",\"Number\":null,\"Data\":[5,null,\"text\"]}")); - } - - class A - { - public string Value { get; set; } - } - - [Test] - public void DumpFail() - { - var arrayOfA = new[] { new A { Value = "a" }, null, new A { Value = "b" } }; - Console.WriteLine(arrayOfA.Dump()); - } - - [Test] - public void Deserialize_array_with_null_elements() - { - var json = "[{\"Value\": \"a\"},null,{\"Value\": \"b\"}]"; - var o = JsonSerializer.DeserializeFromString(json); - o.PrintDump(); - } - } +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests.Text +{ + public enum EnumValues + { + Enum1, + Enum2, + Enum3, + } + + [TestFixture] + public class AdhocJsTests + { + [Test] + public void Can_Deserialize() + { + var items = TypeSerializer.DeserializeFromString>( + "/CustomPath35/api,/CustomPath40/api,/RootPath35,/RootPath40,:82,:83,:5001/api,:5002/api,:5003,:5004"); + + Console.WriteLine(items.Dump()); + } + + [Test] + public void Can_Serialize_Array_of_enums() + { + var enumArr = new[] { EnumValues.Enum1, EnumValues.Enum2, EnumValues.Enum3, }; + var json = JsonSerializer.SerializeToString(enumArr); + Assert.That(json, Is.EqualTo("[\"Enum1\",\"Enum2\",\"Enum3\"]")); + } + + [Test] + public void Can_Serialize_Array_of_chars() + { + var enumArr = new[] { 'A', 'B', 'C', }; + var json = JsonSerializer.SerializeToString(enumArr); + Assert.That(json, Is.EqualTo("[\"A\",\"B\",\"C\"]")); + } + + [Test] + public void Can_Serialize_Array_with_nulls() + { + using (JsConfig.With(new Config { IncludeNullValues = true })) + { + var t = new { + Name = "MyName", + Number = (int?)null, + Data = new object[] { 5, null, "text" } + }; + + var json = JsonSerializer.SerializeToString(t); + Assert.That(json, Is.EqualTo("{\"Name\":\"MyName\",\"Number\":null,\"Data\":[5,null,\"text\"]}")); + } + } + + class A + { + public string Value { get; set; } + } + + [Test] + public void DumpFail() + { + var arrayOfA = new[] { new A { Value = "a" }, null, new A { Value = "b" } }; + Console.WriteLine(arrayOfA.Dump()); + } + + [Test] + public void Deserialize_array_with_null_elements() + { + var json = "[{\"Value\": \"a\"},null,{\"Value\": \"b\"}]"; + var o = JsonSerializer.DeserializeFromString(json); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs b/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs new file mode 100644 index 00000000000..bfb8d3a7c88 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs @@ -0,0 +1,297 @@ +using System; +using System.Runtime.Serialization; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [Route("/route/{Id}")] + 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 FieldId(long id) + { + Id = id; + } + } + + [Route("/route/{Ids}")] + public class ArrayIds : IReturn + { + public long[] Ids { get; set; } + public ArrayIds(params long[] ids) + { + this.Ids = ids; + } + } + + [Route("/route/{Id}")] + public class RequestWithIgnoredDataMembers : IReturn + { + public long Id { get; set; } + + public string Included { get; set; } + + [IgnoreDataMember] + public string Excluded { get; set; } + } + + [DataContract] + [Route("/route/{Id}")] + public class RequestWithDataMembers : IReturn + { + [DataMember] + public long Id { get; set; } + + [DataMember] + public string Included { get; set; } + + public string Excluded { get; set; } + } + + [DataContract] + [Route("/route/{Key}")] + public class RequestWithNamedDataMembers : IReturn + { + [DataMember(Name = "Key")] + public long Id { get; set; } + + [DataMember(Name = "Inc")] + public string Included { get; set; } + + public string Excluded { get; set; } + } + + public enum Gender + { + None = 0, + Male, + Female + } + + [Route("/route/{Id}")] + public class RequestWithValueTypes : IReturn + { + public long Id { get; set; } + + public Gender Gender1 { 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() + { + var url = new JustId { Id = 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() + { + var url = new ArrayIds(1, 2, 3).ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1%2C2%2C3")); + } + + [Test] + public void Cannot_include_ignored_data_members_on_querystring() + { + var url = new RequestWithIgnoredDataMembers { Id = 1, Included = "Yes", Excluded = "No" }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1?included=Yes")); + } + + [Test] + public void Can_include_only_data_members_on_querystring() + { + var url = new RequestWithDataMembers { Id = 1, Included = "Yes", Excluded = "No" }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1?included=Yes")); + } + + [Test] + public void Use_data_member_names_on_querystring() + { + var url = new RequestWithNamedDataMembers { Id = 1, Included = "Yes", Excluded = "No" }.ToUrl("GET"); + 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 Can_combine_Uris_with_toUrl() + { + var serviceEndpoint = new Uri("http://localhost/api/", UriKind.Absolute); + var actionUrl = new Uri(new JustId { Id = 1 }.ToUrl("GET").Substring(1), UriKind.Relative); + + 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")); + } + + [Route("/images/{ImagePath*}")] + public class WildCardPath : IReturn + { + public string ImagePath { get; set; } + } + + [Test] + public void Can_generate_route_with_WildCard_path() + { + var request = new WildCardPath { ImagePath = "this/that/theother.jpg" }; + var url = request.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/images/" + Uri.EscapeDataString(request.ImagePath))); + } + + [Test] + public void Can_generate_empty_route_with_WildCard_path() + { + var request = new WildCardPath(); + var url = request.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/images/")); + } + + [Test] + public void Show_what_uri_escaping_encodes() + { + //INFO on what needs to be url-encoded + //http://stackoverflow.com/a/10385414/85785 + + var data = "amp&mod%space comma,dot.colon:semicolon;slash/"; + + Assert.That(Uri.EscapeUriString(data), Is.EqualTo("amp&mod%25space%20comma,dot.colon:semicolon;slash/")); + 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 e3c449312bd..00000000000 --- a/tests/ServiceStack.Common.Tests/app.config +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file 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 183888c270e..00000000000 --- a/tests/ServiceStack.Messaging.Tests/ServiceStack.Messaging.Tests.csproj +++ /dev/null @@ -1,153 +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 - - - - - 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/MessagingServiceBase.cs b/tests/ServiceStack.Messaging.Tests/Services/MessagingServiceBase.cs deleted file mode 100644 index 02e2277a086..00000000000 --- a/tests/ServiceStack.Messaging.Tests/Services/MessagingServiceBase.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ServiceStack.ServiceInterface; - -namespace ServiceStack.Messaging.Tests.Services -{ - public abstract class MessagingServiceBase - : AsyncServiceBase - { - } - -} \ 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 73c04357667..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.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.RazorHostTests/AppHost.cs b/tests/ServiceStack.RazorHostTests/AppHost.cs new file mode 100644 index 00000000000..20bfe1f450f --- /dev/null +++ b/tests/ServiceStack.RazorHostTests/AppHost.cs @@ -0,0 +1,156 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Funq; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.OrmLite.Sqlite; +using ServiceStack.Razor; +using ServiceStack.Text; + +namespace ServiceStack.RazorHostTests +{ + [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 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) + { + using (var db = DbFactory.OpenDbConnection()) + { + 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" } + }; + } + } + + public class DataSource + { + public string[] Items = new[] { "Eeny", "meeny", "miny", "moe" }; + } + + 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 Rockstar() { } + public Rockstar(int id, string firstName, string lastName, int age) + { + Id = id; + FirstName = firstName; + LastName = lastName; + Age = age; + } + } + + public class AppHost : AppHostBase + { + public AppHost() + : base("Razor Test", typeof(AppHost).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new RazorFormat { + //TemplateProvider = {CompileInParallelWithNoOfThreads = 0} + }); + + container.Register(new DataSource()); + + container.Register( + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + using (var db = container.Resolve().OpenDbConnection()) + { + db.CreateTable(overwrite: false); + db.Insert(Rockstar.SeedData); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/CatchAll.cshtml b/tests/ServiceStack.RazorHostTests/CatchAll.cshtml index 9d42b1ef72b..521db0fabb4 100644 --- a/tests/ServiceStack.RazorHostTests/CatchAll.cshtml +++ b/tests/ServiceStack.RazorHostTests/CatchAll.cshtml @@ -1,22 +1,24 @@ -@inherits ViewPage - -@{ - Layout = "SimplyLayout"; -} - -
      CATCH ALL: @Model.Id
      -
        - @foreach (var name in Get().Items) - { -
      • @name
      • - } - - @Html.TextBoxFor(x => x.Id) -
      - -

      Db.Select<Person>()

      -
        - @foreach(var person in Db.Select(q => q.Age == 27)) { -
      • @person.FirstName - @person.LastName (@person.Age)
      • - } -
      +@inherits ServiceStack.Razor.ViewPage + +@{ + Layout = "SimplyLayout"; +} + +
      CATCH ALL: @Model.Id
      +
        + @foreach (var name in Get().Items) + { +
      • @name
      • + } + + @Html.TextBoxFor(x => x.Id) +
      + +

      Db.Select<Person>()

      +
        + @foreach(var person in Db.Select(q => q.Age == 27)) { +
      • @person.FirstName - @person.LastName (@person.Age)
      • + } +
      + +@Html.Partial("_CatchAllPartial") diff --git a/tests/ServiceStack.RazorHostTests/CatchAllDynamic.cshtml b/tests/ServiceStack.RazorHostTests/CatchAllDynamic.cshtml index 5011b9aa7de..6459da53dd1 100644 --- a/tests/ServiceStack.RazorHostTests/CatchAllDynamic.cshtml +++ b/tests/ServiceStack.RazorHostTests/CatchAllDynamic.cshtml @@ -1,13 +1,13 @@ -@inherits ViewPage - -@{ - Layout = "SimplyLayout"; -} - -
      CATCH ALL: @Model.Id
      -
        - @foreach (var name in Get().Items) - { -
      • @name
      • - } +@inherits ServiceStack.Razor.ViewPage + +@{ + Layout = "SimplyLayout"; +} + +
        CATCH ALL: @Model.Id
        +
          + @foreach (var name in Get().Items) + { +
        • @name
        • + }
        \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Embedded/CatchEmbedded.cshtml b/tests/ServiceStack.RazorHostTests/Embedded/CatchEmbedded.cshtml index e0d4db139e9..0c0d142d535 100644 --- a/tests/ServiceStack.RazorHostTests/Embedded/CatchEmbedded.cshtml +++ b/tests/ServiceStack.RazorHostTests/Embedded/CatchEmbedded.cshtml @@ -1,6 +1,6 @@ @using ServiceStack -@inherits ViewPage +@inherits ServiceStack.Razor.ViewPage @{ Layout = "SimplyLayout"; diff --git a/tests/ServiceStack.RazorHostTests/Embedded/Views/Rockstars.cshtml b/tests/ServiceStack.RazorHostTests/Embedded/Views/Rockstars.cshtml index 2a1f4b33ee4..910e7ba8714 100644 --- a/tests/ServiceStack.RazorHostTests/Embedded/Views/Rockstars.cshtml +++ b/tests/ServiceStack.RazorHostTests/Embedded/Views/Rockstars.cshtml @@ -1,4 +1,4 @@ -@inherits ViewPage +@inherits ServiceStack.Razor.ViewPage @{ ViewBag.Title = Model.Aged.HasValue ? "{0} year old rockstars".Fmt(Model.Aged) : "All Rockstars"; diff --git a/tests/ServiceStack.RazorHostTests/Embedded/Views/Shared/HtmlReport.cshtml b/tests/ServiceStack.RazorHostTests/Embedded/Views/Shared/HtmlReport.cshtml index e6553e1ea71..1be3dddd3ad 100644 --- a/tests/ServiceStack.RazorHostTests/Embedded/Views/Shared/HtmlReport.cshtml +++ b/tests/ServiceStack.RazorHostTests/Embedded/Views/Shared/HtmlReport.cshtml @@ -1,4 +1,5 @@ - +@using ServiceStack.Razor + @ViewBag.Title diff --git a/tests/ServiceStack.RazorHostTests/Global.asax b/tests/ServiceStack.RazorHostTests/Global.asax index f99bfbb6ce1..c19d4dd86f1 100644 --- a/tests/ServiceStack.RazorHostTests/Global.asax +++ b/tests/ServiceStack.RazorHostTests/Global.asax @@ -1 +1 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="ServiceStack.RazorHostTests.Global" Language="C#" %> +<%@ Application Codebehind="Global.asax.cs" Inherits="ServiceStack.RazorHostTests.Global" Language="C#" %> diff --git a/tests/ServiceStack.RazorHostTests/Global.asax.cs b/tests/ServiceStack.RazorHostTests/Global.asax.cs index de7a9c3bbcc..0cba2e990b8 100644 --- a/tests/ServiceStack.RazorHostTests/Global.asax.cs +++ b/tests/ServiceStack.RazorHostTests/Global.asax.cs @@ -1,171 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using Funq; -using ServiceStack.Common; -using ServiceStack.DataAnnotations; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.Razor; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints; -using System.Reflection; - -namespace ServiceStack.RazorHostTests -{ - public class DataSource - { - public string[] Items = new[] { "Eeny", "meeny", "miny", "moe" }; - } - - 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 Rockstar() { } - public Rockstar(int id, string firstName, string lastName, int age) - { - Id = id; - FirstName = firstName; - LastName = lastName; - Age = age; - } - } - - public class AppHost : AppHostBase - { - public AppHost() - : base("Razor Test", typeof(AppHost).Assembly) { } - - public override void Configure(Container container) - { - Plugins.Add(new RazorFormat()); - - container.Register(new DataSource()); - - container.Register( - new OrmLiteConnectionFactory(":memory:", false, SqliteOrmLiteDialectProvider.Instance)); - - using (var db = container.Resolve().OpenDbConnection()) - { - db.CreateTable(overwrite: false); - db.Insert(Rockstar.SeedData); - } - } - } - - public class Global : System.Web.HttpApplication - { - void Application_Start(object sender, EventArgs e) - { - // Code that runs on application startup - new AppHost().Init(); - - foreach(var resource in typeof(AppHost).Assembly.GetManifestResourceNames()) - { - var tokens = resource.TokenizeResourcePath(); - } - } - } - - [RestService("/rockstars")] - [RestService("/rockstars/aged/{Age}")] - [RestService("/rockstars/delete/{Delete}")] - [RestService("/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 RockstarsService : RestServiceBase - { - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnGet(Rockstars request) - { - using (var db = DbFactory.OpenDbConnection()) - { - 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.GetScalar("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 override object OnPost(Rockstars request) - { - using (var db = DbFactory.OpenDbConnection()) - { - db.Insert(request.TranslateTo()); - return OnGet(new Rockstars()); - } - } - } - - [RestService("/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 : ServiceBase - { - protected override object Run(ViewThatUsesLayoutAndModel request) - { - return new ViewThatUsesLayoutAndModelResponse { - Name = request.Id ?? "Foo", - Results = new List { "Tom", "Dick", "Harry" } - }; - } - } -} +using System; +using ServiceStack.VirtualPath; + +namespace ServiceStack.RazorHostTests +{ + public class Global : System.Web.HttpApplication + { + void Application_Start(object sender, EventArgs e) + { + // Code that runs on application startup + new AppHost().Init(); + + foreach(var resource in typeof(AppHost).Assembly.GetManifestResourceNames()) + { + var tokens = resource.TokenizeResourcePath(); + } + } + } +} diff --git a/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs b/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs index 6fdb7b56943..dfb479c5cf4 100644 --- a/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs @@ -1,35 +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.RazorHostTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceStack.RazorHostTests")] -[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("e40d956b-67f5-476d-858d-e52a4b69aaba")] - -// 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")] +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.RazorHostTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ServiceStack.RazorHostTests")] +[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("e40d956b-67f5-476d-858d-e52a4b69aaba")] + +// 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("6.0.0.0")] diff --git a/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj b/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj index fba8a5d7609..eaf700a78ea 100644 --- a/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj +++ b/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj @@ -1,201 +1,242 @@ - - - - Debug - AnyCPU - - - 2.0 - {CEAB2047-A095-4A96-8B23-325C6BB5690D} - {349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - ServiceStack.RazorHostTests - ServiceStack.RazorHostTests - false - - - True - full - False - bin\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - True - bin\ - TRACE - prompt - 4 - - - - - ..\..\lib\tests\Mono.Data.Sqlite.dll - - - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - - - - - - - - - - - - - - - - - - - sqlite3.dll - PreserveNewest - - - - - Web.config - - - Web.config - - - - - Global.asax - - - - - - - - - - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {672F2DFE-4EE8-498B-B449-23E9E7F6961C} - ServiceStack.FluentValidation.Mvc3 - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - {64128C85-B9AF-4B4C-BE83-04983EF7F8C9} - ServiceStack.Razor - - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface - - - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} - ServiceStack - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - True - 43487 - / - - - False - False - - - False - - - - - - - - - - + + + + + Debug + AnyCPU + + + 2.0 + {CEAB2047-A095-4A96-8B23-325C6BB5690D} + {349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + ServiceStack.RazorHostTests + ServiceStack.RazorHostTests + false + v4.7.2 + + + 4.0 + + + + + + + ..\..\src\ + true + + + + + + + True + full + False + bin\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + True + bin\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + Web.config + + + Web.config + + + + + + Global.asax + + + + + + + + + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416DB-C143-4028-A0C3-CF41892D18D3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {d73274ae-006b-4cee-ba60-0ecf5873048d} + ServiceStack.Razor + + + {680A1709-25EB-4D52-A87F-EE03FFD94BAA} + ServiceStack + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + bin\ + TRACE + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + false + + + + + + + + + False + False + 58772 + / + + + False + False + + + False + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/Rockstars.cshtml b/tests/ServiceStack.RazorHostTests/Views/Rockstars.cshtml index d3d69036ed3..910e7ba8714 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Rockstars.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Rockstars.cshtml @@ -1,51 +1,51 @@ -@inherits ViewPage - -@{ - ViewBag.Title = Model.Aged.HasValue ? "{0} year old rockstars".Fmt(Model.Aged) : "All Rockstars"; - Layout = "HtmlReport"; -} - -
        - View this page in: - json, - xml, - jsv, - csv - -

         

        -
        -
        @Html.Label("FirstName") @Html.TextBox("FirstName","Amy")
        -
        @Html.Label("LastName") @Html.TextBox("LastName","Winehouse")
        -
        @Html.Label("Age") @Html.TextBox("Age","27")
        -

        - -
        - -

        We have @Model.Total Rockstars, showing @ViewBag.Title

        -
      - - - - - - - - - - - - - - @foreach (var rockstar in Model.Results) - { - - - - - - } - -
      NameAge
      -

      Show all @Model.Total Rockstars

      -

      Reset Rockstars

      -
      @rockstar.FirstName @rockstar.LastName @rockstar.Agedelete
      +@inherits ServiceStack.Razor.ViewPage + +@{ + ViewBag.Title = Model.Aged.HasValue ? "{0} year old rockstars".Fmt(Model.Aged) : "All Rockstars"; + Layout = "HtmlReport"; +} + +
      + View this page in: + json, + xml, + jsv, + csv + +

       

      +
      +
      @Html.Label("FirstName") @Html.TextBox("FirstName","Amy")
      +
      @Html.Label("LastName") @Html.TextBox("LastName","Winehouse")
      +
      @Html.Label("Age") @Html.TextBox("Age","27")
      +

      +
      +
      + +

      We have @Model.Total Rockstars, showing @ViewBag.Title

      + + + + + + + + + + + + + + + @foreach (var rockstar in Model.Results) + { + + + + + + } + +
      NameAge
      +

      Show all @Model.Total Rockstars

      +

      Reset Rockstars

      +
      @rockstar.FirstName @rockstar.LastName @rockstar.Agedelete
      diff --git a/tests/ServiceStack.RazorHostTests/Views/Shared/HtmlReport.cshtml b/tests/ServiceStack.RazorHostTests/Views/Shared/HtmlReport.cshtml index 95355c1a5fe..1be3dddd3ad 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Shared/HtmlReport.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Shared/HtmlReport.cshtml @@ -1,4 +1,5 @@ - +@using ServiceStack.Razor + @ViewBag.Title @@ -175,19 +176,19 @@ H3 { font-size: 18px; margin: 0 0 10px 0; } -#content { - clear: both; - margin: auto; - width: 760px; - padding: 10px; -} -form div b { - width: 100px; - display: inline-block; -} -tfoot td { - text-align: center -} +#content { + clear: both; + margin: auto; + width: 760px; + padding: 10px; +} +form div b { + width: 100px; + display: inline-block; +} +tfoot td { + text-align: center +} @@ -195,8 +196,8 @@ tfoot td {

      @ViewBag.Title

      -
      - @RenderBody() +
      + @RenderBody()
      diff --git a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithManySections.cshtml b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithManySections.cshtml index 48a362b8b7e..91d0e99325a 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithManySections.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithManySections.cshtml @@ -1,21 +1,22 @@ - - - - - - -

      SimplyLayout

      -
      - @RenderSection("FirstSection") -
      -
      - @RenderSection("SecondSection") -
      -
      - @RenderBody() -
      -
      - @RenderSection("ThirdSection") -
      - +@using ServiceStack.Razor + + + + + + +

      SimplyLayout

      +
      + @RenderSection("FirstSection") +
      +
      + @RenderSection("SecondSection") +
      +
      + @RenderBody() +
      +
      + @RenderSection("ThirdSection") +
      + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSection.cshtml b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSection.cshtml index 179a20997e1..be818d9a0b6 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSection.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSection.cshtml @@ -1,15 +1,16 @@ - - - - - - -

      SimplyLayout

      -
      - @RenderSection("FirstSection", required: false) -
      -
      - @RenderBody() -
      - +@using ServiceStack.Razor + + + + + + +

      SimplyLayout

      +
      + @RenderSection("FirstSection", required: false) +
      +
      + @RenderBody() +
      + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSectionWithDefaults.cshtml b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSectionWithDefaults.cshtml index 37ca1190d9f..217d2dfdaf5 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSectionWithDefaults.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithOptionalSectionWithDefaults.cshtml @@ -1,19 +1,20 @@ - - - - - - -

      SectionWithDefaultsLayout

      -
      - @if (IsSectionDefined("FirstSection")) { - @RenderSection("FirstSection", required: false) - } else { -
      OptionalSectionDefault
      - } -
      -
      - @RenderBody() -
      - +@using ServiceStack.Razor + + + + + + +

      SectionWithDefaultsLayout

      +
      + @if (IsSectionDefined("FirstSection")) { + @RenderSection("FirstSection", required: false) + } else { +
      OptionalSectionDefault
      + } +
      +
      + @RenderBody() +
      + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithSection.cshtml b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithSection.cshtml index 21eb1556812..a87dbc83c6d 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithSection.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Shared/LayoutWithSection.cshtml @@ -1,15 +1,16 @@ - - - - - - -

      SimplyLayout

      -
      - @RenderSection("FirstSection") -
      -
      - @RenderBody() -
      - +@using ServiceStack.Razor + + + + + + +

      SimplyLayout

      +
      + @RenderSection("FirstSection") +
      +
      + @RenderBody() +
      + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/Shared/SimplyLayout.cshtml b/tests/ServiceStack.RazorHostTests/Views/Shared/SimplyLayout.cshtml index 6b2839a3a28..c5fc590826d 100644 --- a/tests/ServiceStack.RazorHostTests/Views/Shared/SimplyLayout.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/Shared/SimplyLayout.cshtml @@ -1,12 +1,13 @@ - - - - simple layout - - -

      Simply Layout

      -
      - @RenderBody() -
      - +@using ServiceStack.Razor + + + + simple layout + + +

      Simply Layout

      +
      + @RenderBody() +
      + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayout.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayout.cshtml index a4b0b4e4967..8472a0eca56 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayout.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayout.cshtml @@ -1,5 +1,6 @@ -@{ - Layout = "SimplyLayout"; -} - +@using ServiceStack.Razor +@{ + Layout = "SimplyLayout"; +} +
      ViewThatUsesLayout
      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndManySection.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndManySection.cshtml index 14afd6c485f..824f4c34dfe 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndManySection.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndManySection.cshtml @@ -1,17 +1,18 @@ -@{ - Layout = "LayoutWithManySections"; -} - -@section FirstSection { -
      First section in ViewThatUsesLayoutAndManySection
      -} - -@section SecondSection { -
      Second section in ViewThatUsesLayoutAndManySection
      -} - -@section ThirdSection { -
      Third section in ViewThatUsesLayoutAndManySection
      -} - +@using ServiceStack.Razor +@{ + Layout = "LayoutWithManySections"; +} + +@section FirstSection { +
      First section in ViewThatUsesLayoutAndManySection
      +} + +@section SecondSection { +
      Second section in ViewThatUsesLayoutAndManySection
      +} + +@section ThirdSection { +
      Third section in ViewThatUsesLayoutAndManySection
      +} +
      ViewThatUsesLayoutAndManySection
      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndModel.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndModel.cshtml index 044df89c84c..fd5aa57ed26 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndModel.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndModel.cshtml @@ -1,22 +1,22 @@ -@inherits ViewPage - -@{ - Layout = "SimplyLayout"; -} - -
      ViewThatUsesLayoutAndModel: @Model.Name
      -@Html.LabelFor(x => x.Name) -@Html.TextBoxFor(x => x.Name) -

      Model

      -
        - @foreach(var name in Model.Results) { -
      • @name
      • - } -
      - -

      Db.Select<Person>()

      -
        - @foreach(var person in Db.Select()) { -
      • @person.FirstName - @person.LastName (@person.Age)
      • - } -
      +@inherits ServiceStack.Razor.ViewPage + +@{ + Layout = "SimplyLayout"; +} + +
      ViewThatUsesLayoutAndModel: @Model.Name
      +@Html.LabelFor(x => x.Name) +@Html.TextBoxFor(x => x.Name) +

      Model

      +
        + @foreach(var name in Model.Results) { +
      • @name
      • + } +
      + +

      Db.Select<Person>()

      +
        + @foreach(var person in Db.Select()) { +
      • @person.FirstName - @person.LastName (@person.Age)
      • + } +
      diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSection.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSection.cshtml index bfa4817aace..e9267f7c1d1 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSection.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSection.cshtml @@ -1,5 +1,6 @@ -@{ - Layout = "LayoutWithOptionalSection"; -} - +@using ServiceStack.Razor +@{ + Layout = "LayoutWithOptionalSection"; +} +
      ViewThatUsesLayoutAndOptionalSection
      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionOverridingDefaults.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionOverridingDefaults.cshtml index 45875a516c5..9eeed60cada 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionOverridingDefaults.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionOverridingDefaults.cshtml @@ -1,7 +1,8 @@ -@{ - Layout = "LayoutWithOptionalSectionWithDefaults"; -} -@section FirstSection { -
      OptionalSectionOverride
      -} +@using ServiceStack.Razor +@{ + Layout = "LayoutWithOptionalSectionWithDefaults"; +} +@section FirstSection { +
      OptionalSectionOverride
      +}
      ViewThatUsesLayoutAndOptionalSectionOverridingDefaults
      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionWithDefaults.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionWithDefaults.cshtml index 9437180a7c4..dcafdbf41a6 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionWithDefaults.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndOptionalSectionWithDefaults.cshtml @@ -1,5 +1,6 @@ -@{ - Layout = "LayoutWithOptionalSectionWithDefaults"; -} - +@using ServiceStack.Razor +@{ + Layout = "LayoutWithOptionalSectionWithDefaults"; +} +
      ViewThatUsesLayoutAndOptionalSectionWithDefaults
      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndSection.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndSection.cshtml index 0b26cac073e..4691ccc993d 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndSection.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesLayoutAndSection.cshtml @@ -1,10 +1,11 @@ -@{ - Layout = "LayoutWithSection"; -} - -@section FirstSection { -
      First section in ViewThatUsesLayoutAndSection
      -} - - +@using ServiceStack.Razor +@{ + Layout = "LayoutWithSection"; +} + +@section FirstSection { +
      First section in ViewThatUsesLayoutAndSection
      +} + +
      ViewThatUsesLayoutAndSection
      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesModelCSharp.cshtml b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesModelCSharp.cshtml index 19b6ce4dee9..f373b46bea2 100644 --- a/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesModelCSharp.cshtml +++ b/tests/ServiceStack.RazorHostTests/Views/ViewThatUsesModelCSharp.cshtml @@ -1,3 +1,4 @@ -@model System.DateTime - +@using ServiceStack.Razor +@model System.DateTime +

      Hello at @Model.ToString("MM/dd/yyyy")

      \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Web.Debug.config b/tests/ServiceStack.RazorHostTests/Web.Debug.config index 962e6b73a26..2c6dd51a705 100644 --- a/tests/ServiceStack.RazorHostTests/Web.Debug.config +++ b/tests/ServiceStack.RazorHostTests/Web.Debug.config @@ -1,30 +1,30 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Web.Release.config b/tests/ServiceStack.RazorHostTests/Web.Release.config index 141832ba77e..4122d79bfe2 100644 --- a/tests/ServiceStack.RazorHostTests/Web.Release.config +++ b/tests/ServiceStack.RazorHostTests/Web.Release.config @@ -1,31 +1,31 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/Web.config b/tests/ServiceStack.RazorHostTests/Web.config index 2a0e986ca05..fe51acf0b53 100644 --- a/tests/ServiceStack.RazorHostTests/Web.config +++ b/tests/ServiceStack.RazorHostTests/Web.config @@ -1,68 +1,75 @@ - - - - - - - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 a0fea01d450..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 00b9d41b080..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 c9481bc5e8f..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 24f974c89fb..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 fa23dbf3f04..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 f273d1e03a1..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 89% rename from tests/ServiceStack.Messaging.Tests/MessageSerializationTests.cs rename to tests/ServiceStack.Server.Tests/Messaging/MessageSerializationTests.cs index d379862d143..a2077f001e4 100644 --- a/tests/ServiceStack.Messaging.Tests/MessageSerializationTests.cs +++ b/tests/ServiceStack.Server.Tests/Messaging/MessageSerializationTests.cs @@ -1,94 +1,95 @@ -using System; -using NUnit.Framework; -using ServiceStack.DesignPatterns.Model; -using ServiceStack.Messaging.Tests.Services; -using ServiceStack.Text; - -namespace ServiceStack.Messaging.Tests -{ - [TestFixture] - public class MessageSerializationTests - { - [Test] - public void Can_Serialize_and_basic_Message() - { - var message = new Message(new Greet { Name = "Test" }); - Serialize(message); - } - - [Test] - public void Serializing_basic_IMessage_returns_null() - { - var message = new Message(new Greet { Name = "Test" }); - var messageString = TypeSerializer.SerializeToString(message); - Assert.That(messageString, Is.Not.Null); - - var result = TypeSerializer.DeserializeFromString>(messageString); - Assert.That(result, Is.Null); - } - - [Test] - public void Can_Serialize_IMessage_and_Deserialize_into_Message() - { - var message = new Message(new Greet { Name = "Test" }); - var messageString = TypeSerializer.SerializeToString((IMessage)message); - Assert.That(messageString, Is.Not.Null); - - var fromMessageString = TypeSerializer.DeserializeFromString>( - messageString); - - Assert.That(fromMessageString, Is.Not.Null); - Assert.That(fromMessageString.Id, Is.EqualTo(message.Id)); - } - - [Test] - 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() - }; - Serialize(message); - } - - - private static void Serialize(T message) - where T : IHasId - { - var messageString = TypeSerializer.SerializeToString(message); - Assert.That(messageString, Is.Not.Null); - - var fromMessageString = TypeSerializer.DeserializeFromString(messageString); - - Assert.That(fromMessageString, Is.Not.Null); - Assert.That(fromMessageString.Id, Is.EqualTo(message.Id)); - } - - [Test] - public void Does_serialize_to_correct_MQ_name() - { - var message = new Message(new Greet { Name = "Test" }) {}; - var message2 = new Message { Body = new Greet { Name = "Test" }, }; - - const string expected = "mq:Greet.inq"; - - Assert.That(QueueNames.In, Is.EqualTo(expected)); - Assert.That(message.ToInQueueName(), Is.EqualTo(expected)); - Assert.That(((IMessage)message).ToInQueueName(), Is.EqualTo(expected)); - - Assert.That(message2.ToInQueueName(), Is.EqualTo(expected)); - Assert.That(((IMessage)message2).ToInQueueName(), Is.EqualTo(expected)); - Assert.That(((IMessage)(object)message2).ToInQueueName(), Is.EqualTo(expected)); - } - - [Test] - public void Cast_Tests() - { - var message = new Message(new Greet { Name = "Test" }) { }; - - Assert.That(message is IMessage, Is.True); - Assert.That(typeof(IMessage).IsAssignableFrom(message.GetType()), Is.True); - Assert.That(message.GetType().IsAssignableFrom(typeof(IMessage)), Is.False); - } - } +using System; +using System.Reflection; +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Model; +using ServiceStack.Server.Tests.Services; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + [TestFixture] + public class MessageSerializationTests + { + [Test] + public void Can_Serialize_and_basic_Message() + { + var message = new Message(new Greet { Name = "Test" }); + Serialize(message); + } + + [Test] + public void Serializing_basic_IMessage_returns_null() + { + var message = new Message(new Greet { Name = "Test" }); + var messageString = TypeSerializer.SerializeToString(message); + Assert.That(messageString, Is.Not.Null); + + var result = TypeSerializer.DeserializeFromString>(messageString); + Assert.That(result, Is.Null); + } + + [Test] + public void Can_Serialize_IMessage_and_Deserialize_into_Message() + { + var message = new Message(new Greet { Name = "Test" }); + var messageString = TypeSerializer.SerializeToString((IMessage)message); + Assert.That(messageString, Is.Not.Null); + + var fromMessageString = TypeSerializer.DeserializeFromString>( + messageString); + + Assert.That(fromMessageString, Is.Not.Null); + Assert.That(fromMessageString.Id, Is.EqualTo(message.Id)); + } + + [Test] + public void Can_Serialize_and_Message_with_Error() + { + var message = new Message(new Greet { Name = "Test" }) { + Error = new ArgumentNullException("Test").ToResponseStatus() + }; + Serialize(message); + } + + + private static void Serialize(T message) + where T : IHasId + { + var messageString = TypeSerializer.SerializeToString(message); + Assert.That(messageString, Is.Not.Null); + + var fromMessageString = TypeSerializer.DeserializeFromString(messageString); + + Assert.That(fromMessageString, Is.Not.Null); + Assert.That(fromMessageString.Id, Is.EqualTo(message.Id)); + } + + [Test] + public void Does_serialize_to_correct_MQ_name() + { + var message = new Message(new Greet { Name = "Test" }) {}; + var message2 = new Message { Body = new Greet { Name = "Test" }, }; + + const string expected = "mq:Greet.inq"; + + Assert.That(QueueNames.In, Is.EqualTo(expected)); + Assert.That(message.ToInQueueName(), Is.EqualTo(expected)); + Assert.That(((IMessage)message).ToInQueueName(), Is.EqualTo(expected)); + + Assert.That(message2.ToInQueueName(), Is.EqualTo(expected)); + Assert.That(((IMessage)message2).ToInQueueName(), Is.EqualTo(expected)); + Assert.That(((IMessage)(object)message2).ToInQueueName(), Is.EqualTo(expected)); + } + + [Test] + public void Cast_Tests() + { + var message = new Message(new Greet { Name = "Test" }) { }; + + Assert.That(message is IMessage, Is.True); + Assert.That(typeof(IMessage).IsAssignableFrom(message.GetType()), Is.True); + Assert.That(message.GetType().IsAssignableFrom(typeof(IMessage)), Is.False); + } + } } \ No newline at end of file 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 02213148d7c..39824fe2bf2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/App.config +++ b/tests/ServiceStack.ServiceHost.Tests/App.config @@ -1,27 +1,47 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs b/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs index 72642b8708c..1ace56648ec 100644 --- a/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs +++ b/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs @@ -1,20 +1,20 @@ -using System; - -namespace ServiceStack.ServiceHost.Tests.AppData -{ - public class FormatHelpers - { - public static FormatHelpers Instance = new FormatHelpers(); - - 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); - } - } +using System; + +namespace ServiceStack.ServiceHost.Tests.AppData +{ + public class FormatHelpers + { + public static FormatHelpers Instance = new FormatHelpers(); + + 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); + } + } } \ 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 97ef4a6d1fb..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; } - } +using System; +using System.Collections.Generic; + +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; } + } } \ 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 3f172d3763b..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); - - 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); - } - } +using System.Collections.Generic; +using System.Linq; + +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); + + 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 new file mode 100644 index 00000000000..c393af07787 --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/BasicAppHostTests.cs @@ -0,0 +1,16 @@ +using NUnit.Framework; +using ServiceStack.Testing; + +namespace ServiceStack.ServiceHost.Tests +{ + [TestFixture] + public class BasicAppHostTests + { + [Test] + public void Can_dispose_without_init() + { + BasicAppHost appHost = new BasicAppHost(); + appHost.Dispose(); + } + } +} 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 f2c4524b55f..c79a62a5663 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionExampleTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionExampleTests.cs @@ -1,244 +1,243 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using NUnit.Framework; - -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 = -@"# Razor Example - -### Hello @name, the year is @DateTime.Now.Year - -Checkout [this product](/Product/Details/@productId)"; - - var expectedHtml = -@"

      Razor Example

      - -

      Hello Demis, the year is 2012

      - -

      Checkout this product

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, new Dictionary { - {"name", "Demis"}, {"productId", 10} }); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Simple_loop() - { - var template = @" -@foreach (var p in products) { - - @p.Name: (@p.Price) -} -"; - - var expectedHtml = -@"
        -
      • Pen: (1.99)
      • -
      • Glass: (9.99)
      • -
      • Book: (14.99)
      • -
      • DVD: (11.99)
      • -
      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Simple_loop_with_parens_free_syntax() - { - var template = @" -@foreach p in products { - - @p.Name: (@p.Price) -} -"; - - var expectedHtml = -@"
        -
      • Pen: (1.99)
      • -
      • Glass: (9.99)
      • -
      • Book: (14.99)
      • -
      • DVD: (11.99)
      • -
      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void If_Statment() - { - var template = @" -@if (products.Count == 0) { -Sorry - no products in this category -} else { -We have products for you! -} -"; - - var expectedHtml = -@"

      We have products for you!

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

      We have products for you!

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [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

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Integrating_content_and_code() - { - var template = -@"Send mail to demis.bellot@gmail.com telling him the time: @DateTime.Now. -"; - - 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); - - Console.WriteLine(html); - Assert.That(html, Is.StringMatching(expectedHtml.Substring(0, expectedHtml.Length - 25))); - } - - - [Test] - public void Identifying_nested_content() - { - var template = -@" -@if (DateTime.Now.Year == 2012) { - -If the year is 2012 then print this -multi-line text block and -the date: @DateTime.Now -} -"; - - var expectedHtml = -@"

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

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

      Some Content <span>html</span>

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, new Dictionary { - {"stringContainingHtml", "html"} - }); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - } +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using NUnit.Framework; +using ServiceStack.Text; + +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; + + [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 = +@"

      Razor Example

      +

      Hello Demis, the year is 2022

      +

      Checkout this product

      +".NormalizeNewLines(); + + var html = RenderToHtml(template, new Dictionary { + {"name", "Demis"}, {"productId", 10} }); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Simple_loop() + { + var template = @" +@foreach (var p in products) { + - @p.Name: (@p.Price) +} +"; + + var expectedHtml = +@"
        +
      • Pen: (1.99)
      • +
      • Glass: (9.99)
      • +
      • Book: (14.99)
      • +
      • DVD: (11.99)
      • +
      +".NormalizeNewLines(); + + var html = RenderToHtml(template, productArgs); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Simple_loop_with_parens_free_syntax() + { + var template = @" +@foreach p in products { + - @p.Name: (@p.Price) +} +"; + + var expectedHtml = +@"
        +
      • Pen: (1.99)
      • +
      • Glass: (9.99)
      • +
      • Book: (14.99)
      • +
      • DVD: (11.99)
      • +
      +".NormalizeNewLines(); + + var html = RenderToHtml(template, productArgs); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void If_Statment() + { + var template = @" +@if (products.Count == 0) { +Sorry - no products in this category +} else { +We have products for you! +} +"; + + var expectedHtml = +@"

      We have products for you!

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

      We have products for you!

      +".NormalizeNewLines(); + + var html = RenderToHtml(template, productArgs); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + [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

      +".NormalizeNewLines(); + + var html = RenderToHtml(template, productArgs); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Integrating_content_and_code() + { + var template = +@"Send mail to demis.bellot@gmail.com telling him the time: @DateTime.Now. +"; + + 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); + + Console.WriteLine(html); + Assert.That(html, Does.Match(expectedHtml.Substring(0, expectedHtml.Length - 25))); + } + + + [Test] + public void Identifying_nested_content() + { + var template = +@" +@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 2022 then print this +multi-line text block and +the date: 02/06/2014 06:42:45

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

      Some Content <span>html</span>

      +".NormalizeNewLines(); + + var html = RenderToHtml(template, new Dictionary { + {"stringContainingHtml", "html"} + }); + + 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 c96caedbc01..602acbff65c 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionLayoutTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionLayoutTests.cs @@ -1,361 +1,345 @@ -using System; -using System.Collections.Generic; -using System.Text; -using NUnit.Framework; -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; - -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; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - EndpointHost.VirtualPathProvider = pathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()); - markdownFormat = new MarkdownFormat { - VirtualPathProvider = pathProvider, - }; - } - - [Test] - public void Simple_Layout_Example() - { - var websiteTemplate = -@" - - - Simple Site - - - -
      - Home - About -
      - -
      - -
      - - -".NormalizeNewLines(); - - var pageTemplate = -@"@Layout websiteTemplate - -# About this Site - -This is some content that will make up the ""about"" -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: @DateTime.Now.Year -"; - - var expectedHtml = @" - - - Simple Site - - - -
      - Home - About -
      - -
      -
        -
      • About Item 1
      • -
      • About Item 2
      • -
      - -
      - -
      - -

      About this Site

      - -

      This is some content that will make up the ""about"" -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: 2012

      - - - -
      - -
      -

      This is my custom footer for Home

      - -
      - - -".NormalizeNewLines(); - - - markdownFormat.AddFileAndPage( - new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); - - markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); - - var html = markdownFormat.RenderDynamicPageHtml(PageName); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - - [Test] - public void Layout_MasterPage_Scenarios_Adding_Sections() - { - var websiteTemplate = -@" - - - Simple Site - - - -
      - Home - About -
      - -
      - -
      - -
      - -
      - -
      - -
      - - -".NormalizeNewLines(); - - var pageTemplate = -@"@Layout websiteTemplate - -# About this Site - -This is some content that will make up the ""about"" -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: @DateTime.Now.Year - -@section Menu { - - About Item 1 - - About Item 2 -} - -@section Footer { -This is my custom footer for Home -} -"; - - var expectedHtml = @" - - - Simple Site - - - -
      - Home - About -
      - -
      -
        -
      • About Item 1
      • -
      • About Item 2
      • -
      - -
      - -
      - -

      About this Site

      - -

      This is some content that will make up the ""about"" -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: 2012

      - - - -
      - -
      -

      This is my custom footer for Home

      - -
      - - -".NormalizeNewLines(); - - - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); - - markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); - - var html = markdownFormat.RenderDynamicPageHtml(PageName); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Encapsulation_and_reuse_with_HTML_helpers() - { - var pageTemplate = -@"@model ServiceStack.ServiceHost.Tests.Formats.Product -
      - Edit Product - -
      - @Html.LabelFor(m => m.ProductID) -
      -
      - @Html.TextBoxFor(m => m.ProductID) -
      -
      "; - - var expectedHtml = @" -
      - Edit Product - -
      -
      -
      -
      -
      -".NormalizeNewLines(); - - var product = new Product {ProductID = 10}; - var html = RenderToHtml(pageTemplate, product); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Using_External_HTML_Helpers() - { - var pageTemplate = -@"@model System.Collections.Generic.List -@helper Prod: ServiceStack.ServiceHost.Tests.Formats.ExternalProductHelper - -
      - All Products - @Prod.ProductTable(Model) -
      "; - - var expectedHtml = @" -
      - All Products - - - - - -
      IdNamePrice
      0Pen1.99
      0Glass9.99
      0Book14.99
      0DVD11.99
      -
      -".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); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Using_Custom_base_class() - { - var pageTemplate = -@"@inherits ServiceStack.ServiceHost.Tests.Formats.CustomBaseClass - -
      - All Products - @Field(""Name"", Model.Name) -
      "; - - var expectedHtml = @" -
      - All Products - - -
      -".NormalizeNewLines(); - - var html = RenderToHtml(pageTemplate, new Product("Pen", 1.99m)); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - } +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.Html; +using ServiceStack.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 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 = +@" + + + Simple Site + + + +
      + Home + About +
      + +
      + +
      + +".NormalizeNewLines(); + + var pageTemplate = +@"@Layout websiteTemplate + +# About this Site + +This is some content that will make up the ""about"" +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: @DateTime.Now.Year +".NormalizeNewLines(); + + var expectedHtml = @" + + + Simple Site + + + +
      + Home + About +
      + +
      +

      About this Site

      +

      This is some content that will make up the "about" +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: 2022

      + +
      + +".NormalizeNewLines(); + + + markdownFormat.AddFileAndPage( + new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); + + markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); + + var html = markdownFormat.RenderDynamicPageHtml(PageName); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + + [Test] + public void Layout_MasterPage_Scenarios_Adding_Sections() + { + var websiteTemplate = +@" + + + Simple Site + + + +
      + Home + About +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +".NormalizeNewLines(); + + var pageTemplate = +@"@Layout websiteTemplate + +# About this Site + +This is some content that will make up the ""about"" +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: @DateTime.Now.Year + +@section Menu { + - About Item 1 + - About Item 2 +} + +@section Footer { +This is my custom footer for Home +} +".NormalizeNewLines(); + + var expectedHtml = @" + + + Simple Site + + + +
      + Home + About +
      + +
      +
        +
      • About Item 1
      • +
      • About Item 2
      • +
      + +
      + +
      +

      About this Site

      +

      This is some content that will make up the "about" +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: 2022

      + +
      + +
      +

      This is my custom footer for Home

      + +
      + + +".NormalizeNewLines(); + + + markdownFormat.AddPage( + new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); + + markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); + + var html = markdownFormat.RenderDynamicPageHtml(PageName); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Encapsulation_and_reuse_with_HTML_helpers() + { + var pageTemplate = +@"@model ServiceStack.ServiceHost.Tests.Formats.Product +
      + Edit Product +
      + @Html.LabelFor(m => m.ProductID) +
      +
      + @Html.TextBoxFor(m => m.ProductID) +
      +
      ".NormalizeNewLines(); + + var expectedHtml = +@"
      + Edit Product +
      +
      +
      +
      +
      ".NormalizeNewLines(); + + var product = new Product { ProductID = 10 }; + var html = RenderToHtml(pageTemplate, product); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Using_External_HTML_Helpers() + { + var pageTemplate = +@"@model System.Collections.Generic.List +@helper Prod: ServiceStack.ServiceHost.Tests.Formats.ExternalProductHelper + +
      + All Products + @Prod.ProductTable(Model) +
      ".NormalizeNewLines(); + + var expectedHtml = +@"
      + All Products + + + + + +
      IdNamePrice
      0Pen1.99
      0Glass9.99
      0Book14.99
      0DVD11.99
      +
      ".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); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Using_Custom_base_class() + { + var pageTemplate = +@"@inherits ServiceStack.ServiceHost.Tests.Formats.CustomBaseClass + +
      + All Products + @Field(""Name"", Model.Name) +
      ".NormalizeNewLines(); + + var expectedHtml = +@"
      + All Products + + +
      ".NormalizeNewLines(); + + var html = RenderToHtml(pageTemplate, new Product("Pen", 1.99m)); + + 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 d0ce9d6521e..34e533d8080 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatExtensions.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatExtensions.cs @@ -1,23 +1,23 @@ -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; - -namespace ServiceStack.ServiceHost.Tests.Formats -{ - public static class MarkdownFormatExtensions - { - public static void AddFileAndPage(this MarkdownFormat markdown, MarkdownPage markdownPage) - { - var pathProvider = (InMemoryVirtualPathProvider)markdown.VirtualPathProvider; - pathProvider.AddFile(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); - markdown.AddTemplate(filePath, contents); - } - } +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.Support.Markdown; + +namespace ServiceStack.ServiceHost.Tests.Formats +{ + public static class MarkdownFormatExtensions + { + public static void AddFileAndPage(this MarkdownFormat markdown, MarkdownPage markdownPage) + { + 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 = (MemoryVirtualFiles)markdown.VirtualPathProvider; + pathProvider.WriteFile(filePath, contents); + markdown.AddTemplate(filePath, contents); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs index 812935f74f7..5356d1cbcc2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs @@ -1,115 +1,114 @@ -using System; -using System.Collections.Generic; -using System.IO; -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.ServiceInterface.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()), - }; - } - - [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)); - - var pageNames = new List(); - markdownFormat.ViewPages.ForEach((k, v) => pageNames.Add(k)); - - 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"); - - Assert.That(html, Is.Not.Null); - Assert.That(html, Is.StringStarting("

      Static Markdown template

      ")); - } - - [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("")); - } - - [Test] - public void Can_Render_DynamicPage() - { - var person = new Person { FirstName = "Demis", LastName = "Bellot" }; - markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); - - 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); - - expectedHtml = tplContent.Replace("", expectedHtml); - - "Template: {0}".Fmt(html).Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.Testing; +using ServiceStack.Text; + +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", + }; + + + [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()); + + 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)); + + 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"); + + 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"); + + html.Print(); + + 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()); + + 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); + + expectedHtml = tplContent.Replace("", expectedHtml); + + "Template: {0}".Fmt(html).Print(); + 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 4c4b0068554..2da9dcc4fda 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownTestBase.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownTestBase.cs @@ -1,67 +1,78 @@ -using System.Collections.Generic; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; - -namespace ServiceStack.ServiceHost.Tests.Formats -{ - 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()) - }; - - markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate) { - Template = "websiteTemplate", - }); - - return markdownFormat; - } - - public MarkdownFormat Create(string pageTemplate) - { - var markdownFormat = new MarkdownFormat(); - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate)); - - 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, 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 static class MarkdownTestExtensions - { - public static string NormalizeNewLines(this string text) - { - return text.Replace("\r\n", "\n"); - } - } +using System.Collections.Generic; +using System.Linq; +using System.Text; +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 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) + { + Template = "websiteTemplate", + }); + + return markdownFormat; + } + + public MarkdownFormat Create(string pageTemplate) + { + var markdownFormat = new MarkdownFormat(); + markdownFormat.AddPage( + new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate)); + + 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, 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 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(); + text.Replace("\r\n", "\n").Split('\n').ToList().ConvertAll(x => x.Trim()).ForEach(x => sb.Append(x)); + return sb.ToString(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/MockClass.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/MockClass.cs index c63fae7c591..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.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; - - 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)); - } - } -} +using System; +using System.IO; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Html; + +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; + + 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)); + } + } +} diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateExtentionTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateExtentionTests.cs index cde813170ac..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; - -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(); - - Assert.That(result, Is.EqualTo("this[is]atest")); - } - } +using NUnit.Framework; +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(); + + 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 0675cf491ca..da63ba76837 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateTests.cs @@ -1,996 +1,959 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.Html; -using ServiceStack.Markdown; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; - -namespace ServiceStack.ServiceHost.Tests.Formats -{ - [TestFixture] - public class TemplateTests - { - string staticTemplatePath; - string staticTemplateContent; - string dynamicPagePath; - string dynamicPageContent; - string dynamicListPagePath; - string dynamicListPageContent; - - private MarkdownFormat markdownFormat; - Dictionary templateArgs; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - staticTemplatePath = "~/Views/Shared/_Layout.shtml".MapProjectPath(); - staticTemplateContent = File.ReadAllText(staticTemplatePath); - - dynamicPagePath = "~/Views/Template/DynamicTpl.md".MapProjectPath(); - dynamicPageContent = File.ReadAllText(dynamicPagePath); - - dynamicListPagePath = "~/Views/Template/DynamicListTpl.md".MapProjectPath(); - dynamicListPageContent = File.ReadAllText(dynamicListPagePath); - } - - [SetUp] - public void OnBeforeEachTest() - { - markdownFormat = new MarkdownFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()) - }; - templateArgs = new Dictionary { { MarkdownPage.ModelName, person } }; - } - - [Test] - public void Can_Render_MarkdownTemplate() - { - var template = new MarkdownTemplate(staticTemplatePath, "default", staticTemplateContent); - template.Prepare(); - - Assert.That(template.TextBlocks.Length, Is.EqualTo(2)); - - const string mockResponse = "[Replaced with Template]"; - var expectedHtml = staticTemplateContent.ReplaceFirst(MarkdownFormat.TemplatePlaceHolder, mockResponse); - - var mockArgs = new Dictionary { { MarkdownTemplate.BodyPlaceHolder, mockResponse } }; - var templateOutput = template.RenderToString(mockArgs); - - Console.WriteLine("Template Output: " + templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - public class Person - { - public string FirstName { get; set; } - public string LastName { get; set; } - public List Links { get; set; } - } - - public class Link - { - public Link() - { - this.Labels = new List(); - } - public string Name { get; set; } - public string Href { get; set; } - public List Labels { get; set; } - } - - 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"} }, - }, - }; - - - [Test] - public void Can_Render_MarkdownPage() - { - var dynamicPage = new MarkdownPage(markdownFormat, dynamicPageContent, "DynamicTpl", dynamicPageContent); - dynamicPage.Compile(); - - Assert.That(dynamicPage.HtmlBlocks.Length, Is.EqualTo(9)); - - var expectedHtml = markdownFormat.Transform(dynamicPageContent) - .Replace("@Model.FirstName", person.FirstName) - .Replace("@Model.LastName", person.LastName); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine("Template Output: " + templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_MarkdownPage_with_foreach() - { - var dynamicPage = new MarkdownPage(markdownFormat, - dynamicListPagePath, "DynamicListTpl", dynamicListPageContent); - dynamicPage.Compile(); - - Assert.That(dynamicPage.HtmlBlocks.Length, Is.EqualTo(11)); - - var expectedMarkdown = dynamicListPageContent - .Replace("@Model.FirstName", person.FirstName) - .Replace("@Model.LastName", person.LastName); - - var foreachLinks = " - ServiceStack - http://www.servicestack.net\r\n" - + " - AjaxStack - http://www.ajaxstack.com\r\n"; - - expectedMarkdown = expectedMarkdown.ReplaceForeach(foreachLinks); - - var expectedHtml = markdownFormat.Transform(expectedMarkdown); - - Console.WriteLine("ExpectedHtml: " + expectedHtml); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine("Template Output: " + templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_MarkdownPage_with_IF_statement() - { - var template = @"# Dynamic If Markdown Template - -Hello @Model.FirstName, - -@if (Model.FirstName == ""Bellot"") { - * @Model.FirstName -} -@if (Model.LastName == ""Bellot"") { - * @Model.LastName -} - -### heading 3"; - - var expected = @"# Dynamic If Markdown Template - -Hello Demis, - - * Bellot - -### heading 3"; - - var expectedHtml = markdownFormat.Transform(expected); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_Markdown_with_Nested_Statements() - { - var template = @"# @Model.FirstName Dynamic Nested Markdown Template - -# heading 1 - -@foreach (var link in Model.Links) { - @if (link.Name == ""AjaxStack"") { - - @link.Name - @link.Href - } -} - -@if (Model.Links.Count == 2) { -## Haz 2 links - - @foreach (var link in Model.Links) { - - @link.Name - @link.Href - @foreach (var label in link.Labels) { - - @label - } - } -} - -### heading 3"; - - var expected = @"# Demis Dynamic Nested Markdown Template - -# heading 1 - - - AjaxStack - http://www.ajaxstack.com - -## Haz 2 links - - - ServiceStack - http://www.servicestack.net - - REST - - JSON - - XML - - AjaxStack - http://www.ajaxstack.com - - HTML5 - - AJAX - - SPA - -### heading 3"; - - var expectedHtml = markdownFormat.Transform(expected); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicNestedTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - public class CustomMarkdownViewBase : MarkdownViewBase - { - public MvcHtmlString Table(Person model) - { - return new CustomMarkdownViewBase().Table(model); - } - } - - public class CustomMarkdownViewBase : MarkdownViewBase - { - public MvcHtmlString Table(Person model) - { - var sb = new StringBuilder(); - - sb.AppendFormat("", model.FirstName); - sb.AppendLine(""); - sb.AppendLine(""); - foreach (var link in model.Links) - { - sb.AppendFormat("", link.Name, link.Href); - } - sb.AppendLine(""); - sb.AppendLine("
      {0}'s Links
      NameLink
      {0}{1}
      "); - - return MvcHtmlString.Create(sb.ToString()); - } - - private static string[] MenuItems = new[] { "About Us", "Blog", "Links", "Contact" }; - - public void Menu(string selectedId) - { - var sb = new StringBuilder(); - sb.Append("
        \n"); - foreach (var menuItem in MenuItems) - { - var cls = menuItem == selectedId ? " class='selected'" : ""; - sb.AppendFormat("
      • {0}
      • \n", menuItem, cls); - } - sb.Append("
      \n"); - ScopeArgs.Add("Menu", MvcHtmlString.Create(sb.ToString())); - } - } - - public class CustomMarkdownHelper - { - public static CustomMarkdownHelper Instance = new CustomMarkdownHelper(); - - public MvcHtmlString InlineBlock(string content, string id) - { - return MvcHtmlString.Create( - "
      " + content + "
      "); - } - } - - [Test] - public void Can_Render_Markdown_with_StaticMethods() - { - var headerTemplate = @"## Header Links! - - [Google](http://google.com) - - [Bing](http://bing.com)"; - - var template = @"## Welcome to Razor! +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.Html; +using ServiceStack.Markdown; +using ServiceStack.Support.Markdown; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.IO; + +namespace ServiceStack.ServiceHost.Tests.Formats +{ + [TestFixture] + public class TemplateTests + { + string staticTemplatePath; + string staticTemplateContent; + string dynamicPagePath; + string dynamicPageContent; + string dynamicListPagePath; + string dynamicListPageContent; + + private MarkdownFormat markdownFormat; + Dictionary templateArgs; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + staticTemplatePath = "~/Views/Shared/_Layout.shtml".MapProjectPath(); + staticTemplateContent = File.ReadAllText(staticTemplatePath); + + dynamicPagePath = "~/Views/Template/DynamicTpl.md".MapProjectPath(); + dynamicPageContent = File.ReadAllText(dynamicPagePath); + + dynamicListPagePath = "~/Views/Template/DynamicListTpl.md".MapProjectPath(); + dynamicListPageContent = File.ReadAllText(dynamicListPagePath); + } + + [SetUp] + public void OnBeforeEachTest() + { + markdownFormat = new MarkdownFormat + { + VirtualPathProvider = new MemoryVirtualFiles() + }; + templateArgs = new Dictionary { { MarkdownPage.ModelName, person } }; + } + + [Test] + public void Can_Render_MarkdownTemplate() + { + var template = new MarkdownTemplate(staticTemplatePath, "default", staticTemplateContent); + template.Prepare(); + + Assert.That(template.TextBlocks.Length, Is.EqualTo(2)); + + const string mockResponse = "[Replaced with Template]"; + var expectedHtml = staticTemplateContent.ReplaceFirst(MarkdownFormat.TemplatePlaceHolder, mockResponse); + + var mockArgs = new Dictionary { { MarkdownTemplate.BodyPlaceHolder, mockResponse } }; + var templateOutput = template.RenderToString(mockArgs); + + Console.WriteLine("Template Output: " + templateOutput); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + public class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + public List Links { get; set; } + } + + public class Link + { + public Link() + { + this.Labels = new List(); + } + public string Name { get; set; } + public string Href { get; set; } + public List Labels { get; set; } + } + + 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"} }, + }, + }; + + + [Test] + public void Can_Render_MarkdownPage() + { + var dynamicPage = new MarkdownPage(markdownFormat, dynamicPageContent, "DynamicTpl", dynamicPageContent); + dynamicPage.Compile(); + + Assert.That(dynamicPage.HtmlBlocks.Length, Is.EqualTo(9)); + + var expectedHtml = markdownFormat.Transform(dynamicPageContent) + .Replace("@Model.FirstName", person.FirstName) + .Replace("@Model.LastName", person.LastName); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + + Console.WriteLine("Template Output: " + templateOutput); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_MarkdownPage_with_foreach() + { + var dynamicPage = new MarkdownPage(markdownFormat, + dynamicListPagePath, "DynamicListTpl", dynamicListPageContent); + dynamicPage.Compile(); + + Assert.That(dynamicPage.HtmlBlocks.Length, Is.EqualTo(11)); + + var expectedMarkdown = dynamicListPageContent + .Replace("@Model.FirstName", person.FirstName) + .Replace("@Model.LastName", person.LastName); + + var foreachLinks = " - ServiceStack - http://www.servicestack.net\r\n" + + " - AjaxStack - http://www.ajaxstack.com\r\n"; + + expectedMarkdown = expectedMarkdown.ReplaceForeach(foreachLinks); + + var expectedHtml = markdownFormat.Transform(expectedMarkdown); + + Console.WriteLine("ExpectedHtml: " + expectedHtml); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + + Console.WriteLine("Template Output: " + templateOutput); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_MarkdownPage_with_IF_statement() + { + var template = @"# Dynamic If Markdown Template + +Hello @Model.FirstName, + +@if (Model.FirstName == ""Bellot"") { + * @Model.FirstName +} +@if (Model.LastName == ""Bellot"") { + * @Model.LastName +} + +### heading 3"; + + var expected = @"# Dynamic If Markdown Template + +Hello Demis, + + * Bellot + +### heading 3"; + + var expectedHtml = markdownFormat.Transform(expected); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_Markdown_with_Nested_Statements() + { + var template = @"# @Model.FirstName Dynamic Nested Markdown Template + +# heading 1 + +@foreach (var link in Model.Links) { + @if (link.Name == ""AjaxStack"") { + - @link.Name - @link.Href + } +} + +@if (Model.Links.Count == 2) { +## Haz 2 links + + @foreach (var link in Model.Links) { + - @link.Name - @link.Href + @foreach (var label in link.Labels) { + - @label + } + } +} + +### heading 3".NormalizeNewLines(); + + var expected = @"# Demis Dynamic Nested Markdown Template + +# heading 1 + + - AjaxStack - http://www.ajaxstack.com + +## Haz 2 links + + - ServiceStack - http://www.servicestack.net + - REST + - JSON + - XML + - AjaxStack - http://www.ajaxstack.com + - HTML5 + - AJAX + - SPA + +### heading 3".NormalizeNewLines(); + + var expectedHtml = markdownFormat.Transform(expected); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicNestedTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + public class CustomMarkdownViewBase : MarkdownViewBase + { + public MvcHtmlString Table(Person model) + { + return new CustomMarkdownViewBase().Table(model); + } + } + + public class CustomMarkdownViewBase : MarkdownViewBase + { + public MvcHtmlString Table(Person model) + { + var sb = new StringBuilder(); + + sb.AppendFormat("", model.FirstName); + sb.AppendLine(""); + sb.AppendLine(""); + foreach (var link in model.Links) + { + sb.AppendFormat("", link.Name, link.Href); + } + sb.AppendLine(""); + sb.AppendLine("
      {0}'s Links
      NameLink
      {0}{1}
      "); + + return MvcHtmlString.Create(sb.ToString()); + } + + private static string[] MenuItems = new[] { "About Us", "Blog", "Links", "Contact" }; + + public void Menu(string selectedId) + { + var sb = new StringBuilder(); + sb.Append("
        \n"); + foreach (var menuItem in MenuItems) + { + var cls = menuItem == selectedId ? " class='selected'" : ""; + sb.AppendFormat("
      • {0}
      • \n", menuItem, cls); + } + sb.Append("
      \n"); + ScopeArgs.Add("Menu", MvcHtmlString.Create(sb.ToString())); + } + } + + public class CustomMarkdownHelper + { + public static CustomMarkdownHelper Instance = new CustomMarkdownHelper(); + + public MvcHtmlString InlineBlock(string content, string id) + { + return MvcHtmlString.Create( + "
      " + content + "
      "); + } + } + + [Test] + public void Can_Render_Markdown_with_StaticMethods() + { + var headerTemplate = @"## Header Links! + - [Google](http://google.com) + - [Bing](http://bing.com)"; + + var template = @"## Welcome to Razor! @Html.Partial(""HeaderLinks"", Model) - -Hello @Upper(Model.LastName), @Model.FirstName - -### Breadcrumbs -@Combine("" / "", Model.FirstName, Model.LastName) - -### Menus -@foreach (var link in Model.Links) { - - @link.Name - @link.Href - @foreach (var label in link.Labels) { - - @label - } -} - -### HTML Table -@Table(Model) -"; - - var expectedHtml = @"

      Welcome to Razor!

      - -

      Header Links!

      - - - -

      Hello BELLOT, Demis

      - -

      Breadcrumbs

      - -Demis / Bellot -

      Menus

      - -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
      • -
      - -

      HTML Table

      - - - - -
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      -".Replace("\r\n", "\n"); - - - markdownFormat.MarkdownBaseType = typeof(CustomMarkdownViewBase); - markdownFormat.MarkdownGlobalHelpers = new Dictionary - { - {"Ext", typeof(CustomMarkdownHelper)} - }; - - markdownFormat.RegisterMarkdownPage(new MarkdownPage(markdownFormat, - "/path/to/page", "HeaderLinks", headerTemplate)); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - templateOutput.Print(); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_inherit_from_Generic_view_page_from_model_directive() - { - var template = @"@model ServiceStack.ServiceHost.Tests.Formats.TemplateTests+Person -# Generic View Page - -## Form fields -@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) -"; - - var expectedHtml = @" -

      Generic View Page

      - -

      Form fields

      - - ".Replace("\r\n", "\n"); - - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase<>))); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_inherit_from_CustomViewPage_using_inherits_directive() - { - var template = @"@inherits ServiceStack.ServiceHost.Tests.Formats.TemplateTests+CustomMarkdownViewBase -# Generic View Page - -## Form fields -@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) - -## Person Table -@Table(Model) -"; - - var expectedHtml = @" -

      Generic View Page

      - -

      Form fields

      - - -

      Person Table

      - - - - -
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      -".Replace("\r\n", "\n"); - - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(CustomMarkdownViewBase<>))); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_MarkdownPage_with_external_helper() - { - var template = @"# View Page with Custom Helper - -## External Helper - -@Ext.InlineBlock(Model.FirstName, ""first-name"") -"; - - var expectedHtml = @"

      View Page with Custom Helper

      - -

      External Helper

      - -

      -

      Demis
      ".Replace("\r\n", "\n"); - - - markdownFormat.MarkdownGlobalHelpers.Add("Ext", typeof(CustomMarkdownHelper)); - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_MarkdownPage_with_external_helper_using_helper_directive() - { - var template = @"@helper Ext: ServiceStack.ServiceHost.Tests.Formats.TemplateTests+CustomMarkdownHelper -# View Page with Custom Helper - -## External Helper - -@Ext.InlineBlock(Model.FirstName, ""first-name"") -"; - - var expectedHtml = @" -

      View Page with Custom Helper

      - -

      External Helper

      - -

      -

      Demis
      ".Replace("\r\n", "\n"); - - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_page_to_Markdown_only() - { - var headerTemplate = @"## Header Links! - - [Google](http://google.com) - - [Bing](http://bing.com) -"; - - var template = @"## Welcome to Razor! + +Hello @Upper(Model.LastName), @Model.FirstName + +### Breadcrumbs +@Combine("" / "", Model.FirstName, Model.LastName) + +### Menus +@foreach (var link in Model.Links) { + - @link.Name - @link.Href + @foreach (var label in link.Labels) { + - @label + } +} + +### HTML Table +@Table(Model) +".NormalizeNewLines(); + + var expectedHtml = @"

      Welcome to Razor!

      +

      Header Links!

      + +

      Hello BELLOT, Demis

      +

      Breadcrumbs

      +Demis / Bellot

      Menus

      +
        +
      • +ServiceStack - http://www.servicestack.net +
          +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • +AjaxStack - http://www.ajaxstack.com +
          +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      +

      HTML Table

      + + + +
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      +".NormalizeNewLines(); + + + markdownFormat.MarkdownBaseType = typeof(CustomMarkdownViewBase); + markdownFormat.MarkdownGlobalHelpers = new Dictionary + { + {"Ext", typeof(CustomMarkdownHelper)} + }; + + markdownFormat.RegisterMarkdownPage(new MarkdownPage(markdownFormat, + "/path/to/page", "HeaderLinks", headerTemplate)); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + templateOutput.Print(); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_inherit_from_Generic_view_page_from_model_directive() + { + var template = @"@model ServiceStack.ServiceHost.Tests.Formats.TemplateTests+Person +# Generic View Page + +## Form fields +@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) +"; + + var expectedHtml = @"

      Generic View Page

      +

      Form fields

      + ".NormalizeNewLines(); + + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase<>))); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_inherit_from_CustomViewPage_using_inherits_directive() + { + var template = @"@inherits ServiceStack.ServiceHost.Tests.Formats.TemplateTests+CustomMarkdownViewBase +# Generic View Page + +## Form fields +@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) + +## Person Table +@Table(Model) +"; + + var expectedHtml = @"

      Generic View Page

      +

      Form fields

      +

      Person Table

      + + + +
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      +".NormalizeNewLines(); + + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(CustomMarkdownViewBase<>))); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_MarkdownPage_with_external_helper() + { + var template = @"# View Page with Custom Helper + +## External Helper +![inline-img](path/to/img) +@Ext.InlineBlock(Model.FirstName, ""first-name"") +"; + + var expectedHtml = @"

      View Page with Custom Helper

      +

      External Helper

      +

      +

      Demis
      ".NormalizeNewLines(); + + + markdownFormat.MarkdownGlobalHelpers.Add("Ext", typeof(CustomMarkdownHelper)); + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_MarkdownPage_with_external_helper_using_helper_directive() + { + var template = @"@helper Ext: ServiceStack.ServiceHost.Tests.Formats.TemplateTests+CustomMarkdownHelper +# View Page with Custom Helper + +## External Helper +![inline-img](path/to/img) +@Ext.InlineBlock(Model.FirstName, ""first-name"") +"; + + var expectedHtml = @"

      View Page with Custom Helper

      +

      External Helper

      +

      +

      Demis
      ".NormalizeNewLines(); + + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_page_to_Markdown_only() + { + var headerTemplate = @"## Header Links! + - [Google](http://google.com) + - [Bing](http://bing.com) +"; + + var template = @"## Welcome to Razor! @Html.Partial(""HeaderLinks"", Model) - -Hello @Upper(Model.LastName), @Model.FirstName - -### Breadcrumbs -@Combine("" / "", Model.FirstName, Model.LastName) - - -### Menus -@foreach (var link in Model.Links) { - - @link.Name - @link.Href - @foreach (var label in link.Labels) { - - @label - } -}"; - var expectedHtml = @"## Welcome to Razor! - - ## Header Links! - - [Google](http://google.com) - - [Bing](http://bing.com) - -Hello BELLOT, Demis - -### Breadcrumbs - Demis / Bellot - -### Menus - - ServiceStack - http://www.servicestack.net - - REST - - JSON - - XML - - AjaxStack - http://www.ajaxstack.com - - HTML5 - - AJAX - - SPA -".Replace("\r\n", "\n"); - - markdownFormat.RegisterMarkdownPage(new MarkdownPage(markdownFormat, - "/path/to/page", "HeaderLinks", headerTemplate)); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToMarkdown(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Can_Render_Markdown_with_variable_statements() - { - var template = @"## Welcome to Razor! + +Hello @Upper(Model.LastName), @Model.FirstName + +### Breadcrumbs +@Combine("" / "", Model.FirstName, Model.LastName) + + +### Menus +@foreach (var link in Model.Links) { + - @link.Name - @link.Href + @foreach (var label in link.Labels) { + - @label + } +}".NormalizeNewLines(); + var expectedHtml = @"## Welcome to Razor! + + ## Header Links! + - [Google](http://google.com) + - [Bing](http://bing.com) + +Hello BELLOT, Demis + +### Breadcrumbs + Demis / Bellot + +### Menus + - ServiceStack - http://www.servicestack.net + - REST + - JSON + - XML + - AjaxStack - http://www.ajaxstack.com + - HTML5 + - AJAX + - SPA +".NormalizeNewLines(); + + markdownFormat.RegisterMarkdownPage(new MarkdownPage(markdownFormat, + "/path/to/page", "HeaderLinks", headerTemplate)); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToMarkdown(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Can_Render_Markdown_with_variable_statements() + { + var template = @"## Welcome to Razor! @var lastName = Model.LastName; - -Hello @Upper(lastName), @Model.FirstName - - -### Breadcrumbs -@Combine("" / "", Model.FirstName, lastName) - -@var links = Model.Links - -### Menus -@foreach (var link in links) { - - @link.Name - @link.Href - @var labels = link.Labels - @foreach (var label in labels) { - - @label - } -}"; - var expectedHtml = @"## Welcome to Razor! - - -Hello BELLOT, Demis - - -### Breadcrumbs - Demis / Bellot - -### Menus - - ServiceStack - http://www.servicestack.net - - REST - - JSON - - XML - - AjaxStack - http://www.ajaxstack.com - - HTML5 - - AJAX - - SPA -".Replace("\r\n", "\n"); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToMarkdown(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_MarkdownPage_with_comments() - { - var template = @"# Dynamic If Markdown Template -Hello @Model.FirstName, - -@if (Model.FirstName == ""Bellot"") { - * @Model.FirstName -} -@* -@if (Model.LastName == ""Bellot"") { - * @Model.LastName -} -*@ - -@* -Plain text in a comment -*@ - -### heading 3"; - - var expectedHtml = @"

      Dynamic If Markdown Template

      - -

      Hello Demis,

      - - -

      heading 3

      -".Replace("\r\n", "\n"); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_MarkdownPage_with_unmatching_escaped_braces() - { - var template = @"# Dynamic If Markdown Template -Hello @Model.FirstName, { -- unmatched, leave unescaped outside statement - -{ -- inside matching braces, outside statement -- } - -@if (Model.LastName == ""Bellot"") { - * @Model.LastName - -{{ -- inside matching braces, escape inside statement -- }} - -{{ -- unmatched - -} - -### heading 3"; - - var expectedHtml = @"

      Dynamic If Markdown Template

      - -

      Hello Demis, { -- unmatched, leave unescaped outside statement

      - -

      { -- inside matching braces, outside statement -- }

      - -
        -
      • Bellot
      • -
      - -

      { -- inside matching braces, escape inside statement -- }

      - -

      { -- unmatched

      - -

      heading 3

      -".Replace("\r\n", "\n"); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_capture_Section_statements_and_store_them_in_scopeargs() - { - var template = @"## Welcome to Razor! + +Hello @Upper(lastName), @Model.FirstName + + +### Breadcrumbs +@Combine("" / "", Model.FirstName, lastName) + +@var links = Model.Links + +### Menus +@foreach (var link in links) { + - @link.Name - @link.Href + @var labels = link.Labels + @foreach (var label in labels) { + - @label + } +}".NormalizeNewLines(); + var expectedHtml = @"## Welcome to Razor! + + +Hello BELLOT, Demis + + +### Breadcrumbs + Demis / Bellot + +### Menus + - ServiceStack - http://www.servicestack.net + - REST + - JSON + - XML + - AjaxStack - http://www.ajaxstack.com + - HTML5 + - AJAX + - SPA +".NormalizeNewLines(); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToMarkdown(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_MarkdownPage_with_comments() + { + var template = @"# Dynamic If Markdown Template +Hello @Model.FirstName, + +@if (Model.FirstName == ""Bellot"") { + * @Model.FirstName +} +@* +@if (Model.LastName == ""Bellot"") { + * @Model.LastName +} +*@ + +@* +Plain text in a comment +*@ + +### heading 3"; + + var expectedHtml = @"

      Dynamic If Markdown Template

      +

      Hello Demis,

      +

      heading 3

      +".NormalizeNewLines(); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_MarkdownPage_with_unmatching_escaped_braces() + { + var template = @"# Dynamic If Markdown Template +Hello @Model.FirstName, { -- unmatched, leave unescaped outside statement + +{ -- inside matching braces, outside statement -- } + +@if (Model.LastName == ""Bellot"") { + * @Model.LastName + +{{ -- inside matching braces, escape inside statement -- }} + +{{ -- unmatched + +} + +### heading 3"; + + var expectedHtml = @"

      Dynamic If Markdown Template

      +

      Hello Demis, { -- unmatched, leave unescaped outside statement

      +

      { -- inside matching braces, outside statement -- }

      +
        +
      • Bellot
      • +
      +

      { -- inside matching braces, escape inside statement -- }

      +

      { -- unmatched

      +

      heading 3

      +".NormalizeNewLines(); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicIfTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_capture_Section_statements_and_store_them_in_scopeargs() + { + var template = @"## Welcome to Razor! @var lastName = Model.LastName; -@section Salutations { -Hello @Upper(lastName), @Model.FirstName -} - -@section Breadcrumbs { -### Breadcrumbs -@Combine("" / "", Model.FirstName, lastName) -} - -@var links = Model.Links -@section Menus { -### Menus -@foreach (var link in links) { - - @link.Name - @link.Href - @var labels = link.Labels - @foreach (var label in labels) { - - @label - } -} -} - -## Captured Sections - - - -@Menus - -## Salutations -@Salutations -"; - var expectedHtml = @"

      Welcome to Razor!

      - - - - -

      Captured Sections

      - - - -

      Menus

      - -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
      • -
      -

      - -

      Salutations

      - -

      Hello BELLOT, Demis

      -

      -".Replace("\r\n", "\n"); - - var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); - dynamicPage.Compile(); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); - - Console.WriteLine(templateOutput); - - Assert.That(templateArgs["Salutations"].ToString(), Is.EqualTo("

      Hello BELLOT, Demis

      \n")); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_Template_with_section_and_variable_placeholders() - { - var template = @"## Welcome to Razor! +@section Salutations { +Hello @Upper(lastName), @Model.FirstName +} + +@section Breadcrumbs { +### Breadcrumbs +@Combine("" / "", Model.FirstName, lastName) +} + +@var links = Model.Links +@section Menus { +### Menus +@foreach (var link in links) { + - @link.Name - @link.Href + @var labels = link.Labels + @foreach (var label in labels) { + - @label + } +} +} + +## Captured Sections + + + +@Menus + +## Salutations +@Salutations".NormalizeNewLines(); + + var expectedHtml = @"

      Welcome to Razor!

      +

      Captured Sections

      + +

      Menus

      +
        +
      • +ServiceStack - http://www.servicestack.net +
          +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • +AjaxStack - http://www.ajaxstack.com +
          +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      +

      +

      Salutations

      +

      Hello BELLOT, Demis

      +

      +".NormalizeNewLines(); + + var dynamicPage = new MarkdownPage(markdownFormat, "/path/to/tpl", "DynamicModelTpl", template); + dynamicPage.Compile(); + + var templateOutput = dynamicPage.RenderToHtml(templateArgs); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Assert.That(dynamicPage.ExecutionContext.BaseType, Is.EqualTo(typeof(MarkdownViewBase))); + + Console.WriteLine(templateOutput); + + Assert.That(templateArgs["Salutations"].ToString(), Is.EqualTo("

      Hello BELLOT, Demis

      \n")); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_Template_with_section_and_variable_placeholders() + { + var template = @"## Welcome to Razor! @var lastName = Model.LastName; - -Hello @Upper(lastName), @Model.FirstName, - -@section Breadcrumbs { -### Breadcrumbs -@Combine("" / "", Model.FirstName, lastName) -} - -@section Menus { -### Menus -@foreach (var link in Model.Links) { - - @link.Name - @link.Href - @var labels = link.Labels - @foreach (var label in labels) { - - @label - } -} -}"; - - var websiteTemplate = @" - - - <!--@lastName--> page - - - -
      - -
      - -

      Website Template

      - -
      - -
      - -
      - - -"; - - var expectedHtml = @" - - - Bellot page - - - -
      -

      Menus

      - -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
      • -
      - -
      - -

      Website Template

      - -

      Welcome to Razor!

      - - -

      Hello BELLOT, Demis,

      - - -
      - -
      -

      Breadcrumbs

      - -

      Demis / Bellot

      - -
      - - -".Replace("\r\n", "\n"); - - markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); - - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, "/path/to/page-tpl", "DynamicModelTpl", template) { - Template = "websiteTemplate" - }); - - var templateOutput = markdownFormat.RenderDynamicPageHtml("DynamicModelTpl", person); - templateOutput = templateOutput.Replace("\r\n", "\n"); - - Console.WriteLine(templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_Static_ContentPage_that_populates_variable_and_displayed_on_website_template() - { - - var websiteTemplate = @" - - - Static page - - -
      - -
      - - - -

      Website Template

      - -
      - - -".NormalizeNewLines(); - - var template = @"# Static Markdown Template -@Menu(""Links"") - -@section Header { -### Static Page Title -} - -### heading 3 -paragraph"; - - var expectedHtml = @" - - - Static page - - -
      -

      Static Page Title

      - -
      - - - -

      Website Template

      - -

      Static Markdown Template

      - - - -

      heading 3

      - -

      paragraph

      -
      - - -".NormalizeNewLines(); - - markdownFormat.MarkdownBaseType = typeof(CustomMarkdownViewBase); - - markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); - - markdownFormat.RegisterMarkdownPage( - new MarkdownPage(markdownFormat, "pagetpl", "StaticTpl", template, MarkdownPageType.ContentPage) { - Template = "websiteTemplate" - }); - - var templateOutput = markdownFormat.RenderStaticPage("pagetpl", true); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - } + +Hello @Upper(lastName), @Model.FirstName, + +@section Breadcrumbs { +### Breadcrumbs +@Combine("" / "", Model.FirstName, lastName) +} + +@section Menus { +### Menus +@foreach (var link in Model.Links) { + - @link.Name - @link.Href + @var labels = link.Labels + @foreach (var label in labels) { + - @label + } +} +}".NormalizeNewLines(); + + var websiteTemplate = @" + + + <!--@lastName--> page + + + +
      + +
      + +

      Website Template

      + +
      + +
      + +
      + + +".NormalizeNewLines(); + + var expectedHtml = @" + + + Bellot page + + + +
      +

      Menus

      +
        +
      • +ServiceStack - http://www.servicestack.net +
          +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • +AjaxStack - http://www.ajaxstack.com +
          +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      + +
      + +

      Website Template

      + +

      Welcome to Razor!

      +

      Hello BELLOT, Demis,

      +
      + +
      +

      Breadcrumbs

      +

      Demis / Bellot

      + +
      + + +".NormalizeNewLines(); + + markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); + + markdownFormat.AddPage( + new MarkdownPage(markdownFormat, "/path/to/page-tpl", "DynamicModelTpl", template) + { + Template = "websiteTemplate" + }); + + var templateOutput = markdownFormat.RenderDynamicPageHtml("DynamicModelTpl", person); + templateOutput = templateOutput.Replace("\r\n", "\n"); + + Console.WriteLine(templateOutput); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_Static_ContentPage_that_populates_variable_and_displayed_on_website_template() + { + + var websiteTemplate = @" + + + Static page + + +
      + +
      + + + +

      Website Template

      + +
      + + +".NormalizeNewLines(); + + var template = @"# Static Markdown Template +@Menu(""Links"") + +@section Header { +### Static Page Title +} + +### heading 3 +paragraph"; + + var expectedHtml = @" + + + Static page + + +
      +

      Static Page Title

      + +
      + + + +

      Website Template

      + +

      Static Markdown Template

      +

      heading 3

      +

      paragraph

      +
      + + +".NormalizeNewLines(); + + markdownFormat.MarkdownBaseType = typeof(CustomMarkdownViewBase); + + markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); + + markdownFormat.RegisterMarkdownPage( + new MarkdownPage(markdownFormat, "pagetpl", "StaticTpl", template, MarkdownPageType.ContentPage) + { + Template = "websiteTemplate" + }); + + var templateOutput = markdownFormat.RenderStaticPage("pagetpl", true); + + Console.WriteLine(templateOutput); + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs index 36bacfb26bb..1f222aa59fb 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs @@ -1,208 +1,224 @@ -using System; -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; - -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); - } - - [Test] - public void Does_replace_foreach_statements_with_expr_placeholders() - { - var content = (string)dynamicListPageContent.Clone(); - - var expected = content.ReplaceForeach("@^1"); ; - - var statements = new List(); - var parsedContent = StatementExprBlock.Extract(content, statements); - - 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")); - } - - [Test] - public void Does_replace_multiple_statements_with_expr_placeholders() - { - const string template = @" -## Statement 1 - -@if (Model.IsValid) { -### This is valid -} - -@foreach (var link in Model.Links) { - - @link.Name - @link.Href -} - -## Statement 2 - -@foreach (var text in Model.Texts) { -### @text.Name -@text.body -} - -@if (!Model.IsValid) { -### This is not valid -} - -# EOF"; - const string expected = @" -## Statement 1 - -@^1 - -@^2 - -## Statement 2 - -@^3 - -@^4 - -# EOF"; - 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\r\n")); - Assert.That(statements[1].Condition, Is.EqualTo("var link in Model.Links")); - Assert.That(statements[1].Statement, Is.EqualTo(" - @link.Name - @link.Href\r\n")); - Assert.That(statements[2].Condition, Is.EqualTo("var text in Model.Texts")); - Assert.That(statements[2].Statement, Is.EqualTo("### @text.Name\r\n@text.body\r\n")); - Assert.That(statements[3].Condition, Is.EqualTo("!Model.IsValid")); - Assert.That(statements[3].Statement, Is.EqualTo("### This is not valid\r\n")); - } - - [Test] - public void Does_parse_parens_free_statements() - { - const string template = @" -## Statement 1 - -@if Model.IsValid { -### This is valid -} - -@foreach var link in Model.Links { - - @link.Name - @link.Href -} - -## Statement 2 - -@foreach text in Model.Texts { -### @text.Name -@text.body -} - -@if !Model.IsValid{ -### This is not valid -} - -# EOF"; - const string expected = @" -## Statement 1 - -@^1 - -@^2 - -## Statement 2 - -@^3 - -@^4 - -# EOF"; - - 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)); - - var stat1 = (IfStatementExprBlock)statements[0]; - Assert.That(stat1.Condition, Is.EqualTo("Model.IsValid")); - Assert.That(stat1.Statement, Is.EqualTo("### This is valid\r\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\r\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\r\n@text.body\r\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\r\n")); - } - - [Test] - public void Does_transform_escaped_html_start_tags() - { - var markdownText = - @"#### Showing Results 1 - 5 - -^
      - -### Markdown > [About Docs](http://path.com/to/about) - -^
      - -Text".NormalizeNewLines(); - - 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 html = textBlock.TransformHtml(markdownText); - - Console.WriteLine(html); - - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - } +using System; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; +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; + + [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(); + + var expected = content.ReplaceForeach("@^1"); ; + + var statements = new List(); + var parsedContent = StatementExprBlock.Extract(content, statements); + + 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")); + } + + [Test] + public void Does_handle_foreach_when_enumerable_is_empty_first_time() + { + var content = (string)dynamicListPageContent.Clone(); + var markdownPage = new MarkdownPage(new MarkdownFormat(), dynamicListPagePath, "", content); + markdownPage.Compile(); + var model = new Person { Links = new List() }; + var scopeArgs = new Dictionary { { "Model", model } }; + markdownPage.RenderToHtml(scopeArgs); // First time the list is empty + + var expected = "A new list item"; + 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 = @" +## Statement 1 + +@if (Model.IsValid) { +### This is valid +} + +@foreach (var link in Model.Links) { + - @link.Name - @link.Href +} + +## Statement 2 + +@foreach (var text in Model.Texts) { +### @text.Name +@text.body +} + +@if (!Model.IsValid) { +### This is not valid +} + +# EOF".NormalizeNewLines(); + + string expected = @" +## Statement 1 + +@^1 + +@^2 + +## Statement 2 + +@^3 + +@^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 = @" +## Statement 1 + +@if Model.IsValid { +### This is valid +} + +@foreach var link in Model.Links { + - @link.Name - @link.Href +} + +## Statement 2 + +@foreach text in Model.Texts { +### @text.Name +@text.body +} + +@if !Model.IsValid{ +### This is not valid +} + +# EOF".NormalizeNewLines(); + + string expected = @" +## Statement 1 + +@^1 + +@^2 + +## Statement 2 + +@^3 + +@^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)); + + 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 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")); + } + + [Test] + public void Does_transform_escaped_html_start_tags() + { + var markdownText = + @"#### Showing Results 1 - 5 + +^
      + +### Markdown > [About Docs](http://path.com/to/about) + +^
      + +Text".NormalizeNewLines(); + + 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 html = textBlock.TransformHtml(markdownText); + + Console.WriteLine(html); + + 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 07b6c4de10a..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); - - var expected = tempalte.Substring(0, startPos) - + replaceWith - + tempalte.Substring(endPos + 1); - - return expected; - } - } +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); + + var expected = tempalte.Substring(0, startPos) + + replaceWith + + tempalte.Substring(endPos + 1); + + 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 5e7d547bdc6..73bb45b5ace 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/UseCaseTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/UseCaseTests.cs @@ -1,230 +1,213 @@ -using System; -using System.Collections.Generic; -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 = -@" - - - Simple Site - - -
      - Home -
      - -
      - -
      - -".NormalizeNewLines(); - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - var jsonPages = File.ReadAllText("~/AppData/Pages.json".MapProjectPath()); - - Pages = JsonSerializer.DeserializeFromString>(jsonPages); - - 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) { - -#### Your search did not match any documents. - -## Suggestions: - - - Make sure all words are spelled correctly. - - Try different keywords. - - Try more general keywords. - - Try fewer keywords. -} - -@if (Model.Results.Count > 0) { -#### Showing Results 1 - @Model.Results.Count -} - -
      -@foreach page in Model.Results { -### @page.Category > [@page.Name](@page.AbsoluteUrl) -@page.Content -} -
      "; - var expectedHtml = @" - - - Simple Site - - -
      - Home -
      - -
      - - -

      Showing Results 1 - 5

      - -
      -

      Markdown > About Docs

      - -

      Markdown > Markdown Features

      - -

      Markdown > Markdown Razor

      - -

      Framework > Home

      - -

      Framework > Overview

      -
      - -
      - -".NormalizeNewLines(); - - var markdownFormat = Create(websiteTemplate, pageTemplate); - - var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); - - Console.WriteLine(html); - - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Can_display_search_results() - { - var pageTemplate = @"@var Title = ""Search results for "" + Model.Query - -@if (Model.Results.Count == 0) { - -#### Your search did not match any documents. - -## Suggestions: - - - Make sure all words are spelled correctly. - - Try different keywords. - - Try more general keywords. - - Try fewer keywords. - -} else { - -#### Showing Results 1 - @Model.Results.Count - -^
      - -@foreach page in Model.Results { - -### @page.Category > [@page.Name](@page.AbsoluteUrl) -@page.Content - -} - -^
      - -}"; - var expectedHtml = @" - - - Simple Site - - -
      - Home -
      - -
      - -

      Showing Results 1 - 5

      - -
      - -

      Markdown > About Docs

      - -

      Markdown > Markdown Features

      - -

      Markdown > Markdown Razor

      - -

      Framework > Home

      - -

      Framework > Overview

      - -
      - -
      - -".NormalizeNewLines(); - - var markdownFormat = Create(websiteTemplate, pageTemplate); - - var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); - - Console.WriteLine(html); - - Assert.That(html, Is.EqualTo(expectedHtml)); - } - } - -} - - +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NUnit.Framework; +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 = +@" + + + Simple Site + + +
      + Home +
      + +
      + +
      + +".NormalizeNewLines(); + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + var jsonPages = File.ReadAllText("~/AppData/Pages.json".MapProjectPath()); + + Pages = JsonSerializer.DeserializeFromString>(jsonPages); + + 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) { + +#### Your search did not match any documents. + +## Suggestions: + + - Make sure all words are spelled correctly. + - Try different keywords. + - Try more general keywords. + - Try fewer keywords. +} + +@if (Model.Results.Count > 0) { +#### Showing Results 1 - @Model.Results.Count +} + +
      +@foreach page in Model.Results { +### @page.Category > [@page.Name](@page.AbsoluteUrl) +@page.Content +} +
      "; + var expectedHtml = @" + + + Simple Site + + +
      + Home +
      + +
      +

      Showing Results 1 - 5

      +
      +

      Markdown > About Docs

      +

      Markdown > Markdown Features

      +

      Markdown > Markdown Razor

      +

      Framework > Home

      +

      Framework > Overview

      +
      +
      + +".NormalizeNewLines(); + + var markdownFormat = Create(websiteTemplate, pageTemplate); + + var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); + + Console.WriteLine(html); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Can_display_search_results() + { + var pageTemplate = @"@var Title = ""Search results for "" + Model.Query + +@if (Model.Results.Count == 0) { + +#### Your search did not match any documents. + +## Suggestions: + + - Make sure all words are spelled correctly. + - Try different keywords. + - Try more general keywords. + - Try fewer keywords. + +} else { + +#### Showing Results 1 - @Model.Results.Count + +^
      + +@foreach page in Model.Results { + +### @page.Category > [@page.Name](@page.AbsoluteUrl) +@page.Content + +} + +^
      + +}"; + var expectedHtml = @" + + + Simple Site + + +
      + Home +
      + +
      +

      Showing Results 1 - 5

      +
      +

      Markdown > About Docs

      +

      Markdown > Markdown Features

      +

      Markdown > Markdown Razor

      +

      Framework > Home

      +

      Framework > Overview

      +
      + +
      + +".NormalizeNewLines(); + + var markdownFormat = Create(websiteTemplate, pageTemplate); + + var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); + + Console.WriteLine(html); + + 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 cfefe6e082b..d0caa6cdbc5 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/ViewTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/ViewTests.cs @@ -1,285 +1,262 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Text; -using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.Html; -using ServiceStack.ServiceHost.Tests.AppData; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; - -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 - }; - markdownFormat.Register(appHost); - } - - public class AppHost : IAppHost - { - public AppHost() - { - this.Config = new EndpointHostConfig { - MarkdownReplaceTokens = 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 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 Action ExceptionHandler { 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 void LoadPlugin(params IPlugin[] plugins) - { - plugins.ToList().ForEach(x => x.Register(this)); - } - - public IVirtualPathProvider VirtualPathProvider { get; set; } - } - - 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); - - 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() - { - this.Headers = new Dictionary(); - this.MemoryStream = new MemoryStream(); - this.Cookies = new Cookies(this); - } - - public object OriginalResponse - { - get { throw new NotImplementedException(); } - } - - public int StatusCode { set; private get; } - - public string StatusDescription { set; private get; } - - public string ContentType { get; set; } - - private Dictionary Headers { get; set; } - - public ICookies Cookies { get; set; } - - public void AddHeader(string name, string value) - { - this.Headers.Add(name, value); - } - - public void Redirect(string url) - { - this.Headers[HttpHeaders.Location] = url; - } - - public Stream OutputStream { get { return MemoryStream; } } - - public void Write(string text) - { - var bytes = Encoding.UTF8.GetBytes(text); - MemoryStream.Write(bytes, 0, bytes.Length); - } - - public string Contents { get; set; } - - public void Close() - { - this.Contents = Encoding.UTF8.GetString(MemoryStream.ToArray()); - MemoryStream.Close(); - this.IsClosed = true; - } - - public void End() - { - Close(); - } - - public void Flush() - { - MemoryStream.Flush(); - } - - public bool IsClosed { get; private set; } - } - - [Test] - public void Does_process_Markdown_pages() - { - var markdownHandler = new MarkdownHandler { - MarkdownFormat = markdownFormat, - PathInfo = "/AppData/NoTemplate/Static.md", - FilePath = "~/AppData/NoTemplate/Static.md".MapProjectPath(), - }; - var httpReq = new MockHttpRequest { QueryString = new NameValueCollection() }; - var httpRes = new MockHttpResponse(); - markdownHandler.ProcessRequest(httpReq, httpRes, "Static"); - - var expectedHtml = markdownFormat.Transform( - File.ReadAllText("~/AppData/NoTemplate/Static.md".MapProjectPath())); - - httpRes.Close(); - Assert.That(httpRes.Contents, Is.EqualTo(expectedHtml)); - } - - } - +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.Host; +using ServiceStack.ServiceHost.Tests.AppData; +using ServiceStack.Support.Markdown; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.ServiceHost.Tests.Formats +{ + [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(), + }; + httpReq.QueryString.Add("format", format); + using (var ms = new MemoryStream()) + { + 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) + { + 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/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); + + 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; } + + private Dictionary Headers { get; set; } + + public ICookies Cookies { get; set; } + + public void AddHeader(string name, string value) + { + this.Headers.Add(name, value); + } + + 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 void End() + { + Close(); + } + + public void Flush() + { + MemoryStream.Flush(); + } + + public Task FlushAsync(CancellationToken token = new CancellationToken()) => MemoryStream.FlushAsync(token); + + public bool IsClosed { get; private set; } + + public void SetContentLength(long contentLength) + { + Headers[HttpHeaders.ContentLength] = contentLength.ToString(); + } + + public bool KeepAlive { get; set; } + + public bool HasStarted { get; set; } + + public Dictionary Items { get; private set; } + + public void SetCookie(Cookie cookie) + { + } + + 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(); + + 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 53989b33c1e..08b9feb27dd 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/CustomRazorBasePage.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/CustomRazorBasePage.cs @@ -1,11 +1,11 @@ -using ServiceStack.Razor; -using ServiceStack.ServiceHost.Tests.AppData; - -namespace ServiceStack.ServiceHost.Tests.Formats_Razor -{ - public abstract class CustomRazorBasePage : ViewPage - { - public FormatHelpers Fmt = new FormatHelpers(); - public NorthwindHelpers Nwnd = new NorthwindHelpers(); - } -} \ No newline at end of file +using ServiceStack.Razor; +using ServiceStack.ServiceHost.Tests.AppData; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + 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 dca294b9ad2..00567946ea4 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionExampleRazorTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionExampleRazorTests.cs @@ -1,211 +1,211 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Razor; -using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints; - -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 }; - } - - [SetUp] - public void SetUp() - { - RazorFormat = new RazorFormat { - DefaultBaseType = typeof(CustomRazorBasePage<>), - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), - TemplateProvider = { CompileInParallelWithNoOfThreads = 0 }, - }; - RazorFormat.Init(); - } - - [Test] - public void Basic_Razor_Example() - { - var template = -@"

      Razor Example

      - -

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

      - -

      Checkout this product

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

      Razor Example

      - -

      Hello Demis, the year is 2012

      - -

      Checkout this product

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, new { name = "Demis", productId = 10 }); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Simple_loop() - { - var template = @"
        -@foreach (var p in Model.products) { -
      • @p.Name: (@p.Price)
      • -} -
      -".NormalizeNewLines(); - - var expectedHtml = -@"
        -
      • Pen: (1.99)
      • -
      • Glass: (9.99)
      • -
      • Book: (14.99)
      • -
      • DVD: (11.99)
      • -
      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - [Test] - public void If_Statment() - { - var template = @" -@if (Model.products.Count == 0) { -

      Sorry - no products in this category

      -} else { -

      We have products for you!

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

      We have products for you!

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

      Your Message: @message

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

      Your Message: Number is 1

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - - [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 = -@"

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

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.StringMatching(expectedHtml.Substring(0, expectedHtml.Length - 25))); - } - - - [Test] - public void Identifying_nested_content() - { - var template = -@" -@if (DateTime.Now.Year == 2012) { -

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

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

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

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, productArgs); - - Console.WriteLine(html); - Assert.That(html, Is.StringMatching(expectedHtml.Substring(0, expectedHtml.Length - 25))); - } - - [Test] - public void HTML_encoding() - { - var template = -@"

      Some Content @Model.stringContainingHtml

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

      Some Content <span>html</span>

      -".NormalizeNewLines(); - - var html = RenderToHtml(template, new { stringContainingHtml = "html"}); - - html.Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - } -} \ No newline at end of file +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Razor; +using ServiceStack.ServiceHost.Tests.Formats; +using ServiceStack.Testing; +using ServiceStack.Text; + +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; + + 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 + { + PageBaseType = typeof(CustomRazorBasePage<>), + VirtualFileSources = new MemoryVirtualFiles(), + }.Init(); + } + + [Test] + public void Basic_Razor_Example() + { + var template = +@"

      Razor Example

      + +

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

      + +

      Checkout this product

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

      Razor Example

      + +

      Hello Demis, the year is 2022

      + +

      Checkout this product

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

      Sorry - no products in this category

      +} else { +

      We have products for you!

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

      We have products for you!

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

      Your Message: @message

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

      Your Message: Number is 1

      +".NormalizeNewLines(); + + var html = RazorFormat.CreateAndRenderToHtml(template, model: productArgs); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + } + + + [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 = +@"

      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); + + Assert.That(html, Does.Match(expectedHtml.Substring(0, expectedHtml.Length - 25))); + } + + + [Test] + public void Identifying_nested_content() + { + var template = +@" +@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 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); + + Assert.That(html, Does.Match(expectedHtml.Substring(0, expectedHtml.Length - 25))); + } + + [Test] + public void HTML_encoding() + { + var template = +@"

      Some Content @Model.stringContainingHtml

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

      Some Content <span>html</span>

      +".NormalizeNewLines(); + + var html = RazorFormat.CreateAndRenderToHtml(template, new { stringContainingHtml = "html" }); + + 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 2a2cd8cc03c..8d981e5eeb7 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionLayoutRazorTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionLayoutRazorTests.cs @@ -1,349 +1,387 @@ -using System; -using System.Collections.Generic; -using System.Text; -using NUnit.Framework; -using ServiceStack.Html; -using ServiceStack.Razor; -using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.VirtualPath; - -namespace ServiceStack.ServiceHost.Tests.Formats_Razor -{ - 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 : ViewPage - { - 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 IntroductionLayoutRazorTests : RazorTestBase - { - [SetUp] - public void OnBeforeEachTest() - { - base.RazorFormat = new RazorFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), - TemplateProvider = { CompileInParallelWithNoOfThreads = 0 }, - }; - base.RazorFormat.Init(); - } - - [Test] - public void Simple_Layout_Example() - { - var websiteTemplate = -@" - - - Simple Site - - - -
      - Home - About -
      - -
      - @RenderBody() -
      - - -".NormalizeNewLines(); - - var pageTemplate = -@"@{ Layout = ""websiteTemplate.cshtml""; } - -

      About this Site

      - -

      This is some content that will make up the ""about"" -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: @DateTime.Now.Year

      -".NormalizeNewLines(); - - var expectedHtml = @" - - - Simple Site - - - -
      - Home - About -
      - -
      - -

      About this Site

      - -

      This is some content that will make up the ""about"" -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: 2012

      - -
      - - -".NormalizeNewLines(); - - - RazorFormat.AddFileAndTemplate("websiteTemplate.cshtml", websiteTemplate); - var dynamicPage = AddViewPage(PageName, @"C:\path\to\page-tpl", pageTemplate); - - var template = dynamicPage.RenderToHtml(); - - Console.WriteLine(template); - Assert.That(template, Is.EqualTo(expectedHtml)); - } - - - - [Test] - public void Layout_MasterPage_Scenarios_Adding_Sections() - { - var websiteTemplate = -@" - - - Simple Site - - - -
      - Home - About -
      - -
      - @RenderSection(""Menu"") -
      - -
      - @RenderBody() -
      - -
      - @RenderSection(""Footer"") -
      - - -".NormalizeNewLines(); - - var pageTemplate = @"

      About this Site

      - -

      This is some content that will make up the ""about"" -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: @DateTime.Now.Year

      - -@section Menu { -
        -
      • About Item 1
      • -
      • About Item 2
      • -
      -} - -@section Footer { -

      This is my custom footer for Home

      -} -".NormalizeNewLines(); - - var expectedHtml = @" - - - Simple Site - - - -
      - Home - About -
      - -
      - -
        -
      • About Item 1
      • -
      • About Item 2
      • -
      - -
      - -
      -

      About this Site

      - -

      This is some content that will make up the ""about"" -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: 2012

      - - - - - -
      - -
      - -

      This is my custom footer for Home

      - -
      - - -".NormalizeNewLines(); - - - RazorFormat.AddFileAndTemplate("websiteTemplate.cshtml", websiteTemplate); - - var dynamicPage = AddViewPage( - PageName, @"C:\path\to\page-tpl.cshtml", pageTemplate, "websiteTemplate.cshtml"); - - - var html = dynamicPage.RenderToHtml(); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Encapsulation_and_reuse_with_HTML_helpers() - { - var pageTemplate = -@"@model ServiceStack.ServiceHost.Tests.Formats_Razor.Product -
      - Edit Product - -
      - @Html.LabelFor(m => m.ProductID) -
      -
      - @Html.TextBoxFor(m => m.ProductID) -
      -
      -".NormalizeNewLines(); - - var expectedHtml = -@"
      - Edit Product - -
      - -
      -
      - -
      -
      -".NormalizeNewLines(); - - var product = new Product { ProductID = 10 }; - var html = RenderToHtml(pageTemplate, product); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Using_External_HTML_Helpers() - { - var pageTemplate = -@"@model System.Collections.Generic.List - -
      - All Products - @Prod.ProductTable(Model) -
      ".NormalizeNewLines(); - - var expectedHtml = @" -
      - All Products - - - - - -
      IdNamePrice
      0Pen1.99
      0Glass9.99
      0Book14.99
      0DVD11.99
      - -
      ".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), - }; - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - var html = RenderToHtml(pageTemplate, products); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Using_Custom_base_class() - { - var pageTemplate = -@"@inherits ServiceStack.ServiceHost.Tests.Formats_Razor.CustomBaseClass - -
      - All Products - @Field(""Name"", Model.Name) -
      ".NormalizeNewLines(); - - var expectedHtml = @" -
      - All Products - - - -
      ".NormalizeNewLines(); - - RazorFormat.DefaultBaseType = typeof(CustomBaseClass<>); - - var html = RenderToHtml(pageTemplate, new Product("Pen", 1.99m)); - - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - } -} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using ServiceStack.Html; +using ServiceStack.IO; +using ServiceStack.Razor; +using ServiceStack.ServiceHost.Tests.Formats; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + 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 : ViewPage + { + 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()); + } + + 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 + { + VirtualFileSources = new MemoryVirtualFiles(), + }.Init(); + } + + [Test] + public void Simple_Layout_Example() + { + var websiteTemplate = +@" + + + Simple Site + + + +
      + Home + About +
      + +
      + @RenderBody() +
      + + +".NormalizeNewLines(); + + var pageTemplate = +@"@layout websiteTemplate + +

      About this Site

      + +

      This is some content that will make up the ""about"" +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: @DateTime.Now.Year

      +".NormalizeNewLines(); + + var expectedHtml = @" + + + Simple Site + + + +
      + Home + About +
      + +
      +

      About this Site

      + +

      This is some content that will make up the ""about"" +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: 2022

      +
      + + +".NormalizeNewLines(); + + + RazorFormat.AddFileAndPage("/views/websiteTemplate.cshtml", websiteTemplate); + var dynamicPage = RazorFormat.AddFileAndPage(@"/page.cshtml", pageTemplate); + + var template = RazorFormat.RenderToHtml(dynamicPage); + + Assert.That(template.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + } + + [Test] + public void Nested_Layout_Example_With_Sections() + { + var websiteTemplate2 = + @"
      @RenderBody()
      + @RenderSection(""Section1"")" + .StripLinesAndWhitespace(); + + var websiteTemplate1 = + @"@{Layout=""websiteTemplate2"";} +
      @RenderBody()
      + @RenderSection(""Section1"") + @section Section1 {
      Menu2
      }" + .StripLinesAndWhitespace(); + + var pageTemplate = + @"@{Layout=""websiteTemplate1"";} +

      @DateTime.Now.Year

      + @section Section1 {
      Menu1
      }" + .StripLinesAndWhitespace(); + + var expectedHtml = (@"
      +

      " + DateTime.Now.Year + @"

      +
      Menu1
      Menu2
      ") + .StripLinesAndWhitespace(); + + RazorFormat.AddFileAndPage("/views/websiteTemplate2.cshtml", websiteTemplate2); + RazorFormat.AddFileAndPage("/views/websiteTemplate1.cshtml", websiteTemplate1); + var dynamicPage = RazorFormat.AddFileAndPage(@"/page.cshtml", pageTemplate); + var template = RazorFormat.RenderToHtml(dynamicPage); + + Assert.That(template, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Layout_MasterPage_Scenarios_Adding_Sections() + { + var websiteTemplate = +@" + + + Simple Site + + + +
      + Home + About +
      + +
      + @RenderSection(""Menu"") +
      + +
      + @RenderBody() +
      + +
      + @RenderSection(""Footer"") +
      + + +".NormalizeNewLines(); + + var pageTemplate = @"

      About this Site

      + +

      This is some content that will make up the ""about"" +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: @DateTime.Now.Year

      + +@section Menu { +
        +
      • About Item 1
      • +
      • About Item 2
      • +
      +} + +@section Footer { +

      This is my custom footer for Home

      +} +".NormalizeNewLines(); + + var expectedHtml = @" + + + Simple Site + + + +
      + Home + About +
      + +
      + +
        +
      • About Item 1
      • +
      • About Item 2
      • +
      + +
      + +
      +

      About this Site

      + +

      This is some content that will make up the ""about"" +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: 2022

      + + + +
      + +
      + +

      This is my custom footer for Home

      + +
      + + +".NormalizeNewLines(); + + + RazorFormat.AddFileAndPage("/views/websiteTemplate.cshtml", websiteTemplate); + + var dynamicPage = RazorFormat.AddFileAndPage("/page.cshtml", pageTemplate); + + var html = RazorFormat.RenderToHtml(dynamicPage, layout: "websiteTemplate"); + + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Encapsulation_and_reuse_with_HTML_helpers() + { + var pageTemplate = +@"@model ServiceStack.ServiceHost.Tests.Formats_Razor.Product +
      + Edit Product + +
      + @Html.LabelFor(m => m.ProductID) +
      +
      + @Html.TextBoxFor(m => m.ProductID) +
      +
      +".NormalizeNewLines(); + + var expectedHtml = +@"
      + Edit Product + +
      + +
      +
      + +
      +
      +".NormalizeNewLines(); + + var product = new Product { ProductID = 10 }; + var html = RazorFormat.CreateAndRenderToHtml(pageTemplate, product); + + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Using_External_HTML_Helpers() + { + var pageTemplate = +@"@model System.Collections.Generic.List + +
      + All Products + @Prod.ProductTable(Model) +
      ".NormalizeNewLines(); + + var expectedHtml = @"
      + All Products + + + + + +
      IdNamePrice
      0Pen1.99
      0Glass9.99
      0Book14.99
      0DVD11.99
      + +
      ".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), + }; + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + var html = RazorFormat.CreateAndRenderToHtml(pageTemplate, model: products); + + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Using_Custom_base_class() + { + var pageTemplate = +@"@inherits ServiceStack.ServiceHost.Tests.Formats_Razor.CustomBaseClass + +
      + All Products + @Field(""Name"", Model.Name) +
      ".NormalizeNewLines(); + + var expectedHtml = @"
      + All Products + + + +
      ".NormalizeNewLines(); + + RazorFormat.PageBaseType = typeof(CustomBaseClass<>); + + var html = RazorFormat.CreateAndRenderToHtml(pageTemplate, new Product("Pen", 1.99m)); + + 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 f5d23b8999d..1486a5a7838 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorEngineTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorEngineTests.cs @@ -1,110 +1,161 @@ -using System; -using NUnit.Framework; -using ServiceStack.Razor; - -namespace ServiceStack.ServiceHost.Tests.Formats_Razor -{ - [TestFixture] - public class RazorEngineTests - { - const string LayoutHtml = "
      @RenderSection(\"Title\")
      @RenderBody()"; - - RazorFormat mvcRazorFormat; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - mvcRazorFormat = new RazorFormat { DefaultBaseType = typeof(CustomRazorBasePage<>) }; - mvcRazorFormat.Init(); - } - - [SetUp] - public void OnBeforeEachTest() - { - mvcRazorFormat.TemplateService.Compile(LayoutHtml, "TheLayout.cshtml"); - } - - [Test] - public void Can_compile_simple_template() - { - const string template = "This is my sample template, Hello @Model.Name!"; - var result = mvcRazorFormat.TemplateService.Parse(template, new { Name = "World" }); - - Assert.That(result, Is.EqualTo("This is my sample template, Hello World!")); - } - - [Test] - public void Can_compile_simple_template_by_name() - { - const string template = "This is my sample template, Hello @Model.Name!"; - mvcRazorFormat.TemplateService.Compile(template, "simple"); - var result = mvcRazorFormat.TemplateService.Run(new { Name = "World" }, "simple"); - - Assert.That(result, Is.EqualTo("This is my sample template, 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!"; - mvcRazorFormat.TemplateService.Compile(template, "simple"); - - var result = mvcRazorFormat.TemplateService.Run(new { Name = "World" }, "simple"); - Assert.That(result, Is.EqualTo("This is my sample template, Hello World!")); - - var result2 = mvcRazorFormat.TemplateService.Run(new { Name = "World2" }, "simple"); - Assert.That(result2, Is.EqualTo("This is my sample template, Hello World2!")); - } - - [Test] - public void Can_get_executed_template_by_name_with_layout() - { - const string html = "@{ Layout = \"TheLayout.cshtml\"; }This is my sample template, Hello @Model.Name!"; - mvcRazorFormat.TemplateService.Compile(html, "simple2"); - - var template = mvcRazorFormat.TemplateService.ExecuteTemplate(new { Name = "World" }, "simple2"); - - Assert.That(template.ChildTemplate.Layout, Is.EqualTo("TheLayout.cshtml")); - Assert.That(template.ChildTemplate.Sections.Count, Is.EqualTo(0)); - Assert.That(template.Result, Is.EqualTo("
      This is my sample template, Hello World!")); - - template = mvcRazorFormat.TemplateService.GetTemplate("simple2"); - Assert.That(template.Layout, Is.EqualTo("TheLayout.cshtml")); - } - - [Test] - 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!

      }"; - mvcRazorFormat.TemplateService.Compile(html, "simple3"); - - var template = mvcRazorFormat.TemplateService.ExecuteTemplate(new { Name = "World" }, "simple3"); - - Assert.That(template.ChildTemplate.Layout, Is.EqualTo("TheLayout.cshtml")); - Assert.That(template.ChildTemplate.Sections.Count, Is.EqualTo(1)); - Assert.That(template.Result, Is.EqualTo("

      Hello World!

      This is my sample template, ")); - - template = mvcRazorFormat.TemplateService.GetTemplate("simple3"); - Assert.That(template.Layout, Is.EqualTo("TheLayout.cshtml")); - - var titleAction = template.Sections["Title"]; - template.Clear(); - titleAction(); - Assert.That(template.Result, Is.EqualTo("

      Hello World!

      ")); - } - - [Test] - public void Can_compile_template_with_RenderBody() - { - const string html = "@{ Layout = \"TheLayout.cshtml\"; }This is my sample template, @section Title {

      Hello @Model.Name!

      }"; - mvcRazorFormat.TemplateService.Compile(html, "simple4"); - - var template = mvcRazorFormat.TemplateService.ExecuteTemplate(new { Name = "World" }, "simple4"); - - Console.WriteLine(template.Result); - - Assert.That(template.Result, Is.EqualTo("

      Hello World!

      This is my sample template, ")); - } - - } -} \ No newline at end of file +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Html; +using ServiceStack.IO; +using ServiceStack.Razor; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + [TestFixture] + public class RazorEngineTests + { + const string LayoutHtml = "
      @RenderSection(\"Title\")
      @RenderBody()"; + + 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; + + var fileSystem = new MemoryVirtualFiles(); + fileSystem.WriteFile("/views/TheLayout.cshtml", LayoutHtml); + InitializeFileSystem(fileSystem); + + RazorFormat = new RazorFormat + { + VirtualFileSources = fileSystem, + PageBaseType = typeof(CustomRazorBasePage<>), + EnableLiveReload = false, + PrecompilePages = PrecompileEnabled, + WaitForPrecompilationOnStartup = WaitForPrecompileEnabled, + }.Init(); + } + + 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" }); + + Assert.That(result, Is.EqualTo("This is my sample template, Hello World!")); + } + + [Test] + 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" }); + + 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); + + 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"); + Assert.That(result2, Is.EqualTo("This is my sample template, Hello World2!")); + } + + [Test] + 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); + + var result = RazorFormat.RenderToHtml("/simple2.cshtml", new { Name = "World" }); + + Assert.That(result, Is.EqualTo("
      This is my sample template, Hello World!")); + } + + [Test] + 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); + + IRazorView view; + var result = RazorFormat.RenderToHtml(page, out view, model: new { Name = "World" }); + + Assert.That(result, Is.EqualTo("

      Hello World!

      This is my sample template, ")); + + Assert.That(view.ChildPage.Layout, Is.EqualTo("TheLayout.cshtml")); + + Assert.That(view.ChildPage.IsSectionDefined("Title"), Is.True); + + var titleResult = view.ChildPage.RenderSectionToHtml("Title"); + Assert.That(titleResult, Is.EqualTo("

      Hello World!

      ")); + } + + [Test] + 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 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 79922e5f1d9..f408584adf3 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorTestBase.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorTestBase.cs @@ -1,92 +1,24 @@ -using System.Collections.Generic; -using ServiceStack.Razor; -using ServiceStack.VirtualPath; - -namespace ServiceStack.ServiceHost.Tests.Formats_Razor -{ - public static class MarkdownFormatExtensions - { - public static void AddFileAndView(this RazorFormat razorFormat, ViewPageRef viewPage) - { - var pathProvider = (InMemoryVirtualPathProvider)razorFormat.VirtualPathProvider; - pathProvider.AddFile(viewPage.FilePath, viewPage.Contents); - razorFormat.AddPage(viewPage); - } - - public static void AddFileAndTemplate(this RazorFormat razorFormat, string filePath, string contents) - { - var pathProvider = (InMemoryVirtualPathProvider)razorFormat.VirtualPathProvider; - pathProvider.AddFile(filePath, contents); - razorFormat.AddTemplate(filePath, contents); - } - } - - public class RazorTestBase - { - public const string TemplateName = "Template"; - protected const string PageName = "Page"; - protected RazorFormat RazorFormat; - - public RazorFormat AddPage(string websiteTemplate, string pageTemplate) - { - RazorFormat.AddTemplate("websiteTemplate", websiteTemplate); - RazorFormat.AddPage( - new ViewPageRef(RazorFormat, "/path/to/tpl", PageName, pageTemplate) { - Template = "websiteTemplate", - }); - - return RazorFormat; - } - - public RazorFormat AddPage(string pageTemplate) - { - RazorFormat.AddPage( - new ViewPageRef(RazorFormat, "/path/to/tpl", PageName, pageTemplate) { - Service = RazorFormat.TemplateService - }); - - RazorFormat.TemplateService.RegisterPage("/path/to/tpl", PageName); - RazorFormat.TemplateProvider.CompileQueuedPages(); - - return RazorFormat; - } - - protected ViewPageRef AddViewPage(string pageName, string pagePath, string pageContents, string templatePath = null) - { - var dynamicPage = new ViewPageRef(RazorFormat, - pagePath, pageName, pageContents, RazorPageType.ViewPage) { - Template = templatePath, - Service = RazorFormat.TemplateService - }; - - RazorFormat.AddPage(dynamicPage); - - RazorFormat.TemplateService.RegisterPage(pagePath, pageName); - RazorFormat.TemplateProvider.CompileQueuedPages(); - - return dynamicPage; - } - - public string RenderToHtml(string pageTemplate, Dictionary scopeArgs) - { - AddPage(pageTemplate); - var template = RazorFormat.ExecuteTemplate(scopeArgs, PageName, null); - return template.Result; - } - - public string RenderToHtml(string pageTemplate, Dictionary scopeArgs, string websiteTemplate) - { - AddPage(pageTemplate); - var template = RazorFormat.ExecuteTemplate(scopeArgs, PageName, websiteTemplate); - return template.Result; - } - - public string RenderToHtml(string pageTemplate, T model) - { - AddPage(pageTemplate); - var template = RazorFormat.ExecuteTemplate(model, PageName, null); - return template.Result; - } - } - -} \ No newline at end of file +using System; +using System.Collections.Generic; +using ServiceStack.Razor; +using ServiceStack.Razor.Managers; +using ServiceStack.IO; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + public static class RazorFormatExtensions + { + public static RazorPage AddFileAndPage(this RazorFormat razorFormat, string filePath, string contents) + { + razorFormat.VirtualFileSources.WriteFile(filePath, contents); + return razorFormat.AddPage(filePath); + } + } + + public class RazorTestBase + { + 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 new file mode 100644 index 00000000000..901f62b84e8 --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/StandAloneExampleTests.cs @@ -0,0 +1,43 @@ +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Razor; +using ServiceStack.Testing; +using ServiceStack.Text; + +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 + { + VirtualFileSources = new MemoryVirtualFiles(), + EnableLiveReload = false, + }.Init(); + + var page = razor.CreatePage("Hello @Model.Name! Welcome to Razor!"); + var html = razor.RenderToHtml(page, new { Name = "World" }); + html.Print(); + + Assert.That(html, Is.EqualTo("Hello World! Welcome to Razor!")); + } + } +} diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs index d64677c7bfe..1f1e12410af 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs @@ -1,900 +1,937 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.Html; -using ServiceStack.Markdown; -using ServiceStack.Razor; -using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.VirtualPath; - -namespace ServiceStack.ServiceHost.Tests.Formats_Razor -{ - public class Person - { - public string FirstName { get; set; } - public string LastName { get; set; } - public List Links { get; set; } - } - - public class Link - { - public Link() - { - this.Labels = new List(); - } - public string Name { get; set; } - public string Href { get; set; } - public List Labels { get; set; } - } - - public class CustomViewBase : ViewPage - { - public CustomMarkdownHelper Ext = new CustomMarkdownHelper(); - public ExternalProductHelper Prod = new ExternalProductHelper(); - - public MvcHtmlString Table(dynamic obj) - { - Person model = obj; - var sb = new StringBuilder(); - - sb.AppendFormat("", model.FirstName); - sb.AppendLine(""); - sb.AppendLine(""); - foreach (var link in model.Links) - { - sb.AppendFormat("", link.Name, link.Href); - } - sb.AppendLine(""); - sb.AppendLine("
      {0}'s Links
      NameLink
      {0}{1}
      "); - - return MvcHtmlString.Create(sb.ToString()); - } - - private static string[] MenuItems = new[] { "About Us", "Blog", "Links", "Contact" }; - - public MvcHtmlString Menu(string selectedId) - { - var sb = new StringBuilder(); - sb.Append("
        \n"); - foreach (var menuItem in MenuItems) - { - var cls = menuItem == selectedId ? " class='selected'" : ""; - sb.AppendFormat("
      • {0}
      • \n", menuItem, cls); - } - sb.Append("
      \n"); - - return MvcHtmlString.Create(sb.ToString()); - } - - public string Lower(string name) - { - return name == null ? null : name.ToLower(); - } - - public string Upper(string name) - { - return name == null ? null : name.ToUpper(); - } - - public string Combine(string separator, params string[] parts) - { - return string.Join(separator, parts); - } - } - - public class CustomMarkdownHelper - { - public static CustomMarkdownHelper Instance = new CustomMarkdownHelper(); - - public MvcHtmlString InlineBlock(string content, string id) - { - return MvcHtmlString.Create( - "
      " + content + "
      "); - } - } - - [TestFixture] - public class RazorTemplateTests : RazorTestBase - { - string staticTemplatePath; - string staticTemplateContent; - string dynamicPagePath; - string dynamicPageContent; - string dynamicListPagePath; - string dynamicListPageContent; - - Person templateArgs; - - 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"} }, - }, - }; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - staticTemplatePath = "Views/Shared/_Layout.cshtml"; - staticTemplateContent = File.ReadAllText("~/{0}".Fmt(staticTemplatePath).MapProjectPath()); - - dynamicPagePath = "Views/Template/DynamicTpl.cshtml"; - dynamicPageContent = File.ReadAllText("~/{0}".Fmt(dynamicPagePath).MapProjectPath()); - - dynamicListPagePath = "Views/Template/DynamicListTpl.cshtml".MapProjectPath(); - dynamicListPageContent = File.ReadAllText("~/{0}".Fmt(dynamicListPagePath).MapProjectPath()); - - templateArgs = person; - } - - [SetUp] - public void OnBeforeEachTest() - { - base.RazorFormat = new RazorFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), - TemplateProvider = { CompileInParallelWithNoOfThreads = 0 }, - }; - RazorFormat.Init(); - } - - [Test] - public void Can_Render_RazorTemplate() - { - const string mockContents = "[Replaced with Template]"; - - RazorFormat.AddFileAndTemplate(staticTemplatePath, staticTemplateContent); - var page = AddViewPage("MockPage", "/path/to/page", mockContents, staticTemplatePath); - - var expectedHtml = staticTemplateContent.ReplaceFirst(RazorFormat.TemplatePlaceHolder, mockContents); - - var templateOutput = page.RenderToString(templateArgs); - - Console.WriteLine(templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_RazorPage() - { - RazorFormat.AddFileAndTemplate(staticTemplatePath, staticTemplateContent); - var dynamicPage = AddViewPage("DynamicTpl", dynamicPagePath, dynamicPageContent, staticTemplatePath); - - var expectedHtml = dynamicPageContent - .Replace("@Model.FirstName", person.FirstName) - .Replace("@Model.LastName", person.LastName); - - expectedHtml = staticTemplateContent.Replace(RazorFormat.TemplatePlaceHolder, expectedHtml); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_RazorPage_with_foreach() - { - RazorFormat.AddFileAndTemplate(staticTemplatePath, staticTemplateContent); - var dynamicPage = AddViewPage("DynamicListTpl", dynamicListPagePath, dynamicListPageContent, staticTemplatePath); - - var expectedHtml = dynamicListPageContent - .Replace("@Model.FirstName", person.FirstName) - .Replace("@Model.LastName", person.LastName); - - var foreachLinks = "
    • ServiceStack - http://www.servicestack.net
    • \r\n" - + "
    • AjaxStack - http://www.ajaxstack.com
    • "; - - expectedHtml = expectedHtml.ReplaceForeach(foreachLinks); - - expectedHtml = staticTemplateContent.Replace(RazorFormat.TemplatePlaceHolder, expectedHtml); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_RazorPage_with_IF_statement() - { - var template = @"

      Dynamic If Markdown Template

      - -

      Hello @Model.FirstName,

      - -
        -@if (Model.FirstName == ""Bellot"") { -
      • @Model.FirstName
      • -} -@if (Model.LastName == ""Bellot"") { -
      • @Model.LastName
      • -} -
      - -

      heading 3

      "; - - var expectedHtml = @"

      Dynamic If Markdown Template

      - -

      Hello Demis,

      - -
        -
      • Bellot
      • -
      - -

      heading 3

      "; - - var dynamicPage = AddViewPage("DynamicIfTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_RazorPage_with_Nested_Statements() - { - var template = @"

      @Model.FirstName Dynamic Nested Markdown Template

      - -

      heading 1

      - -
        -@foreach (var link in Model.Links) { - @if (link.Name == ""AjaxStack"") { -
      • @link.Name - @link.Href
      • - } -} -
      - -@if (Model.Links.Count == 2) { -

      Haz 2 links

      -
        - @foreach (var link in Model.Links) { -
      • @link.Name - @link.Href
      • - @foreach (var label in link.Labels) { -
      • @label
      • - } - } -
      -} - -

      heading 3

      "; - - var expectedHtml = @"

      Demis Dynamic Nested Markdown Template

      - -

      heading 1

      - -
        -
      • AjaxStack - http://www.ajaxstack.com
      • -
      - -

      Haz 2 links

      -
        -
      • ServiceStack - http://www.servicestack.net
      • -
      • REST
      • -
      • JSON
      • -
      • XML
      • -
      • AjaxStack - http://www.ajaxstack.com
      • -
      • HTML5
      • -
      • AJAX
      • -
      • SPA
      • -
      - -

      heading 3

      "; - - - var dynamicPage = AddViewPage("DynamicNestedTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_Razor_with_StaticMethods() - { - var headerTemplate = @"

      Header Links!

      -".NormalizeNewLines(); - - var template = @"

      Welcome to Razor!

      - -@Html.Partial(""HeaderLinks"", Model) - -

      Hello @Upper(Model.LastName), @Model.FirstName

      - -

      Breadcrumbs

      - -@Combine("" / "", Model.FirstName, Model.LastName) - -

      Menus

      -
        -@foreach (var link in Model.Links) { -
      • @link.Name - @link.Href -
          - @foreach (var label in link.Labels) { -
        • @label
        • - } -
        -
      • -} -
      - -

      HTML Table

      -@Table(Model)".NormalizeNewLines(); - - var expectedHtml = @"

      Welcome to Razor!

      - -

      Header Links!

      - - -

      Hello BELLOT, Demis

      - -

      Breadcrumbs

      - -Demis / Bellot - -

      Menus

      -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
        -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
        -
      • -
      - -

      HTML Table

      - - - -
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      -".NormalizeNewLines(); - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - AddViewPage("HeaderLinks", "/path/to/page", headerTemplate); - - var dynamicPage = AddViewPage("DynamicIfTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_inherit_from_Generic_RazorViewPage_from_model_directive() - { - var template = @"@model ServiceStack.ServiceHost.Tests.Formats_Razor.Person -

      Generic View Page

      - -

      Form fields

      -@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) -"; - - var expectedHtml = @"

      Generic View Page

      - -

      Form fields

      - -".NormalizeNewLines(); - - - var dynamicPage = AddViewPage("DynamicModelTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_inherit_from_CustomViewPage_using_inherits_directive() - { - var template = @"@inherits ServiceStack.ServiceHost.Tests.Formats_Razor.CustomViewBase -

      Generic View Page

      - -

      Form fields

      -@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) - -

      Person Table

      -@Table(Model)"; - - var expectedHtml = @"

      Generic View Page

      - -

      Form fields

      - - -

      Person Table

      - - - -
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      -".NormalizeNewLines(); - - var dynamicPage = AddViewPage("DynamicModelTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Can_Render_RazorPage_with_external_helper() - { - var template = @"

      View Page with Custom Helper

      - -

      External Helper

      - -@Ext.InlineBlock(Model.FirstName, ""first-name"") -"; - - var expectedHtml = - @"

      View Page with Custom Helper

      - -

      External Helper

      - -
      Demis
      -".NormalizeNewLines(); - - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - var dynamicPage = AddViewPage("DynamicModelTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_RazorPage_with_variable_statements() - { - var template = @"

      Welcome to Razor!

      - -@{ var lastName = Model.LastName; } -Hello @Upper(lastName), @Model.FirstName - -

      Breadcrumbs

      -@Combine("" / "", Model.FirstName, lastName) - -@{ var links = Model.Links; } -

      Menus

      -
        -@foreach (var link in links) { -
      • @link.Name - @link.Href -
          - @{ var labels = link.Labels; } - @foreach (var label in labels) { -
        • @label
        • - } -
        -
      • -} -
      "; - - var expectedHtml = @"

      Welcome to Razor!

      - -Hello BELLOT, Demis - -

      Breadcrumbs

      -Demis / Bellot - -

      Menus

      -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
        -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
        -
      • -
      ".NormalizeNewLines(); - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - var dynamicPage = AddViewPage("DynamicModelTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Can_Render_RazorPage_with_comments() - { - var template = @"

      Dynamic If Markdown Template

      - -

      Hello @Model.FirstName,

      - -@if (Model.FirstName == ""Bellot"") { -
        -
      • @Model.FirstName
      • -
      -} -@* -@if (Model.LastName == ""Bellot"") { - * @Model.LastName -} -*@ - -@* -Plain text in a comment -*@ -

      heading 3

      "; - - var expectedHtml = @"

      Dynamic If Markdown Template

      - -

      Hello Demis,

      - -

      heading 3

      ".NormalizeNewLines(); - - var dynamicPage = AddViewPage("DynamicIfTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - - [Test] - public void Can_capture_Section_statements_and_store_them_in_Sections() - { - var template = @"

      Welcome to Razor!

      - -@{ var lastName = Model.LastName; } -@section Salutations { -

      Hello @Upper(lastName), @Model.FirstName

      -} - -@section Breadcrumbs { -

      Breadcrumbs

      -

      @Combine("" / "", Model.FirstName, lastName)

      -} - -@{ var links = Model.Links; } -@section Menus { -

      Menus

      -
        -@foreach (var link in links) { -
      • @link.Name - @link.Href -
          - @{ var labels = link.Labels; } - @foreach (var label in labels) { -
        • @label
        • - } -
        -
      • -} -
      -} - -

      Captured Sections

      - - - -@RenderSection(""Menus"") - -

      Salutations

      -@RenderSection(""Salutations"")"; - - var expectedHtml = - @"

      Welcome to Razor!

      - - - - - - - -

      Captured Sections

      - - - - -

      Menus

      -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
        -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
        -
      • -
      - - -

      Salutations

      - -

      Hello BELLOT, Demis

      -".NormalizeNewLines(); - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - var dynamicPage = AddViewPage("DynamicModelTpl", "/path/to/tpl", template); - - var templateOutput = dynamicPage.RenderToHtml(templateArgs).NormalizeNewLines(); - - Console.WriteLine(templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - - var razorTemplate = dynamicPage.GetRazorTemplate(); - - razorTemplate.Clear(); - Action section; - razorTemplate.Sections.TryGetValue("Salutations", out section); - section(); - - Assert.That(razorTemplate.Result, Is.EqualTo("\r\n

      Hello BELLOT, Demis

      \r\n")); - } - - - [Test] - public void Can_Render_RazorTemplate_with_section_and_variable_placeholders() - { - var template = @"

      Welcome to Razor!

      - -@{ var lastName = Model.LastName; } - -

      Hello @Upper(lastName), @Model.FirstName,

      - -@section Breadcrumbs { -

      Breadcrumbs

      -@Combine("" / "", Model.FirstName, lastName) -} - -@section Menus { -

      Menus

      -
        -@foreach (var link in Model.Links) { -
      • @link.Name - @link.Href -
          - @{ var labels = link.Labels; } - @foreach (var label in labels) { -
        • @label
        • - } -
        -
      • -} -
      -}"; - var websiteTemplatePath = "websiteTemplate.cshtml"; - - var websiteTemplate = @" - - - Bellot page - - - -
      - @RenderSection(""Menus"") -
      - -

      Website Template

      - -
      @RenderBody()
      - -
      - @RenderSection(""Breadcrumbs"") -
      - - -"; - - var expectedHtml = - @" - - - Bellot page - - - -
      - -

      Menus

      -
        -
      • ServiceStack - http://www.servicestack.net -
          -
        • REST
        • -
        • JSON
        • -
        • XML
        • -
        -
      • -
      • AjaxStack - http://www.ajaxstack.com -
          -
        • HTML5
        • -
        • AJAX
        • -
        • SPA
        • -
        -
      • -
      - -
      - -

      Website Template

      - -

      Welcome to Razor!

      - - -

      Hello BELLOT, Demis,

      - - - -
      - -
      - -

      Breadcrumbs

      -Demis / Bellot - -
      - - -".NormalizeNewLines(); - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - RazorFormat.AddFileAndTemplate(websiteTemplatePath, websiteTemplate); - AddViewPage("DynamicModelTpl", "/path/to/page-tpl", template, websiteTemplatePath); - - var razorTemplate = RazorFormat.ExecuteTemplate( - person, "DynamicModelTpl", websiteTemplatePath); - - var templateOutput = razorTemplate.Result.NormalizeNewLines(); - - Console.WriteLine(templateOutput); - - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - [Test] - public void Can_Render_Static_RazorContentPage_that_populates_variable_and_displayed_on_website_template() - { - - var websiteTemplate = @" - - - Static page - - -
      - @RenderSection(""Header"") -
      - - - -

      Website Template

      - -
      @RenderBody()
      - - -".NormalizeNewLines(); - - var template = @"

      Static Markdown Template

      -@section Menu { - @Menu(""Links"") -} - -@section Header { -

      Static Page Title

      -} - -

      heading 3

      -

      paragraph

      "; - - var expectedHtml = @" - - - Static page - - -
      - -

      Static Page Title

      - -
      - - - -

      Website Template

      - -

      Static Markdown Template

      - - - - -

      heading 3

      -

      paragraph

      - - -".NormalizeNewLines(); - - RazorFormat.TemplateService.TemplateBaseType = typeof(CustomViewBase<>); - - var websiteTemplatePath = "websiteTemplate.cshtml"; - RazorFormat.AddFileAndTemplate(websiteTemplatePath, websiteTemplate); - - var staticPage = new ViewPageRef(RazorFormat, - "pagetpl", "StaticTpl", template, RazorPageType.ContentPage) { - Service = RazorFormat.TemplateService, - Template = websiteTemplatePath, - }; - - RazorFormat.AddPage(staticPage); - RazorFormat.TemplateService.RegisterPage("pagetpl", "StaticTpl"); - RazorFormat.TemplateProvider.CompileQueuedPages(); - - var templateOutput = RazorFormat.RenderStaticPage("pagetpl").NormalizeNewLines(); - - Console.WriteLine(templateOutput); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); - } - - } -} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Html; +using ServiceStack.IO; +using ServiceStack.Razor; +using ServiceStack.ServiceHost.Tests.Formats; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + public class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + public List Links { get; set; } + } + + public class Link + { + public Link() + { + this.Labels = new List(); + } + public string Name { get; set; } + public string Href { get; set; } + public List Labels { get; set; } + } + + public class CustomViewBase : ViewPage + { + public CustomMarkdownHelper Ext = new CustomMarkdownHelper(); + public ExternalProductHelper Prod = new ExternalProductHelper(); + + public MvcHtmlString Table(dynamic obj) + { + Person model = obj; + var sb = new StringBuilder(); + + sb.AppendFormat("", model.FirstName); + sb.AppendLine(""); + sb.AppendLine(""); + foreach (var link in model.Links) + { + sb.AppendFormat("", link.Name, link.Href); + } + sb.AppendLine(""); + sb.AppendLine("
      {0}'s Links
      NameLink
      {0}{1}
      "); + + return MvcHtmlString.Create(sb.ToString()); + } + + private static string[] MenuItems = new[] { "About Us", "Blog", "Links", "Contact" }; + + public MvcHtmlString Menu(string selectedId) + { + var sb = new StringBuilder(); + sb.Append("
        \n"); + foreach (var menuItem in MenuItems) + { + var cls = menuItem == selectedId ? " class='selected'" : ""; + sb.AppendFormat("
      • {0}
      • \n", menuItem, cls); + } + sb.Append("
      \n"); + + return MvcHtmlString.Create(sb.ToString()); + } + + public string Lower(string name) + { + return name == null ? null : name.ToLower(); + } + + public string Upper(string name) + { + return name == null ? null : name.ToUpper(); + } + + public string Combine(string separator, params string[] parts) + { + return string.Join(separator, parts); + } + + public override void Execute() + { + throw new NotImplementedException(); + } + } + + public class CustomMarkdownHelper + { + public static CustomMarkdownHelper Instance = new CustomMarkdownHelper(); + + public MvcHtmlString InlineBlock(string content, string id) + { + return MvcHtmlString.Create( + "
      " + content + "
      "); + } + } + + [TestFixture] + public class RazorTemplateTests : RazorTestBase + { + string staticTemplatePath; + string staticTemplateContent; + string dynamicPagePath; + string dynamicPageContent; + string dynamicListPagePath; + string dynamicListPageContent; + + Person templateArgs; + + 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"} }, + }, + }; + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + + staticTemplatePath = "Views/Shared/_Layout.cshtml"; + staticTemplateContent = File.ReadAllText("~/{0}".Fmt(staticTemplatePath).MapProjectPath()); + + dynamicPagePath = "Views/Template/DynamicTpl.cshtml"; + dynamicPageContent = File.ReadAllText("~/{0}".Fmt(dynamicPagePath).MapProjectPath()); + + dynamicListPagePath = "Views/Template/DynamicListTpl.cshtml".MapProjectPath(); + dynamicListPageContent = File.ReadAllText("~/{0}".Fmt(dynamicListPagePath).MapProjectPath()); + + templateArgs = person; + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [SetUp] + public void OnBeforeEachTest() + { + RazorFormat.Instance = null; + base.RazorFormat = new RazorFormat + { + VirtualFileSources = new MemoryVirtualFiles(), + EnableLiveReload = false, + }.Init(); + } + + [Test] + public void Can_Use_HtmlHelper_In_Page() + { + const string pageSource = "@Html.TextBox(\"textBox\")"; + var page = RazorFormat.CreatePage(pageSource); + + var output = RazorFormat.RenderToHtml(page, model: templateArgs); + + Assert.That(output, Is.EqualTo(@"")); + } + + [Test] + public void Can_Use_Model_Directive_With_HtmlHelper() + { + string pageSource = "@model " + typeof(Person).FullName + @" +@Html.TextBoxFor(a => a.FirstName)"; + + var page = RazorFormat.CreatePage(pageSource); + var output = RazorFormat.RenderToHtml(page, model: templateArgs); + + Assert.That(output, Is.EqualTo(@"")); + } + + [Test] + public void Can_Access_ViewData() + { + const string val = "Hello"; + const string pageSource = @"@{ Html.ViewData[""X""] = """ + val + @"""; } +@Html.ViewData[""X""] +"; + + var page = RazorFormat.CreatePage(pageSource); + var output = RazorFormat.RenderToHtml(page, model: templateArgs).Trim(); + + Assert.That(output, Is.EqualTo(val)); + } + + [Test] + public void Can_Access_ViewBag_From_Layout() + { + const string val = "Hello"; + const string pageSource = @"@{ ViewBag.X = """ + val + @"""; }@ViewBag.X"; + + var page = RazorFormat.CreatePage(pageSource); + RazorFormat.AddFileAndPage(staticTemplatePath, @"@ViewBag.X@RenderBody()"); + var output = RazorFormat.RenderToHtml(page, model: templateArgs).Trim(); + + Assert.That(output, Is.EqualTo(@"HelloHello")); + } + + [Test] + public void Can_Render_RazorTemplate() + { + const string mockContents = "[Replaced with Template]"; + + RazorFormat.AddFileAndPage(staticTemplatePath, staticTemplateContent); + var page = RazorFormat.CreatePage(mockContents); + + var expectedHtml = staticTemplateContent.ReplaceFirst(RazorFormat.TemplatePlaceHolder, mockContents); + + var templateOutput = RazorFormat.RenderToHtml(page, model: templateArgs); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_RazorPage() + { + RazorFormat.AddFileAndPage(staticTemplatePath, staticTemplateContent); + var dynamicPage = RazorFormat.AddFileAndPage(dynamicPagePath, dynamicPageContent); + + var expectedHtml = dynamicPageContent + .Replace("@Model.FirstName", person.FirstName) + .Replace("@Model.LastName", person.LastName); + + expectedHtml = staticTemplateContent.Replace(RazorFormat.TemplatePlaceHolder, expectedHtml); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_RazorPage_with_foreach() + { + RazorFormat.AddFileAndPage(staticTemplatePath, staticTemplateContent); + var dynamicPage = RazorFormat.AddFileAndPage(dynamicListPagePath, dynamicListPageContent); + + var expectedHtml = dynamicListPageContent + .Replace("@Model.FirstName", person.FirstName) + .Replace("@Model.LastName", person.LastName); + + var foreachLinks = "
    • ServiceStack - http://www.servicestack.net
    • \r\n" + + "
    • AjaxStack - http://www.ajaxstack.com
    • "; + + expectedHtml = expectedHtml.ReplaceForeach(foreachLinks); + + expectedHtml = staticTemplateContent.Replace(RazorFormat.TemplatePlaceHolder, expectedHtml); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_RazorPage_with_IF_statement() + { + var template = @"

      Dynamic If Markdown Template

      + +

      Hello @Model.FirstName,

      + +
        +@if (Model.FirstName == ""Bellot"") { +
      • @Model.FirstName
      • +} +@if (Model.LastName == ""Bellot"") { +
      • @Model.LastName
      • +} +
      + +

      heading 3

      "; + + var expectedHtml = @"

      Dynamic If Markdown Template

      + +

      Hello Demis,

      + +
        +
      • Bellot
      • +
      + +

      heading 3

      "; + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_RazorPage_with_Nested_Statements() + { + var template = @"

      @Model.FirstName Dynamic Nested Markdown Template

      + +

      heading 1

      + +
        +@foreach (var link in Model.Links) { + if (link.Name == ""AjaxStack"") { +
      • @link.Name - @link.Href
      • + } +} +
      + +@if (Model.Links.Count == 2) { +

      Haz 2 links

      +
        + @foreach (var link in Model.Links) { +
      • @link.Name - @link.Href
      • + foreach (var label in link.Labels) { +
      • @label
      • + } + } +
      +} + +

      heading 3

      "; + + var expectedHtml = @"

      Demis Dynamic Nested Markdown Template

      + +

      heading 1

      + +
        +
      • AjaxStack - http://www.ajaxstack.com
      • +
      + +

      Haz 2 links

      +
        +
      • ServiceStack - http://www.servicestack.net
      • +
      • REST
      • +
      • JSON
      • +
      • XML
      • +
      • AjaxStack - http://www.ajaxstack.com
      • +
      • HTML5
      • +
      • AJAX
      • +
      • SPA
      • +
      + +

      heading 3

      "; + + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_Razor_with_StaticMethods() + { + var headerTemplate = @"

      Header Links!

      +".NormalizeNewLines(); + + var template = @"

      Welcome to Razor!

      + +@Html.Partial(""HeaderLinks"", Model) + +

      Hello @Upper(Model.LastName), @Model.FirstName

      + +

      Breadcrumbs

      + +@Combine("" / "", Model.FirstName, Model.LastName) + +

      Menus

      +
        +@foreach (var link in Model.Links) { +
      • @link.Name - @link.Href +
          + @foreach (var label in link.Labels) { +
        • @label
        • + } +
        +
      • +} +
      + +

      HTML Table

      +@Table(Model)".NormalizeNewLines(); + + var expectedHtml = @"

      Welcome to Razor!

      + +

      Header Links!

      + + +

      Hello BELLOT, Demis

      + +

      Breadcrumbs

      + +Demis / Bellot + +

      Menus

      +
        +
      • ServiceStack - http://www.servicestack.net +
          +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • AjaxStack - http://www.ajaxstack.com +
          +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      + +

      HTML Table

      + + + +
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      +".NormalizeNewLines(); + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + RazorFormat.AddFileAndPage("/views/HeaderLinks.cshtml", headerTemplate); + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_inherit_from_Generic_RazorViewPage_from_model_directive() + { + var template = @"@model ServiceStack.ServiceHost.Tests.Formats_Razor.Person +

      Generic View Page

      + +

      Form fields

      +@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) +"; + + var expectedHtml = @"

      Generic View Page

      + +

      Form fields

      + +".NormalizeNewLines(); + + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_inherit_from_CustomViewPage_using_inherits_directive() + { + var template = @"@inherits ServiceStack.ServiceHost.Tests.Formats_Razor.CustomViewBase +

      Generic View Page

      + +

      Form fields

      +@Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) + +

      Person Table

      +@Table(Model)"; + + var expectedHtml = @"

      Generic View Page

      + +

      Form fields

      + + +

      Person Table

      + + + +
      Demis's Links
      NameLink
      ServiceStackhttp://www.servicestack.net
      AjaxStackhttp://www.ajaxstack.com
      +".NormalizeNewLines(); + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Can_Render_RazorPage_with_external_helper() + { + var template = @"

      View Page with Custom Helper

      + +

      External Helper

      + +@Ext.InlineBlock(Model.FirstName, ""first-name"") +"; + + var expectedHtml = + @"

      View Page with Custom Helper

      + +

      External Helper

      + +
      Demis
      +".NormalizeNewLines(); + + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_RazorPage_with_variable_statements() + { + var template = @"

      Welcome to Razor!

      + +@{ var lastName = Model.LastName; } +Hello @Upper(lastName), @Model.FirstName + +

      Breadcrumbs

      +@Combine("" / "", Model.FirstName, lastName) + +@{ var links = Model.Links; } +

      Menus

      +
        +@foreach (var link in links) { +
      • @link.Name - @link.Href +
          + @{ var labels = link.Labels; } + @foreach (var label in labels) { +
        • @label
        • + } +
        +
      • +} +
      "; + + var expectedHtml = @"

      Welcome to Razor!

      + + +Hello BELLOT, Demis + +

      Breadcrumbs

      +Demis / Bellot + + +

      Menus

      +
        +
      • ServiceStack - http://www.servicestack.net +
          + +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • AjaxStack - http://www.ajaxstack.com +
          + +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      ".NormalizeNewLines(); + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Can_Render_RazorPage_with_comments() + { + var template = @"

      Dynamic If Markdown Template

      + +

      Hello @Model.FirstName,

      + +@if (Model.FirstName == ""Bellot"") { +
        +
      • @Model.FirstName
      • +
      +} +@* +@if (Model.LastName == ""Bellot"") { + * @Model.LastName +} +*@ + +@* +Plain text in a comment +*@ +

      heading 3

      "; + + var expectedHtml = @"

      Dynamic If Markdown Template

      + +

      Hello Demis,

      + +

      heading 3

      ".NormalizeNewLines(); + + var dynamicPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + + [Test] + public void Can_capture_Section_statements_and_store_them_in_Sections() + { + var template = @"

      Welcome to Razor!

      + +@{ var lastName = Model.LastName; } +@section Salutations { +

      Hello @Upper(lastName), @Model.FirstName

      +} + +@section Breadcrumbs { +

      Breadcrumbs

      +

      @Combine("" / "", Model.FirstName, lastName)

      +} + +@{ var links = Model.Links; } +@section Menus { +

      Menus

      +
        +@foreach (var link in links) { +
      • @link.Name - @link.Href +
          + @{ var labels = link.Labels; } + @foreach (var label in labels) { +
        • @label
        • + } +
        +
      • +} +
      +} + +

      Captured Sections

      + + + +@RenderSection(""Menus"") + +

      Salutations

      +@RenderSection(""Salutations"")"; + + var expectedHtml = + @"

      Welcome to Razor!

      + + + + + + +

      Captured Sections

      + + + + +

      Menus

      +
        +
      • ServiceStack - http://www.servicestack.net +
          + +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • AjaxStack - http://www.ajaxstack.com +
          + +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      + + +

      Salutations

      + +

      Hello BELLOT, Demis

      +".NormalizeNewLines(); + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + var dynamicPage = RazorFormat.CreatePage(template); + + IRazorView razorView; + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, out razorView, model: templateArgs).NormalizeNewLines(); + + Assert.That(templateOutput.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + + var sectionHtml = razorView.RenderSectionToHtml("Salutations"); + Assert.That(sectionHtml.NormalizeNewLines(), Is.EqualTo("

      Hello BELLOT, Demis

      ")); + } + + + [Test] + public void Can_Render_RazorTemplate_with_section_and_variable_placeholders() + { + var template = @"

      Welcome to Razor!

      + +@{ var lastName = Model.LastName; } + +

      Hello @Upper(lastName), @Model.FirstName,

      + +@section Breadcrumbs { +

      Breadcrumbs

      +@Combine("" / "", Model.FirstName, lastName) +} + +@section Menus { +

      Menus

      +
        +@foreach (var link in Model.Links) { +
      • @link.Name - @link.Href +
          + @{ var labels = link.Labels; } + @foreach (var label in labels) { +
        • @label
        • + } +
        +
      • +} +
      +}"; + var websiteTemplatePath = "websiteTemplate.cshtml"; + + var websiteTemplate = @" + + + Bellot page + + + +
      + @RenderSection(""Menus"") +
      + +

      Website Template

      + +
      @RenderBody()
      + +
      + @RenderSection(""Breadcrumbs"") +
      + + +"; + + var expectedHtml = + @" + + + Bellot page + + + +
      + +

      Menus

      +
        +
      • ServiceStack - http://www.servicestack.net +
          + +
        • REST
        • +
        • JSON
        • +
        • XML
        • +
        +
      • +
      • AjaxStack - http://www.ajaxstack.com +
          + +
        • HTML5
        • +
        • AJAX
        • +
        • SPA
        • +
        +
      • +
      + +
      + +

      Website Template

      + +

      Welcome to Razor!

      + + + +

      Hello BELLOT, Demis,

      + + +
      + +
      + +

      Breadcrumbs

      +Demis / Bellot + +
      + + +".NormalizeNewLines(); + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + RazorFormat.AddFileAndPage("/views/{0}".Fmt(websiteTemplatePath), websiteTemplate); + var page = RazorFormat.CreatePage(template); + + var result = RazorFormat.RenderToHtml(page, model: person, layout: websiteTemplatePath); + + var templateOutput = result.NormalizeNewLines(); + + Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + } + + [Test] + public void Can_Render_Static_RazorContentPage_that_populates_variable_and_displayed_on_website_template() + { + + var websiteTemplate = @" + + + Static page + + +
      + @RenderSection(""Header"") +
      + + + +

      Website Template

      + +
      @RenderBody()
      + + +".NormalizeNewLines(); + + var template = @"

      Static Markdown Template

      +@section Menu { + @Menu(""Links"") +} + +@section Header { +

      Static Page Title

      +} + +

      heading 3

      +

      paragraph

      "; + + var expectedHtml = @" + + + Static page + + +
      + +

      Static Page Title

      + +
      + + + +

      Website Template

      + +

      Static Markdown Template

      + + +

      heading 3

      +

      paragraph

      + + +".NormalizeNewLines(); + + RazorFormat.PageBaseType = typeof(CustomViewBase<>); + + var websiteTemplatePath = "/views/websiteTemplate.cshtml"; + RazorFormat.AddFileAndPage(websiteTemplatePath, websiteTemplate); + + var staticPage = RazorFormat.CreatePage(template); + + var templateOutput = RazorFormat.RenderToHtml(staticPage, layout: "websiteTemplate").NormalizeNewLines(); + + 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/HttpRequestMock.cs b/tests/ServiceStack.ServiceHost.Tests/HttpRequestMock.cs new file mode 100644 index 00000000000..41302e8869d --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/HttpRequestMock.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ServiceStack.Web; + +namespace ServiceStack.ServiceHost.Tests +{ + 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 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 string Accept + { + 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[] AcceptTypes + { + get { throw new NotImplementedException(); } + } + + public string PathInfo + { + get { return "index.html"; } + } + + public string OriginalPathInfo => PathInfo; + + public System.IO.Stream InputStream + { + get { throw new NotImplementedException(); } + } + + public long ContentLength + { + get { throw new NotImplementedException(); } + } + + public IHttpFile[] Files + { + get { throw new NotImplementedException(); } + } + + public string ApplicationFilePath + { + get { return "~".MapAbsolutePath(); } + } + + public T TryResolve() + { + throw new NotImplementedException(); + } + + public Uri UrlReferrer + { + get { throw new NotImplementedException(); } + } + } +} diff --git a/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs b/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs index 800d271110b..68adaf07af4 100644 --- a/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs @@ -1,67 +1,359 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; -using ServiceStack.ServiceHost.Tests.Support; -using Funq; - -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)); - } - } -} +using System; +using System.Collections.Generic; +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)); + } + + public class DependencyWithBuiltInTypes + { + public DependencyWithBuiltInTypes() + { + this.String = "A String"; + this.Age = 27; + } + + public IFoo Foo { get; set; } + public IBar Bar { get; set; } + public string String { get; set; } + public int Age { get; set; } + } + + [Test] + public void Does_not_AutoWire_BuiltIn_BCL_and_ValueTypes() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + + //Should not be autowired + container.Register(c => "Replaced String"); + container.Register(c => 99); + + container.RegisterAutoWired(); + + 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 176ae49934b..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.Register(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 c7312a000ad..d2f2b3917af 100644 --- a/tests/ServiceStack.ServiceHost.Tests/RequestContextExtensionsTest.cs +++ b/tests/ServiceStack.ServiceHost.Tests/RequestContextExtensionsTest.cs @@ -1,65 +1,59 @@ -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 NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests { [TestFixture] public class RequestContextExtensionsTest - { - [Test] - public void Can_optimize_html_result_with_ToOptimizedResult() - { - CanOptimizeResult("text/html", new HtmlFormat()); - } - - [Test] - public void Can_optimize_csv_result_with_ToOptimizedResult() - { - CanOptimizeResult("text/csv", new CsvFormat()); - } - - [Test] - public void Can_optimize_json_result_with_ToOptimizedResult() - { - CanOptimizeResult(ContentType.Json, null); - } - - [Test] - public void Can_optimize_xml_result_with_ToOptimizedResult() - { - CanOptimizeResult(ContentType.Xml, null); - } - - [Test] - public void Can_optimize_jsv_result_with_ToOptimizedResult() - { - CanOptimizeResult(ContentType.Jsv, null); - } - - private static void CanOptimizeResult(string contentType, IPlugin pluginFormat) - { - var dto = new TestDto {Name = "test"}; - - var httpReq = new MockHttpRequest(); - 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); - Assert.IsNotNull(result); - Assert.IsTrue(result is CompressedResult); - } + { + [Test] + public void Can_optimize_html_result_with_ToOptimizedResult() + { + CanOptimizeResult("text/html", new HtmlFormat()); + } + + [Test] + public void Can_optimize_csv_result_with_ToOptimizedResult() + { + CanOptimizeResult("text/csv", new CsvFormat()); + } + + [Test] + public void Can_optimize_json_result_with_ToOptimizedResult() + { + CanOptimizeResult(MimeTypes.Json, null); + } + + [Test] + public void Can_optimize_xml_result_with_ToOptimizedResult() + { + CanOptimizeResult(MimeTypes.Xml, null); + } + + [Test] + public void Can_optimize_jsv_result_with_ToOptimizedResult() + { + CanOptimizeResult(MimeTypes.Jsv, null); + } + + private static void CanOptimizeResult(string contentType, IPlugin pluginFormat) + { + using var appHost = new BasicAppHost().Init(); + var dto = new TestDto { Name = "test" }; + + var httpReq = new MockHttpRequest { + PathInfo = "/" + }; + httpReq.Headers.Add(HttpHeaders.AcceptEncoding, "gzip,deflate,sdch"); + httpReq.ResponseContentType = contentType; + + if (pluginFormat != null) pluginFormat.Register(appHost); + + object result = httpReq.ToOptimizedResult(dto); + Assert.IsNotNull(result); + Assert.IsTrue(result is CompressedResult); + } public class TestDto { diff --git a/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs b/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs index 1531ad62c59..dbcb8c83ab1 100644 --- a/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs @@ -1,195 +1,499 @@ -using System; -using NUnit.Framework; -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 BbcMusicRequest - { - public Guid mbz_guid { get; set; } - - public string release_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); - - var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); - Assert.That(restPath.IsMatch("GET", reqestTestPath), Is.True); - - Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); - - 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)); - } - - [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}/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", - "4/music", - 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", - "5/music", - new BbcMusicRequest { mbz_guid = mbz, release_type = "albums", content_type = "json" }); - } - - public class RackSpaceRequest - { - public string version { get; set; } - - public string id { get; set; } - - public string resource_type { get; set; } - - public string action { 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); - - var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); - Assert.That(restPath.IsMatch("GET", reqestTestPath), Is.True); - - Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); - - 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)); - } - - [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.{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", - "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{}); - } - - } +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.ServiceHost.Tests +{ + [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}"); + var request = restPath.CreateRequest( + "/complex/5/Is Alive/unique/4583B364-BBDC-427F-A289-C2923DEBD547") as ComplexTypeWithFields; + + 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 BbcMusicRequest + { + public Guid mbz_guid { get; set; } + + public string release_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); + + var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); + Assert.That(restPath.IsMatch("GET", reqestTestPath, out _), Is.True); + + Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); + + 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)); + } + + [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}/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", + "4/music", + 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", + "5/music", + new BbcMusicRequest { mbz_guid = mbz, release_type = "albums", content_type = "json" }); + } + + public class RackSpaceRequest + { + public string version { get; set; } + + public string id { get; set; } + + public string resource_type { get; set; } + + public string action { 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); + + var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); + Assert.That(restPath.IsMatch("GET", reqestTestPath, out _), Is.True); + + Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); + + 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)); + } + + [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.{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", + "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 { }); + } + + 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 e3dfbaa43b7..ed74c0c61f7 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Routes/ServiceRoutesTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Routes/ServiceRoutesTests.cs @@ -1,66 +1,115 @@ -using System.Linq; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.ServiceHost.Tests.Routes -{ - [TestFixture] - public class ServiceRoutesTests - { - [Test] - public void Can_Register_Routes_From_Assembly() - { - var routes = new ServiceRoutes(); - routes.AddFromAssembly(typeof(RestServiceWithAllVerbsImplemented).Assembly); - - RestPath restWithAllMethodsRoute = - (from r in routes.RestPaths - where r.Path == "RequestDto2" - 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")); - } - - [Test] - public void Can_Register_Routes_With_Partially_Implemented_REST_Verbs() - { - var routes = new ServiceRoutes(); - routes.AddFromAssembly(typeof(RestServiceWithSomeVerbsImplemented).Assembly); - - RestPath restWithAFewMethodsRoute = - (from r in routes.RestPaths - where r.Path == "RequestDto" - select r).FirstOrDefault(); - - Assert.That(restWithAFewMethodsRoute, Is.Not.Null); - - 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); - } - - [Test] - public void Can_Register_Routes_Using_Add_Extension() - { - var routes = new ServiceRoutes(); - 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}"); - } - } - - public class Customer - { - public string Name { get; set; } - public int OrderId { get; set; } - } +using System.Linq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; + +namespace ServiceStack.ServiceHost.Tests.Routes +{ + [TestFixture] + public class ServiceRoutesTests + { + ServiceStackHost appHost; + + [SetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [TearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_Register_NewApi_Routes_From_Assembly() + { + var routes = new ServiceRoutes(appHost); + routes.AddFromAssembly(typeof(NewApiRestServiceWithAllVerbsImplemented).Assembly); + + RestPath restWithAllMethodsRoute = + (from r in appHost.RestPaths + where r.Path == "/NewApiRequestDto" + 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")); + + RestPath restWithAllMethodsRoute2 = + (from r in appHost.RestPaths + where r.Path == "/NewApiRequestDto2" + select r).FirstOrDefault(); + + Assert.That(restWithAllMethodsRoute2, Is.Not.Null); + + Assert.That(restWithAllMethodsRoute2.AllowedVerbs.Contains("GET")); + Assert.That(restWithAllMethodsRoute2.AllowedVerbs.Contains("POST")); + Assert.That(restWithAllMethodsRoute2.AllowedVerbs.Contains("PUT")); + Assert.That(restWithAllMethodsRoute2.AllowedVerbs.Contains("DELETE")); + Assert.That(restWithAllMethodsRoute2.AllowedVerbs.Contains("PATCH")); + } + + [Test] + public void Can_Register_NewApi_Routes_With_Id_and_Any_Fallback_From_Assembly() + { + var routes = new ServiceRoutes(appHost); + routes.AddFromAssembly(typeof(NewApiRequestDtoWithIdService).Assembly); + + 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 appHost.RestPaths + where r.Path == "/NewApiRequestDtoWithId/{Id}" + select r).FirstOrDefault(); + + Assert.That(route, Is.Not.Null); + 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(appHost); + routes.AddFromAssembly(typeof(NewApiRequestDtoWithFieldIdService).Assembly); + + var route = (from r in appHost.RestPaths + where r.Path == "/NewApiRequestDtoWithFieldId" + select r).FirstOrDefault(); + + Assert.That(route, Is.Not.Null); + Assert.That(route.AllowedVerbs, Is.Null); + + route = (from r in appHost.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_Routes_Using_Add_Extension() + { + var routes = new ServiceRoutes(appHost); + routes.Add("/Users/{0}/Orders/{1}", ApplyTo.Get, x => x.Name, x => x.OrderId); + var route = appHost.RestPaths.Last(); + Assert.That(route.Path, Is.EqualTo("/Users/{Name}/Orders/{OrderId}")); + } + } + + public class Customer + { + public string Name { get; set; } + public int OrderId { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs b/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs index 7676bc6d4f6..2d6927205cd 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs @@ -1,57 +1,105 @@ using System.Net; -using ServiceStack.Common.Web; -using ServiceStack.ServiceInterface; +using ServiceStack.Web; namespace ServiceStack.ServiceHost.Tests.Routes { - public class RequestDto + public class NewApiRequestDto { public string Name { get; set; } } - public class RestServiceWithSomeVerbsImplemented : RestServiceBase + public class NewApiRequestDto2 { - public override object OnGet(RequestDto request) + public string Name { get; set; } + } + + public class NewApiRestServiceWithAllVerbsImplemented : IService + { + public object Get(NewApiRequestDto request) { return new HttpResult { StatusCode = HttpStatusCode.OK }; } - public override object OnPut(RequestDto request) + public object Put(NewApiRequestDto request) { return new HttpResult { StatusCode = HttpStatusCode.OK }; } - } - - public class RequestDto2 - { - public string Name { get; set; } - } - - public class RestServiceWithAllVerbsImplemented : RestServiceBase - { - public override object OnGet(RequestDto2 request) + + public object Post(NewApiRequestDto request) { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnPut(RequestDto2 request) + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Delete(NewApiRequestDto request) { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnPost(RequestDto2 request) + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Patch(NewApiRequestDto request) { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnDelete(RequestDto2 request) + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Get(NewApiRequestDto2 request) { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnPatch(RequestDto2 request) + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Put(NewApiRequestDto2 request) + { + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Post(NewApiRequestDto2 request) + { + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Delete(NewApiRequestDto2 request) { - return new HttpResult {StatusCode = HttpStatusCode.OK}; + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Patch(NewApiRequestDto2 request) + { + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + } + + public class NewApiRequestDtoWithId + { + public int Id { get; set; } + } + + public class NewApiRequestDtoWithIdService : IService + { + public object Get(NewApiRequestDtoWithId request) + { + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Any(NewApiRequestDtoWithId 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 199e525f3a8..77244c650d0 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceControllerTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceControllerTests.cs @@ -1,125 +1,173 @@ -using NUnit.Framework; +using System; +using Funq; +using NUnit.Framework; +using ServiceStack.Host; using ServiceStack.ServiceHost.Tests.Support; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests { - [TestFixture] - public class ServiceControllerTests - { - [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; - - var request = new AutoWire(); - - var response = serviceController.Execute(request) as AutoWireResponse; + [TestFixture] + public class ServiceControllerTests + { + [Test] + public void Can_register_all_services_in_an_assembly() + { + using (var appHost = new BasicAppHost(typeof(BasicService).Assembly).Init()) + { + var container = appHost.Container; + var serviceController = appHost.ServiceController; - Assert.That(response, Is.Not.Null); - } + container.Register(c => new Foo()); + container.Register(c => new Bar()); - [Test] - public void Can_override_service_creation_with_custom_implementation() - { - var serviceManager = new ServiceManager(typeof(BasicService).Assembly); - serviceManager.Init(); + var request = new AutoWire(); + var response = serviceController.Execute(request) as AutoWireResponse; - var container = serviceManager.Container; - container.Register(c => new Foo()); - container.Register(c => new Bar()); + Assert.That(response, Is.Not.Null); + } + } - var serviceController = serviceManager.ServiceController; + [Test] + public void Can_override_service_creation_with_custom_implementation() + { + 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(); - Assert.That(response, Is.Not.Null); - Assert.That(response.Foo as Foo, Is.Not.Null); - Assert.That(response.Bar as Bar, Is.Not.Null); + var response = serviceController.Execute(request) as AutoWireResponse; - container.Register(c => - new AutoWireService(new Foo2()) { - Bar = new Bar2() - }); + Assert.That(response, Is.Not.Null); + Assert.That(response.Foo as Foo, Is.Not.Null); + Assert.That(response.Bar as Bar, Is.Not.Null); - response = serviceController.Execute(request) as AutoWireResponse; + container.Register(c => new AutoWireService(new Foo2()) + { + Bar = new Bar2() + }); - Assert.That(response, Is.Not.Null); - Assert.That(response.Foo as Foo2, Is.Not.Null); - Assert.That(response.Bar as Bar2, Is.Not.Null); - } + response = serviceController.Execute(request) as AutoWireResponse; - [Test] - public void Can_inject_RequestContext_for_IRequiresRequestContext_services() - { - var serviceManager = new ServiceManager(typeof(RequiresContextService).Assembly); - serviceManager.Init(); + Assert.That(response, Is.Not.Null); + Assert.That(response.Foo as Foo2, Is.Not.Null); + Assert.That(response.Bar as Bar2, Is.Not.Null); + } + } - var serviceController = serviceManager.ServiceController; + [Test] + public void Can_inject_RequestContext_for_IRequiresRequestContext_services() + { + 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 + { + 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()) { - 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); + var serviceController = appHost.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); + } + } + + [Test] + public void Service_with_generic_IGet_marker_interface_can_be_registered_without_DefaultRequestAttribute() + { + var appHost = new AppHost(); + appHost.ServiceController = new ServiceController(appHost); + + Assert.That(appHost.RestPaths.Count, Is.EqualTo(0)); + + appHost.RegisterService("/route"); + + Assert.That(appHost.RestPaths.Count, Is.EqualTo(1)); + } + } + + public class GetRequest { } + + public class GetRequestResponse { } + + [DefaultRequest(typeof(GetRequest))] + public class GetMarkerService : Service + { + public object Get(GetRequest request) + { + return new GetRequestResponse(); + } + } + + public class AppHost : AppHostHttpListenerBase + { + 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 46dee685df9..6be24229f82 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceCreationTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceCreationTests.cs @@ -1,98 +1,126 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.Endpoints.Support; -using System.Collections; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.ServiceInterface.Validation; -using Funq; -using ServiceStack.ServiceInterface; -using ServiceStack.FluentValidation; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; - -namespace ServiceStack.ServiceHost.Tests -{ - [RestService("/notsingleton")] - public class ServiceCreation - { - public bool RequestFilterExecuted { get; set; } - public bool ContextualRequestFilterExecuted { get; set; } - public bool RequestFilterDependenyIsResolved { get; set; } - } - public class ServiceCreationResponse - { - public int RequestCount { get; set; } - } - - public class ServiceCreationService : IService - { - public int RequestCounter = 0; - - public object Execute(ServiceCreation request) - { - this.RequestCounter++; - return new ServiceCreationResponse() - { - RequestCount = this.RequestCounter - }; - } - } - - [TestFixture] - public class ServiceCreationTest - { - private const string ListeningOn = "http://localhost:82/"; - private const string ServiceClientBaseUri = "http://localhost:82/"; - - public class AttributeFiltersAppHostHttpListener - : AppHostHttpListenerBase - { - - public AttributeFiltersAppHostHttpListener() - : base("Service Creation Tests", typeof(ServiceCreationService).Assembly) { } - - public override void Configure(Funq.Container container) - { - container.Register(new MemoryCacheClient()); - } - } - - AttributeFiltersAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new AttributeFiltersAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - protected static IRestClient[] RestClients = - { - new JsonServiceClient(ServiceClientBaseUri), - new XmlServiceClient(ServiceClientBaseUri), - new JsvServiceClient(ServiceClientBaseUri) - }; - - [Test, TestCaseSource("RestClients")] - public void Service_is_not_singleton(IRestClient client) - { - for (int i = 0; i < 5; i++) - { - var response = client.Post("notsingleton", new ServiceCreation() { }); - Assert.That(response.RequestCount, Is.EqualTo(1)); - } - } - } -} +using NUnit.Framework; +using ServiceStack.Caching; +using Funq; + +namespace ServiceStack.ServiceHost.Tests +{ + [Route("/notsingleton")] + public class ServiceCreation + { + public bool RequestFilterExecuted { get; set; } + public bool ContextualRequestFilterExecuted { get; set; } + public bool RequestFilterDependenyIsResolved { get; set; } + } + public class ServiceCreationResponse + { + public int RequestCount { get; set; } + } + + public class ServiceCreationService : Service + { + public int RequestCounter = 0; + + public object Any(ServiceCreation request) + { + this.RequestCounter++; + return new ServiceCreationResponse() + { + RequestCount = this.RequestCounter + }; + } + } + + [TestFixture] + public class ServiceCreationTest + { + private const string ListeningOn = "http://localhost:82/"; + private const string ServiceClientBaseUri = "http://localhost:82/"; + + public class AttributeFiltersAppHostHttpListener + : AppHostHttpListenerBase + { + + public AttributeFiltersAppHostHttpListener() + : base("Service Creation Tests", typeof(ServiceCreationService).Assembly) { } + + public override void Configure(Funq.Container container) + { + container.Register(new MemoryCacheClient()); + } + } + + AttributeFiltersAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new AttributeFiltersAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + protected static IRestClient[] RestClients = + { + new JsonServiceClient(ServiceClientBaseUri), + new XmlServiceClient(ServiceClientBaseUri), + new JsvServiceClient(ServiceClientBaseUri) + }; + + [Test, TestCaseSource("RestClients")] + public void Service_is_not_singleton(IRestClient client) + { + for (int i = 0; i < 5; i++) + { + var response = client.Post("notsingleton", new ServiceCreation() { }); + Assert.That(response.RequestCount, Is.EqualTo(1)); + } + } + + public class Foo + { + public static int GlobalId = 0; + public int Id { get; set; } + + public Foo() + { + this.Id = GlobalId++; + } + } + + [Test] + public void Funq_is_singleton_by_Default() + { + Foo.GlobalId = 0; + var container = new Container(); + container.Register(c => new Foo()); + + var foo = container.Resolve(); + Assert.That(foo.Id, Is.EqualTo(0)); + foo = container.Resolve(); + Assert.That(foo.Id, Is.EqualTo(0)); + foo = container.Resolve(); + Assert.That(foo.Id, Is.EqualTo(0)); + } + + [Test] + public void Funq_does_transient_scope() + { + Foo.GlobalId = 0; + var container = new Container(); + container.Register(c => new Foo()).ReusedWithin(ReuseScope.None); + + var foo = container.Resolve(); + Assert.That(foo.Id, Is.EqualTo(0)); + foo = container.Resolve(); + Assert.That(foo.Id, Is.EqualTo(1)); + foo = container.Resolve(); + Assert.That(foo.Id, Is.EqualTo(2)); + } + } +} diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceHostTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceHostTests.cs index 26a57c83546..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.ServiceHost.Tests.Support; -using ServiceStack.ServiceHost.Tests.TypeFactory; -using ServiceStack.Text; -using ServiceStack.Text.Common; - -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")); - } - } -} +using System; +using Funq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.ServiceHost.Tests.Support; +using ServiceStack.ServiceHost.Tests.TypeFactory; +using ServiceStack.Testing; + +namespace ServiceStack.ServiceHost.Tests +{ + [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 3d9d97c123d..7f4b8451c56 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj @@ -1,255 +1,291 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {94A33BC4-AC22-49A3-A38E-2ABFCD997ABA} - Library - Properties - ServiceStack.ServiceHost.Tests - ServiceStack.ServiceHost.Tests - 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 - True - - - 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.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - - - ..\..\lib\ServiceStack.Text.dll - - - - 3.5 - - - 3.0 - - - - 3.5 - - - 3.5 - - - - - ..\..\lib\tests\nunit.framework.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sqlite3.dll - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - {64128C85-B9AF-4B4C-BE83-04983EF7F8C9} - ServiceStack.Razor - - - {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 - - - - - - - - - - - - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {94A33BC4-AC22-49A3-A38E-2ABFCD997ABA} + Library + Properties + ServiceStack.ServiceHost.Tests + ServiceStack.ServiceHost.Tests + 512 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + ..\..\src\ + true + v4.7.2 + + + + + + True + full + False + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + false + false + + + pdbonly + True + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + false + + + True + bin\STATIC_ONLY NO_EXPRESSIONS\ + DEBUG;TRACE + full + AnyCPU + prompt + 4 + False + AllRules.ruleset + false + + + True + bin\MonoTouch\ + DEBUG;TRACE + full + AnyCPU + prompt + 4 + False + AllRules.ruleset + false + + + bin\Signed\ + TRACE + true + pdbonly + AnyCPU + prompt + AllRules.ruleset + false + + + + + + + + + 3.5 + + + + 3.0 + + + + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416DB-C143-4028-A0C3-CF41892D18D3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {D73274AE-006B-4CEE-BA60-0ECF5873048D} + ServiceStack.Razor + + + {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.ServiceHost.Tests/ServiceStackHandlerPathTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerPathTests.cs index bd8dcc7b7ab..d7427090c1d 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerPathTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerPathTests.cs @@ -1,103 +1,120 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using ServiceStack.Text; - -namespace ServiceStack.ServiceHost.Tests -{ - public class RequestPath - { - public RequestPath(string path, string host, string pathInfo, string rawUrl) - { - Path = path; - Host = host; - PathInfo = pathInfo; - RawUrl = rawUrl; - AbsoluteUri = "http://localhost" + rawUrl; - } - - public string Path { get; set; } - public string Host { get; set; } - public string PathInfo { get; set; } - public string RawUrl { get; set; } - public string AbsoluteUri { get; set; } - } - - [TestFixture] - public class ServiceStackHandlerPathTests - { - public string ResolvePath(string mode, string path) - { - return WebHost.Endpoints.Extensions.HttpRequestExtensions. - GetPathInfo(path, mode, path.Split('/').First(x => x != "")); - } - - [Test] - public void Can_resolve_root_path() - { - var results = new List { - ResolvePath(null, "/handler.all35"), - ResolvePath(null, "/handler.all35/"), - ResolvePath("api", "/location.api.wildcard35/api"), - ResolvePath("api", "/location.api.wildcard35/api/"), - ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack"), - ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack/"), - }; - - Console.WriteLine(results.Dump()); - - Assert.That(results.All(x => x == "/")); - } - - [Test] - public void Can_resolve_metadata_paths() - { - var results = new List { - ResolvePath(null, "/handler.all35/metadata"), - ResolvePath(null, "/handler.all35/metadata/"), - ResolvePath("api", "/location.api.wildcard35/api/metadata"), - ResolvePath("api", "/location.api.wildcard35/api/metadata/"), - ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack/metadata"), - ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack/metadata/"), - }; - - Console.WriteLine(results.Dump()); - - Assert.That(results.All(x => x == "/metadata")); - } - - [Test] - public void Can_resolve_metadata_json_paths() - { - var results = new List { - ResolvePath(null, "/handler.all35/json/metadata"), - ResolvePath(null, "/handler.all35/json/metadata/"), - ResolvePath("api", "/location.api.wildcard35/api/json/metadata"), - ResolvePath("api", "/location.api.wildcard35/api/json/metadata/"), - ResolvePath("servicestack", "/location.api.wildcard35/servicestack/json/metadata"), - ResolvePath("servicestack", "/location.api.wildcard35/servicestack/json/metadata/"), - }; - - Console.WriteLine(results.Dump()); - - Assert.That(results.All(x => x == "/json/metadata")); - } - - [Test] - public void Can_resolve_paths_with_multipart_root() - { - var results = new List { - WebHost.Endpoints.Extensions.HttpRequestExtensions.GetPathInfo("/api/foo/metadata", "api/foo", "api"), - WebHost.Endpoints.Extensions.HttpRequestExtensions.GetPathInfo("/api/foo/1.0/wildcard/metadata", "api/foo/1.0/wildcard", "api"), - WebHost.Endpoints.Extensions.HttpRequestExtensions.GetPathInfo("/location.api.wildcard35/api/foo/metadata", "api/foo", "api"), - WebHost.Endpoints.Extensions.HttpRequestExtensions.GetPathInfo("/this/is/very/nested/metadata", "this/is/very/nested", "api"), - }; - - Console.WriteLine(results.Dump()); - - Assert.That(results.All(x => x == "/metadata")); - } - } - -} +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.ServiceHost.Tests +{ + public class RequestPath + { + public RequestPath(string path, string host, string pathInfo, string rawUrl) + { + Path = path; + Host = host; + PathInfo = pathInfo; + RawUrl = rawUrl; + AbsoluteUri = "http://localhost" + rawUrl; + } + + public string Path { get; set; } + public string Host { get; set; } + public string PathInfo { get; set; } + public string RawUrl { get; set; } + public string AbsoluteUri { get; set; } + } + + [TestFixture] + public class ServiceStackHandlerPathTests + { + public string ResolvePath(string mode, string path) + { + return HttpRequestExtensions. + GetPathInfo(path, mode, path.Split('/').First(x => x != "")); + } + + [Test] + public void Can_resolve_root_path() + { + var results = new List { + ResolvePath(null, "/handler.all35"), + ResolvePath(null, "/handler.all35/"), + ResolvePath("api", "/location.api.wildcard35/api"), + ResolvePath("api", "/location.api.wildcard35/api/"), + ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack"), + ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack/"), + }; + + Console.WriteLine(results.Dump()); + + Assert.That(results.All(x => x == "/")); + } + + [Test] + public void Can_resolve_metadata_paths() + { + var results = new List { + ResolvePath(null, "/handler.all35/metadata"), + ResolvePath("api", "/location.api.wildcard35/api/metadata"), + ResolvePath("servicestack", "/location.servicestack.wildcard35/servicestack/metadata"), + }; + + Console.WriteLine(results.Dump()); + + Assert.That(results.All(x => x == "/metadata")); + } + + [Test] + public void Can_resolve_metadata_json_paths() + { + var results = new List { + ResolvePath(null, "/handler.all35/json/metadata"), + ResolvePath("api", "/location.api.wildcard35/api/json/metadata"), + ResolvePath("servicestack", "/location.api.wildcard35/servicestack/json/metadata"), + }; + + Console.WriteLine(results.Dump()); + + Assert.That(results.All(x => x == "/json/metadata")); + } + + [Test] + public void Can_resolve_paths_with_multipart_root() + { + var results = new List { + HttpRequestExtensions.GetPathInfo("/api/foo/metadata", "api/foo", "api"), + HttpRequestExtensions.GetPathInfo("/api/foo/1.0/wildcard/metadata", "api/foo/1.0/wildcard", "api"), + HttpRequestExtensions.GetPathInfo("/location.api.wildcard35/api/foo/metadata", "api/foo", "api"), + HttpRequestExtensions.GetPathInfo("/this/is/very/nested/metadata", "this/is/very/nested", "api"), + }; + + Console.WriteLine(results.Dump()); + + Assert.That(results.All(x => x == "/metadata")); + } + + [Test] + public void GetPhysicalPath_Honours_WebHostPhysicalPath() + { + using (var appHost = new BasicAppHost + { + ConfigFilter = c => + { + c.WebHostPhysicalPath = "c:/Windows/Temp"; + } + }.Init()) + { + var mock = new HttpRequestMock(); + + string originalPath = appHost.Config.WebHostPhysicalPath; + string path = mock.GetPhysicalPath(); + + var normalizePaths = (Func)(p => p == null ? null : p.Replace('\\', '/')); + + Assert.That(normalizePaths(path), Is.EqualTo(normalizePaths("{0}/{1}".Fmt(originalPath, mock.PathInfo)))); + } + } + } + +} diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerUrlTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerUrlTests.cs index 312efd7946f..7b7de0349cc 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerUrlTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceStackHandlerUrlTests.cs @@ -1,144 +1,159 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Net; -using NUnit.Framework; -using ServiceStack.Text; - -namespace ServiceStack.ServiceHost.Tests -{ - [TestFixture] - public class ServiceStackHandlerUrlTests - { - public static string ResolvePath(string mode, string path) - { - return WebHost.Endpoints.Extensions.HttpRequestExtensions. - GetPathInfo(path, mode, path.Split('/').First(x => x != "")); - } - - public class MockUrlHttpRequest : IHttpRequest - { - public MockUrlHttpRequest() { } - - public MockUrlHttpRequest(string mode, string path, string rawUrl) - { - this.PathInfo = ResolvePath(mode, path); - this.RawUrl = rawUrl; - AbsoluteUri = "http://localhost" + rawUrl; - } - - public object OriginalRequest - { - get { throw new NotImplementedException(); } - } - - public T TryResolve() - { - throw new NotImplementedException(); - } - - public string OperationName { get; private set; } - public string ContentType { get; private set; } - public string HttpMethod { get; private set; } - public string UserAgent { get; set; } - - public IDictionary Cookies { get; private set; } - public string ResponseContentType { get; set; } - public Dictionary Items { get; private set; } - public NameValueCollection Headers { get; private set; } - public NameValueCollection QueryString { get; private set; } - public NameValueCollection FormData { get; private set; } - - public string GetRawBody() - { - throw new NotImplementedException(); - } - - public string RawUrl { get; private set; } - public string AbsoluteUri { get; set; } - public string UserHostAddress { get; private set; } - - public string RemoteIp { get; set; } - - public bool IsSecureConnection { get; private set; } - public string[] AcceptTypes { get; private set; } - public string PathInfo { get; private set; } - public Stream InputStream { get; private set; } - public long ContentLength { get; private set; } - public IFile[] Files { get; private set; } - - public string ApplicationFilePath { get; private set; } - } - - readonly List allResults = new List { - new MockUrlHttpRequest(null, "/handler.all35/json/metadata", "/handler.all35/json/metadata?op=Hello"), - new MockUrlHttpRequest(null, "/handler.all35/json/metadata/", "/handler.all35/json/metadata/?op=Hello"), - }; - - readonly List apiResults = new List { - new MockUrlHttpRequest(null, "/location.api.wildcard35/api/json/metadata", "/location.api.wildcard35/api/json/metadata?op=Hello"), - new MockUrlHttpRequest(null, "/location.api.wildcard35/api/json/metadata/", "/location.api.wildcard35/api/json/metadata/?op=Hello"), - }; - - readonly List serviceStacksResults = new List { - new MockUrlHttpRequest(null, "/location.servicestack.wildcard35/servicestack/json/metadata", "/location.servicestack.wildcard35/servicestack/json/metadata?op=Hello"), - new MockUrlHttpRequest(null, "/location.servicestack.wildcard35/servicestack/json/metadata/", "/location.servicestack.wildcard35/servicestack/json/metadata/?op=Hello"), - }; - - [Test] - public void Does_return_expected_absolute_and_path_urls() - { - var absolutePaths = allResults.ConvertAll(x => x.GetAbsolutePath()); - var pathUrls = allResults.ConvertAll(x => x.GetPathUrl()); - Assert.That(absolutePaths.All(x => x == "/handler.all35/json/metadata")); - Assert.That(pathUrls.All(x => x == "http://localhost/handler.all35/json/metadata")); - - absolutePaths = apiResults.ConvertAll(x => x.GetAbsolutePath()); - pathUrls = apiResults.ConvertAll(x => x.GetPathUrl()); - Assert.That(absolutePaths.All(x => x == "/location.api.wildcard35/api/json/metadata")); - Assert.That(pathUrls.All(x => x == "http://localhost/location.api.wildcard35/api/json/metadata")); - - absolutePaths = serviceStacksResults.ConvertAll(x => x.GetAbsolutePath()); - pathUrls = serviceStacksResults.ConvertAll(x => x.GetPathUrl()); - Assert.That(absolutePaths.All(x => x == "/location.servicestack.wildcard35/servicestack/json/metadata")); - Assert.That(pathUrls.All(x => x == "http://localhost/location.servicestack.wildcard35/servicestack/json/metadata")); - } - - [Test] - public void Does_return_expected_parent_absolute_and_path_urls() - { - var absolutePaths = allResults.ConvertAll(x => x.GetParentAbsolutePath()); - var pathUrls = allResults.ConvertAll(x => x.GetParentPathUrl()); - - Assert.That(absolutePaths.All(x => x == "/handler.all35/json")); - Assert.That(pathUrls.All(x => x == "http://localhost/handler.all35/json")); - - absolutePaths = apiResults.ConvertAll(x => x.GetParentAbsolutePath()); - pathUrls = apiResults.ConvertAll(x => x.GetParentPathUrl()); - Assert.That(absolutePaths.All(x => x == "/location.api.wildcard35/api/json")); - Assert.That(pathUrls.All(x => x == "http://localhost/location.api.wildcard35/api/json")); - - absolutePaths = serviceStacksResults.ConvertAll(x => x.GetParentAbsolutePath()); - pathUrls = serviceStacksResults.ConvertAll(x => x.GetParentPathUrl()); - Assert.That(absolutePaths.All(x => x == "/location.servicestack.wildcard35/servicestack/json")); - Assert.That(pathUrls.All(x => x == "http://localhost/location.servicestack.wildcard35/servicestack/json")); - } - - [Test] - public void Can_Get_UrlHostName() - { - var urls = new List { "http://localhost/a", "https://localhost/a", - "http://localhost:81", "http://localhost:81/", "http://localhost" }; - - var httpReqs = urls.ConvertAll(x => new MockUrlHttpRequest { AbsoluteUri = x }); - var hostNames = httpReqs.ConvertAll(x => x.GetUrlHostName()); - - Console.WriteLine(hostNames.Dump()); - - Assert.That(hostNames.All(x => x == "localhost")); - } - - } +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.ServiceHost.Tests +{ + [TestFixture] + public class ServiceStackHandlerUrlTests + { + public static string ResolvePath(string mode, string path) + { + return HttpRequestExtensions. + GetPathInfo(path, mode, path.Split('/').First(x => x != "")); + } + + public class MockUrlHttpRequest : IHttpRequest + { + public MockUrlHttpRequest() { } + + public MockUrlHttpRequest(string mode, string path, string rawUrl) + { + this.PathInfo = ResolvePath(mode, path); + this.RawUrl = rawUrl; + AbsoluteUri = "http://localhost" + rawUrl; + } + + public object OriginalRequest + { + get { throw new NotImplementedException(); } + } + + public IResponse Response { get; private set; } + + public T TryResolve() + { + throw new NotImplementedException(); + } + + 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; private set; } + public IHttpResponse HttpResponse { get; private set; } + public string HttpMethod { get; private set; } + public string UserAgent { get; set; } + public bool IsLocal { get; set; } + + public IDictionary Cookies { get; private set; } + public string ResponseContentType { get; set; } + public bool HasExplicitResponseContentType { get; private set; } + public Dictionary Items { get; private set; } + public NameValueCollection Headers { get; private set; } + public NameValueCollection QueryString { get; private set; } + public NameValueCollection FormData { get; private set; } + public bool UseBufferedStream { get; set; } + + public string GetRawBody() => throw new NotImplementedException(); + + public Task GetRawBodyAsync() => throw new NotImplementedException(); + + public string RawUrl { get; private set; } + public string AbsoluteUri { get; set; } + public string UserHostAddress { get; private set; } + public Uri UrlReferrer { get; private set; } + + public string RemoteIp { get; set; } + public string Authorization { get; set; } + public string XForwardedFor { get; set; } + public int? XForwardedPort { get; set; } + public string XForwardedProtocol { get; set; } + public string XRealIp { get; set; } + public string Accept { get; set; } + public bool IsSecureConnection => (RequestAttributes & RequestAttributes.Secure) == RequestAttributes.Secure; + public string[] AcceptTypes { get; private set; } + public string PathInfo { get; private set; } + public string OriginalPathInfo => PathInfo; + public Stream InputStream { get; private set; } + public long ContentLength { get; private set; } + public IHttpFile[] Files { get; private set; } + + public string ApplicationFilePath { get; private set; } + } + + readonly List allResults = new List { + new MockUrlHttpRequest(null, "/handler.all35/json/metadata", "/handler.all35/json/metadata?op=Hello"), + }; + + readonly List apiResults = new List { + new MockUrlHttpRequest(null, "/location.api.wildcard35/api/json/metadata", "/location.api.wildcard35/api/json/metadata?op=Hello"), + }; + + readonly List serviceStacksResults = new List { + new MockUrlHttpRequest(null, "/location.servicestack.wildcard35/servicestack/json/metadata", "/location.servicestack.wildcard35/servicestack/json/metadata?op=Hello"), + }; + + [Test] + public void Does_return_expected_absolute_and_path_urls() + { + var absolutePaths = allResults.ConvertAll(x => x.GetAbsolutePath()); + var pathUrls = allResults.ConvertAll(x => x.GetPathUrl()); + Assert.That(absolutePaths.All(x => x == "/handler.all35/json/metadata")); + Assert.That(pathUrls.All(x => x == "http://localhost/handler.all35/json/metadata")); + + absolutePaths = apiResults.ConvertAll(x => x.GetAbsolutePath()); + pathUrls = apiResults.ConvertAll(x => x.GetPathUrl()); + Assert.That(absolutePaths.All(x => x == "/location.api.wildcard35/api/json/metadata")); + Assert.That(pathUrls.All(x => x == "http://localhost/location.api.wildcard35/api/json/metadata")); + + absolutePaths = serviceStacksResults.ConvertAll(x => x.GetAbsolutePath()); + pathUrls = serviceStacksResults.ConvertAll(x => x.GetPathUrl()); + Assert.That(absolutePaths.All(x => x == "/location.servicestack.wildcard35/servicestack/json/metadata")); + Assert.That(pathUrls.All(x => x == "http://localhost/location.servicestack.wildcard35/servicestack/json/metadata")); + } + + [Test] + public void Does_return_expected_parent_absolute_and_path_urls() + { + var absolutePaths = allResults.ConvertAll(x => x.GetParentAbsolutePath()); + var pathUrls = allResults.ConvertAll(x => x.GetParentPathUrl()); + + Assert.That(absolutePaths.All(x => x == "/handler.all35/json")); + Assert.That(pathUrls.All(x => x == "http://localhost/handler.all35/json")); + + absolutePaths = apiResults.ConvertAll(x => x.GetParentAbsolutePath()); + pathUrls = apiResults.ConvertAll(x => x.GetParentPathUrl()); + Assert.That(absolutePaths.All(x => x == "/location.api.wildcard35/api/json")); + Assert.That(pathUrls.All(x => x == "http://localhost/location.api.wildcard35/api/json")); + + absolutePaths = serviceStacksResults.ConvertAll(x => x.GetParentAbsolutePath()); + pathUrls = serviceStacksResults.ConvertAll(x => x.GetParentPathUrl()); + Assert.That(absolutePaths.All(x => x == "/location.servicestack.wildcard35/servicestack/json")); + Assert.That(pathUrls.All(x => x == "http://localhost/location.servicestack.wildcard35/servicestack/json")); + } + + [Test] + public void Can_Get_UrlHostName() + { + var urls = new List { "http://localhost/a", "https://localhost/a", + "http://localhost:81", "http://localhost:81/", "http://localhost" }; + + var httpReqs = urls.ConvertAll(x => new MockUrlHttpRequest { AbsoluteUri = x }); + var hostNames = httpReqs.ConvertAll(x => x.GetUrlHostName()); + + Console.WriteLine(hostNames.Dump()); + + Assert.That(hostNames.All(x => x == "localhost")); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/AutoWireService.cs b/tests/ServiceStack.ServiceHost.Tests/Support/AutoWireService.cs index e45fecc960b..f8f8b836391 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Support/AutoWireService.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Support/AutoWireService.cs @@ -2,62 +2,61 @@ namespace ServiceStack.ServiceHost.Tests.Support { - [DataContract] - public class AutoWire { } - - [DataContract] - public class AutoWireResponse - { - public IFoo Foo { get; set; } - public IBar Bar { get; set; } - } - - public class AutoWireService - : IService - { - private readonly IFoo foo; - - public IFoo Foo - { - get { return foo; } - } - - public IBar Bar { get; set; } - - public int Count { get; set; } - - public AutoWireService(IFoo foo) - { - this.foo = foo; - } - - public object Execute(AutoWire request) - { - return new AutoWireResponse { Foo = foo, Bar = Bar }; - } - } - - public class Foo : IFoo - { - } - - public class Foo2 : IFoo - { - } - - public interface IFoo - { - } - - public class Bar : IBar - { - } - - public class Bar2 : IBar - { - } - - public interface IBar - { - } + [DataContract] + public class AutoWire { } + + [DataContract] + public class AutoWireResponse + { + public IFoo Foo { get; set; } + public IBar Bar { get; set; } + } + + public class AutoWireService : IService + { + private readonly IFoo foo; + + public IFoo Foo + { + get { return foo; } + } + + public IBar Bar { get; set; } + + public int Count { get; set; } + + public AutoWireService(IFoo foo) + { + this.foo = foo; + } + + public object Any(AutoWire request) + { + return new AutoWireResponse { Foo = foo, Bar = Bar }; + } + } + + public class Foo : IFoo + { + } + + public class Foo2 : IFoo + { + } + + public interface IFoo + { + } + + public class Bar : IBar + { + } + + public class Bar2 : IBar + { + } + + public interface IBar + { + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/BasicService.cs b/tests/ServiceStack.ServiceHost.Tests/Support/BasicService.cs index 16c7510453e..d7b22b01b91 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Support/BasicService.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Support/BasicService.cs @@ -2,17 +2,17 @@ namespace ServiceStack.ServiceHost.Tests.Support { - [DataContract] - public class BasicRequest { } + [DataContract] + public class EmptyRequest { } - [DataContract] - public class BasicRequestResponse { } + [DataContract] + public class EmptyRequestResponse { } - public class BasicService : IService - { - public object Execute(BasicRequest request) - { - return new BasicRequestResponse(); - } - } + public class BasicService : IService + { + public object Any(EmptyRequest request) + { + return new EmptyRequestResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/CustomerUseCaseConfig.cs b/tests/ServiceStack.ServiceHost.Tests/Support/CustomerUseCaseConfig.cs index e63c62236ed..cd974fd4542 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Support/CustomerUseCaseConfig.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Support/CustomerUseCaseConfig.cs @@ -2,13 +2,13 @@ namespace ServiceStack.ServiceHost.Tests.Support { - public class CustomerUseCaseConfig - { - public CustomerUseCaseConfig() - { - this.UseCache = CustomerUseCase.UseCache; - } + public class CustomerUseCaseConfig + { + public CustomerUseCaseConfig() + { + this.UseCache = CustomerUseCase.UseCache; + } - public bool UseCache { get; set; } - } + public bool UseCache { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/GenericService.cs b/tests/ServiceStack.ServiceHost.Tests/Support/GenericService.cs index 93e3e86bca0..d750b583334 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Support/GenericService.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Support/GenericService.cs @@ -19,11 +19,11 @@ public class Generic3 public T Data { get; set; } } - public class GenericService : IService - { - public object Execute(T request) + public class GenericService : IService + { + public object Any(T request) { - return new Generic1Response() { Data = request.GetType().FullName }; + return new Generic1Response { Data = request.GetType().FullName }; } } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/InMemoryDbConnection.cs b/tests/ServiceStack.ServiceHost.Tests/Support/InMemoryDbConnection.cs index dd4503c4a88..a614a361969 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Support/InMemoryDbConnection.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Support/InMemoryDbConnection.cs @@ -3,73 +3,73 @@ namespace ServiceStack.ServiceHost.Tests.Support { - /// - /// LAMO hack I'm forced to do to because I can't register a simple delegate - /// to create my instance type - /// - public class InMemoryDbConnection - : IDbConnection - { - private readonly IDbConnection inner; - public InMemoryDbConnection() - { - this.inner = ":memory:".OpenDbConnection(); - } + /// + /// LAMO hack I'm forced to do to because I can't register a simple delegate + /// to create my instance type + /// + public class InMemoryDbConnection + : IDbConnection + { + private readonly IDbConnection inner; + public InMemoryDbConnection() + { + this.inner = ":memory:".OpenDbConnection(); + } - public void Dispose() - { - this.inner.Dispose(); - } + public void Dispose() + { + this.inner.Dispose(); + } - public IDbTransaction BeginTransaction() - { - return this.inner.BeginTransaction(); - } + public IDbTransaction BeginTransaction() + { + return this.inner.BeginTransaction(); + } - public IDbTransaction BeginTransaction(IsolationLevel il) - { - return this.inner.BeginTransaction(il); - } + public IDbTransaction BeginTransaction(IsolationLevel il) + { + return this.inner.BeginTransaction(il); + } - public void Close() - { - this.inner.Close(); - } + public void Close() + { + this.inner.Close(); + } - public void ChangeDatabase(string databaseName) - { - this.inner.ChangeDatabase(databaseName); - } + public void ChangeDatabase(string databaseName) + { + this.inner.ChangeDatabase(databaseName); + } - public IDbCommand CreateCommand() - { - return this.inner.CreateCommand(); - } + public IDbCommand CreateCommand() + { + return this.inner.CreateCommand(); + } - public void Open() - { - this.inner.Open(); - } + public void Open() + { + this.inner.Open(); + } - public string ConnectionString - { - get { return this.inner.ConnectionString; } - set { this.inner.ConnectionString = value; } - } + public string ConnectionString + { + get { return this.inner.ConnectionString; } + set { this.inner.ConnectionString = value; } + } - public int ConnectionTimeout - { - get { return this.inner.ConnectionTimeout; } - } + public int ConnectionTimeout + { + get { return this.inner.ConnectionTimeout; } + } - public string Database - { - get { return this.inner.Database; } - } + public string Database + { + get { return this.inner.Database; } + } - public ConnectionState State - { - get { return this.inner.State; } - } - } + public ConnectionState State + { + get { return this.inner.State; } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/RequiresContextService.cs b/tests/ServiceStack.ServiceHost.Tests/Support/RequiresContextService.cs deleted file mode 100644 index ea5a1e336ad..00000000000 --- a/tests/ServiceStack.ServiceHost.Tests/Support/RequiresContextService.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace ServiceStack.ServiceHost.Tests.Support -{ - [DataContract] - public class RequiresContext { } - - [DataContract] - public class RequiresContextResponse { } - - public class RequiresContextService - : IService, IRequiresRequestContext - { - public IRequestContext RequestContext { get; set; } - - public object Execute(RequiresContext requires) - { - if (RequestContext == null) - throw new ArgumentNullException("RequestContext"); - - return new RequiresContextResponse(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/RequiresService.cs b/tests/ServiceStack.ServiceHost.Tests/Support/RequiresService.cs new file mode 100644 index 00000000000..5a95898ecf9 --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/Support/RequiresService.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.ServiceHost.Tests.Support +{ + [DataContract] + public class RequiresContext { } + + [DataContract] + public class RequiresContextResponse { } + + public class RequiresService + : IService, IRequiresRequest + { + public IRequest Request { get; set; } + + public object Any(RequiresContext requires) + { + if (Request == null) + throw new ArgumentNullException("RequestContext"); + + return new RequiresContextResponse(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Support/RestTestService.cs b/tests/ServiceStack.ServiceHost.Tests/Support/RestTestService.cs index 3168e7533ed..ab2d10e9cb2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Support/RestTestService.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Support/RestTestService.cs @@ -3,46 +3,41 @@ namespace ServiceStack.ServiceHost.Tests.Support { - [DataContract] - public class RestTest { } + [DataContract] + public class RestTest { } - [DataContract] - public class RestTestResponse - { - [DataMember] - public string MethodName { get; set; } - } + [DataContract] + public class RestTestResponse + { + [DataMember] + public string MethodName { get; set; } + } - public class RestTestService - : IService - , IRestGetService - , IRestPutService - , IRestPostService - , IRestDeleteService - { - public object Execute(RestTest request) - { - return new RestTestResponse { MethodName = "Execute" }; - } + public class RestTestService : IService + { + public object Any(RestTest request) + { + return new RestTestResponse { MethodName = "Any" }; + } - public object Get(RestTest request) - { - return new RestTestResponse { MethodName = "Get" }; - } + public object Get(RestTest request) + { + return new RestTestResponse { MethodName = "Get" }; + } - public object Put(RestTest request) - { - return new RestTestResponse { MethodName = "Put" }; - } + public object Put(RestTest request) + { + return new RestTestResponse { MethodName = "Put" }; + } - public object Post(RestTest request) - { - return new RestTestResponse { MethodName = "Post" }; - } + public object Post(RestTest request) + { + return new RestTestResponse { MethodName = "Post" }; + } - public object Delete(RestTest request) - { - return new RestTestResponse { MethodName = "Delete" }; - } - } + public object Delete(RestTest request) + { + return new RestTestResponse { MethodName = "Delete" }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/TypeFactory/FuncTypeFactory.cs b/tests/ServiceStack.ServiceHost.Tests/TypeFactory/FuncTypeFactory.cs index 30791e6ef75..6fd84494c7b 100644 --- a/tests/ServiceStack.ServiceHost.Tests/TypeFactory/FuncTypeFactory.cs +++ b/tests/ServiceStack.ServiceHost.Tests/TypeFactory/FuncTypeFactory.cs @@ -6,35 +6,35 @@ namespace ServiceStack.ServiceHost.Tests.TypeFactory { - public class FuncTypeFactory - : ITypeFactory - { - private readonly Container container; - private readonly Dictionary> resolveFnMap = new Dictionary>(); + public class FuncTypeFactory + : ITypeFactory + { + private readonly Container container; + private readonly Dictionary> resolveFnMap = new Dictionary>(); - public FuncTypeFactory(Container container) - { - this.container = container; - } + public FuncTypeFactory(Container container) + { + this.container = container; + } - public object CreateInstance(Type type) - { - Func resolveFn; + public object CreateInstance(IResolver resolver, Type type) + { + Func resolveFn; - if (!this.resolveFnMap.TryGetValue(type, out resolveFn)) - { - var containerInstance = Expression.Constant(this.container); - var resolveInstance = Expression.Call(containerInstance, "Resolve", new[] {type}, new Expression[0]); - var resolveObject = Expression.Convert(resolveInstance, typeof (object)); - resolveFn = (Func)Expression.Lambda(resolveObject, new ParameterExpression[0]).Compile(); + if (!this.resolveFnMap.TryGetValue(type, out resolveFn)) + { + var containerInstance = Expression.Constant(this.container); + var resolveInstance = Expression.Call(containerInstance, "Resolve", new[] { type }, new Expression[0]); + var resolveObject = Expression.Convert(resolveInstance, typeof(object)); + resolveFn = (Func)Expression.Lambda(resolveObject, new ParameterExpression[0]).Compile(); - lock (this.resolveFnMap) - { - this.resolveFnMap[type] = resolveFn; - } - } + lock (this.resolveFnMap) + { + this.resolveFnMap[type] = resolveFn; + } + } - return resolveFn(); - } - } + return resolveFn(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/TypeFactory/ReflectionTypeFunqContainer.cs b/tests/ServiceStack.ServiceHost.Tests/TypeFactory/ReflectionTypeFunqContainer.cs index a2d44e95ee2..d281f1183ae 100644 --- a/tests/ServiceStack.ServiceHost.Tests/TypeFactory/ReflectionTypeFunqContainer.cs +++ b/tests/ServiceStack.ServiceHost.Tests/TypeFactory/ReflectionTypeFunqContainer.cs @@ -1,108 +1,110 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Funq; -using ServiceStack.Configuration; - -namespace ServiceStack.ServiceHost.Tests.TypeFactory -{ - /// - /// Reflection example provided for performance comparisons - /// - public class ReflectionTypeFunqContainer - : ITypeFactory - { - protected Container container; - public ReuseScope Scope { get; set; } - - public ReflectionTypeFunqContainer(Container container) - { - this.container = container; - this.Scope = ReuseScope.None; - } - - protected static MethodInfo GetResolveMethod(Type typeWithResolveMethod, Type serviceType) - { - var methodInfo = typeWithResolveMethod.GetMethod("Resolve", new Type[0]); - return methodInfo.MakeGenericMethod(new[] { serviceType }); - } - - public static ConstructorInfo GetConstructorWithMostParams(Type type) - { - return type.GetConstructors() - .OrderByDescending(x => x.GetParameters().Length) - .First(ctor => !ctor.IsStatic); - } - - public Func AutoWire(Func resolveFn) - { - var serviceType = typeof(TService); - var ci = GetConstructorWithMostParams(serviceType); - - var paramValues = new List(); - var ciParams = ci.GetParameters(); - foreach (var parameterInfo in ciParams) - { - var paramValue = resolveFn(parameterInfo.ParameterType); - paramValues.Add(paramValue); - } - - var service = ci.Invoke(paramValues.ToArray()); - - foreach (var propertyInfo in serviceType.GetProperties()) - { - if (propertyInfo.PropertyType.IsValueType) continue; - - var propertyValue = resolveFn(propertyInfo.PropertyType); - var propertySetter = propertyInfo.GetSetMethod(); - if (propertySetter != null) - { - propertySetter.Invoke(service, new[] { propertyValue }); - } - } - - return () => (TService)service; - } - - private static Func Resolve(Container container) - { - return delegate(Type serviceType) { - var resolveMethodInfo = GetResolveMethod(container.GetType(), serviceType); - return resolveMethodInfo.Invoke(container, new object[0]); - }; - } - - public void Register() - { - //Everything from here needs to be optimized - Func registerFn = delegate(Container c) { - Func serviceFactoryFn = AutoWire(Resolve(c)); - return serviceFactoryFn(); - }; - - this.container.Register(registerFn).ReusedWithin(this.Scope); - } - - public void Register(params Type[] serviceTypes) - { - RegisterTypes(serviceTypes); - } - - public void RegisterTypes(IEnumerable serviceTypes) - { - foreach (var serviceType in serviceTypes) - { - var methodInfo = GetType().GetMethod("Register", new Type[0]); - var registerMethodInfo = methodInfo.MakeGenericMethod(new[] { serviceType }); - registerMethodInfo.Invoke(this, new object[0]); - } - } - - public object CreateInstance(Type type) - { - var factoryFn = Resolve(this.container); - return factoryFn(type); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Funq; +using ServiceStack.Configuration; + +namespace ServiceStack.ServiceHost.Tests.TypeFactory +{ + /// + /// Reflection example provided for performance comparisons + /// + public class ReflectionTypeFunqContainer + : ITypeFactory + { + protected Container container; + public ReuseScope Scope { get; set; } + + public ReflectionTypeFunqContainer(Container container) + { + this.container = container; + this.Scope = ReuseScope.None; + } + + protected static MethodInfo GetResolveMethod(Type typeWithResolveMethod, Type serviceType) + { + var methodInfo = typeWithResolveMethod.GetMethod("Resolve", new Type[0]); + return methodInfo.MakeGenericMethod(new[] { serviceType }); + } + + public static ConstructorInfo GetConstructorWithMostParams(Type type) + { + return type.GetConstructors() + .OrderByDescending(x => x.GetParameters().Length) + .First(ctor => !ctor.IsStatic); + } + + public Func AutoWire(Func resolveFn) + { + var serviceType = typeof(TService); + var ci = GetConstructorWithMostParams(serviceType); + + var paramValues = new List(); + var ciParams = ci.GetParameters(); + foreach (var parameterInfo in ciParams) + { + var paramValue = resolveFn(parameterInfo.ParameterType); + paramValues.Add(paramValue); + } + + var service = ci.Invoke(paramValues.ToArray()); + + foreach (var propertyInfo in serviceType.GetProperties()) + { + if (propertyInfo.PropertyType.IsValueType) continue; + + var propertyValue = resolveFn(propertyInfo.PropertyType); + var propertySetter = propertyInfo.GetSetMethod(); + if (propertySetter != null) + { + propertySetter.Invoke(service, new[] { propertyValue }); + } + } + + return () => (TService)service; + } + + private static Func Resolve(Container container) + { + return delegate (Type serviceType) + { + var resolveMethodInfo = GetResolveMethod(container.GetType(), serviceType); + return resolveMethodInfo.Invoke(container, new object[0]); + }; + } + + public void Register() + { + //Everything from here needs to be optimized + Func registerFn = delegate (Container c) + { + Func serviceFactoryFn = AutoWire(Resolve(c)); + return serviceFactoryFn(); + }; + + this.container.Register(registerFn).ReusedWithin(this.Scope); + } + + public void Register(params Type[] serviceTypes) + { + RegisterTypes(serviceTypes); + } + + public void RegisterTypes(IEnumerable serviceTypes) + { + foreach (var serviceType in serviceTypes) + { + var methodInfo = GetType().GetMethod("Register", new Type[0]); + var registerMethodInfo = methodInfo.MakeGenericMethod(new[] { serviceType }); + registerMethodInfo.Invoke(this, new object[0]); + } + } + + public object CreateInstance(IResolver resolver, Type type) + { + var factoryFn = Resolve(this.container); + return factoryFn(type); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/UseCase/CustomerUseCase.cs b/tests/ServiceStack.ServiceHost.Tests/UseCase/CustomerUseCase.cs index b5b2f6f5c0f..921103b92de 100644 --- a/tests/ServiceStack.ServiceHost.Tests/UseCase/CustomerUseCase.cs +++ b/tests/ServiceStack.ServiceHost.Tests/UseCase/CustomerUseCase.cs @@ -1,171 +1,174 @@ -using System; -using System.Data; -using System.Diagnostics; -using System.Linq.Expressions; -using Funq; -using NUnit.Framework; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceHost.Tests.Support; -using ServiceStack.ServiceHost.Tests.TypeFactory; -using ServiceStack.ServiceHost.Tests.UseCase.Operations; -using ServiceStack.ServiceHost.Tests.UseCase.Services; - -namespace ServiceStack.ServiceHost.Tests.UseCase -{ - [Ignore] - [TestFixture] - public class CustomerUseCase - { - private const int Times = 100000; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - OrmLite.OrmLiteConfig.DialectProvider = new SqliteOrmLiteDialectProvider(); - } - - public const bool UseCache = false; - private ServiceController serviceController; - - [SetUp] - public void OnBeforeEachTest() - { - serviceController = new ServiceController(null); - } - - [Test] - public void Perf_All_IOC() - { - AutoWiredFunq_Perf(); - NativeFunq_Perf(); - } - - - [Test] - public void NativeFunq_Perf() - { - RegisterServices(serviceController, GetNativeFunqTypeFactory()); - - StoreAndGetCustomers(serviceController); - - var request = new GetCustomer { CustomerId = 2 }; - Console.WriteLine("NativeFunq_Perf(): {0}", Measure(() => serviceController.Execute(request), Times)); - } - - [Test] - public void AutoWiredFunq_Perf() - { - RegisterServices(serviceController, GetAutoWiredFunqTypeFactory()); - - StoreAndGetCustomers(serviceController); - - var request = new GetCustomer { CustomerId = 2 }; - Console.WriteLine("AutoWiredFunq_Perf(): {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; - } - - [Test] - public void Using_NativeFunq() - { - RegisterServices(serviceController, GetNativeFunqTypeFactory()); - - StoreAndGetCustomers(serviceController); - } - - [Test] - public void Using_AutoWiredFunq() - { - RegisterServices(serviceController, GetAutoWiredFunqTypeFactory()); - - StoreAndGetCustomers(serviceController); - } - - private static void StoreAndGetCustomers(ServiceController serviceController) - { - var storeCustomers = new StoreCustomers { - Customers = { - new Customer { Id = 1, FirstName = "First", LastName = "Customer" }, - new Customer { Id = 2, FirstName = "Second", LastName = "Customer" }, - } - }; - serviceController.Execute(storeCustomers); - - storeCustomers = new StoreCustomers { - Customers = { - new Customer {Id = 3, FirstName = "Third", LastName = "Customer"}, - } - }; - serviceController.Execute(storeCustomers); - - var response = serviceController.Execute(new GetCustomer { CustomerId = 2 }); - - Assert.That(response as GetCustomerResponse, Is.Not.Null); - - var customer = ((GetCustomerResponse)response).Customer; - Assert.That(customer.FirstName, Is.EqualTo("Second")); - } - - private static void RegisterServices(ServiceController serviceController, ITypeFactory typeFactory) - { - serviceController.Register(typeof(StoreCustomers), typeof(StoreCustomersService), typeFactory); - serviceController.Register(typeof(GetCustomer), typeof(GetCustomerService), typeFactory); - } - - public static ITypeFactory GetNativeFunqTypeFactory() - { - var container = GetContainerWithDependencies(); - - container.Register(c => new StoreCustomersService(c.Resolve())) - .ReusedWithin(ReuseScope.None); - - container.Register(c => - new GetCustomerService(c.Resolve(), c.Resolve()) { - CacheClient = c.TryResolve() - } - ) - .ReusedWithin(ReuseScope.None); - - return new FuncTypeFactory(container); - } - - public static ITypeFactory GetAutoWiredFunqTypeFactory() - { - var container = GetContainerWithDependencies(); - - container.RegisterAutoWiredType(typeof(StoreCustomersService), typeof(GetCustomerService)); - - return new ContainerResolveCache(container); - } - - private static Container GetContainerWithDependencies() - { - var container = new Container(); - - container.Register(c => ":memory:".OpenDbConnection()) - .ReusedWithin(ReuseScope.Container); - container.Register(c => new MemoryCacheClient()) - .ReusedWithin(ReuseScope.Container); - container.Register(c => new CustomerUseCaseConfig()) - .ReusedWithin(ReuseScope.Container); - - return container; - } - } - -} +using System; +using System.Data; +using System.Diagnostics; +using System.Linq.Expressions; +using Funq; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.Configuration; +using ServiceStack.Host; +using ServiceStack.OrmLite; +using ServiceStack.OrmLite.Sqlite; +using ServiceStack.ServiceHost.Tests.Support; +using ServiceStack.ServiceHost.Tests.TypeFactory; +using ServiceStack.ServiceHost.Tests.UseCase.Operations; +using ServiceStack.ServiceHost.Tests.UseCase.Services; + +namespace ServiceStack.ServiceHost.Tests.UseCase +{ + [Ignore("Performance tests")] + [TestFixture] + public class CustomerUseCase + { + private const int Times = 100000; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + OrmLite.OrmLiteConfig.DialectProvider = new SqliteOrmLiteDialectProvider(); + } + + public const bool UseCache = false; + private ServiceController serviceController; + + [SetUp] + public void OnBeforeEachTest() + { + serviceController = new ServiceController(null); + } + + [Test] + public void Perf_All_IOC() + { + AutoWiredFunq_Perf(); + NativeFunq_Perf(); + } + + + [Test] + public void NativeFunq_Perf() + { + RegisterServices(serviceController, GetNativeFunqTypeFactory()); + + StoreAndGetCustomers(serviceController); + + var request = new GetCustomer { CustomerId = 2 }; + Console.WriteLine("NativeFunq_Perf(): {0}", Measure(() => serviceController.Execute(request), Times)); + } + + [Test] + public void AutoWiredFunq_Perf() + { + RegisterServices(serviceController, GetAutoWiredFunqTypeFactory()); + + StoreAndGetCustomers(serviceController); + + var request = new GetCustomer { CustomerId = 2 }; + Console.WriteLine("AutoWiredFunq_Perf(): {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; + } + + [Test] + public void Using_NativeFunq() + { + RegisterServices(serviceController, GetNativeFunqTypeFactory()); + + StoreAndGetCustomers(serviceController); + } + + [Test] + public void Using_AutoWiredFunq() + { + RegisterServices(serviceController, GetAutoWiredFunqTypeFactory()); + + StoreAndGetCustomers(serviceController); + } + + private static void StoreAndGetCustomers(ServiceController serviceController) + { + var storeCustomers = new StoreCustomers + { + Customers = { + new Customer { Id = 1, FirstName = "First", LastName = "Customer" }, + new Customer { Id = 2, FirstName = "Second", LastName = "Customer" }, + } + }; + serviceController.Execute(storeCustomers); + + storeCustomers = new StoreCustomers + { + Customers = { + new Customer {Id = 3, FirstName = "Third", LastName = "Customer"}, + } + }; + serviceController.Execute(storeCustomers); + + var response = serviceController.Execute(new GetCustomer { CustomerId = 2 }); + + Assert.That(response as GetCustomerResponse, Is.Not.Null); + + var customer = ((GetCustomerResponse)response).Customer; + Assert.That(customer.FirstName, Is.EqualTo("Second")); + } + + private static void RegisterServices(ServiceController serviceController, ITypeFactory typeFactory) + { + serviceController.RegisterServiceExecutor(typeof(StoreCustomers), typeof(StoreCustomersService), typeFactory); + serviceController.RegisterServiceExecutor(typeof(GetCustomer), typeof(GetCustomerService), typeFactory); + } + + public static ITypeFactory GetNativeFunqTypeFactory() + { + var container = GetContainerWithDependencies(); + + container.Register(c => new StoreCustomersService(c.Resolve())) + .ReusedWithin(ReuseScope.None); + + container.Register(c => + new GetCustomerService(c.Resolve(), c.Resolve()) + { + CacheClient = c.TryResolve() + } + ) + .ReusedWithin(ReuseScope.None); + + return new FuncTypeFactory(container); + } + + public static ITypeFactory GetAutoWiredFunqTypeFactory() + { + var container = GetContainerWithDependencies(); + + container.RegisterAutoWiredType(typeof(StoreCustomersService), typeof(GetCustomerService)); + + return new ContainerResolveCache(container); + } + + private static Container GetContainerWithDependencies() + { + var container = new Container(); + + container.Register(c => ":memory:".OpenDbConnection()) + .ReusedWithin(ReuseScope.Container); + container.Register(c => new MemoryCacheClient()) + .ReusedWithin(ReuseScope.Container); + container.Register(c => new CustomerUseCaseConfig()) + .ReusedWithin(ReuseScope.Container); + + return container; + } + } + +} diff --git a/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/GetCustomer.cs b/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/GetCustomer.cs index 204f2b665f4..60891a55ba5 100644 --- a/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/GetCustomer.cs +++ b/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/GetCustomer.cs @@ -2,30 +2,30 @@ namespace ServiceStack.ServiceHost.Tests.UseCase.Operations { - [DataContract] - public class GetCustomer - { - [DataMember] - public long CustomerId { get; set; } - } + [DataContract] + public class GetCustomer + { + [DataMember] + public long CustomerId { get; set; } + } - [DataContract] - public class GetCustomerResponse - { - [DataMember] - public Customer Customer { get; set; } - } + [DataContract] + public class GetCustomerResponse + { + [DataMember] + public Customer Customer { get; set; } + } - [DataContract] - public class Customer - { - [DataMember] - public long Id { get; set; } + [DataContract] + public class Customer + { + [DataMember] + public long Id { get; set; } - [DataMember] - public string FirstName { get; set; } + [DataMember] + public string FirstName { get; set; } - [DataMember] - public string LastName { get; set; } - } + [DataMember] + public string LastName { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/StoreCustomers.cs b/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/StoreCustomers.cs index 96f5305fc42..a730c6cc4ff 100644 --- a/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/StoreCustomers.cs +++ b/tests/ServiceStack.ServiceHost.Tests/UseCase/Operations/StoreCustomers.cs @@ -4,15 +4,15 @@ namespace ServiceStack.ServiceHost.Tests.UseCase.Operations { - [DataContract] - public class StoreCustomers - { - public StoreCustomers() - { - Customers = new List(); - } + [DataContract] + public class StoreCustomers + { + public StoreCustomers() + { + Customers = new List(); + } - [DataMember] - public List Customers { get; set; } - } + [DataMember] + public List Customers { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/GetCustomerService.cs b/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/GetCustomerService.cs index 95e13504f63..a3bc2736e66 100644 --- a/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/GetCustomerService.cs +++ b/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/GetCustomerService.cs @@ -1,45 +1,43 @@ -using System; using System.Data; -using ServiceStack.CacheAccess; -using ServiceStack.Configuration; +using ServiceStack.Caching; using ServiceStack.OrmLite; using ServiceStack.ServiceHost.Tests.Support; using ServiceStack.ServiceHost.Tests.UseCase.Operations; namespace ServiceStack.ServiceHost.Tests.UseCase.Services { - public class GetCustomerService - : IService - { - private static readonly string CacheKey = typeof (GetCustomer).Name; - - private readonly IDbConnection db; - private readonly CustomerUseCaseConfig config; - - public GetCustomerService(IDbConnection dbConn, CustomerUseCaseConfig config) - { - this.db = dbConn; - this.config = config; - } - - public ICacheClient CacheClient { get; set; } - - public object Execute(GetCustomer request) - { - if (config.UseCache) - { - var inCache = this.CacheClient.Get(CacheKey); - if (inCache != null) return inCache; - } - - var response = new GetCustomerResponse { - Customer = db.GetById(request.CustomerId) - }; - - if (config.UseCache) - this.CacheClient.Set(CacheKey, response); - - return response; - } - } + public class GetCustomerService : IService + { + private static readonly string CacheKey = typeof(GetCustomer).Name; + + private readonly IDbConnection db; + private readonly CustomerUseCaseConfig config; + + public GetCustomerService(IDbConnection dbConn, CustomerUseCaseConfig config) + { + this.db = dbConn; + this.config = config; + } + + public ICacheClient CacheClient { get; set; } + + public object Any(GetCustomer request) + { + if (config.UseCache) + { + var inCache = this.CacheClient.Get(CacheKey); + if (inCache != null) return inCache; + } + + var response = new GetCustomerResponse + { + Customer = db.SingleById(request.CustomerId) + }; + + if (config.UseCache) + this.CacheClient.Set(CacheKey, response); + + return response; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/StoreCustomersService.cs b/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/StoreCustomersService.cs index f964c115309..2e19b635f58 100644 --- a/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/StoreCustomersService.cs +++ b/tests/ServiceStack.ServiceHost.Tests/UseCase/Services/StoreCustomersService.cs @@ -5,27 +5,26 @@ namespace ServiceStack.ServiceHost.Tests.UseCase.Services { - public class StoreCustomersService - : IService - { - private readonly IDbConnection db; + public class StoreCustomersService : IService + { + private readonly IDbConnection db; - public StoreCustomersService(IDbConnection dbConn) - { - this.db = dbConn; - //Console.WriteLine("StoreCustomersService()"); - } + public StoreCustomersService(IDbConnection dbConn) + { + this.db = dbConn; + //Console.WriteLine("StoreCustomersService()"); + } - public object Execute(StoreCustomers request) - { - db.CreateTable(false); - foreach (var customer in request.Customers) - { - db.Insert(customer); - } + public object Any(StoreCustomers request) + { + db.DropAndCreateTable(); + foreach (var customer in request.Customers) + { + db.Insert(customer); + } - return null; - } - } + return null; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomers.cs b/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomers.cs index 609de342786..d95f1c84242 100644 --- a/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomers.cs +++ b/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomers.cs @@ -1,25 +1,24 @@ -using ServiceStack.ServiceInterface.ServiceModel; -using System.Runtime.Serialization; - -namespace ServiceStack.ServiceModel.Tests.DataContracts.Operations -{ - [DataContract(Namespace = "http://schemas.servicestack.net/types/")] - public class GetCustomers : IExtensibleDataObject - { - public GetCustomers() - { - this.CustomerIds = new ArrayOfIntId(); - this.Version = 100; - } - - [DataMember] - public ArrayOfIntId CustomerIds { get; set; } - - - [DataMember] - public int Version { get; set; } - [DataMember] - public Properties Properties { get; set; } - public ExtensionDataObject ExtensionData { get; set; } - } +using System.Runtime.Serialization; + +namespace ServiceStack.ServiceModel.Tests.DataContracts.Operations +{ + [DataContract(Namespace = "http://schemas.servicestack.net/types/")] + public class GetCustomers : IExtensibleDataObject + { + public GetCustomers() + { + this.CustomerIds = new ArrayOfIntId(); + this.Version = 100; + } + + [DataMember] + public ArrayOfIntId CustomerIds { get; set; } + + + [DataMember] + public int Version { get; set; } + [DataMember] + public Properties Properties { get; set; } + public ExtensionDataObject ExtensionData { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomersResponse.cs b/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomersResponse.cs index 13d49ef535b..1af38609b14 100644 --- a/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomersResponse.cs +++ b/tests/ServiceStack.ServiceModel.Tests/DataContracts/Operations/GetCustomersResponse.cs @@ -1,28 +1,27 @@ -using ServiceStack.ServiceInterface.ServiceModel; -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace ServiceStack.ServiceModel.Tests.DataContracts.Operations -{ - [DataContract(Namespace = "http://schemas.servicestack.net/types/")] - public class GetCustomersResponse : IExtensibleDataObject - { - public GetCustomersResponse() - { - this.Version = 100; - this.Customers = new List(); - } - - [DataMember] - public List Customers { get; set; } - - - [DataMember] - public int Version { get; set; } - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - [DataMember] - public Properties Properties { get; set; } - public ExtensionDataObject ExtensionData { get; set; } - } +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace ServiceStack.ServiceModel.Tests.DataContracts.Operations +{ + [DataContract(Namespace = "http://schemas.servicestack.net/types/")] + public class GetCustomersResponse : IExtensibleDataObject + { + public GetCustomersResponse() + { + this.Version = 100; + this.Customers = new List(); + } + + [DataMember] + public List Customers { get; set; } + + + [DataMember] + public int Version { get; set; } + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + [DataMember] + public Properties Properties { get; set; } + public ExtensionDataObject ExtensionData { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceModel.Tests/KeyValueDataContractDeserializerTests.cs b/tests/ServiceStack.ServiceModel.Tests/KeyValueDataContractDeserializerTests.cs index ad287f9ddca..afbc221d429 100644 --- a/tests/ServiceStack.ServiceModel.Tests/KeyValueDataContractDeserializerTests.cs +++ b/tests/ServiceStack.ServiceModel.Tests/KeyValueDataContractDeserializerTests.cs @@ -1,26 +1,27 @@ +using NUnit.Framework; +using ServiceStack.Serialization; +using ServiceStack.ServiceModel.Tests.DataContracts.Operations; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using NUnit.Framework; -using ServiceStack.ServiceModel.Serialization; -using ServiceStack.ServiceModel.Tests.DataContracts.Operations; +using ServiceStack.Text; namespace ServiceStack.ServiceModel.Tests { - [TestFixture] - public class KeyValueDataContractDeserializerTests - { - [Test] - public void create_dto_request_from_ids() - { - var dtoType = typeof(GetCustomers); - var textValue = "1,2,3"; - var convertedValue = textValue.Split(',').ToList().ConvertAll(x => Convert.ToInt32(x)); - var valueMap = new Dictionary { { "CustomerIds", textValue } }; - var result = (GetCustomers)KeyValueDataContractDeserializer.Instance.Parse(valueMap, dtoType); - Assert.That(result.CustomerIds, Is.EquivalentTo(convertedValue)); - } + [TestFixture] + public class KeyValueDataContractDeserializerTests + { + [Test] + public void create_dto_request_from_ids() + { + var dtoType = typeof(GetCustomers); + var textValue = "1,2,3"; + var convertedValue = textValue.Split(',').ToList().ConvertAll(x => Convert.ToInt32(x)); + var valueMap = new Dictionary { { "CustomerIds", textValue } }; + var result = (GetCustomers)KeyValueDataContractDeserializer.Instance.Parse(valueMap, dtoType); + Assert.That(result.CustomerIds, Is.EquivalentTo(convertedValue)); + } [DataContract] public class Customer @@ -30,17 +31,93 @@ public class Customer [DataMember(Name = "last_name")] public string LastName { get; set; } + + [DataMember(Name = "age")] + public int? Age { get; set; } + + [DataMember(Name = "dob")] + public DateTime? DOB { get; set; } } - [Test] - public void KVP_Serializer_does_use_DataMember_Name_attribute() - { + [Test] + public void KVP_Serializer_does_use_DataMember_Name_attribute() + { var valueMap = new Dictionary { { "first_name", "james" }, { "last_name", "bond" } }; var result = (Customer)KeyValueDataContractDeserializer.Instance.Parse(valueMap, typeof(Customer)); Assert.That(result.FirstName, Is.EqualTo("james")); Assert.That(result.LastName, Is.EqualTo("bond")); - } - } -} \ No newline at end of file + } + + [Test] + public void KVP_Serializer_does_not_set_nullable_properties_when_values_are_empty() + { + var valueMap = new Dictionary { { "first_name", "james" }, { "last_name", "bond" }, { "age", "" }, { "dob", "" } }; + + var result = (Customer)KeyValueDataContractDeserializer.Instance.Parse(valueMap, typeof(Customer)); + + Assert.That(result.Age, Is.Null); + Assert.That(result.DOB, Is.Null); + } + + public class Customer2 + { + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string FullName + { + get { return FirstName + " " + LastName; } + } + } + + [Test] + public void KVP_Serializer_ignores_readonly_properties() + { + var valueMap = new Dictionary { { "FirstName", "james" }, { "LastName", "bond" }, { "FullName", "james bond" } }; + var result = (Customer2)KeyValueDataContractDeserializer.Instance.Parse(valueMap, typeof(Customer2)); + Assert.That(result.FirstName, Is.EqualTo("james")); + Assert.That(result.LastName, Is.EqualTo("bond")); + } + + public class CustomerWithFields + { + public readonly string FirstName; + + public readonly string LastName; + + public string FullName + { + get { return FirstName + " " + LastName; } + } + + public CustomerWithFields(string firstName, string lastName) + { + FirstName = firstName; + LastName = lastName; + } + } + + [Test] + public void KVP_Serializer_fills_public_fields() + { + using (JsConfig.With(new Config { IncludePublicFields = true })) + { + var valueMap = new Dictionary { { "FirstName", "james" }, { "LastName", "bond" }, { "FullName", "james bond" } }; + var result = (CustomerWithFields)KeyValueDataContractDeserializer.Instance.Parse(valueMap, typeof(CustomerWithFields)); + Assert.That(result.FirstName, Is.EqualTo("james")); + Assert.That(result.LastName, Is.EqualTo("bond")); + } + } + + [Test] + public void Dont_try_to_decode_as_JSV_strings_for_string_properties() + { + var valueMap = new Dictionary { { "FirstName", "\"this is a \" test" } }; + var result = (Customer)KeyValueDataContractDeserializer.Instance.Parse(valueMap, typeof(Customer)); + Assert.That(result.FirstName, Is.EqualTo("\"this is a \" test")); + } + } +} diff --git a/tests/ServiceStack.ServiceModel.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.ServiceModel.Tests/Properties/AssemblyInfo.cs index a9c39880765..2159f9f6fd7 100644 --- a/tests/ServiceStack.ServiceModel.Tests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.ServiceModel.Tests/Properties/AssemblyInfo.cs @@ -10,8 +10,8 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ServiceStack.Serialization.Tests")] -[assembly: AssemblyCopyright("Copyright © 2008")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCopyright("Copyright (c) 2008")] +[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.ServiceModel.Tests/ServiceModelSerializerTests.cs b/tests/ServiceStack.ServiceModel.Tests/ServiceModelSerializerTests.cs deleted file mode 100644 index 8e0afc2b8fc..00000000000 --- a/tests/ServiceStack.ServiceModel.Tests/ServiceModelSerializerTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Northwind.Common.DataModel; -using Northwind.Common.ComplexModel; -using NUnit.Framework; -using ServiceStack.ServiceModel.Serialization; -using ServiceStack.ServiceModel.Tests.DataContracts.Operations; -using ServiceStack.Text; - -namespace ServiceStack.ServiceModel.Tests -{ - [TestFixture] - public class ServiceModelSerializerTests - { - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - NorthwindData.LoadData(false); - } - - [Test] - public void Can_serialize_northind_models() - { - Serialize(NorthwindData.Categories); - Serialize(NorthwindData.Customers); - Serialize(NorthwindData.Employees); - Serialize(NorthwindData.Shippers); - Serialize(NorthwindData.Orders); - Serialize(NorthwindData.Products); - Serialize(NorthwindData.OrderDetails); - Serialize(NorthwindData.CustomerCustomerDemos); - Serialize(NorthwindData.Regions); - Serialize(NorthwindData.Territories); - Serialize(NorthwindData.EmployeeTerritories); - } - - [Test] - [Ignore("Could not find Platform.dll")] - public void Can_serialize_complex_northind_dtos() - { - Serialize(DtoFactory.ArrayDtoWithOrders); - Serialize(DtoFactory.CustomerDto); - Serialize(DtoFactory.CustomerOrderArrayDto); - Serialize(DtoFactory.CustomerOrderListDto); - Serialize(DtoFactory.MultiCustomerProperties); - Serialize(DtoFactory.MultiDtoWithOrders); - Serialize(DtoFactory.MultiOrderProperties); - Serialize(DtoFactory.OrderDto); - Serialize(DtoFactory.SupplierDto); - } - - public void Serialize(T model) - { - var serializedXml = DataContractSerializer.Instance.Parse(model); - var deserializedXml = DataContractDeserializer.Instance.Parse(serializedXml, typeof(T)); - Assert.That(deserializedXml, Is.Not.Null, "XML serialization error for: " + typeof(T).Name); - - var serializedJson = JsonDataContractSerializer.Instance.SerializeToString(model); - var deserializedJson = JsonDataContractDeserializer.Instance.DeserializeFromString(serializedJson, typeof(T)); - Assert.That(deserializedJson, Is.Not.Null, "JSON serialization error for: " + typeof(T).Name); - - var serializedJsv = TypeSerializer.SerializeToString(model); - var deserializedJsv = TypeSerializer.DeserializeFromString(serializedJsv); - Assert.That(deserializedJsv, Is.Not.Null, "JSV serialization error for: " + typeof(T).Name); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.ServiceModel.Tests/ServiceStack.ServiceModel.Tests.csproj b/tests/ServiceStack.ServiceModel.Tests/ServiceStack.ServiceModel.Tests.csproj index 880e35cd12a..c401ce870c1 100644 --- a/tests/ServiceStack.ServiceModel.Tests/ServiceStack.ServiceModel.Tests.csproj +++ b/tests/ServiceStack.ServiceModel.Tests/ServiceStack.ServiceModel.Tests.csproj @@ -1,153 +1,34 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {A5646013-C243-453F-A2B6-3B6870A9637D} - Library - Properties - ServiceStack.ServiceModel.Tests - ServiceStack.ServiceModel.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 - True - - - 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\tests\protobuf-net.dll - - - - 3.5 - - - 3.0 - - - 3.5 - - - 3.5 - - - - - ..\..\lib\tests\Northwind.Common.dll - - - ..\..\lib\tests\nunit.framework.dll - - - ..\..\lib\ServiceStack.Text.dll - - - - - - - - - - - - - - - - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - - - 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 + + + + net472 + ServiceStack.ServiceModel.Tests + ServiceStack.ServiceModel.Tests + false + false + false + false + false + false + false + false + + + + + + + + + + + + + + + + + + + + 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.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 27e212d3ee2..30b4bd62901 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostConfigTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostConfigTests.cs @@ -1,50 +1,38 @@ -using System; -using NUnit.Framework; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class AppHostConfigTests - { - protected const string ListeningOn = "http://localhost:85/"; - - TestConfigAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - LogManager.LogFactory = new ConsoleLogFactory(); - - appHost = new TestConfigAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - Dispose(); - } - - public void Dispose() - { - if (appHost == null) return; - appHost.Dispose(); - appHost = null; - } - - - [Test] - public void Actually_uses_the_BclJsonSerializers() - { - var json = (ListeningOn + "login/user/pass").DownloadJsonFromUrl(); - - Console.WriteLine(json); - Assert.That(json, Is.EqualTo("{\"pwd\":\"pass\",\"uname\":\"user\"}")); - } - } -} \ No newline at end of file +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class AppHostConfigTests + { + protected const string ListeningOn = "http://localhost:1337/"; + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new TestConfigAppHostHttpListener() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Actually_uses_the_BclJsonSerializers() + { + var json = (ListeningOn + "login/user/pass").GetJsonFromUrl(); + + json.Print(); + Assert.That(json, Is.EqualTo("{\"pwd\":\"pass\",\"uname\":\"user\"}") + .Or.EqualTo("{\"uname\":\"user\",\"pwd\":\"pass\"}")); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs index fa96c6d6267..351004dfb43 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs @@ -1,212 +1,201 @@ -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.WebHost.Endpoints.Tests.Support.Host; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - class AppHostHttpListenerLongRunningBaseTests - { - private const string ListeningOn = "http://localhost:82/"; - ExampleAppHostHttpListenerLongRunning appHost; - - static AppHostHttpListenerLongRunningBaseTests() - { - LogManager.LogFactory = new ConsoleLogFactory(); - } - - [TestFixtureSetUp] - public void OnTestFixtureStartUp() - { - appHost = new ExampleAppHostHttpListenerLongRunning(); - 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; - } - - [Test] - public void Root_path_redirects_to_metadata_page() - { - var html = ListeningOn.DownloadUrl(); - Assert.That(html.Contains("The following operations are supported.")); - } - - [Test] - public void Can_download_webpage_html_page() - { - var html = (ListeningOn + "webpage.html").DownloadUrl(); - Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); - } - - [Test] - public void Can_download_requestinfo_json() - { - var html = (ListeningOn + "_requestinfo").DownloadUrl(); - Assert.That(html.Contains("\"Host\":")); - } - - [Test] - public void Gets_404_on_non_existant_page() - { - var webRes = (ListeningOn + "nonexistant.html").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); - } - - [Test] - public void Gets_403_on_page_with_non_whitelisted_extension() - { - var webRes = (ListeningOn + "webpage.forbidden").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden)); - } - - [Test] - public void Can_call_GetFactorial_WebService() - { - var client = new XmlServiceClient(ListeningOn); - var request = new GetFactorial { ForNumber = 3 }; - var response = client.Send(request); - - Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); - } - - [Test] - public void Can_call_jsv_debug_on_GetFactorial_WebService() - { - const string url = ListeningOn + "jsv/syncreply/GetFactorial?ForNumber=3&debug=true"; - var contents = new StreamReader(WebRequest.Create(url).GetResponse().GetResponseStream()).ReadToEnd(); - - Console.WriteLine("JSV DEBUG: " + contents); - - Assert.That(contents, Is.Not.Null); - } - - [Test] - public void Calling_missing_web_service_does_not_break_HttpListener() - { - var missingUrl = ListeningOn + "missing.html"; - int errorCount = 0; - try - { - new StreamReader(WebRequest.Create(missingUrl).GetResponse().GetResponseStream()).ReadToEnd(); - } - catch (Exception ex) - { - errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); - } - try - { - new StreamReader(WebRequest.Create(missingUrl).GetResponse().GetResponseStream()).ReadToEnd(); - } - catch (Exception ex) - { - errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); - } - - Assert.That(errorCount, Is.EqualTo(2)); - } - - [Test] - public void Can_call_MoviesZip_WebService() - { - var client = new JsonServiceClient(ListeningOn); - var request = new MoviesZip(); - var response = client.Send(request); - - Assert.That(response.Movies.Count, Is.GreaterThan(0)); - } - - [Test] - 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"); - } - catch (WebServiceException ex) - { - Assert.That(ex.StatusCode, Is.EqualTo(405)); - } - } - - [Test] - public void Can_GET_single_gethttpresult_using_RestClient_with_JSONP_from_service_returning_HttpResult() - { - var url = ListeningOn + "gethttpresult?callback=cb"; - string response; - - var webReq = (HttpWebRequest)WebRequest.Create(url); - webReq.Accept = "*/*"; - using (var webRes = webReq.GetResponse()) - { - Assert.That(webRes.ContentType, Is.StringStarting(ContentType.Json)); - response = webRes.DownloadText(); - } - - Assert.That(response, Is.Not.Null, "No response received"); - Console.WriteLine(response); - Assert.That(response, Is.StringStarting("cb(")); - Assert.That(response, Is.StringEnding(")")); - } - - [Test, Ignore] - public void DebugHost() - { - Thread.Sleep(180 * 1000); - } - - [Test, Ignore] - public void PerformanceTest() - { - const int clientCount = 500; - var threads = new List(clientCount); - //ThreadPool.SetMinThreads(500, 50); - //ThreadPool.SetMaxThreads(1000, 50); - - for (int i = 0; i < clientCount; i++) - { - threads.Add(new Thread(() => { - var html = (ListeningOn + "long_running").DownloadUrl(); - })); - } - - var sw = new Stopwatch(); - sw.Start(); - for (int i = 0; i < clientCount; i++) - { - threads[i].Start(); - } - - - for (int i = 0; i < clientCount; i++) - { - threads[i].Join(); - } - - sw.Stop(); - - Trace.TraceInformation("Elapsed time for " + clientCount + " requests : " + sw.Elapsed); - } - } -} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Threading; +using NUnit.Framework; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + class AppHostHttpListenerLongRunningBaseTests + { + private const string ListeningOn = "http://localhost:1337/"; + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureStartUp() + { + appHost = new ExampleAppHostHttpListenerPool() + .Init() + .Start(ListeningOn); + + Console.WriteLine(@"ExampleAppHost Created at {0}, listening on {1}", DateTime.Now, ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Root_path_redirects_to_metadata_page() + { + var html = ListeningOn.GetStringFromUrl(); + Assert.That(html.Contains("The following operations are supported.")); + } + + [Test] + public void Can_download_webpage_html_page() + { + var html = (ListeningOn + "webpage.html").GetStringFromUrl(); + Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); + } + + [Test] + public void Can_download_requestinfo_json() + { + var html = (ListeningOn + "?debug=requestinfo").GetStringFromUrl(); + Assert.That(html.Contains("\"Host\":")); + } + + [Test] + public void Gets_404_on_non_existant_page() + { + var webRes = (ListeningOn + "nonexistant.html").GetErrorResponse(); + Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); + } + + [Test] + public void Gets_403_on_page_with_non_whitelisted_extension() + { + var webRes = (ListeningOn + "webpage.forbidden").GetErrorResponse(); + Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden)); + } + + [Test] + public void Can_call_GetFactorial_WebService() + { + var client = new XmlServiceClient(ListeningOn); + var request = new GetFactorial { ForNumber = 3 }; + var response = client.Send(request); + + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); + } + + [Test] + public void Can_call_jsv_debug_on_GetFactorial_WebService() + { + const string url = ListeningOn + "jsv/reply/GetFactorial?ForNumber=3&debug=true"; + var contents = url.GetStringFromUrl(); + + + Console.WriteLine("JSV DEBUG: " + contents); + + Assert.That(contents, Is.Not.Null); + } + + [Test] + public void Calling_missing_web_service_does_not_break_HttpListener() + { + var missingUrl = ListeningOn + "missing.html"; + int errorCount = 0; + try + { + missingUrl.GetStringFromUrl(); + } + catch (Exception ex) + { + errorCount++; + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); + } + try + { + missingUrl.GetStringFromUrl(); + } + catch (Exception ex) + { + errorCount++; + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); + } + + Assert.That(errorCount, Is.EqualTo(2)); + } + + [Test] + public void Can_call_MoviesZip_WebService() + { + var client = new JsonServiceClient(ListeningOn); + var request = new MoviesZip(); + var response = client.Send(request); + + Assert.That(response.Movies.Count, Is.GreaterThan(0)); + } + + [Test] + public void Calling_not_implemented_method_returns_405() + { + var client = new JsonServiceClient(ListeningOn); + try + { + var response = client.Put("all-movies.zip", new MoviesZip()); + Assert.Fail("Should throw 405 excetpion"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(405)); + } + } + + [Test] + public void Can_GET_single_gethttpresult_using_RestClient_with_JSONP_from_service_returning_HttpResult() + { + var url = ListeningOn + "gethttpresult?callback=cb"; + string response; + + var webReq = WebRequest.CreateHttp(url); + webReq.Accept = "*/*"; + using (var webRes = webReq.GetResponse()) + { + 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, Does.StartWith("cb(")); + Assert.That(response, Does.EndWith(")")); + } + + [Test, Ignore("Helper test")] + public void DebugHost() + { + Thread.Sleep(180 * 1000); + } + + [Test, Ignore("Performance test")] + public void PerformanceTest() + { + const int clientCount = 500; + var threads = new List(clientCount); + //ThreadPool.SetMinThreads(500, 50); + //ThreadPool.SetMaxThreads(1000, 50); + + for (int i = 0; i < clientCount; i++) + { + threads.Add(new Thread(() => { + var html = (ListeningOn + "long_running").GetStringFromUrl(); + })); + } + + var sw = new Stopwatch(); + sw.Start(); + for (int i = 0; i < clientCount; i++) + { + threads[i].Start(); + } + + + for (int i = 0; i < clientCount; i++) + { + threads[i].Join(); + } + + sw.Stop(); + + Trace.TraceInformation("Elapsed time for " + clientCount + " requests : " + sw.Elapsed); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs index 9ef935d1bc9..137db420268 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs @@ -1,213 +1,268 @@ -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 System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using NUnit.Framework; +#if !NETCORE +using ServiceStack.Host.HttpListener; +#endif +using ServiceStack.Logging; +using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class AppHostListenerBaseTests - { - private const string ListeningOn = "http://localhost:82/"; - ExampleAppHostHttpListener appHost; - - static AppHostListenerBaseTests() - { - LogManager.LogFactory = new ConsoleLogFactory(); - } - - [TestFixtureSetUp] - public void OnTestFixtureStartUp() - { - appHost = new ExampleAppHostHttpListener(); - 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; - } - - [Test] - public void Root_path_redirects_to_metadata_page() - { - var html = ListeningOn.DownloadUrl(); - Assert.That(html.Contains("The following operations are supported.")); - } - - [Test] - public void Can_download_webpage_html_page() - { - var html = (ListeningOn + "webpage.html").DownloadUrl(); - Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); - } - - [Test] - public void Can_download_requestinfo_json() - { - var html = (ListeningOn + "_requestinfo").DownloadUrl(); - Assert.That(html.Contains("\"Host\":")); - } - - [Test] - public void Gets_404_on_non_existant_page() - { - var webRes = (ListeningOn + "nonexistant.html").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); - } - - [Test] - public void Gets_403_on_page_with_non_whitelisted_extension() - { - var webRes = (ListeningOn + "webpage.forbidden").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden)); - } - - [Test] - public void Can_call_GetFactorial_WebService() - { - var client = new XmlServiceClient(ListeningOn); - var request = new GetFactorial { ForNumber = 3 }; - var response = client.Send(request); - - Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); - } - - [Test] - public void Can_call_jsv_debug_on_GetFactorial_WebService() - { - const string url = ListeningOn + "jsv/syncreply/GetFactorial?ForNumber=3&debug=true"; - var contents = new StreamReader(WebRequest.Create(url).GetResponse().GetResponseStream()).ReadToEnd(); - - Console.WriteLine("JSV DEBUG: " + contents); - - Assert.That(contents, Is.Not.Null); - } - - [Test] - public void Calling_missing_web_service_does_not_break_HttpListener() - { - var missingUrl = ListeningOn + "missing.html"; - int errorCount = 0; - try - { - new StreamReader(WebRequest.Create(missingUrl).GetResponse().GetResponseStream()).ReadToEnd(); - } - catch (Exception ex) - { - errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); - } - try - { - new StreamReader(WebRequest.Create(missingUrl).GetResponse().GetResponseStream()).ReadToEnd(); - } - catch (Exception ex) - { - errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); - } - - Assert.That(errorCount, Is.EqualTo(2)); - } - - [Test] - public void Can_call_MoviesZip_WebService() - { - var client = new JsonServiceClient(ListeningOn); - var request = new MoviesZip(); - var response = client.Send(request); - - Assert.That(response.Movies.Count, Is.GreaterThan(0)); - } - - [Test] - 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"); - } - catch (WebServiceException ex) - { - Assert.That(ex.StatusCode, Is.EqualTo(405)); - } - } - - [Test] - public void Can_GET_single_gethttpresult_using_RestClient_with_JSONP_from_service_returning_HttpResult() - { - var url = ListeningOn + "gethttpresult?callback=cb"; - string response; - - var webReq = (HttpWebRequest)WebRequest.Create(url); - webReq.Accept = "*/*"; - using (var webRes = webReq.GetResponse()) - { - Assert.That(webRes.ContentType, Is.StringStarting(ContentType.Json)); - response = webRes.DownloadText(); - } - - Assert.That(response, Is.Not.Null, "No response received"); - Console.WriteLine(response); - Assert.That(response, Is.StringStarting("cb(")); - Assert.That(response, Is.StringEnding(")")); - } - - [Test, Ignore] - public void DebugHost() - { - Thread.Sleep(180 * 1000); - } - - [Test, Ignore] - public void PerformanceTest() - { - const int clientCount = 500; - var threads = new List(clientCount); - ThreadPool.SetMinThreads(500, 50); - ThreadPool.SetMaxThreads(1000, 50); - - for (int i = 0; i < clientCount; i++) - { - threads.Add(new Thread(() => - { - var html = (ListeningOn + "long_running").DownloadUrl(); - })); - } - - var sw = new Stopwatch(); - sw.Start(); - for (int i = 0; i < clientCount; i++) - { - threads[i].Start(); - } - - - for (int i = 0; i < clientCount; i++) - { - threads[i].Join(); - } - - sw.Stop(); - - Trace.TraceInformation("Elapsed time for " + clientCount + " requests : " + sw.Elapsed); - } - } + [TestFixture] + public class AppHostListenerBaseTests + { + private const string ListeningOn = "http://localhost:1337/"; + ServiceStackHost appHost; + + static AppHostListenerBaseTests() + { + LogManager.LogFactory = new ConsoleLogFactory(); + } + + [OneTimeSetUp] + public void OnTestFixtureStartUp() + { + appHost = new ExampleAppHostHttpListener() + .Init() + .Start(ListeningOn); + + "ExampleAppHost Created at {0}, listening on {1}".Print(DateTime.Now, ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Root_path_redirects_to_metadata_page() + { + var html = ListeningOn.GetStringFromUrl(); + Assert.That(html.Contains("The following operations are supported.")); + } + + [Test] + public void Can_download_webpage_html_page() + { + var html = (ListeningOn + "webpage.html").GetStringFromUrl(); + Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); + } + + [Test] + public void Can_download_requestinfo_json() + { + var html = (ListeningOn + "?debug=requestinfo").GetStringFromUrl(); + Assert.That(html.Contains("\"Host\":")); + } + + [Test] + public void Gets_404_on_non_existant_page() + { + var webRes = (ListeningOn + "nonexistant.html").GetErrorResponse(); + Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); + } + + [Test] + public void Gets_403_on_page_with_non_whitelisted_extension() + { + var webRes = (ListeningOn + "webpage.forbidden").GetErrorResponse(); + Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden)); + } + + [Test] + public void Can_call_GetFactorial_WebService() + { + var client = new XmlServiceClient(ListeningOn); + var request = new GetFactorial { ForNumber = 3 }; + var response = client.Send(request); + + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); + } + + [Test] + public void Can_call_jsv_debug_on_GetFactorial_WebService() + { + var url = ListeningOn + "jsv/reply/GetFactorial?ForNumber=3&debug=true"; + var contents = url.GetStringFromUrl(); + + Console.WriteLine(@"JSV DEBUG: " + contents); + + Assert.That(contents, Is.Not.Null); + } + + [Test] + public void Calling_missing_web_service_does_not_break_HttpListener() + { + var missingUrl = ListeningOn + "missing.html"; + int errorCount = 0; + try + { + missingUrl.GetStringFromUrl(); + } + catch (Exception ex) + { + errorCount++; + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); + } + try + { + missingUrl.GetStringFromUrl(); + } + catch (Exception ex) + { + errorCount++; + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); + } + + Assert.That(errorCount, Is.EqualTo(2)); + } + + [Test] + public void Can_call_MoviesZip_WebService() + { + var client = new JsonServiceClient(ListeningOn); + var request = new MoviesZip(); + var response = client.Send(request); + + Assert.That(response.Movies.Count, Is.GreaterThan(0)); + } + + [Test] + public void Calling_not_implemented_method_returns_405() + { + var client = new JsonServiceClient(ListeningOn); + try + { + var response = client.Put("all-movies.zip", new MoviesZip()); + Assert.Fail("Should throw 405 exception"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(405)); + } + } + + [Test] + public void Can_GET_single_gethttpresult_using_RestClient_with_JSONP_from_service_returning_HttpResult() + { + var url = ListeningOn + "gethttpresult?callback=cb"; + string response; + + var webReq = WebRequest.CreateHttp(url); + webReq.Accept = "*/*"; + using (var webRes = webReq.GetResponse()) + { + 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, Does.StartWith("cb(")); + Assert.That(response, Does.EndWith(")")); + } + + [Test, Ignore("Dubug test")] + public void DebugHost() + { + Thread.Sleep(180 * 1000); + } + + [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++) + { + threads.Add(new Thread(() => { + var html = (ListeningOn + "long_running").GetStringFromUrl(); + })); + } + + var sw = new Stopwatch(); + sw.Start(); + for (int i = 0; i < clientCount; i++) + { + threads[i].Start(); + } + + + for (int i = 0; i < clientCount; i++) + { + threads[i].Join(); + } + + sw.Stop(); + + Trace.TraceInformation("Elapsed time for " + clientCount + " requests : " + sw.Elapsed); + } + +#if !NETCORE + [Test] + public void Can_infer_handler_path_from_listener_uris() + { + var map = new Dictionary { + {"http://*:1337/",null}, + {"http://localhost:1337/",null}, + {"http://127.0.0.1:1337/",null}, + {"http://*/",null}, + {"http://localhost/",null}, + {"http://localhost:1337/subdir/","subdir"}, + {"http://localhost:1337/subdir/subdir2/","subdir/subdir2"}, + }; + + foreach (var entry in map) + { + 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() + { + var localAppHost = new ExampleAppHostHttpListener(); + + for (int i = 0; i < 100; i++) + { + localAppHost.Start(GetBaseAddressWithFreePort()); +#if !NETCORE + localAppHost.Stop(); +#endif + } + } + + private static string GetBaseAddressWithFreePort() + { + var listener = new TcpListener(IPAddress.Loopback, 0); + listener.Start(); + + if (listener.LocalEndpoint is IPEndPoint endPoint) + { + string address = endPoint.Address.ToString(); + int port = endPoint.Port; + Uri uri = new UriBuilder("http://", address, port).Uri; + + listener.Stop(); + + return uri.ToString(); + } + + throw new InvalidOperationException("Can not find a port to start the WpcsServer!"); + } + } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs new file mode 100644 index 00000000000..bdfdea1cb1e --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs @@ -0,0 +1,165 @@ +using System.Net; +using System.Text; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Host.Handlers; +#if !NETCORE +using ServiceStack.Host.HttpListener; +#endif +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class AppHostListenerEchoRequestTests + { + public class AppHost : AppHostHttpListenerBase + { + public AppHost() + : base("Echo AppHost", typeof(AppHost).Assembly) + { + } + + 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")] + [Route("/echo/{PathInfoParam}")] + public class Echo : IReturn + { + public string Param { get; set; } + public string PathInfoParam { get; set; } + } + + [Route("/customhtml")] + public class CustomHtml {} + + public class EchoService : Service + { + public Echo Any(Echo request) + { + return request; + } + + public RequestInfoResponse Any(RequestInfo request) + { + var requestInfo = RequestInfoHandler.GetRequestInfo(base.Request); + return requestInfo; + } + + public object Any(CustomHtml request) + { + return @" + + + + + + +
      + + + +
      + +"; + } + } + + private AppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + 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, Does.EndWith("/echo?Param=test%3a%2f%2f%3f%26%25+encoding")); + + var json = url.GetJsonFromUrl(); + var response = json.FromJson(); + Assert.That(response.Param, Is.EqualTo(testEncoding)); + } + + [Test] + public void Does_url_decode_raw_PathInfo() + { + var testEncoding = "test encoding"; + var url = "{0}echo/{1}".Fmt(Config.AbsoluteBaseUri, testEncoding.UrlEncode()); + Assert.That(url, Does.EndWith("/echo/test+encoding")); + + var json = url.GetJsonFromUrl(); + var response = json.FromJson(); + Assert.That(response.PathInfoParam, Is.EqualTo(testEncoding)); + } + + [Test] + public void Does_url_transparently_decode_QueryString() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var request = new Echo { Param = "test://?&% encoding" }; + var response = client.Get(request); + Assert.That(response.Param, Is.EqualTo(request.Param)); + } + + [Test] + public void Does_url_transparently_decode_PathInfo() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var request = new Echo { PathInfoParam = "test%2Fpath:?&% encoding" }; + var response = client.Get(request); + Assert.That(response.PathInfoParam, Is.EqualTo(request.PathInfoParam)); + } + + [Test] + public void Does_url_transparently_decode_RequestBody() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var request = new Echo { Param = "test://?&% encoding" }; + var response = client.Post(request); + 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 64b2764fe30..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 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 +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + 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 8a3fa43401e..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 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 +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + 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 66e941d457d..a379c9ca499 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTest.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTest.cs @@ -1,277 +1,413 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -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.Text; -using ServiceStack.WebHost.Endpoints.Utils; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - //Always executed - public class FilterTestAttribute : Attribute, IHasRequestFilter - { - private static ICacheClient previousCache; - - public ICacheClient Cache { get; set; } - - public int Priority { get; set; } - - public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto) - { - var dto = requestDto as AttributeFiltered; - 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; - } - - public IHasRequestFilter Copy() - { - return (IHasRequestFilter) this.MemberwiseClone(); - } - } - - //Only executed for the provided HTTP methods (GET, POST) - public class ContextualFilterTestAttribute : RequestFilterAttribute - { - public ContextualFilterTestAttribute(ApplyTo applyTo) - : base(applyTo) - { - } - - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) - { - var dto = requestDto as AttributeFiltered; - dto.ContextualRequestFilterExecuted = true; - } - } - - [RestService("/attributefiltered")] - [FilterTest] - [ContextualFilterTest(ApplyTo.Delete | ApplyTo.Put)] - public class AttributeFiltered - { - public bool RequestFilterExecuted { get; set; } - public bool ContextualRequestFilterExecuted { get; set; } - public bool RequestFilterDependenyIsResolved { get; set; } - } - - //Always executed - public class ResponseFilterTestAttribute : Attribute, IHasResponseFilter - { - private static ICacheClient previousCache; - - public ICacheClient Cache { get; set; } - - public int Priority { get; set; } - - public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response) - { - var dto = response.ToResponseDto() as AttributeFilteredResponse; - dto.ResponseFilterExecuted = true; - dto.ResponseFilterDependencyIsResolved = Cache != null && !Cache.Equals(previousCache); - - previousCache = Cache; - } - - public IHasResponseFilter Copy() - { - return (IHasResponseFilter)this.MemberwiseClone(); - } - } - - //Only executed for the provided HTTP methods (GET, POST) - public class ContextualResponseFilterTestAttribute : ResponseFilterAttribute - { - public ContextualResponseFilterTestAttribute(ApplyTo applyTo) - : base(applyTo) - { - } - - public override void Execute(IHttpRequest req, IHttpResponse res, object responseDto) - { - var dto = responseDto as AttributeFilteredResponse; - dto.ContextualResponseFilterExecuted = true; - } - } - - [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 ContextualRequestFilterExecuted { get; set; } - - public bool RequestFilterDependenyIsResolved { get; set; } - public bool ResponseFilterDependencyIsResolved { get; set; } - } - - public class AttributeFilteredService : IService - { - public object Execute(AttributeFiltered request) - { - return new AttributeFilteredResponse() { - ResponseFilterExecuted = false, - ContextualResponseFilterExecuted = false, - RequestFilterExecuted = request.RequestFilterExecuted, - ContextualRequestFilterExecuted = request.ContextualRequestFilterExecuted, - RequestFilterDependenyIsResolved = request.RequestFilterDependenyIsResolved, - ResponseFilterDependencyIsResolved = false - }; - } - } - - [TestFixture] - public class AttributeFiltersTest - { - private const string ListeningOn = "http://localhost:82/"; - private const string ServiceClientBaseUri = "http://localhost:82/"; - - public class AttributeFiltersAppHostHttpListener - : AppHostHttpListenerBase - { - - public AttributeFiltersAppHostHttpListener() - : base("Attribute Filters Tests", typeof(AttributeFilteredService).Assembly) { } - - public override void Configure(Funq.Container container) - { - container.Register(c => new MemoryCacheClient()).ReusedWithin(Funq.ReuseScope.None); - } - } - - AttributeFiltersAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new AttributeFiltersAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - 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 AttributeFiltered { 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); - } - - static IRestClient[] RestClients = - { - new JsonServiceClient(ServiceClientBaseUri), - new XmlServiceClient(ServiceClientBaseUri), - new JsvServiceClient(ServiceClientBaseUri) - }; - - [Test, TestCaseSource("RestClients")] - public void Request_and_Response_Filters_are_executed_using_RestClient(IRestClient client) - { - var response = client.Post("attributefiltered", new AttributeFiltered() { 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"); - 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", new AttributeFiltered() { 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); - } - - [FilterTest] - [RequiredRole("test")] - [Authenticate] - [RequiredPermission("test")] - public class DummyHolder { } - - [Test] - public void RequestFilters_are_prioritized() - { - EndpointHost.ServiceManager = new ServiceManager(typeof(DummyHolder).Assembly); - EndpointHost.ServiceManager.ServiceController.RequestServiceTypeMap[typeof(DummyHolder)] - = typeof(AttributeFilteredService); - - var attributes = FilterAttributeCache.GetRequestFilterAttributes(typeof(DummyHolder)); - var attrPriorities = attributes.ToList().ConvertAll(x => x.Priority); - Assert.That(attrPriorities, Is.EquivalentTo(new[] { -100, -90, -80, 0 })); - - var execOrder = new IHasRequestFilter[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); - Console.WriteLine(execOrderPriorities.Dump()); - Assert.That(execOrderPriorities, Is.EquivalentTo(new[] { -100, -90, -80, 0 })); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +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 FilterTestAttribute : AttributeBase, IHasRequestFilter + { + private static ICacheClient previousCache; + + public ICacheClient Cache { get; set; } + + public int Priority { get; set; } + + public void RequestFilter(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFiltered)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; + } + + public IRequestFilterBase Copy() => (IRequestFilterBase)this.MemberwiseClone(); + } + + //Only executed for the provided HTTP methods (GET, POST) + public class ContextualFilterTestAttribute : RequestFilterAttribute + { + public ContextualFilterTestAttribute(ApplyTo applyTo) + : base(applyTo) + { + } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFiltered)requestDto; + dto.AttrsExecuted.Add(GetType().Name); + dto.ContextualRequestFilterExecuted = true; + } + } + + [Route("/attributefiltered")] + [FilterTest] + [ContextualFilterTest(ApplyTo.Delete | ApplyTo.Put)] + public class AttributeFiltered + { + public AttributeFiltered() + { + 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 ResponseFilterTestAttribute : AttributeBase, IHasResponseFilter + { + private static ICacheClient previousCache; + + public ICacheClient Cache { get; set; } + + public int Priority { get; set; } + + public void ResponseFilter(IRequest req, IResponse res, object response) + { + var dto = response.GetResponseDto() as AttributeFilteredResponse; + dto.ResponseFilterExecuted = true; + dto.ResponseFilterDependencyIsResolved = Cache != null && !Cache.Equals(previousCache); + + previousCache = Cache; + } + + public IResponseFilterBase Copy() => (IResponseFilterBase)this.MemberwiseClone(); + } + + //Only executed for the provided HTTP methods (GET, POST) + public class ContextualResponseFilterTestAttribute : ResponseFilterAttribute + { + public ContextualResponseFilterTestAttribute(ApplyTo applyTo) + : base(applyTo) + { + } + + public override void Execute(IRequest req, IResponse res, object responseDto) + { + var dto = responseDto as AttributeFilteredResponse; + dto.ContextualResponseFilterExecuted = true; + } + } + + public class ThrowingFilterAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + throw new ArgumentException("exception message"); + } + } + + [Route("/throwingattributefiltered")] + public class ThrowingAttributeFiltered : IReturn + { + } + + [ThrowingFilter] + public class ThrowingAttributeFilteredService : IService + { + public object Any(ThrowingAttributeFiltered request) + { + return "OK"; + } + } + + public class AttributeFilteredResponse + { + 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 PriortyAttributeService : Service + { + [Priority(3, "3rd")] + [Priority(2, "2nd")] + [Priority(1, "1st")] + public object Any(PriorityAttributeTest request) + { + 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 + }; + } + } + + 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:1337/"; + private const string ServiceClientBaseUri = "http://localhost:1337/"; + + public class AttributeFiltersAppHostHttpListener + : AppHostHttpListenerBase + { + + public AttributeFiltersAppHostHttpListener() + : 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 + } + } + + AttributeFiltersAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new AttributeFiltersAppHostHttpListener(); + 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 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 = + { + 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 ThrowingAttributeFiltered()); + } + 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", new AttributeFiltered() { 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"); + 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", new AttributeFiltered() { 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 PriorityAttributeTest()); + + response.PrintDump(); + + Assert.That(response.Names, Is.EqualTo(new[] { "1st", "2nd", "3rd" })); + } + + public class ExecutedFirstAttribute : RequestFilterAttribute + { + public ExecutedFirstAttribute() + { + Priority = int.MinValue; + } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFiltered)requestDto; + dto.AttrsExecuted.Add(GetType().Name); + } + } + + [ExecutedFirst] + [FilterTest] + [RequiredRole("test")] + [Authenticate] + [RequiredPermission("test")] + public class DummyHolder { } + + [Test] + public void RequestFilters_are_prioritized() + { + 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, 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/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 8e71edfbd3a..9d105557388 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthTests.cs @@ -1,421 +1,1647 @@ -using System; -using System.IO; -using System.Net; -using System.Threading; -using Funq; -using NUnit.Framework; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -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.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Services; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [RestService("/secured")] - public class Secured - { - public string Name { get; set; } - } - - public class SecuredResponse - { - public string Result { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - [Authenticate] - public class SecuredService : RestServiceBase - { - public override object OnPost(Secured request) - { - return new SecuredResponse { Result = request.Name }; - } - - public override object OnGet(Secured request) - { - throw new ArgumentException("unicorn nuggets"); - } - } - - [RestService("/securedfileupload")] - public class SecuredFileUpload - { - public int CustomerId { get; set; } - public string CustomerName { get; set; } - } - - [Authenticate] - public class SecuredFileUploadService : RestServiceBase - { - public override object OnPost(SecuredFileUpload request) - { - var file = this.RequestContext.Files[0]; - return new FileUploadResponse - { - FileName = file.FileName, - ContentLength = file.ContentLength, - ContentType = file.ContentType, - Contents = new StreamReader(file.InputStream).ReadToEnd(), - CustomerId = request.CustomerId, - CustomerName = request.CustomerName - }; - } - } - - - public class RequiresRole - { - public string Name { get; set; } - } - - public class RequiresRoleResponse - { - public string Result { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - [RequiredRole("TheRole")] - public class RequiresRoleService : ServiceBase - { - protected override object Run(RequiresRole request) - { - return new RequiresRoleResponse { Result = request.Name }; - } - } - - public class CustomUserSession : AuthUserSession - { - public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, System.Collections.Generic.Dictionary authInfo) - { - if (!session.Roles.Contains("TheRole")) - session.Roles.Add("TheRole"); - - authService.RequestContext.Get().SaveSession(session); - } - } - - public class AuthTests - { - private const string ListeningOn = "http://localhost:82/"; - - private const string UserName = "user"; - private const string Password = "p@55word"; - - public class AuthAppHostHttpListener - : AppHostHttpListenerBase - { - public AuthAppHostHttpListener() - : base("Validation Tests", typeof(CustomerService).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(new MemoryCacheClient()); - var userRep = new InMemoryAuthRepository(); - container.Register(userRep); - - string hash; - string salt; - new SaltedHash().GetHashAndSaltString(Password, out hash, out salt); - - userRep.CreateUserAuth(new UserAuth { - Id = 1, - DisplayName = "DisplayName", - Email = "as@if.com", - UserName = UserName, - FirstName = "FirstName", - LastName = "LastName", - PasswordHash = hash, - Salt = salt, - }, Password); - } - } - - AuthAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new AuthAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - private static void FailOnAsyncError(T response, Exception ex) - { - Assert.Fail(ex.Message); - } - - IServiceClient GetClient() - { - return new JsonServiceClient(ListeningOn); - } - - IServiceClient GetClientWithUserPassword() - { - return new JsonServiceClient(ListeningOn) { - UserName = UserName, - Password = Password, - }; - } - - [Test] - public void No_Credentials_throws_UnAuthorized() - { - try - { - var client = GetClient(); - var request = new Secured { Name = "test" }; - var response = client.Send(request); - - Assert.Fail("Shouldn't be allowed"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - Console.WriteLine(webEx.ResponseDto.Dump()); - } - } - - [Test] - public void PostFile_with_no_Credentials_throws_UnAuthorized() - { - try - { - var client = GetClient(); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - client.PostFile(ListeningOn + "/securedfileupload", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); - - Assert.Fail("Shouldn't be allowed"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - Console.WriteLine(webEx.ResponseDto.Dump()); - } - } - - [Test] - public void PostFile_does_work_with_BasicAuth() - { - var client = GetClientWithUserPassword(); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - - var expectedContents = new StreamReader(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)); - Assert.That(response.Contents, Is.EqualTo(expectedContents)); - } - - [Test] - 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 expectedContents = new StreamReader(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)); - Assert.That(response.Contents, Is.EqualTo(expectedContents)); - Assert.That(response.CustomerName, Is.EqualTo("Foo")); - Assert.That(response.CustomerId, Is.EqualTo(123)); - } - - [Test] - public void Does_work_with_BasicAuth() - { - 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 void Does_always_send_BasicAuth() - { - try - { - var client = (ServiceClientBase)GetClientWithUserPassword(); - client.AlwaysSendBasicAuthHeader = true; - client.LocalHttpWebRequestFilter = req => { - bool hasAuthentication = false; - foreach (var key in req.Headers.Keys) - { - if (key.ToString() == "Authorization") - hasAuthentication = true; - } - Assert.IsTrue(hasAuthentication); - }; - - 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 Does_work_with_CredentailsAuth() - { - try - { - var client = GetClient(); - - var authResponse = client.Send(new Auth { - provider = CredentialsAuthProvider.Name, - UserName = "user", - Password = "p@55word", - RememberMe = true, - }); - - Console.WriteLine(authResponse.Dump()); - - 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 Does_work_with_CredentailsAuth_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 => { - Console.WriteLine(authResponse.Dump()); - client.SendAsync(request, r => response = r, FailOnAsyncError); - - }, FailOnAsyncError); - - Thread.Sleep(TimeSpan.FromSeconds(1)); - Assert.That(response.Result, Is.EqualTo(request.Name)); - } - - [Test] - public void Can_call_RequiredRole_service_with_BasicAuth() - { - try - { - var client = GetClientWithUserPassword(); - 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_work_with_CredentailsAuth_Multiple_Times() - { - try - { - var client = GetClient(); - - var authResponse = client.Send(new Auth { - provider = CredentialsAuthProvider.Name, - UserName = "user", - Password = "p@55word", - RememberMe = true, - }); - - Console.WriteLine(authResponse.Dump()); - - for(int i =0; i<500; i++){ - var request = new Secured { Name = "test" }; - var response = client.Send(request); - Assert.That(response.Result, Is.EqualTo(request.Name)); - Console.WriteLine("loop : {0}",i); - } - } - catch (WebServiceException webEx) - { - Assert.Fail(webEx.Message); - } - } - - [Test] - public void Exceptions_thrown_are_received_by_client_when_AlwaysSendBasicAuthHeader_is_false() - { - try - { - var client = (IRestClient)GetClientWithUserPassword(); - ((ServiceClientBase)client).AlwaysSendBasicAuthHeader = false; - var response = client.Get("/secured"); - - Assert.Fail("Should have thrown"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.ErrorMessage, Is.EqualTo("unicorn nuggets")); - } - } - - [Test] - public void Exceptions_thrown_are_received_by_client_when_AlwaysSendBasicAuthHeader_is_true() - { - try - { - var client = (IRestClient)GetClientWithUserPassword(); - ((ServiceClientBase)client).AlwaysSendBasicAuthHeader = true; - var response = client.Get("/secured"); - - Assert.Fail("Should have thrown"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.ErrorMessage, Is.EqualTo("unicorn nuggets")); - } - } - } -} \ No newline at end of file +using System; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Common.Tests.ServiceClient.Web; +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; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [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("/securedfileupload")] + public class SecuredFileUpload + { + public int CustomerId { get; set; } + public string CustomerName { get; set; } + } + + [Authenticate] + public class SecuredService : Service + { + public object Post(Secured request) + { + return new SecuredResponse { Result = request.Name }; + } + + public object Get(Secured request) + { + throw new ArgumentException("unicorn nuggets"); + } + + public object Post(SecuredFileUpload request) + { + var file = this.Request.Files[0]; + return new FileUploadResponse + { + FileName = file.FileName, + ContentLength = file.ContentLength, + ContentType = file.ContentType, + Contents = file.InputStream.ReadToEnd(), + CustomerId = request.CustomerId, + CustomerName = request.CustomerName + }; + } + } + + public class RequiresRole + { + public string Name { get; set; } + } + + public class RequiresRoleResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [RequiredRole("TheRole")] + public class RequiresRoleService : Service + { + public object Any(RequiresRole request) + { + return new RequiresRoleResponse { Result = request.Name }; + } + } + + public class RequiresAnyRole + { + public List Roles { get; set; } + + public RequiresAnyRole() + { + Roles = new List(); + } + } + + public class RequiresAnyRoleResponse + { + public List Result { get; set; } + + public ResponseStatus RepsonseStatus { get; set; } + + public RequiresAnyRoleResponse() + { + Result = new List(); + } + } + + [RequiresAnyRole("TheRole", "TheRole2")] + public class RequiresAnyRoleService : Service + { + public object Any(RequiresAnyRole request) + { + return new RequiresAnyRoleResponse { Result = request.Roles }; + } + } + + public class RequiresPermission + { + public string Name { get; set; } + } + + public class RequiresPermissionResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [RequiredPermission("ThePermission")] + public class RequiresPermissionService : Service + { + public RequiresPermissionResponse Any(RequiresPermission request) + { + return new RequiresPermissionResponse { Result = request.Name }; + } + } + + public class RequiresAnyPermission + { + public List Permissions { get; set; } + + public RequiresAnyPermission() + { + Permissions = new List(); + } + } + + public class RequiresAnyPermissionResponse + { + public List Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + + public RequiresAnyPermissionResponse() + { + Result = new List(); + } + } + + [RequiresAnyPermission("ThePermission", "ThePermission2")] + public class RequiresAnyPermissionService : Service + { + public RequiresAnyPermissionResponse Any(RequiresAnyPermission request) + { + return new RequiresAnyPermissionResponse { Result = request.Permissions }; + } + } + + public class CustomUserSession : WebSudoAuthUserSession + { + public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, System.Collections.Generic.Dictionary authInfo) + { + 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 + { + public CustomAuthProvider() + { + this.Provider = "custom"; + } + + public override bool IsAuthorized(IAuthSession session, IAuthTokens tokens, Authenticate request = null) + { + return false; + } + + public override Task AuthenticateAsync(IServiceBase authService, IAuthSession session, Authenticate request, + CancellationToken token = default) + { + throw new NotImplementedException(); + } + } + + public class RequiresCustomAuth + { + public string Name { get; set; } + } + + public class RequiresCustomAuthResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [Authenticate(Provider = "custom")] + public class RequiresCustomAuthService : Service + { + public RequiresCustomAuthResponse Any(RequiresCustomAuth request) + { + return new RequiresCustomAuthResponse { Result = request.Name }; + } + } + + public class CustomAuthenticateAttribute : AuthenticateAttribute + { + 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. + + return base.ExecuteAsync(req, res, requestDto); + } + } + + public class CustomAuthAttr + { + public string Name { get; set; } + } + + public class CustomAuthAttrResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [CustomAuthenticate] + public class CustomAuthAttrService : Service + { + public CustomAuthAttrResponse Any(CustomAuthAttr request) + { + if (!Request.Items.ContainsKey("TriedMyOwnAuthFirst")) + throw new InvalidOperationException("TriedMyOwnAuthFirst not present."); + + return new CustomAuthAttrResponse { Result = request.Name }; + } + } + + public class RequiresWebSudo : IReturn + { + public string Name { get; set; } + } + + 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 AuthAppHost(string webHostUrl, Action configureFn = null) + : base("Validation Tests", typeof(CustomerService).Assembly) + { + this.webHostUrl = webHostUrl; + this.configureFn = configureFn; + } + + private InMemoryAuthRepository userRep; + + public override void Configure(Container container) + { + SetConfig(new HostConfig { WebHostUrl = webHostUrl, DebugMode = true }); + + 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); + + if (configureFn != null) + { + configureFn(container); + } + + 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 + { + 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"; + + 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"; + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new AuthAppHost(WebHostUrl, Configure); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + public virtual void Configure(Container container) + { + } + + private static void FailOnAsyncError(T response, Exception ex) + { + Assert.Fail(ex.Message); + } + + IServiceClient GetClient() + { + return new JsonServiceClient(ListeningOn); + } + + IServiceClient GetHtmlClient() + { + return new HtmlServiceClient(ListeningOn) { BaseUri = ListeningOn }; + } + + IServiceClient GetClientWithUserPassword() + { + return new JsonServiceClient(ListeningOn) + { + UserName = UserName, + Password = Password + }; + } + + private void AssertDoesThrowUnauthorized(Action send) + { + try + { + send(GetClient()); + + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException webEx) + { + 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 Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + var request = new RequiresCustomAuth { Name = "test" }; + var response = client.Send(request); + + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void PostFile_with_no_Credentials_throws_UnAuthorized() + { + try + { + var client = GetClient(); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + client.PostFile(ListeningOn + "/securedfileupload", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); + + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void PostFile_does_work_with_BasicAuth() + { + var client = GetClientWithUserPassword(); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + 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)); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + } + + [Test] + 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".MapProjectPlatformPath()); + + 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)); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + Assert.That(response.CustomerName, Is.EqualTo("Foo")); + Assert.That(response.CustomerId, Is.EqualTo(123)); + } + + [Test] + public void Does_work_with_BasicAuth() + { + 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_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() + { + try + { + 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)); + } + 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 + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + 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 Can_sent_Session_using_Headers() + { + try + { + var client = GetClient(); + + var authResponse = client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + 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 = clientWithHeaders.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public async Task Does_work_with_CredentialsAuth_Async() + { + var client = GetClient(); + + var request = new Secured { Name = "test" }; + var authResponse = await client.SendAsync( + new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + var response = await client.SendAsync(request); + + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_call_RequiredRole_service_with_BasicAuth() + { + try + { + var client = GetClientWithUserPassword(); + 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 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() + { + try + { + var client = GetClient(); + var request = new RequiresRole { Name = "test" }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void RequiredRole_service_returns_forbidden_if_basic_auth_header_exists() + { + try + { + var client = GetClient(); + ((ServiceClientBase)client).UserName = EmailBasedUsername; + ((ServiceClientBase)client).Password = PasswordForEmailBasedAccount; + + var request = new RequiresRole { Name = "test" }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void Can_call_RequiredPermission_service_with_BasicAuth() + { + try + { + var client = GetClientWithUserPassword(); + var request = new RequiresPermission { 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 RequiredPermission_service_returns_unauthorized_if_no_basic_auth_header_exists() + { + try + { + var client = GetClient(); + var request = new RequiresPermission { Name = "test" }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void RequiredPermission_service_returns_forbidden_if_basic_auth_header_exists() + { + try + { + var client = GetClient(); + ((ServiceClientBase)client).UserName = EmailBasedUsername; + ((ServiceClientBase)client).Password = PasswordForEmailBasedAccount; + + var request = new RequiresPermission { Name = "test" }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + 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 Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + Console.WriteLine(authResponse.Dump()); + + for (int i = 0; i < 10; i++) + { + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + Console.WriteLine("loop : {0}", i); + } + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [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() + { + try + { + var client = (IRestClient)GetClientWithUserPassword(); + ((ServiceClientBase)client).AlwaysSendBasicAuthHeader = false; + var response = client.Get("/secured"); + + Assert.Fail("Should have thrown"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.ErrorMessage, Is.EqualTo("unicorn nuggets")); + } + } + + [Test] + public void Exceptions_thrown_are_received_by_client_when_AlwaysSendBasicAuthHeader_is_true() + { + try + { + var client = (IRestClient)GetClientWithUserPassword(); + ((ServiceClientBase)client).AlwaysSendBasicAuthHeader = true; + var response = client.Get("/secured"); + + Assert.Fail("Should have thrown"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.ErrorMessage, Is.EqualTo("unicorn nuggets")); + } + } + + [Test] + public void Html_clients_receive_redirect_to_login_page_when_accessing_unauthenticated() + { + var client = (ServiceClientBase)GetHtmlClient(); + client.AllowAutoRedirect = false; + string lastResponseLocationHeader = null; + client.ResponseFilter = response => + { + lastResponseLocationHeader = response.Headers["Location"]; + }; + + var request = new Secured { Name = "test" }; + 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); + var loginPath = "/".CombineWith(VirtualDirectory).CombineWith(LoginUrl); + Assert.That(locationUri.AbsolutePath, Is.EqualTo(loginPath).IgnoreCase); + } + + [Test] + public void Html_clients_receive_secured_url_attempt_in_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" }; + 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[Keywords.Redirect]; + var redirectUri = new Uri(redirectQueryString); + + // Should contain the url attempted to access before the redirect to the login page. + 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] + public void Html_clients_receive_session_ReferrerUrl_on_successful_authentication() + { + var client = (ServiceClientBase)GetHtmlClient(); + client.AllowAutoRedirect = false; + string lastResponseLocationHeader = null; + client.ResponseFilter = response => + { + lastResponseLocationHeader = response.Headers["Location"]; + }; + + try + { + 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)); + } + + public void Already_authenticated_session_returns_correct_username() + { + var client = GetClient(); + + var authRequest = new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserName, + Password = Password, + RememberMe = true, + }; + var initialLoginResponse = client.Send(authRequest); + var alreadyLoggedInResponse = client.Send(authRequest); + + Assert.That(alreadyLoggedInResponse.UserName, Is.EqualTo(UserName)); + } + + + [Test] + public void AuthResponse_returns_email_as_username_if_user_registered_with_email() + { + var client = GetClient(); + + var authRequest = new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = EmailBasedUsername, + Password = PasswordForEmailBasedAccount, + RememberMe = true, + }; + var authResponse = client.Send(authRequest); + + Assert.That(authResponse.UserName, Is.EqualTo(EmailBasedUsername)); + } + + [Test] + public void Already_authenticated_session_returns_correct_username_when_user_registered_with_email() + { + var client = GetClient(); + + var authRequest = new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = EmailBasedUsername, + Password = PasswordForEmailBasedAccount, + RememberMe = true, + }; + var initialLoginResponse = client.Send(authRequest); + var alreadyLoggedInResponse = client.Send(authRequest); + + Assert.That(initialLoginResponse.UserName, Is.EqualTo(EmailBasedUsername)); + Assert.That(alreadyLoggedInResponse.UserName, Is.EqualTo(EmailBasedUsername)); + } + + [Test] + public void Can_call_RequiresAnyRole_service_with_BasicAuth() + { + try + { + var client = GetClientWithUserPassword(); + var roles = new List() { + "test", "test2" + }; + var request = new RequiresAnyRole { Roles = roles }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Roles)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void RequiresAnyRole_service_returns_unauthorized_if_no_basic_auth_header_exists() + { + try + { + var client = GetClient(); + var roles = new List() { + "test", "test2" + }; + var request = new RequiresAnyRole { Roles = roles }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void RequiresAnyRole_service_returns_forbidden_if_basic_auth_header_exists() + { + try + { + var client = GetClient(); + ((ServiceClientBase)client).UserName = EmailBasedUsername; + ((ServiceClientBase)client).Password = PasswordForEmailBasedAccount; + + var roles = new List() { + "test", "test2" + }; + var request = new RequiresAnyRole { Roles = roles }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void Can_call_RequiresAnyPermission_service_with_BasicAuth() + { + try + { + var client = GetClientWithUserPassword(); + var permissions = new List + { + "test", "test2" + }; + var request = new RequiresAnyPermission { Permissions = permissions }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Permissions)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void RequiresAnyPermission_service_returns_unauthorized_if_no_basic_auth_header_exists() + { + try + { + var client = GetClient(); + var permissions = new List + { + "test", "test2" + }; + var request = new RequiresAnyPermission { Permissions = permissions }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void RequiresAnyPermission_service_returns_forbidden_if_basic_auth_header_exists() + { + try + { + var client = GetClient(); + ((ServiceClientBase)client).UserName = EmailBasedUsername; + ((ServiceClientBase)client).Password = PasswordForEmailBasedAccount; + var permissions = new List + { + "test", "test2" + }; + var request = new RequiresAnyPermission { Permissions = permissions }; + var response = client.Send(request); + Assert.Fail(); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void Calling_AddSessionIdToRequest_from_a_custom_auth_attribute_does_not_duplicate_session_cookies() + { + WebHeaderCollection headers = null; + var client = GetClientWithUserPassword(); + ((ServiceClientBase)client).AlwaysSendBasicAuthHeader = true; + ((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( + System.Text.RegularExpressions.Regex.Matches(headers["Set-Cookie"], "ss-id=").Count, + 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(); + } + } +} 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 new file mode 100644 index 00000000000..807d92467df --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/BufferedRequestTests.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class BufferedRequestTests + { + private BufferedRequestAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BufferedRequestAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void BufferedRequest_allows_rereading_of_Request_InputStream() + { + appHost.LastRequestBody = null; + appHost.UseBufferedStream = true; + + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + var request = new MyRequest { Data = "RequestData" }; + var response = client.Post(request); + + Assert.That(response.Data, Is.EqualTo(request.Data)); + Assert.That(appHost.LastRequestBody, Is.EqualTo(request.ToJson())); + } + + [Test] + public void Cannot_reread_Request_InputStream_without_buffering() + { + appHost.LastRequestBody = null; + appHost.UseBufferedStream = false; + + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + var request = new MyRequest { Data = "RequestData" }; + + 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_buffering() + { + appHost.LastRequestBody = null; + appHost.UseBufferedStream = false; + + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + var request = new MyRequest { Data = "RequestData" }; + + 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")); + } + } + } + + [TestFixture] + public class BufferedRequestLoggerTests + { + private BufferedRequestAppHost appHost; + MyRequest request = new MyRequest { Data = "RequestData" }; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BufferedRequestAppHost { EnableRequestBodyTracking = true }; + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking() + { + var logBody = Run(new JsonServiceClient(Config.ServiceStackBaseUri)); + Assert.That(appHost.LastRequestBody, Is.EqualTo(request.ToJson())); + Assert.That(logBody, Is.EqualTo(request.ToJson())); + } + +#if !NETCORE + [Test] + public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking_Soap12() + { + const string soap12start = @"MyRequesturn:uuid:"; + const string soap12end = "RequestData"; + + var logBody = Run(new Soap12ServiceClient(Config.ServiceStackBaseUri)); + + 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() + { + const string soap11 = @"RequestData"; + + var logBody = Run(new Soap11ServiceClient(Config.ServiceStackBaseUri)); + 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.UseBufferedStream = false; + + var response = client.Send(request); + //Debug.WriteLine(appHost.LastRequestBody); + + Assert.That(response.Data, Is.EqualTo(request.Data)); + + var lastEntry = requestLogger.GetLatestLogs(int.MaxValue); + return lastEntry[lastEntry.Count - 1].RequestBody; + } + + } + + public class BufferedRequestAppHost : AppHostHttpListenerBase + { + public BufferedRequestAppHost() : base(nameof(BufferedRequestTests), typeof(MyService).Assembly) { } + + public string LastRequestBody { 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 (UseBufferedStream) + httpReq.UseBufferedStream = UseBufferedStream; + + LastRequestBody = null; + LastRequestBody = httpReq.GetRawBody(); + }); + + Plugins.Add(new RequestLogsFeature { EnableRequestBodyTracking = EnableRequestBodyTracking }); + } + } + + [DataContract] + public class MyRequest : IReturn + { + [DataMember] + public string Data { get; set; } + } + + public class MyService : IService + { + public object Any(MyRequest request) + { + return request; + } + } +} 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 new file mode 100644 index 00000000000..438378b59dd --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceTests.cs @@ -0,0 +1,84 @@ +using NUnit.Framework; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; +using ServiceStack.ProtoBuf; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class CachedServiceTests + { + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_call_Cached_WebService_with_JSON() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get("/cached/movies"); + + 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() + { + var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get("/cached/movies"); + + Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + } + + [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(")); + } + } +} \ 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 9e170526f04..944fe983d3b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CompressionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CompressionTests.cs @@ -1,141 +1,139 @@ -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.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; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [DataContract(Namespace = "http://schemas.ddnglobal.com/types/")] - public class TestCompress - { - [DataMember] - public int Id { get; set; } - - [DataMember] - public string Name { get; set; } - - public TestCompress() - { - } - - public TestCompress(int id, string name) - { - Id = id; - Name = name; - } - } - - - [TestFixture] - public class CompressionTests - { - private static readonly ILog Log = LogManager.GetLogger(typeof(CompressionTests)); - - [Test] - public void Can_compress_and_decompress_SimpleDto() - { - var simpleDto = new TestCompress(1, "name"); - - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); - - var simpleDtoZip = simpleDtoXml.Deflate(); - - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - - var deserializedSimpleDtoXml = simpleDtoZip.Inflate(); - - Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( - deserializedSimpleDtoXml); - - Assert.That(deserializedSimpleDto, Is.Not.Null); - - Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); - Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); - } - - - [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)); - - var mockResponse = new HttpResponseMock(); - - var simpleDto = new TestCompress(1, "name"); - - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); - - const string expectedXml = "1name"; - - Assert.That(simpleDtoXml, Is.EqualTo(expectedXml)); - - var simpleDtoZip = simpleDtoXml.Deflate(); - - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - - var compressedResult = new CompressedResult(simpleDtoZip); - - var reponseWasAutoHandled = mockResponse.WriteToResponse( - compressedResult, CompressionTypes.Deflate); - - Assert.That(reponseWasAutoHandled, Is.True); - - //var bytesToWriteToResponseStream = new byte[simpleDtoZip.Length - 4]; - //Array.Copy(simpleDtoZip, CompressedResult.Adler32ChecksumLength, bytesToWriteToResponseStream, 0, bytesToWriteToResponseStream.Length); - - 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)); - - Log.Debug("Content-length: " + writtenBytes.Length); - Log.Debug(BitConverter.ToString(writtenBytes)); - } - - [Test] - public void Can_gzip_and_gunzip_SimpleDto() - { - var simpleDto = new TestCompress(1, "name"); - - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); - - var simpleDtoZip = simpleDtoXml.GZip(); - - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - - var deserializedSimpleDtoXml = simpleDtoZip.GUnzip(); - - Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( - deserializedSimpleDtoXml); - - Assert.That(deserializedSimpleDto, Is.Not.Null); - - Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); - Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); - } - - } +using System; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Logging; +using ServiceStack.Serialization; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; +using DataContractSerializer = ServiceStack.Serialization.DataContractSerializer; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [DataContract(Namespace = "http://schemas.ddnglobal.com/types/")] + public class TestCompress + { + [DataMember] + public int Id { get; set; } + + [DataMember] + public string Name { get; set; } + + public TestCompress() + { + } + + public TestCompress(int id, string name) + { + Id = id; + Name = name; + } + } + + + [TestFixture] + 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.SerializeToString(simpleDto); + + var simpleDtoZip = simpleDtoXml.Deflate(); + + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + + var deserializedSimpleDtoXml = simpleDtoZip.Inflate(); + + Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); + + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( + deserializedSimpleDtoXml); + + Assert.That(deserializedSimpleDto, Is.Not.Null); + + Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); + Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); + } + + + [Test] + public void Test_response_with_CompressedResult() + { + using (new BasicAppHost(typeof(CompressionTests).Assembly).Init()) + { + var mockResponse = new MockHttpResponse(); + + var simpleDto = new TestCompress(1, "name"); + + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); + + const string expectedXml = "1name"; + const string expectedXmlNetCore = "1name"; + + Assert.That(simpleDtoXml, Is.EqualTo(expectedXml).Or.EqualTo(expectedXmlNetCore)); + + var simpleDtoZip = simpleDtoXml.Deflate(); + + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + + var compressedResult = new CompressedResult(simpleDtoZip); + + var reponseWasAutoHandled = mockResponse.WriteToResponse( + compressedResult, CompressionTypes.Deflate); + + Assert.That(reponseWasAutoHandled.Result, Is.True); + + //var bytesToWriteToResponseStream = new byte[simpleDtoZip.Length - 4]; + //Array.Copy(simpleDtoZip, CompressedResult.Adler32ChecksumLength, bytesToWriteToResponseStream, 0, bytesToWriteToResponseStream.Length); + + var bytesToWriteToResponseStream = simpleDtoZip; + + 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)); + } + } + + [Test] + public void Can_gzip_and_gunzip_SimpleDto() + { + var simpleDto = new TestCompress(1, "name"); + + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); + + var simpleDtoZip = simpleDtoXml.GZip(); + + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + + var deserializedSimpleDtoXml = simpleDtoZip.GUnzip(); + + Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); + + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( + deserializedSimpleDtoXml); + + Assert.That(deserializedSimpleDto, Is.Not.Null); + + 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.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 new file mode 100644 index 00000000000..45d8fa176ef --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeatureTest.cs @@ -0,0 +1,107 @@ +using System; +using System.Threading; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/corsmethod")] + [EnableCors("http://localhost http://localhost2", "POST, GET", "Type1, Type2", true)] + public class CorsFeatureRequest { } + + public class CorsFeatureResponse + { + public bool IsSuccess { get; set; } + } + + public class CorsFeatureService : IService + { + public object Any(CorsFeatureRequest request) + { + return new CorsFeatureResponse { IsSuccess = true }; + } + } + + [Route("/globalcorsfeature")] + public class GlobalCorsFeatureRequest + { + } + + public class GlobalCorsFeatureResponse + { + public bool IsSuccess { get; set; } + } + + public class GlobalCorsFeatureService : IService + { + public object Any(GlobalCorsFeatureRequest request) + { + return new GlobalCorsFeatureResponse { IsSuccess = true }; + } + } + + [TestFixture] + public class CorsFeatureServiceTest + { + public class CorsFeatureAppHostHttpListener + : AppHostHttpListenerBase + { + public CorsFeatureAppHostHttpListener() + : base("Cors Feature Tests", typeof(CorsFeatureService).Assembly) { } + + public override void Configure(Funq.Container container) {} + } + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new CorsFeatureAppHostHttpListener() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + static IRestClient[] RestClients = + { + new JsonServiceClient(Config.AbsoluteBaseUri), + new XmlServiceClient(Config.AbsoluteBaseUri), + new JsvServiceClient(Config.AbsoluteBaseUri) + }; + + [Ignore("Debug Only")] + public void RunFor5Mins() + { + Thread.Sleep(TimeSpan.FromMinutes(5)); + } + + [Test, TestCaseSource("RestClients")] + public void CorsMethodHasAccessControlHeaders(IRestClient client) + { + appHost.Config.GlobalResponseHeaders.Clear(); + + 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] + public void GlobalCorsHasAccessControlHeaders() + { + appHost.LoadPlugin(new CorsFeature { AutoHandleOptionsRequests = false }); + + 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(CorsFeature.DefaultHeaders)); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs index 24dfe9b25a4..38eda422bb0 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs @@ -1,173 +1,164 @@ -using System; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; -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 +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +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; + + [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 b989e73060d..549dad51c3c 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRequestDataTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRequestDataTests.cs @@ -1,169 +1,176 @@ -using System; -using System.IO; -using System.Net; -using System.Web; -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class CustomRequestDataTests - { - private const string ListeningOn = "http://localhost:82/"; - - ExampleAppHostHttpListener appHost; - readonly JsonServiceClient client = new JsonServiceClient(ListeningOn); - private string customUrl = ListeningOn.CombineWith("customrequestbinder"); - private string predefinedUrl = ListeningOn.CombineWith("json/syncreply/customrequestbinder"); - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - /// - /// first-name=tom&item-0=blah&item-1-delete=1 - /// - [Test] - public void Can_parse_custom_form_data() - { - var webReq = (HttpWebRequest)WebRequest.Create("http://localhost:82/customformdata?format=json"); - webReq.Method = HttpMethods.Post; - webReq.ContentType = ContentType.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(); - - 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.Fail(errorResponse); - } - } - - [Test] - public void Does_use_request_binder_for_GET() - { - var response = client.Get("/customrequestbinder"); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_predefined_GET() - { - var responseStr = predefinedUrl.DownloadJsonFromUrl(); - Console.WriteLine(responseStr); - var response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_predefined_GET_with_QueryString() - { - var customUrlWithQueryString = customUrl + "?IsFromBinder=false"; - var responseStr = customUrlWithQueryString.DownloadJsonFromUrl(); - Console.WriteLine(responseStr); - var response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_Send() - { - var response = client.Send(new CustomRequestBinder()); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_POST() - { - 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", ContentType.FormUrlEncoded, ContentType.Json); - Console.WriteLine(responseStr); - var response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_POST_FormData_without_ContentType() - { - var responseStr = customUrl.PostToUrl("{\"IsFromBinder\":false}", ContentType.Json, ContentType.Json); - Console.WriteLine(responseStr); - var response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - 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 response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_predefined_POST() - { - var responseStr = predefinedUrl.PostJsonToUrl(new CustomRequestBinder()); - Console.WriteLine(responseStr); - var response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_predefined_POST_FormData() - { - var responseStr = predefinedUrl.PostToUrl("k=v", ContentType.FormUrlEncoded, ContentType.Json); - Console.WriteLine(responseStr); - var response = responseStr.FromJson(); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_PUT() - { - var response = client.Put("/customrequestbinder", new CustomRequestBinder()); - Assert.That(response.FromBinder); - } - - [Test] - public void Does_use_request_binder_for_DELETE() - { - var response = client.Delete("/customrequestbinder"); - Assert.That(response.FromBinder); - } - - } - -} +using System; +using System.IO; +using System.Net; +using System.Web; +using NUnit.Framework; +using ServiceStack.Common; +using ServiceStack.Text; +using ServiceStack.Web; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; +using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class CustomRequestDataTests + { + 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/reply/customrequestbinder"); + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + /// + /// first-name=tom&item-0=blah&item-1-delete=1 + /// + [Test] + public void Can_parse_custom_form_data() + { + var webReq = WebRequest.CreateHttp("http://localhost:1337/customformdata?format=json"); + webReq.Method = HttpMethods.Post; + webReq.ContentType = MimeTypes.FormUrlEncoded; + + try + { + using (var sw = new StreamWriter(PclExport.Instance.GetRequestStream(webReq))) + { +#if !NETCORE + sw.Write("&"); +#endif + sw.Write("first-name=tom&item-0=blah&item-1-delete=1"); + } + var response = webReq.GetResponse().GetResponseStream().ReadToEnd(); + + 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 = errorWebResponse.GetResponseStream().ReadToEnd(); + + Assert.Fail(errorResponse); + } + } + + [Test] + public void Does_use_request_binder_for_GET() + { + var response = client.Get("/customrequestbinder"); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_predefined_GET() + { + var responseStr = predefinedUrl.GetJsonFromUrl(); + Console.WriteLine(responseStr); + var response = responseStr.FromJson(); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_predefined_GET_with_QueryString() + { + var customUrlWithQueryString = customUrl + "?IsFromBinder=false"; + var responseStr = customUrlWithQueryString.GetJsonFromUrl(); + Console.WriteLine(responseStr); + var response = responseStr.FromJson(); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_Send() + { + var response = client.Send(new CustomRequestBinder()); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_POST() + { + 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", accept: MimeTypes.Json); + Console.WriteLine(responseStr); + var response = responseStr.FromJson(); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_POST_FormData_without_ContentType() + { + var responseStr = customUrl.PostJsonToUrl("{\"IsFromBinder\":false}"); + Console.WriteLine(responseStr); + var response = responseStr.FromJson(); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_POST_FormData_without_ContentType_with_QueryString() + { + string customUrlWithQueryString = customUrl + "?IsFromBinder=false"; + var responseStr = customUrlWithQueryString.PostToUrl("k=v", accept: MimeTypes.Json); + var response = responseStr.FromJson(); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_predefined_POST() + { + var responseStr = predefinedUrl.PostJsonToUrl(new CustomRequestBinder()); + Console.WriteLine(responseStr); + var response = responseStr.FromJson(); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_predefined_POST_FormData() + { + 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()); + Assert.That(response.FromBinder); + } + + [Test] + public void Does_use_request_binder_for_DELETE() + { + var response = client.Delete("/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 new file mode 100644 index 00000000000..ad1bb1c75d7 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomValidationErrorTests.cs @@ -0,0 +1,306 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.FluentValidation.Results; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class CustomValidationAppHost : AppSelfHostBase + { + 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); + } + + 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 }; + return new HttpError(dto, HttpStatusCode.BadRequest, dto.code, dto.error); + } + } + + public class MyCustomErrorDto + { + public string code { get; set; } + public string error { get; set; } + } + + [Route("/customerror")] + public class CustomError + { + public int Age { get; set; } + public string Company { get; set; } + } + + public class MyValidator : AbstractValidator + { + public MyValidator() + { + RuleFor(x => x.Age).GreaterThan(0); + RuleFor(x => x.Company).NotEmpty(); + } + } + + [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] + public class CustomValidationErrorTests + { + private CustomValidationAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new CustomValidationAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_create_custom_validation_error() + { + try + { + var response = "{0}/customerror".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.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) + { + if (!(ex is WebException webEx) || webEx.Status != WebExceptionStatus.ProtocolError) + return null; + + var errorResponse = ((HttpWebResponse)webEx.Response); + 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 394b078e332..4f2117e5ab6 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerServiceValidationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerServiceValidationTests.cs @@ -1,348 +1,462 @@ -using System; -using System.Collections; -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.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.WebHost.Endpoints.Tests.Support; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [RestService("/customers")] - [RestService("/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; } - } - - public class CustomerService : RestServiceBase - { - public override object OnGet(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public override object OnPost(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public override object OnPut(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public override object OnDelete(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(); - } - - 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))); - - var responseStatus = ResponseStatusTranslator.Instance.Parse(validationResult.ToErrorResult()); - - var errorFields = responseStatus.Errors; - return errorFields ?? new List(); - } - - private string[] ExpectedPostErrorFields = new[] { - "Id", - "LastName", - "FirstName", - "Company", - "Address", - "Postcode", - }; - - private string[] ExpectedPostErrorCodes = new[] { - "NotEqual", - "ShouldNotBeEmpty", - "NotEmpty", - "NotNull", - "Predicate", - "Predicate", - }; - - 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", - }; - } - - [Test] - public void Validates_ValidRequest_request_on_Post() - { - var errorFields = GetValidationFieldErrors(HttpMethod.Post, validRequest); - Assert.That(errorFields.Count, Is.EqualTo(0)); - } - - [Test] - public void Validates_ValidRequest_request_on_Get() - { - var errorFields = GetValidationFieldErrors(HttpMethod.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(HttpMethod.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(HttpMethod.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(HttpMethod.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(HttpMethod.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(HttpMethod.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(true, typeof(SecureService).Assembly); - 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[] { - () => 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 +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.WebHost.Endpoints.Tests.Support; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [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(); + } + + private string[] ExpectedPostErrorFields = new[] { + "Id", + "LastName", + "FirstName", + "Company", + "Address", + "Postcode", + }; + + private string[] ExpectedPostErrorCodes = new[] { + "NotEqual", + "ShouldNotBeEmpty", + "NotEmpty", + "NotNull", + "Predicate", + "Predicate", + }; + + ValidCustomers validRequest; + + [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.GlobalRequestFilters.Count; + appHost.LoadPlugin(new ValidationFeature()); + 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 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 new file mode 100644 index 00000000000..bda196b9891 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/EncodingTests.cs @@ -0,0 +1,89 @@ +using System.Text; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + //[Route("/HelloWorld/Greeting/{FirstName}/{LastName}", "GET")] + [Route("/HelloWorld/Greeting/{FirstName}", "GET")] + [Restrict(RequestAttributes.InternalNetworkAccess)] + public class HelloWorldName : IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + public class HelloWorldGreeting + { + public string Greeting { get; set; } + } + + public class HelloWorldService : Service + { + public HelloWorldGreeting Get(HelloWorldName request) + { + var answer = new HelloWorldGreeting + { + Greeting = "Hello " + request.FirstName + " " + request.LastName + }; + return answer; + } + } + + public class EncodingTestsAppHost : AppHostHttpListenerBase + { + public EncodingTestsAppHost() : base("EncodingTests", typeof(HelloWorldService).Assembly) { } + public override void Configure(Funq.Container container) {} + } + + [TestFixture] + public class EncodingTests + { + private EncodingTestsAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new EncodingTestsAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + private HelloWorldGreeting PerformRequest(string firstName, string lastName) + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + var query = string.Format("/HelloWorld/Greeting/{0}?lastname={1}", firstName, lastName); + return client.Get(query); + } + + [Test] + public void Can_Get_Greeting_When_Querystring_Contains_Non_ASCII_Chars() + { + var firstName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes("Pål")); + var lastName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes("Smådalø")); + Assert.That(PerformRequest(firstName, lastName).Greeting, Is.EqualTo(string.Format("Hello {0} {1}", firstName, lastName))); + } + + [Test] + public void Can_Get_Greeting_When_Only_Url_Contains_Non_ASCII_Chars() + { + var firstName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes("Pål")); + var lastName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes("Smith")); + Assert.That(PerformRequest(firstName, lastName).Greeting, Is.EqualTo(string.Format("Hello {0} {1}", firstName, lastName))); + } + + [Test] + public void Can_Get_Greeting_When_Querystring_Contains_Only_ASCII_Chars() + { + var firstName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes("John")); + var lastName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes("Smith")); + Assert.That(PerformRequest(firstName, lastName).Greeting, Is.EqualTo(string.Format("Hello {0} {1}", firstName, lastName))); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/EndpointRestrictionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/EndpointRestrictionTests.cs index 90f935a893f..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.SyncReply); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.AsyncOneWay); - } - - [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.SyncReply); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.AsyncOneWay); - } - - [Test] - public void Can_access_from_insecure_live_environment() - { - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.SyncReply); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.AsyncOneWay); - } - - [Test] - public void Can_access_from_secure_live_environment() - { - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.SyncReply); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.AsyncOneWay); - } - - - [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 new file mode 100644 index 00000000000..3d6119901ea --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandling2Tests.cs @@ -0,0 +1,301 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using NUnit.Framework; +using ProtoBuf; +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> + { + [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; } + } + + //New: No special naming convention + + [Route("/reqstars2/search")] + [Route("/reqstars2/aged/{Age}")] + [DataContract] + public class SearchReqstars2 : IReturn + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class ReqstarsResponse + { + [DataMember(Order = 1)] + public int Total { get; set; } + + [DataMember(Order = 2)] + public int? Aged { get; set; } + + [DataMember(Order = 3)] + public List Results { get; set; } + + [DataMember(Order = 4)] + public ResponseStatus ResponseStatus { get; set; } + } + + //Naming convention:{Request DTO}Response + + [Route("/reqstars/search")] + [Route("/reqstars/aged/{Age}")] + [DataContract] + public class SearchReqstars : IReturn + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + + [DataContract] + public class SearchReqstarsResponse + { + [DataMember(Order = 1)] + public int Total { get; set; } + + [DataMember(Order = 2)] + public int? Aged { get; set; } + + [DataMember(Order = 3)] + public List Results { get; set; } + + [DataMember(Order = 4)] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ReqstarsService : IService + { + /// + /// Testmethod following the 'old' naming convention (DTO/DTOResponse) + /// + public object Any(SearchReqstars request) + { + if (request.Age.HasValue && request.Age <= 0) + throw new ArgumentException("Invalid Age"); + + var response = new SearchReqstarsResponse { + 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} + } + }; + + return response; + } + + /// + /// Testmethod following no special naming convention (the new behavior) + /// + public object Any(SearchReqstars2 request) + { + if (request.Age.HasValue && request.Age <= 0) + throw new ArgumentException("Invalid Age"); + + var response = new ReqstarsResponse() { + 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} + } + }; + + return response; + } + } + + public class AppHost : AppHostHttpListenerBase + { + public AppHost() + : base("Test ErrorHandling", typeof(ReqstarsService).Assembly) { } + + public override void Configure(Funq.Container container) + { + Plugins.Add(new ProtoBufFormat()); + } + } + + [TestFixture] + public class ExceptionHandling2Tests + { + private static string testUri = Config.ListeningOn; + + AppHost appHost; + + [OneTimeSetUp] + public void Init() + { + try + { + LogManager.LogFactory = null; + appHost = new AppHost(); + appHost.Init(); + appHost.Start(Config.ListeningOn); + appHost.Config.DebugMode = true; + } + catch (Exception ex) + { + ex.ToString().Print(); + } + } + + [OneTimeTearDown] + public void TearDown() + { + appHost.Dispose(); + } + + static IRestClient[] ServiceClients = { + new JsonServiceClient(testUri), + new JsonHttpClient(testUri), + new XmlServiceClient(testUri), + new JsvServiceClient(testUri), + new ProtoBufServiceClient(testUri) + }; + + + /// + ///A test for a good response + /// + [Test, TestCaseSource("ServiceClients")] + [Category("OldNamingConvention")] + public void OldNamingConv_Get_ExpectingResults(IRestClient client) + { + var response = client.Get(new SearchReqstars {Age = 10}); + + Assert.AreEqual(2, response.Total); + } + + /// + ///A GET test for receiving a WebServiceException with status ArgumentException and message "Invalid Age" + /// + [Test, TestCaseSource("ServiceClients")] + [Category("OldNamingConvention")] + public void OldNamingConv_Get_ArgumentException_InvalidAge(IRestClient client) + { + try + { + client.Get(new SearchReqstars {Age = -1}); + } + catch (WebServiceException ex) + { + Assert.AreEqual("ArgumentException", ex.StatusDescription, "Wrong ExceptionType"); + Assert.AreEqual("Invalid Age", ex.ErrorMessage, "Wrong message"); + } + } + + /// + ///A test for a good response with POST request + /// + [Test, TestCaseSource("ServiceClients")] + [Category("OldNamingConvention")] + public void OldNamingConv_Post_ExpectingResults(IRestClient client) + { + var response = client.Post(new SearchReqstars {Age = 10}); + + Assert.AreEqual(2, response.Total); + } + + /// + ///A POST test for receiving a WebServiceException with status ArgumentException and message "Invalid Age" + /// + [Test, TestCaseSource("ServiceClients")] + [Category("OldNamingConvention")] + public void OldNamingConv_Post_ArgumentException_InvalidAge(IRestClient client) + { + try + { + client.Post(new SearchReqstars {Age = -1}); + } + catch (WebServiceException ex) + { + Assert.AreEqual("ArgumentException", ex.StatusDescription, "Wrong ExceptionType"); + Assert.AreEqual("Invalid Age", ex.ErrorMessage, "Wrong message"); + } + } + + + /// + ///A test for a good response + /// + [Test, TestCaseSource("ServiceClients")] + [Category("NoNamingConvention")] + public void NoNamingConv_Get_ExpectingResults(IRestClient client) + { + var response = client.Get(new SearchReqstars2 {Age = 10}); + + Assert.AreEqual(2, response.Total); + } + + /// + ///A GET test for receiving a WebServiceException with status ArgumentException and message "Invalid Age" + /// + [Test, TestCaseSource("ServiceClients")] + [Category("NoNamingConvention")] + public void NoNamingConv_Get_ArgumentException_InvalidAge(IRestClient client) + { + try + { + client.Get(new SearchReqstars2 {Age = -1}); + } + catch (WebServiceException ex) + { + Assert.AreEqual("ArgumentException", ex.StatusDescription, "Wrong ExceptionType"); + Assert.AreEqual("Invalid Age", ex.ErrorMessage, "Wrong message"); + } + } + + /// + ///A test for a good response with POST request + /// + [Test, TestCaseSource("ServiceClients")] + [Category("NoNamingConvention")] + public void NoNamingConv_Post_ExpectingResults(IRestClient client) + { + var response = client.Post(new SearchReqstars2 {Age = 10}); + + Assert.AreEqual(2, response.Total); + } + + /// + ///A POST test for receiving a WebServiceException with status ArgumentException and message "Invalid Age" + /// + [Test, TestCaseSource("ServiceClients")] + [Category("NoNamingConvention")] + public void NoNamingConv_Post_ArgumentException_InvalidAge(IRestClient client) + { + try + { + client.Post(new SearchReqstars2 {Age = -1}); + } + catch (WebServiceException ex) + { + Assert.AreEqual("ArgumentException", ex.StatusDescription, "Wrong ExceptionType"); + 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 7d36fc813df..92afa20e290 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTests.cs @@ -1,247 +1,746 @@ -using System; -using System.Net; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.ServiceInterface; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using NUnit.Framework; -using Funq; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [Route("/users")] - public class User { } - public class UserResponse : IHasResponseStatus - { - public ResponseStatus ResponseStatus { get; set; } - } - - public class UserService : RestServiceBase - { - public override object OnGet(User request) - { - return new HttpError(System.Net.HttpStatusCode.BadRequest, "CanNotExecute", "Failed to execute!"); - } - - public override object OnPost(User request) - { - throw new HttpError(System.Net.HttpStatusCode.BadRequest, "CanNotExecute", "Failed to execute!"); - } - - public override object OnDelete(User request) - { - throw new HttpError(System.Net.HttpStatusCode.Forbidden, "CanNotExecute", "Failed to execute!"); - } - - public override object OnPut(User request) - { - throw new ArgumentException(); - } - } - - public class CustomException : ArgumentException - { - public CustomException() : base("User Defined Error") { } - } - - public class ExceptionWithResponseStatus { } - public class ExceptionWithResponseStatusResponse - { - public ResponseStatus ResponseStatus { get; set; } - } - public class ExceptionWithResponseStatusService : ServiceBase - { - protected override object Run(ExceptionWithResponseStatus request) - { - throw new CustomException(); - } - } - - public class ExceptionNoResponseStatus { } - public class ExceptionNoResponseStatusResponse { } - public class ExceptionNoResponseStatusService : ServiceBase - { - protected override object Run(ExceptionNoResponseStatus request) - { - throw new CustomException(); - } - } - - public class ExceptionNoResponseDto { } - public class ExceptionNoResponseDtoService : ServiceBase - { - protected override object Run(ExceptionNoResponseDto request) - { - throw new CustomException(); - } - } - - [TestFixture] - public class ExceptionHandlingTests - { - private const string ListeningOn = "http://localhost:82/"; - - public class ExceptionHandlingAppHostHttpListener - : AppHostHttpListenerBase - { - - public ExceptionHandlingAppHostHttpListener() - : base("Exception handling tests", typeof(UserService).Assembly) { } - - public override void Configure(Container container) - { - JsConfig.EmitCamelCaseNames = true; - - //Uncomment to enable server-side stack traces - //SetConfig(new EndpointHostConfig { DebugMode = true }); - } - } - - ExceptionHandlingAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new ExceptionHandlingAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - static IRestClient[] ServiceClients = - { - new JsonServiceClient(ListeningOn), - new XmlServiceClient(ListeningOn), - new JsvServiceClient(ListeningOn) - //SOAP not supported in HttpListener - //new Soap11ServiceClient(ServiceClientBaseUri), - //new Soap12ServiceClient(ServiceClientBaseUri) - }; - - - [Test, TestCaseSource("ServiceClients")] - public void Handles_Returned_Http_Error(IRestClient client) - { - try - { - client.Get("/users"); - Assert.Fail(); - } - catch (WebServiceException ex) - { - 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")); - } - } - - [Test, TestCaseSource("ServiceClients")] - public void Handles_Thrown_Http_Error(IRestClient client) - { - try - { - client.Post("/users", new User()); - Assert.Fail(); - } - catch (WebServiceException ex) - { - 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")); - } - } - - [Test, TestCaseSource("ServiceClients")] - public void Handles_Thrown_Http_Error_With_Forbidden_status_code(IRestClient client) - { - try - { - client.Delete("/users"); - Assert.Fail(); - } - catch (WebServiceException ex) - { - 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")); - } - } - - [Test, TestCaseSource("ServiceClients")] - public void Handles_Normal_Exception(IRestClient client) - { - try - { - client.Put("/users", new User()); - Assert.Fail(); - } - catch (WebServiceException ex) - { - Assert.That(ex.ErrorCode, Is.EqualTo("ArgumentException")); - Assert.That(ex.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.BadRequest)); - } - } - - public string PredefinedJsonUrl() - { - return ListeningOn + "json/syncreply/" + typeof(T).Name; - } - - [Test] - public void Returns_populated_dto_when_has_ResponseStatus() - { - try - { - var json = PredefinedJsonUrl().GetJsonFromUrl(); - Assert.Fail("Should throw"); - } - catch (WebException webEx) - { - var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.EqualTo( - "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\",\"errors\":[]}}")); - } - } - - [Test] - public void Returns_empty_dto_when_NoResponseStatus() - { - try - { - var json = PredefinedJsonUrl().GetJsonFromUrl(); - Assert.Fail("Should throw"); - } - catch (WebException webEx) - { - var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.EqualTo("{}")); - } - } - - [Test] - public void Returns_no_body_when_NoResponseDto() - { - try - { - var json = PredefinedJsonUrl().GetJsonFromUrl(); - Assert.Fail("Should throw"); - } - catch (WebException webEx) - { - var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.EqualTo("")); - } - } - } -} +using System; +using System.IO; +using System.Net; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using NUnit.Framework; +using Funq; +using ServiceStack.ProtoBuf; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/users")] + [DataContract] + public class User {} + + [DataContract] + public class UserResponse : IHasResponseStatus + { + [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 UserReturnVoid : IReturnVoid {} + + public class UserService : Service + { + public object Get(User request) + { + return new HttpError(HttpStatusCode.BadRequest, "CanNotExecute", "Failed to execute!"); + } + + public object Post(User request) + { + throw new HttpError(HttpStatusCode.BadRequest, "CanNotExecute", "Failed to execute!"); + } + + public object Delete(User request) + { + throw new HttpError(HttpStatusCode.Forbidden, "CanNotExecute", "Failed to execute!"); + } + + 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 class ExceptionWithResponseStatus {} + + public class ExceptionWithResponseStatusResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class ExceptionWithResponseStatusService : Service + { + public object Any(ExceptionWithResponseStatus request) + { + throw new CustomException(); + } + } + + public class ExceptionNoResponseStatus {} + + public class ExceptionNoResponseStatusResponse {} + + public class ExceptionNoResponseStatusService : Service + { + public object Any(ExceptionNoResponseStatus request) + { + throw new CustomException(); + } + } + + public class ExceptionNoResponseDto {} + + public class ExceptionNoResponseDtoService : Service + { + public object Any(ExceptionNoResponseDto request) + { + throw new CustomException(); + } + } + + 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) + { + //We don't wrap a try..catch block around the service (which happens with ServiceBase<> automatically) + //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; } + } + + public class ExceptionWithRequestBindingService : Service + { + public object Any(ExceptionWithRequestBinding request) + { + return 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); + } + } + + + [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.Init(new Text.Config + { + TextCase = TextCase.CamelCase, + }); + + SetConfig(new HostConfig + { + DebugMode = false, + }); + + Plugins.Add(new ProtoBufFormat()); + + GlobalRequestFilters.Add((req, res, dto) => { + if (dto is UncatchedException || dto is UncatchedExceptionAsync) + throw new ArgumentException(); + }); + + //Custom global uncaught exception handling strategy + this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) => + { + res.WriteAsync($"UncaughtException {ex.GetType().Name}") + .ContinueWith(t => res.EndRequest(skipHeaders: true)); + }); + + this.ServiceExceptionHandlers.Add((httpReq, request, ex) => + { + 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); + } + } + + AppHost appHost; + + public ExceptionHandlingTests() + { + appHost = new AppHost(); + appHost.Init(); + appHost.Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + appHost.UncaughtExceptionHandlers = null; + JsConfig.Reset(); + } + + 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")] + public void Handles_Returned_Http_Error(IRestClient client) + { + try + { + client.Get("/users"); + Assert.Fail(); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.BadRequest)); + 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(IRestClient client) + { + try + { + client.Post("/users", new User()); + Assert.Fail(); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.BadRequest)); + 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(IRestClient client) + { + try + { + client.Delete("/users"); + 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_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.Message, Is.EqualTo("Failed to execute!")); + } + } + + [Test, TestCaseSource("ServiceClients")] + public void Handles_Normal_Exception(IRestClient client) + { + try + { + client.Put("/users", new User()); + Assert.Fail(); + } + 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)); + } + } + + [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 Config.ListeningOn + "json/reply/" + typeof(T).Name; + } + + [Test] + public void Returns_populated_dto_when_has_ResponseStatus() + { + try + { + var json = PredefinedJsonUrl().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + 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\":[]}}")); + } + } + } + + [Test] + public void Returns_empty_dto_when_NoResponseStatus() + { + try + { + var json = PredefinedJsonUrl().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + 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, Is.EqualTo("{}")); + } + } + } + + [Test] + public void Returns_no_body_when_NoResponseDto() + { + try + { + var json = PredefinedJsonUrl().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + 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) + { + 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().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 ac8c6a7808a..dd04f4ddf9e 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/FileUploadTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/FileUploadTests.cs @@ -1,257 +1,461 @@ -using System; -using System.IO; -using System.Net; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -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 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)); - } - - [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 request = new FileUpload{CustomerId = 123, CustomerName = "Foo"}; - var response = client.PostFileWithRequest(ListeningOn + "/fileuploads", uploadFile, request); - - 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.Contents, Is.EqualTo(expectedContents)); - Assert.That(response.CustomerName, Is.EqualTo("Foo")); - 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_POST_upload_file_and_apply_filter_using_ServiceClient() - { - try - { - var client = new JsonServiceClient(ListeningOn); - - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - bool isFilterCalled = false; - ServiceClientBase.HttpWebRequestFilter = request => - { - isFilterCalled = true; - - }; - - var response = client.PostFile( - ListeningOn + "/fileuploads", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); - - - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); - Assert.That(isFilterCalled); - 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)); - } - finally - { - ServiceClientBase.HttpWebRequestFilter = null; //reset this to not cause side-effects - } - } - - [Test] - public void Can_POST_upload_stream_using_ServiceClient() - { - try - { - var client = new JsonServiceClient(ListeningOn); - - using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()).OpenRead()) - { - var fileName = "upload.html"; - - bool isFilterCalled = false; - ServiceClientBase.HttpWebRequestFilter = request => - { - isFilterCalled = true; - - }; - var response = client.PostFile( - ListeningOn + "/fileuploads", fileStream, fileName, MimeTypes.GetMimeType(fileName)); - - fileStream.Position = 0; - var expectedContents = new StreamReader(fileStream).ReadToEnd(); - - Assert.That(isFilterCalled); - 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.HttpWebRequestFilter = null; //reset this to not cause side-effects - } - } - - } +using System; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +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 + { + 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".MapProjectPlatformPath()); + + 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 = 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_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".MapProjectPlatformPath()); + + var request = new FileUpload { CustomerId = 123, CustomerName = "Föяšč" }; + 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("Föяšč")); + 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".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() + { + try + { + var client = new JsonServiceClient(ListeningOn); + + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + bool isFilterCalled = false; + ServiceClientBase.GlobalRequestFilter = request => { isFilterCalled = true; }; + + var response = client.PostFile( + ListeningOn + "/fileuploads", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); + + + 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))); + 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_ServiceClient() + { + try + { + var client = new JsonServiceClient(ListeningOn); + + using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()).OpenRead()) + { + var fileName = "upload.html"; + + bool isFilterCalled = false; + 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( + "/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 + { + 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 a5add4bea97..fdf13941d36 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/HtmlResultTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HtmlResultTests.cs @@ -1,52 +1,49 @@ -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; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class HtmlResultMetadataTests : TestBase - { - protected override void Configure(Funq.Container container) {} - - public static class Html - { - public static HttpResult RedirectTo(string url) - { - var html = string.Format( - "", - url); - - return new HttpResult(html, ContentType.Html) { - Headers = { { "Location", url } }, - }; - } - } - - [Test] - public void Test_response_with_html_result() - { - var mockResponse = new HttpResponseMock(); - - const string url = "http://www.servicestack.net"; - var htmlResult = Html.RedirectTo(url); - - var reponseWasAutoHandled = mockResponse.WriteToResponse(htmlResult, "text/xml"); - - Assert.That(reponseWasAutoHandled, Is.True); - - var expectedOutput = string.Format( - "", url); - - var writtenString = mockResponse.GetOutputStreamAsString(); - Assert.That(writtenString, Is.EqualTo(expectedOutput)); - Assert.That(mockResponse.Headers["Location"], Is.EqualTo(url)); - } - } +using NUnit.Framework; +using ServiceStack.Common.Tests; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class HtmlResultMetadataTests : TestBase + { + protected override void Configure(Funq.Container container) {} + + public static class Html + { + public static HttpResult RedirectTo(string url) + { + var html = string.Format( + "", + url); + + return new HttpResult(html, MimeTypes.Html) + { + Headers = { { "Location", url } }, + }; + } + } + + [Test] + public void Test_response_with_html_result() + { + 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.Result, Is.True); + + var expectedOutput = string.Format( + "", url); + + var writtenString = mockResponse.ReadAsString(); + Assert.That(writtenString, Is.EqualTo(expectedOutput)); + Assert.That(mockResponse.Headers["Location"], Is.EqualTo(url)); + } + } } \ No newline at end of file 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 049d7922f17..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 d8420c90a1b..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,71 +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(); - //Signal advanced web browsers what HTTP Methods you accept - //base.SetConfig(new EndpointHostConfig()); - Routes.Add("/test/plaintext", "GET"); + PreRequestFilters.Add((req,res) => req.UseBufferedStream = res.UseBufferedStream = true); + + //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.ServiceBase<PlainText> { - protected override object Run(PlainText request) { - string contentType = "text/plain"; + [Route("/plain-dto")] + public class PlainDto : IReturn<PlainDto> + { + public string Name { get; set; } + } + + [Route("/httpresult-dto")] + public class HttpResultDto : IReturn<HttpResultDto> + { + public string Name { get; set; } + } + + public class HttpResultServices : Service + { + public object Any(PlainText request) + { + 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 @@ -103,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 f4f05cd4e42..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.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) { } - - [Test] - public void Can_send_ResponseText_test_with_Custom_Header() - { - var mockResponse = new HttpResponseMock(); - - 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); - } - } - +using System.IO; +using NUnit.Framework; +using ServiceStack.Common.Tests; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [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 MockHttpResponse(); + + var customText = "<h1>Custom Text</h1>"; + + 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 new file mode 100644 index 00000000000..15ceb16919f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/CachedMoviesService.cs @@ -0,0 +1,85 @@ +using System; +using System.Runtime.Serialization; +using ServiceStack.Data; +using ServiceStack.Redis; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + [DataContract] + [Route("/cached/movies", "GET")] + [Route("/cached/movies/genres/{Genre}")] + 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 : Service + { + 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 e43f4b2e19a..d5c67723cad 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ConfigureDatabase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ConfigureDatabase.cs @@ -1,35 +1,35 @@ -using System; -using System.Collections.Generic; -using ServiceStack.OrmLite; - -namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests -{ - public class ConfigureDatabase - { - public static List<RestMovie> Top5Movies = new List<RestMovie> - { - new RestMovie { Id = "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"}, }, - new RestMovie { Id = "tt0068646", Title = "The Godfather", Rating = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List<string> {"Crime","Drama", "Thriller"}, }, - new RestMovie { Id = "tt1375666", Title = "Inception", Rating = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List<string>{"Action", "Mystery", "Sci-Fi", "Thriller"}, }, - new RestMovie { Id = "tt0071562", Title = "The Godfather: Part II", Rating = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List<string> {"Crime","Drama", "Thriller"}, }, - new RestMovie { Id = "tt0060196", Title = "The Good, the Bad and the Ugly", Rating = 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<string>{"Adventure","Western"}, }, - }; - - public static void Init(IDbConnectionFactory connectionFactory) - { - try - { - using (var dbConn = connectionFactory.OpenDbConnection()) - using (var dbCmd = dbConn.CreateCommand()) - { - dbCmd.CreateTable<RestMovie>(true); - dbCmd.SaveAll(Top5Movies); - } - } - catch (Exception) - { - throw; - } - } - } +using System; +using System.Collections.Generic; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + public class ConfigureDatabase + { + public static List<RestMovie> Top5Movies = new List<RestMovie> + { + new RestMovie { Id = "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"}, }, + new RestMovie { Id = "tt0068646", Title = "The Godfather", Rating = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List<string> {"Crime","Drama", "Thriller"}, }, + new RestMovie { Id = "tt1375666", Title = "Inception", Rating = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List<string>{"Action", "Mystery", "Sci-Fi", "Thriller"}, }, + new RestMovie { Id = "tt0071562", Title = "The Godfather: Part II", Rating = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List<string> {"Crime","Drama", "Thriller"}, }, + new RestMovie { Id = "tt0060196", Title = "The Good, the Bad and the Ugly", Rating = 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<string>{"Adventure","Western"}, }, + }; + + public static void Init(IDbConnectionFactory connectionFactory) + { + try + { + using (var db = connectionFactory.OpenDbConnection()) + { + db.DropAndCreateTable<RestMovie>(); + db.SaveAll(Top5Movies); + } + } + catch (Exception) + { + throw; + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs index 9387e4faa2c..7304d4370b0 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs @@ -1,93 +1,227 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -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); - } - } - - [RestService("/error")] - [RestService("/error/{Id}")] - public class Error - { - public Error() - { - } - - public string Id { get; set; } - public Error Inner { get; set; } - } - - public class ErrorService : RestServiceBase<Error> - { - public override object OnGet(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 override object OnPost(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; } - } - +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Net; +using System.Threading.Tasks; +using NUnit.Framework; +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); + } + + [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 0f5f6ef1cd0..29a02882737 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ExampleConfig.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ExampleConfig.cs @@ -1,25 +1,24 @@ -using ServiceStack.Common.Utils; -using ServiceStack.Configuration; - -namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests -{ - public class ExampleConfig - { - /// <summary> - /// Would've preferred to use [assembly: ContractNamespace] attribute but it is not supported in Mono - /// </summary> - public const string DefaultNamespace = "http://schemas.servicestack.net/types"; - - public ExampleConfig() { } - - public ExampleConfig(IResourceManager appConfig) - { - ConnectionString = appConfig.GetString("ConnectionString"); - DefaultFibonacciLimit = appConfig.Get("DefaultFibonacciLimit", 10); - } - - public string ConnectionString { get; set; } - public int DefaultFibonacciLimit { get; set; } - - } +using ServiceStack.Configuration; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + public class ExampleConfig + { + /// <summary> + /// Would've preferred to use [assembly: ContractNamespace] attribute but it is not supported in Mono + /// </summary> + public const string DefaultNamespace = "http://schemas.servicestack.net/types"; + + public ExampleConfig() { } + + public ExampleConfig(IAppSettings appConfig) + { + ConnectionString = appConfig.GetString("ConnectionString"); + DefaultFibonacciLimit = appConfig.Get("DefaultFibonacciLimit", 10); + } + + public string ConnectionString { get; set; } + public int DefaultFibonacciLimit { get; set; } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs index 038a3765ab9..4bae9a8244f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs @@ -1,112 +1,114 @@ -using System; -using Funq; -using ServiceStack.Configuration; -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 - //private const string BaseUrl = "http://io:8081/"; - - //private static ILog log; - - public IntegrationTestBase() - : base("ServiceStack Examples", typeof(RestMovieService).Assembly) - { - 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 void SendToEachEndpoint<TRes>(object request, Action<TRes> validate) - { - SendToEachEndpoint(request, null, validate); - } - - /// <summary> - /// Run the request against each Endpoint - /// </summary> - /// <typeparam name="TRes"></typeparam> - /// <param name="request"></param> - /// <param name="validate"></param> - /// <param name="httpMethod"></param> - public void SendToEachEndpoint<TRes>(object request, string httpMethod, Action<TRes> validate) - { - using (var xmlClient = new XmlServiceClient(BaseUrl)) - using (var jsonClient = new JsonServiceClient(BaseUrl)) - using (var jsvClient = new JsvServiceClient(BaseUrl)) - { - xmlClient.HttpMethod = httpMethod; - jsonClient.HttpMethod = httpMethod; - jsvClient.HttpMethod = httpMethod; - - var xmlResponse = xmlClient.Send<TRes>(request); - if (validate != null) validate(xmlResponse); - - var jsonResponse = jsonClient.Send<TRes>(request); - if (validate != null) validate(jsonResponse); - - var jsvResponse = jsvClient.Send<TRes>(request); - if (validate != null) validate(jsvResponse); - } - } - - public void DeleteOnEachEndpoint<TRes>(string relativePathOrAbsoluteUri, Action<TRes> validate) - { - using (var xmlClient = new XmlServiceClient(BaseUrl)) - using (var jsonClient = new JsonServiceClient(BaseUrl)) - using (var jsvClient = new JsvServiceClient(BaseUrl)) - { - var xmlResponse = xmlClient.Delete<TRes>(relativePathOrAbsoluteUri); - if (validate != null) validate(xmlResponse); - - var jsonResponse = jsonClient.Delete<TRes>(relativePathOrAbsoluteUri); - if (validate != null) validate(jsonResponse); - - var jsvResponse = jsvClient.Delete<TRes>(relativePathOrAbsoluteUri); - if (validate != null) validate(jsvResponse); - } - } - } -} \ No newline at end of file +using System; +using Funq; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.Logging; +using ServiceStack.OrmLite; +using ServiceStack.OrmLite.Sqlite; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + public class IntegrationTestBase + { + 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/"; + + public class IntegrationTestAppHost : AppHostHttpListenerBase + { + 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) + { + SendToEachEndpoint(request, null, validate); + } + + /// <summary> + /// Run the request against each Endpoint + /// </summary> + /// <typeparam name="TRes"></typeparam> + /// <param name="request"></param> + /// <param name="validate"></param> + /// <param name="httpMethod"></param> + public void SendToEachEndpoint<TRes>(object request, string httpMethod, Action<TRes> validate) + { + using (var xmlClient = new XmlServiceClient(BaseUrl)) + using (var jsonClient = new JsonServiceClient(BaseUrl)) + using (var jsvClient = new JsvServiceClient(BaseUrl)) + { + xmlClient.HttpMethod = httpMethod; + jsonClient.HttpMethod = httpMethod; + jsvClient.HttpMethod = httpMethod; + + var xmlResponse = xmlClient.Send<TRes>(request); + if (validate != null) validate(xmlResponse); + + var jsonResponse = jsonClient.Send<TRes>(request); + if (validate != null) validate(jsonResponse); + + var jsvResponse = jsvClient.Send<TRes>(request); + if (validate != null) validate(jsvResponse); + } + } + + public void DeleteOnEachEndpoint<TRes>(string relativePathOrAbsoluteUri, Action<TRes> validate) + { + using (var xmlClient = new XmlServiceClient(BaseUrl)) + using (var jsonClient = new JsonServiceClient(BaseUrl)) + using (var jsvClient = new JsvServiceClient(BaseUrl)) + { + var xmlResponse = xmlClient.Delete<TRes>(relativePathOrAbsoluteUri); + if (validate != null) validate(xmlResponse); + + var jsonResponse = jsonClient.Delete<TRes>(relativePathOrAbsoluteUri); + if (validate != null) validate(jsonResponse); + + var jsvResponse = jsvClient.Delete<TRes>(relativePathOrAbsoluteUri); + if (validate != null) validate(jsvResponse); + } + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs index 609ba185995..bdd661cf2a9 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs @@ -1,88 +1,85 @@ -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 -{ - [TestFixture] - public class MovieRestTests - : IntegrationTestBase - { - [SetUp] - public void OnBeforeEachTest() - { - var jsonClient = new JsonServiceClient(BaseUrl); - jsonClient.Post<ResetMoviesResponse>("reset-movies", new ResetMovies()); - } - - [Test] - public void Can_list_all_movies() - { - SendToEachEndpoint<RestMoviesResponse>(new RestMovies(), HttpMethods.Get, response => - Assert.That(response.Movies, Has.Count.EqualTo(ConfigureDatabase.Top5Movies.Count)) - ); - } - - [Test] - public void Can_add_movie() - { - var newMovie = new RestMovie - { - Id = "tt0110912", - Title = "Pulp Fiction", - Rating = 8.9m, - Director = "Quentin Tarantino", - ReleaseDate = new DateTime(1994, 10, 24), - TagLine = "Girls like me don't make invitations like this to just anyone!", - Genres = new List<string> { "Crime", "Drama", "Thriller" }, - }; - - SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Movie = newMovie }, HttpMethods.Put, null); - - SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = newMovie.Id }, HttpMethods.Get, response => - Assert.That(newMovie.Equals(response.Movies[0]), Is.True) - ); - - //Test if possible to get single movie - var topMovie = ConfigureDatabase.Top5Movies[0]; - SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = topMovie.Id }, HttpMethods.Get, response => - Assert.That(topMovie.Equals(response.Movies[0]), Is.True) - ); - - //Test if possible to update movie - var topMovie2 = ConfigureDatabase.Top5Movies[0]; - var updatedMovie = TypeSerializer.Clone(topMovie2); - updatedMovie.Title = "Updated Movie"; - - SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Movie = updatedMovie }, HttpMethods.Post, null); - - SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = topMovie2.Id }, HttpMethods.Get, response => - Assert.That(updatedMovie.Equals(response.Movies[0]), Is.True) - ); - } - - [Test] - public void Can_ResetMovieDatabase() - { - SendToEachEndpoint<ResetMovieDatabaseResponse>(new ResetMovieDatabase(), HttpMethods.Post, response => - Assert.That(response.ResponseStatus.ErrorCode, Is.Null) - ); - } - - [Test] - public void Can_delete_movie() - { - var topMovie = ConfigureDatabase.Top5Movies[0]; - - DeleteOnEachEndpoint<RestMoviesResponse>("restmovies/" + topMovie.Id, null); - - SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = topMovie.Id }, HttpMethods.Get, response => - Assert.That(response.Movies, Has.Count.EqualTo(0)) - ); - } - } +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + [TestFixture] + public class MovieRestTests + : IntegrationTestBase + { + [SetUp] + public void OnBeforeEachTest() + { + var jsonClient = new JsonServiceClient(BaseUrl); + jsonClient.Post<ResetMoviesResponse>("reset-movies", new ResetMovies()); + } + + [Test] + public void Can_list_all_movies() + { + SendToEachEndpoint<RestMoviesResponse>(new RestMovies(), HttpMethods.Get, response => + Assert.That(response.Movies, Has.Count.EqualTo(ConfigureDatabase.Top5Movies.Count)) + ); + } + + [Test] + public void Can_add_movie() + { + var newMovie = new RestMovie + { + Id = "tt0110912", + Title = "Pulp Fiction", + Rating = 8.9m, + Director = "Quentin Tarantino", + ReleaseDate = new DateTime(1994, 10, 24), + TagLine = "Girls like me don't make invitations like this to just anyone!", + Genres = new List<string> { "Crime", "Drama", "Thriller" }, + }; + + SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Movie = newMovie }, HttpMethods.Put, null); + + SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = newMovie.Id }, HttpMethods.Get, response => + Assert.That(newMovie.Equals(response.Movies[0]), Is.True) + ); + + //Test if possible to get single movie + var topMovie = ConfigureDatabase.Top5Movies[0]; + SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = topMovie.Id }, HttpMethods.Get, response => + Assert.That(topMovie.Equals(response.Movies[0]), Is.True) + ); + + //Test if possible to update movie + var topMovie2 = ConfigureDatabase.Top5Movies[0]; + var updatedMovie = TypeSerializer.Clone(topMovie2); + updatedMovie.Title = "Updated Movie"; + + SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Movie = updatedMovie }, HttpMethods.Post, null); + + SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = topMovie2.Id }, HttpMethods.Get, response => + Assert.That(updatedMovie.Equals(response.Movies[0]), Is.True) + ); + } + + [Test] + public void Can_ResetMovieDatabase() + { + SendToEachEndpoint<ResetMovieDatabaseResponse>(new ResetMovieDatabase(), HttpMethods.Post, response => + Assert.That(response.ResponseStatus.ErrorCode, Is.Null) + ); + } + + [Test] + public void Can_delete_movie() + { + var topMovie = ConfigureDatabase.Top5Movies[0]; + + DeleteOnEachEndpoint<RestMoviesResponse>("restmovies/" + topMovie.Id, null); + + SendToEachEndpoint<RestMoviesResponse>(new RestMovies { Id = topMovie.Id }, HttpMethods.Get, response => + Assert.That(response.Movies, Has.Count.EqualTo(0)) + ); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs new file mode 100644 index 00000000000..1caec5a9cea --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs @@ -0,0 +1,32 @@ +#if !NETCORE +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + [TestFixture] + public class MovieSoap11Tests : IntegrationTestBase + { + private Soap11ServiceClient soapClient; + + [SetUp] + public void OnBeforeEachTest(){ + soapClient = new Soap11ServiceClient(BaseUrl); + soapClient.Send<ResetMoviesResponse>(new ResetMovies()); + } + + [Test] + public void Can_list_all_movies() + { + var response = soapClient.Send<RestMoviesResponse>(new GetRestMovies()); + Assert.That(response.Movies, Has.Count.EqualTo(ConfigureDatabase.Top5Movies.Count)); + } + + [Test] + public void Can_ResetMovieDatabase() + { + var response = soapClient.Send<ResetMoviesResponse>(new ResetMovies()); + Assert.That(response.ResponseStatus.ErrorCode, Is.Null); + } + } +} +#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 b23ac6b4393..58f1f43b862 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabase.cs @@ -1,23 +1,24 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests -{ - [DataContract(Namespace = ExampleConfig.DefaultNamespace)] - public class ResetMovieDatabase - { - } - - [DataContract(Namespace = ExampleConfig.DefaultNamespace)] - public class ResetMovieDatabaseResponse - { - public ResetMovieDatabaseResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } +using System.Runtime.Serialization; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + [DataContract(Namespace = ExampleConfig.DefaultNamespace)] + public class ResetMovieDatabase + { + } + + [DataContract(Namespace = ExampleConfig.DefaultNamespace)] + public class ResetMovieDatabaseResponse + { + public ResetMovieDatabaseResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } } \ No newline at end of file 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 2a2f238bc2a..42fe735a944 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovies.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovies.cs @@ -1,44 +1,33 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.Serialization; -using System.Web; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests -{ - - [DataContract] - [Description("Resets the database back to the original Top 5 movies.")] - [RestService("/reset-movies")] - public class ResetMovies { } - - [DataContract] - public class ResetMoviesResponse - : IHasResponseStatus - { - public ResetMoviesResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class ResetMoviesService : RestServiceBase<ResetMovies> - { - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnPost(ResetMovies request) - { - ConfigureDatabase.Init(DbFactory); - - return new ResetMoviesResponse(); - } - } - +using System.ComponentModel; +using System.Runtime.Serialization; +using ServiceStack.Data; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + [DataContract] + [Description("Resets the database back to the original Top 5 movies.")] + [Route("/reset-movies")] + public class ResetMovies { } + + [DataContract] + public class ResetMoviesResponse : IHasResponseStatus + { + public ResetMoviesResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ResetMoviesService : Service + { + public object Post(ResetMovies request) + { + ConfigureDatabase.Init(TryResolve<IDbConnectionFactory>()); + + return new ResetMoviesResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs index 9167e3e67cc..9a5ed31053b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs @@ -1,102 +1,109 @@ -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 - */ -namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests -{ - [DataContract(Namespace = ExampleConfig.DefaultNamespace)] - [RestService("restmovies/{Id}")] - 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 RestMoviesResponse - { - public RestMoviesResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Movies = new List<RestMovie>(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - - [DataMember(EmitDefaultValue = false)] - public List<RestMovie> Movies { get; set; } - } - - [DataContract(Namespace = ExampleConfig.DefaultNamespace)] - public class RestMovie - { - public RestMovie() - { - this.Genres = new List<string>(); - } - - [DataMember] - public string Id { get; set; } - - [DataMember] - public string ImdbId { get; set; } - - [DataMember] - public string Title { get; set; } - - [DataMember] - public decimal Rating { get; set; } - - [DataMember] - public string Director { get; set; } - - [DataMember] - public DateTime ReleaseDate { get; set; } - - [DataMember] - public string TagLine { get; set; } - - [DataMember] - public List<string> Genres { get; set; } - - public bool Equals(RestMovie 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 (RestMovie)) return false; - return Equals((RestMovie) 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; - } - } - } +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +/* + * Examples of preliminery REST method support in ServiceStack + */ +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; } + } + + [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 + { + public RestMoviesResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Movies = new List<RestMovie>(); + } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + + [DataMember(EmitDefaultValue = false)] + public List<RestMovie> Movies { get; set; } + } + + [DataContract(Namespace = ExampleConfig.DefaultNamespace)] + public class RestMovie + { + public RestMovie() + { + this.Genres = new List<string>(); + } + + [DataMember] + public string Id { get; set; } + + [DataMember] + public string ImdbId { get; set; } + + [DataMember] + public string Title { get; set; } + + [DataMember] + public decimal Rating { get; set; } + + [DataMember] + public string Director { get; set; } + + [DataMember] + public DateTime ReleaseDate { get; set; } + + [DataMember] + public string TagLine { get; set; } + + [DataMember] + public List<string> Genres { get; set; } + + public bool Equals(RestMovie 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 (RestMovie)) return false; + return Equals((RestMovie) 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; + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovieService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovieService.cs index 64509871c97..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.OrmLite; -using ServiceStack.ServiceHost; - -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; } - - public IDbConnectionFactory DbFactory { get; set; } - - public object Execute(RestMovies request) - { - return Get(request); - } - - public object Get(RestMovies request) - { - var response = new RestMoviesResponse(); - - DbFactory.Exec(dbCmd => - { - if (request.Id != null) - { - var movie = dbCmd.GetByIdOrDefault<RestMovie>(request.Id); - if (movie != null) - { - response.Movies.Add(movie); - } - } - else - { - response.Movies = dbCmd.Select<RestMovie>(); - } - }); - - return response; - } - - public object Put(RestMovies request) - { - DbFactory.Exec(dbCmd => dbCmd.Save(request.Movie)); - return new RestMoviesResponse(); - } - - public object Delete(RestMovies request) - { - DbFactory.Exec(dbCmd => dbCmd.DeleteById<RestMovie>(request.Id)); - return new RestMoviesResponse(); - } - - public object Post(RestMovies request) - { - DbFactory.Exec(dbCmd => dbCmd.Update(request.Movie)); - return new RestMoviesResponse(); - } - } +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + /// <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 object Any(GetRestMovies request) + { + return Get(request.ConvertTo<RestMovies>()); + } + + public object Get(RestMovies request) + { + var response = new RestMoviesResponse(); + + 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; + } + + public object Put(RestMovies request) + { + using (var db = DbFactory.Open()) + db.Save(request.Movie); + 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) + { + 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 939036c7d72..6cbb04b1724 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IocServiceTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IocServiceTests.cs @@ -1,125 +1,357 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.ServiceClient.Web; -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 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)); - } - - [Test] - public void Does_dispose_service_when_there_is_an_error() - { - IocService.DisposedCount = 0; - IocService.ThrowErrors = true; - - var restClient = new JsonServiceClient(ListeningOn); - Assert.Throws<WebServiceException>(() => restClient.Get<IocResponse>("ioc")); - - Assert.That(IocService.DisposedCount, Is.EqualTo(1)); - } - - [Test] - public void Does_create_correct_instances_per_scope() - { - FunqRequestScopeDepDisposableProperty.DisposeCount = 0; - AltRequestScopeDepDisposableProperty.DisposeCount = 0; - - var restClient = new JsonServiceClient(ListeningOn); - var response1 = restClient.Get<IocScopeResponse>("iocscope"); - var response2 = restClient.Get<IocScopeResponse>("iocscope"); - - response1.PrintDump(); - - 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(FunqRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - Assert.That(AltRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - } - - [Test] - public void Does_create_correct_instances_per_scope_with_exception() - { - FunqRequestScopeDepDisposableProperty.DisposeCount = 0; - AltRequestScopeDepDisposableProperty.DisposeCount = 0; - - var restClient = new JsonServiceClient(ListeningOn); - try { - restClient.Get<IocScopeResponse>("iocscope?Throw=true"); - } catch { } - try { - restClient.Get<IocScopeResponse>("iocscope?Throw=true"); - } catch { } - - Assert.That(FunqRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - Assert.That(AltRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - } - } +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Common.Tests; +using ServiceStack.Configuration; +using ServiceStack.Shared.Tests; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + 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; + + [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() + { + 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)); + } + + [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")); + + var stats = client.Get(new IocStats()); + Assert.That(stats.IocService_DisposeCount, Is.EqualTo(1)); + } + + [Test] + public void Does_create_correct_instances_per_scope() + { + var client = CreateClient(); + var response1 = client.Get<IocScopeResponse>("iocscope"); + var response2 = client.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)); + } + + [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)); + Assert.That(response2.Results[typeof(FunqNoneScope).Name], Is.EqualTo(4)); + + 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() + { + var client = CreateClient(); + try + { + client.Get<IocScopeResponse>("iocscope?Throw=true"); + } + catch { } + try + { + client.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); + + 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() + { + try + { + 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, + }; + + Assert.That(expected.EquivalentTo(response.Results)); + + } + catch (Exception ex) + { + ex.Message.Print(); + throw; + } + } + + [Test] + public void Does_AutoWire_ActionLevel_RequestFilters_Async() + { + 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() + { + 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 response = client.Get(new IocDisposeAsync()); + response = client.Get(new IocDisposeAsync()); + 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)); + } + + } } \ No newline at end of file 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 8db4673679c..61a3a934de3 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/MessageSerializationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/MessageSerializationTests.cs @@ -1,190 +1,192 @@ -using System; -using System.IO; -using System.Runtime.Serialization; -using System.ServiceModel.Channels; -using System.Text; -using System.Xml; -using NUnit.Framework; -using ServiceStack.Messaging; -using ServiceStack.ServiceModel.Serialization; -using Message = System.ServiceModel.Channels.Message; -using DataContractSerializer = ServiceStack.ServiceModel.Serialization.DataContractSerializer; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [DataContract(Namespace = "http://schemas.servicestack.net/types")] - public class Reverse - { - [DataMember] - public string Value { get; set; } - } - - [TestFixture] - public class MessageSerializationTests - { - static string xml = "<Reverse xmlns=\"http://schemas.servicestack.net/types\"><Value>test</Value></Reverse>"; - Reverse request = new Reverse { Value = "test" }; - string msgXml = "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\"><s:Body>" + xml + "</s:Body></s:Envelope>"; - - [Test] - public void Can_Deserialize_Message_from_GetBody() - { - var msg = Message.CreateMessage(MessageVersion.Default, "Reverse", request); - //Console.WriteLine("BODY: " + msg.GetReaderAtBodyContents().ReadOuterXml()); - - var fromRequest = msg.GetBody<Reverse>(new System.Runtime.Serialization.DataContractSerializer(typeof(Reverse))); - Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); - } - - [Test] - public void Can_Deserialize_Message_from_GetReaderAtBodyContents() - { - var msg = Message.CreateMessage(MessageVersion.Default, "Reverse", request); - using (var reader = msg.GetReaderAtBodyContents()) - { - var requestXml = reader.ReadOuterXml(); - var fromRequest = (Reverse)DataContractDeserializer.Instance.Parse(requestXml, typeof(Reverse)); - Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); - } - } - - internal class SimpleBodyWriter : BodyWriter - { - private readonly string message; - - public SimpleBodyWriter(string message) - : base(false) - { - this.message = message; - } - - protected override void OnWriteBodyContents(XmlDictionaryWriter writer) - { - writer.WriteRaw(message); - } - } - - [Test] - public void Can_create_entire_message_from_xml() - { - - //var msg = Message.CreateMessage(MessageVersion.Default, - // "Reverse", new SimpleBodyWriter(msgXml)); - - var doc = new XmlDocument(); - doc.LoadXml(msgXml); - - using (var xnr = new XmlNodeReader(doc)) - { - var msg = Message.CreateMessage(xnr, msgXml.Length, MessageVersion.Soap12WSAddressingAugust2004); - - var xml = msg.GetReaderAtBodyContents().ReadOuterXml(); - Console.WriteLine("BODY: " + DataContractSerializer.Instance.Parse(request)); - Console.WriteLine("EXPECTED BODY: " + xml); - - var fromRequest = (Reverse)DataContractDeserializer.Instance.Parse(xml, typeof(Reverse)); - Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); - } - - //var fromRequest = msg.GetBody<Request>(new DataContractSerializer(typeof(Request))); - } - - [Test] - public void What_do_the_different_soap_payloads_look_like() - { - var doc = new XmlDocument(); - doc.LoadXml(msgXml); - - //var action = "Request"; - string action = null; - var soap12 = Message.CreateMessage(MessageVersion.Soap12, action, request); - var soap12WSAddressing10 = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, action, request); - var soap12WSAddressingAugust2004 = Message.CreateMessage(MessageVersion.Soap12WSAddressingAugust2004, action, request); - - Console.WriteLine("Soap12: " + GetMessageEnvelope(soap12)); - Console.WriteLine("Soap12WSAddressing10: " + GetMessageEnvelope(soap12WSAddressing10)); - Console.WriteLine("Soap12WSAddressingAugust2004: " + GetMessageEnvelope(soap12WSAddressingAugust2004)); - } - - public string GetMessageEnvelope(Message msg) - { - var sb = new StringBuilder(); - using (var sw = XmlWriter.Create(new StringWriter(sb))) - { - msg.WriteMessage(sw); - sw.Flush(); - return sb.ToString(); - } - } - - - protected static Message GetRequestMessage(string requestXml) - { - var doc = new XmlDocument(); - doc.LoadXml(requestXml); - - var msg = Message.CreateMessage(new XmlNodeReader(doc), int.MaxValue, - MessageVersion.Soap11WSAddressingAugust2004); - //var msg = Message.CreateMessage(MessageVersion.Soap12WSAddressingAugust2004, - // "*", new XmlBodyWriter(requestXml)); - - return msg; - } - - [Test] - public void Can_create_message_from_xml() - { - var requestXml = - "<?xml version=\"1.0\" encoding=\"utf-8\"?>" - + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" - + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" - + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>" - + "<Reverse xmlns=\"http://schemas.servicestack.net/types\"><Value>Testing</Value></Reverse>" - + "</soap:Body></soap:Envelope>"; - - var requestMsg = GetRequestMessage(requestXml); - - using (var reader = requestMsg.GetReaderAtBodyContents()) - { - requestXml = reader.ReadOuterXml(); - } - - var requestType = typeof (Reverse); - var request = (Reverse)DataContractDeserializer.Instance.Parse(requestXml, requestType); - Assert.That(request.Value, Is.EqualTo("Testing")); - } - - public class DtoBodyWriter : BodyWriter - { - private readonly object dto; - public DtoBodyWriter(object dto) - : base(true) - { - this.dto = dto; - } - - protected override void OnWriteBodyContents(XmlDictionaryWriter writer) - { - var xml = DataContractSerializer.Instance.Parse(dto); - writer.WriteString(xml); - } - } - - public class XmlBodyWriter : BodyWriter - { - private readonly string xml; - public XmlBodyWriter(string xml) - : base(true) - { - this.xml = xml; - } - - protected override void OnWriteBodyContents(XmlDictionaryWriter writer) - { - writer.WriteString(xml); - } - } - } - - -} \ No newline at end of file +#if NETFX +using System; +using System.IO; +using System.Runtime.Serialization; +using System.ServiceModel.Channels; +using System.Text; +using System.Xml; +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Serialization; +using Message = System.ServiceModel.Channels.Message; +using DataContractSerializer = ServiceStack.Serialization.DataContractSerializer; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [DataContract(Namespace = "http://schemas.servicestack.net/types")] + public class Reverse + { + [DataMember] + public string Value { get; set; } + } + + [TestFixture] + public class MessageSerializationTests + { + static string xml = "<Reverse xmlns=\"http://schemas.servicestack.net/types\"><Value>test</Value></Reverse>"; + Reverse request = new Reverse { Value = "test" }; + string msgXml = "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\"><s:Body>" + xml + "</s:Body></s:Envelope>"; + + [Test] + public void Can_Deserialize_Message_from_GetBody() + { + var msg = Message.CreateMessage(MessageVersion.Default, "Reverse", request); + //Console.WriteLine("BODY: " + msg.GetReaderAtBodyContents().ReadOuterXml()); + + var fromRequest = msg.GetBody<Reverse>(new System.Runtime.Serialization.DataContractSerializer(typeof(Reverse))); + Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); + } + + [Test] + public void Can_Deserialize_Message_from_GetReaderAtBodyContents() + { + var msg = Message.CreateMessage(MessageVersion.Default, "Reverse", request); + using (var reader = msg.GetReaderAtBodyContents()) + { + var requestXml = reader.ReadOuterXml(); + var fromRequest = (Reverse)DataContractSerializer.Instance.DeserializeFromString(requestXml, typeof(Reverse)); + Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); + } + } + + internal class SimpleBodyWriter : BodyWriter + { + private readonly string message; + + public SimpleBodyWriter(string message) + : base(false) + { + this.message = message; + } + + protected override void OnWriteBodyContents(XmlDictionaryWriter writer) + { + writer.WriteRaw(message); + } + } + +#if !NETCORE + [Test] + public void Can_create_entire_message_from_xml() + { + + //var msg = Message.CreateMessage(MessageVersion.Default, + // "Reverse", new SimpleBodyWriter(msgXml)); + + var doc = new XmlDocument(); + doc.LoadXml(msgXml); + + using (var xnr = new XmlNodeReader(doc)) + { + var msg = Message.CreateMessage(xnr, msgXml.Length, MessageVersion.Soap12WSAddressingAugust2004); + + var xml = msg.GetReaderAtBodyContents().ReadOuterXml(); + Console.WriteLine("BODY: " + DataContractSerializer.Instance.SerializeToString(request)); + Console.WriteLine("EXPECTED BODY: " + xml); + + var fromRequest = (Reverse)DataContractSerializer.Instance.DeserializeFromString(xml, typeof(Reverse)); + Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); + } + + //var fromRequest = msg.GetBody<Request>(new DataContractSerializer(typeof(Request))); + } + + [Test] + public void What_do_the_different_soap_payloads_look_like() + { + var doc = new XmlDocument(); + doc.LoadXml(msgXml); + + //var action = "Request"; + string action = null; + var soap12 = Message.CreateMessage(MessageVersion.Soap12, action, request); + var soap12WSAddressing10 = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, action, request); + var soap12WSAddressingAugust2004 = Message.CreateMessage(MessageVersion.Soap12WSAddressingAugust2004, action, request); + + Console.WriteLine("Soap12: " + GetMessageEnvelope(soap12)); + Console.WriteLine("Soap12WSAddressing10: " + GetMessageEnvelope(soap12WSAddressing10)); + Console.WriteLine("Soap12WSAddressingAugust2004: " + GetMessageEnvelope(soap12WSAddressingAugust2004)); + } + + public string GetMessageEnvelope(Message msg) + { + var sb = new StringBuilder(); + using (var sw = XmlWriter.Create(new StringWriter(sb))) + { + msg.WriteMessage(sw); + sw.Flush(); + return sb.ToString(); + } + } + + + protected static Message GetRequestMessage(string requestXml) + { + var doc = new XmlDocument(); + doc.LoadXml(requestXml); + + var msg = Message.CreateMessage(new XmlNodeReader(doc), int.MaxValue, + MessageVersion.Soap11WSAddressingAugust2004); + //var msg = Message.CreateMessage(MessageVersion.Soap12WSAddressingAugust2004, + // "*", new XmlBodyWriter(requestXml)); + + return msg; + } + + [Test] + public void Can_create_message_from_xml() + { + var requestXml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" + + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>" + + "<Reverse xmlns=\"http://schemas.servicestack.net/types\"><Value>Testing</Value></Reverse>" + + "</soap:Body></soap:Envelope>"; + + var requestMsg = GetRequestMessage(requestXml); + + using (var reader = requestMsg.GetReaderAtBodyContents()) + { + requestXml = reader.ReadOuterXml(); + } + + var requestType = typeof(Reverse); + var request = (Reverse)DataContractSerializer.Instance.DeserializeFromString(requestXml, requestType); + Assert.That(request.Value, Is.EqualTo("Testing")); + } +#endif + + public class DtoBodyWriter : BodyWriter + { + private readonly object dto; + public DtoBodyWriter(object dto) + : base(true) + { + this.dto = dto; + } + + protected override void OnWriteBodyContents(XmlDictionaryWriter writer) + { + var xml = DataContractSerializer.Instance.SerializeToString(dto); + writer.WriteString(xml); + } + } + + public class XmlBodyWriter : BodyWriter + { + private readonly string xml; + public XmlBodyWriter(string xml) + : base(true) + { + this.xml = xml; + } + + protected override void OnWriteBodyContents(XmlDictionaryWriter writer) + { + writer.WriteString(xml); + } + } + } +} +#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 new file mode 100644 index 00000000000..c4cf747293d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/NewApiTodos.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack; + +namespace NewApi.Todos +{ + public class AppHost : AppHostHttpListenerBase + { + public AppHost() : base("TODOs Tests", typeof(Todo).Assembly) {} + + public override void Configure(Container container) + { + container.Register(new TodoRepository()); + } + } + + //REST Resource DTO + [Route("/todos")] + [Route("/todos/{Ids}")] + public class Todos : IReturn<List<Todo>> + { + public long[] Ids { get; set; } + + public Todos() {} + public Todos(params long[] ids) + { + this.Ids = ids; + } + } + + [Route("/todos", "POST")] + [Route("/todos/{Id}", "PUT")] + public class Todo : IReturn<Todo> + { + public long Id { get; set; } + public string Content { get; set; } + public int Order { get; set; } + public bool Done { get; set; } + } + + public class TodosService : Service + { + public TodoRepository Repository { get; set; } //Injected by IOC + + public object Get(Todos request) + { + return request.Ids.IsEmpty() + ? Repository.GetAll() + : Repository.GetByIds(request.Ids); + } + + public object Post(Todo todo) + { + return Repository.Store(todo); + } + + public object Put(Todo todo) + { + return Repository.Store(todo); + } + + public void Delete(Todos request) + { + Repository.DeleteByIds(request.Ids); + } + } + + public class TodoRepository + { + List<Todo> todos = new List<Todo>(); + + public List<Todo> GetByIds(long[] ids) + { + return todos.Where(x => ids.Contains(x.Id)).ToList(); + } + + public List<Todo> GetAll() + { + return todos; + } + + public Todo Store(Todo todo) + { + var existing = todos.FirstOrDefault(x => x.Id == todo.Id); + if (existing == null) + { + var newId = todos.Count > 0 ? todos.Max(x => x.Id) + 1 : 1; + todo.Id = newId; + } + todos.Add(todo); + return todo; + } + + public void DeleteByIds(params long[] ids) + { + todos.RemoveAll(x => ids.Contains(x.Id)); + } + } + + [TestFixture] + public class NewApiTodosTests + { + const string BaseUri = "http://localhost:1337/"; + + AppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost(); + appHost.Init(); + appHost.Start(BaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Run() + { + var restClient = new JsonServiceClient(BaseUri); + List<Todo> all = restClient.Get(new Todos()); + Assert.That(all.Count, Is.EqualTo(0)); + + var todo = restClient.Post(new Todo { Content = "New TODO", Order = 1 }); + Assert.That(todo.Id, Is.EqualTo(1)); + all = restClient.Get(new Todos()); + Assert.That(all.Count, Is.EqualTo(1)); + + todo.Content = "Updated TODO"; + todo = restClient.Put(todo); + Assert.That(todo.Content, Is.EqualTo("Updated TODO")); + + restClient.Delete(new Todos(todo.Id)); + all = restClient.Get(new Todos()); + Assert.That(all.Count, Is.EqualTo(0)); + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs index 82270366b81..118b72bcd95 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs @@ -1,21 +1,136 @@ -using System.Net; -using NUnit.Framework; -using ServiceStack.WebHost.Endpoints.Metadata; -using ServiceStack.WebHost.Endpoints.Support; -using ServiceStack.WebHost.Endpoints.Tests.Support; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class OperationTests : MetadataTestBase - { - [Test] - public void Sorts_operations_into_correct_operation_groups() - { - var groupedOperations = new Operations(base.AllOperations); - - Assert.That(groupedOperations.ReplyOperations.Names.Count, Is.EqualTo(base.ReplyOperations.Count)); - Assert.That(groupedOperations.OneWayOperations.Names.Count, Is.EqualTo(base.OneWayOperations.Count)); - } - } +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.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(nameof(GetCustomer), typeof(GetCustomer).Assembly) { } + public override void Configure(Container container) { } + } + + [TestFixture] + public class OperationTests : IService + { + private OperationTestsAppHost appHost; + private OperationControl operationControl; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + 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(""), + Format = Format.Json, + HostName = "localhost", + RequestMessage = "(string)", + ResponseMessage = "(HttpWebResponse)", + Title = "Metadata page", + OperationName = "operationname", + MetadataHtml = "<p>Operation</p>", + }; + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [TearDown] + public void OnTearDown() + { + if (appHost?.Config?.WebHostUrl != null) + appHost.Config.WebHostUrl = null; + } + + [Test] + public async Task OperationControl_render_creates_link_back_to_main_page_using_WebHostUrl_when_set() + { + appHost.Config.WebHostUrl = "https://host.example.com/_api"; + + 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 async Task OperationControl_render_creates_link_back_to_main_page_using_relative_uri_when_WebHostUrl_not_set() + { + 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() + { + appHost.Metadata.Add(GetType(), typeof(HelloImage), null); + + using (new CultureSwitch("tr-TR")) + { + Assert.IsTrue(appHost.Metadata.IsVisible(operationControl.HttpRequest, Format.Json, "HelloImage")); + } + } + } + + [DataContract] + public class HelloImage + { + } + + public class CultureSwitch : IDisposable + { + private readonly CultureInfo _currentCulture; + + 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 new file mode 100644 index 00000000000..7b01ccfd38f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/PartialContentResultTests.cs @@ -0,0 +1,365 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Common.Tests; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/partialfiles/{RelativePath*}")] + public class PartialFile + { + public string RelativePath { get; set; } + + public string MimeType { get; set; } + } + + [Route("/partialfiles/memory")] + public class PartialFromMemory { } + + [Route("/partialfiles/text")] + public class PartialFromText { } + + public class PartialContentService : Service + { + public object Get(PartialFile request) + { + if (request.RelativePath.IsNullOrEmpty()) + throw new ArgumentNullException("RelativePath"); + + string filePath = "~/{0}".Fmt(request.RelativePath).MapProjectPlatformPath(); + if (!File.Exists(filePath)) + throw new FileNotFoundException(request.RelativePath); + + return new HttpResult(new FileInfo(filePath), request.MimeType); + } + + public object Get(PartialFromMemory request) + { + var customText = "123456789012345678901234567890"; + var customTextBytes = customText.ToUtf8Bytes(); + var ms = new MemoryStream(); + ms.Write(customTextBytes, 0, customTextBytes.Length); + + var httpResult = new HttpResult(ms, "audio/mpeg"); + return httpResult; + } + + public object Get(PartialFromText request) + { + const string customText = "123456789012345678901234567890"; + var httpResult = new HttpResult(customText, "text/plain"); + return httpResult; + } + } + + public class PartialContentAppHost : AppHostHttpListenerBase + { + public PartialContentAppHost() : base(typeof(PartialFile).Name, typeof(PartialFile).Assembly) { } + public override void Configure(Container container) {} + } + + [TestFixture] + public class PartialContentResultTests + { + string BaseUri = Config.ServiceStackBaseUri; + string ListeningOn = Config.AbsoluteBaseUri; + + private ServiceStackHost appHost; + + readonly FileInfo uploadedFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + readonly FileInfo uploadedTextFile = new FileInfo("~/TestExistingDir/textfile.txt".MapProjectPlatformPath()); + + [OneTimeSetUp] + public void TextFixtureSetUp() + { + appHost = new PartialContentAppHost() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost?.Dispose(); + + [Test] + 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 {httpRes.GetContentLength()}".Print()); + + "response size {0}".Fmt(actualContents.Length); + + Assert.That(actualContents.Length, Is.EqualTo(uploadedFile.Length)); + } + + [Test] + 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 {httpRes.GetContentLength()}".Print()); + + "response size {0}".Fmt(actualContents.Length); + + Assert.That(actualContents.Length, Is.EqualTo(uploadedFile.Length)); + } + + [Test] + 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.With(c => c.SetRange(5, 11)), + responseFilter: httpRes => + { + $"Content-Length header {httpRes.GetContentLength()}".Print(); + Assert.That(httpRes.MatchesContentType(MimeTypes.GetMimeType(uploadedFile.Name))); + }); + + "Response length {0}".Print(actualContents.Length); + Assert.That(actualContents, Is.EqualTo("DOCTYPE")); + } + + [Test] + 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.With(c => c.SetRange(5, 11)), + responseFilter: httpRes => + { + $"Content-Length header {httpRes.GetContentLength()}".Print(); + Assert.That(httpRes.MatchesContentType(MimeTypes.GetMimeType(uploadedFile.Name))); + }); + + "Response length {0}".Print(actualContents.Length); + Assert.That(actualContents, Is.EqualTo("DOCTYPE")); + } + + [Test] + 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.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_GET_206_Partial_response_for_text_with_range_header() + { + var actualContents = "{0}/partialfiles/text".Fmt(BaseUri).GetStringFromUrl( + 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 async Task Can_respond_to_non_range_requests_with_200_OK_response() + { + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); + + 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 responseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); + Assert.That(responseWasAutoHandled, Is.True); + + string writtenString = mockResponse.ReadAsString(); + Assert.That(writtenString, Is.EqualTo(customText)); + + 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 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() + { + // 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-524287"; + + 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_middle() + { + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); + + mockRequest.Headers[HttpHeaders.Range] = "bytes=0-2"; + + 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("123")); + + Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 0-2/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_middle_to_end() + { + var mockRequest = new MockHttpRequest(); + mockRequest.Headers.Add("Range", "bytes=4-"); + var mockResponse = new MockHttpResponse(mockRequest); + + 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("567890")); + + Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 4-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_middle_to_middle() + { + var mockRequest = new MockHttpRequest(); + mockRequest.Headers.Add("Range", "bytes=3-5"); + var mockResponse = new MockHttpResponse(mockRequest); + + 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 responseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); + Assert.That(responseWasAutoHandled, Is.True); + + string writtenString = mockResponse.ReadAsString(); + Assert.That(writtenString, Is.EqualTo("456")); + + Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 3-5/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_use_fileStream() + { + byte[] fileBytes = uploadedTextFile.ReadFully(); + string fileText = Encoding.ASCII.GetString(fileBytes); + + "File content size {0}".Print(fileBytes.Length); + "File content is {0}".Print(fileText); + + 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 = await mockResponse.WriteToResponse(mockRequest, httpResult); + Assert.That(reponseWasAutoHandled, Is.True); + + 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")); + 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] + [Ignore("Helps debugging when you need to find out WTF is going on")] + public void Run_for_30secs() + { + Thread.Sleep(30000); + } + } +} \ No newline at end of file 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 a3b04ac3626..4ea3fe1bfdd 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/AssemblyInfo.cs @@ -1,46 +1,12 @@ -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")] -[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.Endpoints.Tests")] - +using System.Reflection; +using System.Runtime.Serialization; + +[assembly: AssemblyVersion("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.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")] +[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.Endpoints.Tests")] + 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 188b8135be8..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.Text; -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.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 : ServiceBase<ProtoBufEmail> - { - protected override object Run(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()); - } - } - - } +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.ProtoBuf; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [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: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 e89e7502d8f..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 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 -{ - [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)); - } - - } - +using System.IO; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [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 9a8b50285d3..3ed5423e481 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RemoteEndDropsConnectionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RemoteEndDropsConnectionTests.cs @@ -1,132 +1,132 @@ -using System; -using System.Net; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; -using System.Linq; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class RemoteEndDropsConnectionTests - { - private const string ListeningOn = "http://localhost:82/"; - ExampleAppHostHttpListener appHost; - - public RemoteEndDropsConnectionTests() - { - LogManager.LogFactory = new TestLogFactory(); - } - - [TestFixtureSetUp] - public void OnTestFixtureStartUp() - { - appHost = new ExampleAppHostHttpListener(); - LogManager.LogFactory = new TestLogFactory(); - appHost.Init(); - appHost.Start(ListeningOn); - - Console.WriteLine("ExampleAppHost Created at {0}, listening on {1}", - DateTime.Now, ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - appHost = null; - } - - [SetUp] - public void SetUp() - { - //Clear the logs to get rid of setup messages (registering services) - TestLogger.GetLogs().Clear(); - } - - [TearDown] - public void TearDown() - { - //Clear the logs so other tests dont inherit log entries - TestLogger.GetLogs().Clear(); - } - - /// <summary> - /// *Request* DTO - /// </summary> - [ServiceStack.ServiceHost.RestService("/test/timed", "GET")] - public class Timed - { - /// <summary> - /// Time for the request handler to take before returning. - /// </summary> - public int Milliseconds { get; set; } - } - - public class TimedService : ServiceStack.ServiceInterface.ServiceBase<Timed> - { - protected override object Run(Timed request) - { - Thread.Sleep(request.Milliseconds); - return true; - } - } - - /// <summary> - /// This test calls a test service and then aborts the HTTP GET and verifies the host behave in the expected way. - /// a) when the setting is to write errors to response - /// b) when the setting is NOT to write errors to response - /// </summary> - [Ignore("Hard to know what to change - need to verify this is correct behaviour")] - [TestCase(false)] - [TestCase(true)] - public void TestClientDropsConnection(bool writeErrorsToResponse) - { - EndpointHost.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 - req.Timeout = 100; - try - { - var res = (HttpWebResponse)req.GetResponse(); - } - catch (WebException ex) - { - if (ex.Status != WebExceptionStatus.Timeout) - throw; - - //Do nothing - we are expecting a time out - } - - //Sleep to give the appHost the chance to log the problems so we can investigate - Thread.Sleep(sleepMs * 2); - - foreach (var pair in TestLogger.GetLogs()) - { - Console.WriteLine("TEST: {0}: {1}", pair.Key, pair.Value); - } - - if (!writeErrorsToResponse) - { - //Arguably there should be only one Error reported, but we get two. Lets check them both - - //We should get only one log entry: An ERROR from ProcessRequest - var errorLogs = TestLogger.GetLogs().Where(o => o.Key == TestLogger.Levels.ERROR).ToList(); - Assert.AreEqual(2, errorLogs.Count, "Checking if there is only one ERROR entry"); - - StringAssert.Contains("Error in HttpListenerResponseWrapper", errorLogs[0].Value, "Checking if the error is from HttpListenerResponseWrapper"); - StringAssert.Contains("ProcessRequest", errorLogs[1].Value, "Checking if the error is from ProcessRequest"); - } - else - { - //There is quite a lot of logging going on here and arguably there should be only one Error reported. - } - } - } - -} \ No newline at end of file +using System; +using System.Net; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; +using System.Linq; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class RemoteEndDropsConnectionTests + { + private const string ListeningOn = "http://localhost:1337/"; + ExampleAppHostHttpListener appHost; + + public RemoteEndDropsConnectionTests() + { + LogManager.LogFactory = new TestLogFactory(); + } + + [OneTimeSetUp] + public void OnTestFixtureStartUp() + { + appHost = new ExampleAppHostHttpListener(); + LogManager.LogFactory = new TestLogFactory(); + appHost.Init(); + appHost.Start(ListeningOn); + + Console.WriteLine(@"ExampleAppHost Created at {0}, listening on {1}", + DateTime.Now, ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [SetUp] + public void SetUp() + { + //Clear the logs to get rid of setup messages (registering services) + TestLogger.GetLogs().Clear(); + } + + [TearDown] + public void TearDown() + { + //Clear the logs so other tests dont inherit log entries + TestLogger.GetLogs().Clear(); + } + + /// <summary> + /// *Request* DTO + /// </summary> + [Route("/test/timed", "GET")] + public class Timed + { + /// <summary> + /// Time for the request handler to take before returning. + /// </summary> + public int Milliseconds { get; set; } + } + + public class TimedService : Service + { + public object Any(Timed request) + { + Thread.Sleep(request.Milliseconds); + return true; + } + } + + /// <summary> + /// This test calls a test service and then aborts the HTTP GET and verifies the host behave in the expected way. + /// a) when the setting is to write errors to response + /// b) when the setting is NOT to write errors to response + /// </summary> + [Ignore("Hard to know what to change - need to verify this is correct behaviour")] + [TestCase(false)] + [TestCase(true)] + public void TestClientDropsConnection(bool 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(); + } + catch (WebException ex) + { + if (ex.Status != WebExceptionStatus.Timeout) + throw; + + //Do nothing - we are expecting a time out + } + + //Sleep to give the appHost the chance to log the problems so we can investigate + Thread.Sleep(sleepMs * 2); + + foreach (var pair in TestLogger.GetLogs()) + { + Console.WriteLine(@"TEST: {0}: {1}", pair.Key, pair.Value); + } + + if (!writeErrorsToResponse) + { + //Arguably there should be only one Error reported, but we get two. Lets check them both + + //We should get only one log entry: An ERROR from ProcessRequest + var errorLogs = TestLogger.GetLogs().Where(o => o.Key == TestLogger.Levels.ERROR).ToList(); + Assert.AreEqual(2, errorLogs.Count, "Checking if there is only one ERROR entry"); + + StringAssert.Contains("Error in HttpListenerResponseWrapper", errorLogs[0].Value, "Checking if the error is from HttpListenerResponseWrapper"); + StringAssert.Contains("ProcessRequest", errorLogs[1].Value, "Checking if the error is from ProcessRequest"); + } + else + { + //There is quite a lot of logging going on here and arguably there should be only one Error reported. + } + } + } + +} 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 644450a7515..c13328288e9 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestContextTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestContextTests.cs @@ -1,166 +1,157 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using Funq; -using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Services; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class RequestContextTests - { - private const string ListeningOn = "http://localhost:82/"; - - public class HeadersAppHostHttpListener - : AppHostHttpListenerBase - { - public HeadersAppHostHttpListener() - : base("Request Filters Tests", typeof(HeadersService).Assembly) { } - - public override void Configure(Container container) - { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); - - //Signal advanced web browsers what HTTP Methods you accept - base.SetConfig(new EndpointHostConfig - { - GlobalResponseHeaders = - { - { "Access-Control-Allow-Origin", "*" }, - { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, - }, - }); - - this.RequestFilters.Add((req, res, dto) => - { - var requestFilter = dto as RequestFilter; - if (requestFilter != null) - { - res.StatusCode = requestFilter.StatusCode; - if (!requestFilter.HeaderName.IsNullOrEmpty()) - { - res.AddHeader(requestFilter.HeaderName, requestFilter.HeaderValue); - } - } - }); - } - } - - HeadersAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new HeadersAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - 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; - } - - static Dictionary<string, string> GetResponseHeaders() - { - var webRequest = (HttpWebRequest)WebRequest.Create( - ListeningOn + "json/syncreply/Headers"); - - var webResponse = webRequest.GetResponse(); - - var map = new Dictionary<string, string>(); - for (var i = 0; i < webResponse.Headers.Count; i++) - { - var header = webResponse.Headers.Keys[i]; - map[header] = webResponse.Headers[header]; - } - - return map; - } - - [Test] - public void Can_resolve_CustomHeader() - { - var webRequest = (HttpWebRequest)WebRequest.Create( - ListeningOn + "json/syncreply/Headers?Name=X-CustomHeader"); - webRequest.Headers["X-CustomHeader"] = "CustomValue"; - - var response = JsonSerializer.DeserializeFromStream<HeadersResponse>( - webRequest.GetResponse().GetResponseStream()); - - Assert.That(response.Value, Is.EqualTo("CustomValue")); - } - - [Test] - public void Does_Send_Global_Headers() - { - var headers = GetResponseHeaders(); - Assert.That(headers["Access-Control-Allow-Origin"], Is.EqualTo("*")); - Assert.That(headers["Access-Control-Allow-Methods"], Is.EqualTo("GET, POST, PUT, DELETE, OPTIONS")); - } - - [Test] - public void Does_return_bare_401_StatusCode() - { - try - { - var webRequest = (HttpWebRequest)WebRequest.Create( - ListeningOn + "json/syncreply/RequestFilter?StatusCode=401"); - - webRequest.GetResponse(); - - 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(ListeningOn - + "json/syncreply/RequestFilter?StatusCode=401" - + "&HeaderName=" + HttpHeaders.WwwAuthenticate - + "&HeaderValue=" + "Basic realm=\"Auth Required\"".UrlEncode()); - - webRequest.GetResponse(); - - 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\"")); - } - } - - - } -} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.Common; +using ServiceStack.Text; +using ServiceStack.Web; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class RequestContextTests + { + public class HeadersAppHostHttpListener + : AppHostHttpListenerBase + { + public HeadersAppHostHttpListener() + : base("Request Filters Tests", typeof(HeadersService).Assembly) { } + + public override void Configure(Container container) + { + HostContext.Config.GlobalResponseHeaders.Clear(); + + //Signal advanced web browsers what HTTP Methods you accept + base.SetConfig(new HostConfig + { + GlobalResponseHeaders = + { + { "Access-Control-Allow-Origin", "*" }, + { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, + }, + }); + + this.GlobalRequestFilters.Add((req, res, dto) => + { + if (dto is RequestFilter requestFilter) + { + res.StatusCode = requestFilter.StatusCode; + if (!requestFilter.HeaderName.IsNullOrEmpty()) + { + res.AddHeader(requestFilter.HeaderName, requestFilter.HeaderValue); + } + } + }); + } + } + + HeadersAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new HeadersAppHostHttpListener(); + appHost.Init(); + appHost.Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + public static Dictionary<string, string> GetResponseHeaders(String url) + { + try + { + var webRequest = WebRequest.CreateHttp(url); + + 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]; + } + + return map; + } + catch (WebException e) + { + Console.WriteLine(e); + throw; + } + } + + [Test] + public void Can_resolve_CustomHeader() + { + var webRequest = WebRequest.CreateHttp( + Config.ListeningOn + "json/reply/Headers?Name=X-CustomHeader"); + webRequest.Headers["X-CustomHeader"] = "CustomValue"; + + var response = JsonSerializer.DeserializeFromStream<HeadersResponse>( + webRequest.GetResponse().GetResponseStream()); + + Assert.That(response.Value, Is.EqualTo("CustomValue")); + } + + [Test] + public void Does_Send_Global_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")); + } + + [Test] + public void Does_return_bare_401_StatusCode() + { + try + { + var webRequest = WebRequest.CreateHttp( + Config.ListeningOn + "json/reply/RequestFilter?StatusCode=401"); + + webRequest.GetResponse(); + + 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 = WebRequest.CreateHttp(Config.ListeningOn + + "json/reply/RequestFilter?StatusCode=401" + + "&HeaderName=" + HttpHeaders.WwwAuthenticate + + "&HeaderValue=" + "Basic realm=\"Auth Required\"".UrlEncode()); + + webRequest.GetResponse(); + + 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\"")); + } + } + + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs index 5fd114db507..45ee693d754 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs @@ -1,511 +1,671 @@ -using System; -using System.IO; -using System.Net; -using System.Runtime.Serialization; -using System.Text; -using System.Threading; -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.Text; -using ServiceStack.WebHost.Endpoints.Support; -using ServiceStack.WebHost.Endpoints.Tests.Support; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [DataContract] - [RestService("/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] - [RestService("/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(); - } - - 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(true, typeof(SecureService).Assembly); - 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; - } - } - -#endif - - } +using System; +using System.IO; +using System.Net; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters; +using System.Text; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Text; +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 + { + 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 new file mode 100644 index 00000000000..8bb65c5df9d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RestHandlerTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Threading.Tasks; +using NUnit.Framework; +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 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 = request.Response; + + var handler = new RestHandler + { + RestPath = new RestPath(typeof(RequestType), path) + }; + + await handler.ProcessRequestAsync(request, response, string.Empty); + Assert.That(response.StatusCode, Is.EqualTo(400)); + } + + [Test] + public async Task Throws_binding_exception_when_unable_to_bind_request() + { + var path = "/request/{id}/path"; + var request = ConfigureRequest(path); + var response = request.Response; + + var handler = new RestHandler + { + RestPath = new RestPath(typeof(RequestType), path) + }; + + await handler.ProcessRequestAsync(request, response, string.Empty); + Assert.That(response.StatusCode, Is.EqualTo(400)); + } + + private IHttpRequest ConfigureRequest(string path) + { + var request = new BasicHttpRequest { + PathInfo = path + }; + return request; + } + + public class RequestType + { + public int Id { get; set; } + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs new file mode 100644 index 00000000000..97bfb92a5b2 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs @@ -0,0 +1,199 @@ +using System.Linq; +using NUnit.Framework; +using ServiceStack.DataAnnotations; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; +using ServiceStack.WebHost.Endpoints.Tests.Support.Types; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + + [TestFixture] + public class RouteInferenceTests + { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void InferRoutes() + { + appHost = new BasicAppHost().Init(); + + RouteNamingConvention.PropertyNamesToMatch.Add("Key"); + RouteNamingConvention.AttributeNamesToMatch.Add(typeof(KeyAttribute).Name); + appHost.Routes.AddFromAssembly(typeof(RouteInferenceTests).Assembly); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Should_infer_route_from_RequestDTO_type() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestNoMembers) + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 1); + + Assert.That(restPath.AllowedVerbs.Contains("GET")); + Assert.That(restPath.AllowedVerbs.Contains("POST")); + Assert.That(restPath.AllowedVerbs.Contains("PUT")); + Assert.That(restPath.AllowedVerbs.Contains("DELETE")); + Assert.That(restPath.AllowedVerbs.Contains("PATCH")); + Assert.That(restPath.AllowedVerbs.Contains("HEAD")); + Assert.That(restPath.AllowedVerbs.Contains("OPTIONS")); + + Assert.IsTrue(typeof(RequestNoMembers).Name.EqualsIgnoreCase(restPath.Path.Remove(0,1))); + } + + [Test] + public void Should_infer_route_from_AnyPublicProperty_named_Id() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestWithMemberCalledId) + //routes without {placeholders} are tested above + && r.PathComponentsCount > 1 + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 2); + Assert.IsTrue(restPath.Path.EndsWithInvariant("{Id}")); + } + + [Test] + public void Should_infer_route_from_AnyPublicProperty_named_Ids() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestWithMemberCalledIds) + //routes without {placeholders} are tested above + && r.PathComponentsCount > 1 + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 2); + Assert.IsTrue(restPath.Path.EndsWithInvariant("{Ids}")); + } + + [Test] + public void Should_infer_route_from_AnyPublicProperty_in_MatchingNameStrategy() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestWithMemberCalledSpecialName) + //routes without {placeholders} are tested above + && r.PathComponentsCount > 1 + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 2); + Assert.IsTrue(restPath.Path.EndsWithInvariant("{Key}")); + } + + [Test] + public void Should_infer_route_from_AnyPublicProperty_with_PrimaryKeyAttribute() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestWithPrimaryKeyAttribute) + //routes without {placeholders} are tested above + && r.PathComponentsCount > 1 + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 2); + //it doesn't matter what the placeholder name is; only that 1 placeholer is in the path + Assert.IsTrue(restPath.Path.Count(c => c == '}') == 1); + } + + [Test] + public void Should_infer_route_from_AnyPublicProperty_in_MatchingAttributeStrategy() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestWithMemberWithKeyAttribute) + //routes without {placeholders} are tested above + && r.PathComponentsCount > 1 + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 2); + //it doesn't matter what the placeholder name is; only that 1 placeholer is in the path + Assert.IsTrue(restPath.Path.Count(c => c == '}') == 1); + } + + [Test] + public void Should_infer_route_from_AnyPubicProperty_FromAnyStrategy_AndCompositeTheRoute() + { + var restPath = (from r in appHost.RestPaths + where r.RequestType == typeof(RequestWithCompositeKeys) + //routes without {placeholders} are tested above + && r.PathComponentsCount > 1 + select r).FirstOrDefault(); + + Assert.That(restPath, Is.Not.Null); + + Assert.That(restPath.PathComponentsCount == 3); + //it doesn't matter what the placeholder name is; only that 1 placeholer is in the path + Assert.IsTrue(restPath.Path.Count(c => c == '}') == 2); + } + } + + public class RequestNoMembers { } + + public class RequestWithMemberCalledId + { + public object Id { get; set; } + } + + public class RequestWithMemberCalledIds + { + public object[] Ids { get; set; } + } + + public class RequestWithMemberCalledSpecialName + { + public string Key { get; set; } + } + + public class RequestWithPrimaryKeyAttribute + { + [PrimaryKey] + public int PrimaryKeyAttributeProperty { get; set; } + } + + public class RequestWithMemberWithKeyAttribute + { + [Key] + public string KeyAttributeProperty { get; set; } + } + + public class RequestWithCompositeKeys + { + public int Id { get; set; } + + public int Key { get; set; } + } + + public class RequestNoMembersService : TestRestService<RequestNoMembers> { } + + public class RequestWithMemberCalledIdService : TestRestService<RequestWithMemberCalledId> { } + + public class RequestWithMemberCalledIdsService : TestRestService<RequestWithMemberCalledIds> { } + + public class RequestWithMemberCalledSpecialNameService : TestRestService<RequestWithMemberCalledSpecialName> { } + + public class RequestWithPrimaryKeyAttributeService : TestRestService<RequestWithPrimaryKeyAttribute> { } + + public class RequestWithMemberWithKeyAttributeService : TestRestService<RequestWithMemberWithKeyAttribute> { } + + public class RequestWithCompositeKeysService : TestRestService<RequestWithCompositeKeys> { } +} 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 new file mode 100644 index 00000000000..3a4b6fd8990 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteTests.cs @@ -0,0 +1,658 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class RouteTests + { + private RouteAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new RouteAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_download_original_route() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo") + .GetStringFromUrl(responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.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] + public void Can_download_original_route_with_json_extension() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.json") + .GetStringFromUrl(responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.Json)); + }); + + 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] + public void Can_download_original_route_with_xml_extension() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.xml") + .GetStringFromUrl(responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.Xml)); + }); + + 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] + public void Can_download_original_route_with_html_extension() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.html") + .GetStringFromUrl(responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.Html)); + }); + + Assert.That(response, Does.StartWith("<!doctype html>")); + } + + [Test] + public void Can_download_original_route_with_csv_extension() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.csv") + .GetStringFromUrl(responseFilter: httpRes => + { + 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(nameof(BufferedRequestTests), typeof(CustomRouteService).Assembly) { } + + public override void Configure(Container container) + { + 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; + }); + } + } + + [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; } + } + + [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) => 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 new file mode 100644 index 00000000000..68115b07668 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SendOneWayTests.cs @@ -0,0 +1,120 @@ +using System; +using System.IO; +using System.Net; +using System.Runtime.Serialization; +using System.Text; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/onewayrequest", "DELETE")] + public class DeleteOneWayRequest : IReturnVoid + { + public string Prefix { get; set; } + } + + [Route("/onewayrequest", "POST")] + [Route("/onewayrequest", "PUT")] + [DataContract] + public class PostOneWayRequest : IReturnVoid + { + [DataMember] + public string Prefix { get; set; } + + [DataMember(Name = "some-title")] + public string Title { get; set; } + } + + public class OneWayService : Service + { + public static string LastResult { get; set; } + public void Delete(DeleteOneWayRequest oneWayRequest) + { + LastResult = oneWayRequest.Prefix + " " + Request.Verb; + } + + public void Post(PostOneWayRequest oneWayRequest) + { + LastResult = oneWayRequest.Prefix + " " + Request.Verb + oneWayRequest.Title; + } + + public void Put(PostOneWayRequest oneWayRequest) + { + Post(oneWayRequest); + } + } + + [TestFixture] + public class OneWayServiceTests + { + private const string ListeningOn = "http://localhost:8023/"; + private const string ServiceClientBaseUri = "http://localhost:8023/"; + + public class OneWayServiceAppHostHttpListener + : AppHostHttpListenerBase + { + + public OneWayServiceAppHostHttpListener() + : base("", typeof(OneWayService).Assembly) { } + + public override void Configure(Funq.Container container) + { + } + } + + OneWayServiceAppHostHttpListener appHost; + private IRestClient client; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new OneWayServiceAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + + client = new JsonServiceClient(ServiceClientBaseUri); + OneWayService.LastResult = null; + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + + [Test] + public void Delete() + { + client.Delete(new DeleteOneWayRequest() { Prefix = "Delete" }); + Assert.That(OneWayService.LastResult, Is.EqualTo("Delete DELETE")); + + } + + [Test] + public void Send() + { + client.Post(new PostOneWayRequest() { Prefix = "Post" }); + Assert.That(OneWayService.LastResult, Is.EqualTo("Post POST")); + } + + [Test] + public void Should_Respect_DataMember_Name() + { + GetResponse(ServiceClientBaseUri + "onewayrequest", "{\"some-title\": \"right\", \"Title\": \"wrong\"}"); + Assert.That(OneWayService.LastResult, Is.EqualTo(" PUTright")); + } + + public static string GetResponse(String url, string json) + { + var webRequest = WebRequest.CreateHttp(url); + webRequest.Method = "PUT"; + var formDataBytes = Encoding.UTF8.GetBytes(json); + webRequest.SetContentLength(formDataBytes.Length); + webRequest.ContentType = "application/json"; + PclExport.Instance.GetRequestStream(webRequest).Write(formDataBytes, 0, formDataBytes.Length); + var webResponse = webRequest.GetResponse(); + 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 new file mode 100644 index 00000000000..6c4fdb8dbfb --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientsBuiltInResponseTests.cs @@ -0,0 +1,314 @@ +using System; +using System.IO; +using System.Linq; +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("/poco/{Text}")] + public class Poco : IReturn<PocoResponse> + { + public string Text { get; set; } + } + + public class PocoResponse + { + public string Result { get; set; } + } + + + [Route("/headers/{Text}")] + public class Headers : IReturn<HttpWebResponse> + { + public string Text { get; set; } + } + + [Route("/strings/{Text}")] + public class Strings : IReturn<string> + { + public string Text { get; set; } + } + + [Route("/bytes/{Text}")] + 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> + { + public string Text { get; set; } + } + + [Route("/streamwriter/{Text}")] + public class StreamWriters : IReturn<Stream> + { + public string Text { get; set; } + } + + public class BuiltInTypesService : Service + { + public PocoResponse Any(Poco request) + { + return new PocoResponse { Result = "Hello, " + (request.Text ?? "World!") }; + } + + public void Any(Headers request) + { + base.Response.AddHeader("X-Response", request.Text); + } + + public string Any(Strings request) + { + return "Hello, " + (request.Text ?? "World!"); + } + + public byte[] Any(Bytes request) + { + return new Guid(request.Text).ToByteArray(); + } + + public byte[] Any(BytesAsStreams request) + { + return new Guid(request.Text).ToByteArray(); + } + + 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 : IStreamWriterAsync + { + private byte[] result; + + public StreamWriterResult(byte[] result) + { + this.result = result; + } + + public async Task WriteToAsync(Stream responseStream, CancellationToken token = new CancellationToken()) + { + await responseStream.WriteAsync(result, token); + } + } + + + public class BuiltInTypesAppHost : AppHostHttpListenerBase + { + public BuiltInTypesAppHost() : base(nameof(BuiltInTypesAppHost), typeof(BuiltInTypesService).Assembly) { } + + public string LastRequestBody { get; set; } + public bool UseBufferedStream { get; set; } + public bool EnableRequestBodyTracking { get; set; } + + public override void Configure(Container container) {} + } + + [TestFixture] + public class ServiceClientsBuiltInResponseTests + { + private BufferedRequestAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BufferedRequestAppHost { EnableRequestBodyTracking = true }; + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected static IRestClient[] RestClients = + { + new JsonServiceClient(Config.AbsoluteBaseUri), + new JsonHttpClient(Config.AbsoluteBaseUri), + new XmlServiceClient(Config.AbsoluteBaseUri), + new JsvServiceClient(Config.AbsoluteBaseUri), + }; + + protected static IServiceClient[] ServiceClients = + RestClients.OfType<IServiceClient>().ToArray(); + + [Test, TestCaseSource("RestClients")] + public void Can_download_Poco_response(IRestClient client) + { + PocoResponse response = client.Get(new Poco { Text = "Test" }); + + Assert.That(response.Result, Is.EqualTo("Hello, Test")); + } + + [Test, TestCaseSource("RestClients")] + public void Can_download_Poco_response_as_string(IRestClient client) + { + string response = client.Get<string>("/poco/Test"); + + Assert.That(response, Does.Contain("Hello, Test")); + } + + [Test, TestCaseSource("RestClients")] + public void Can_download_Poco_response_as_bytes(IRestClient client) + { + byte[] response = client.Get<byte[]>("/poco/Test"); + + Assert.That(response.FromUtf8Bytes(), Does.Contain("Hello, Test")); + } + + [Test, TestCaseSource("RestClients")] + public void Can_download_Poco_response_as_Stream(IRestClient client) + { + Stream response = client.Get<Stream>("/poco/Test"); + using (response) + { + 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()) + { + 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 async Task Can_download_Headers_response_Async(IServiceClient client) + { + if (client is JsonHttpClient) return; + + //Note: HttpWebResponse is returned before any response is read, so it's ideal point for streaming in app code + + using (var response = await client.GetAsync(new Headers { Text = "Test" })) + { + Assert.That(response.Headers["X-Response"], Is.EqualTo("Test")); + } + } + + [Test, TestCaseSource("RestClients")] + public void Can_download_Strings_response(IRestClient client) + { + string response = client.Get(new Strings { Text = "Test" }); + Assert.That(response, Is.EqualTo("Hello, Test")); + } + + [Test, TestCaseSource("RestClients")] + public async Task Can_download_Strings_response_Async(IServiceClient client) + { + var response = await client.GetAsync(new Strings { Text = "Test" }); + + Assert.That(response, Is.EqualTo("Hello, Test")); + } + + [Test, TestCaseSource("RestClients")] + public void Can_download_Bytes_response(IRestClient client) + { + var guid = Guid.NewGuid(); + byte[] response = client.Get(new Bytes { Text = guid.ToString() }); + Assert.That(new Guid(response), Is.EqualTo(guid)); + } + + [Test, TestCaseSource("RestClients")] + public async Task Can_download_Bytes_response_Async(IServiceClient client) + { + var guid = Guid.NewGuid(); + + 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) + { + var guid = Guid.NewGuid(); + Stream response = client.Get(new Streams { Text = guid.ToString() }); + using (response) + { + var bytes = response.ReadFully(); + Assert.That(new Guid(bytes), Is.EqualTo(guid)); + } + } + + [Test, TestCaseSource("RestClients")] + 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(); + + var stream = await client.GetAsync(new BytesAsStreams { Text = guid.ToString() }); + + bytes = stream.ReadFully(); + + Assert.That(new Guid(bytes), Is.EqualTo(guid)); + } + + [Test, TestCaseSource("RestClients")] + public void Can_download_StreamWroter_response(IRestClient client) + { + var guid = Guid.NewGuid(); + Stream response = client.Get(new StreamWriters { Text = guid.ToString() }); + using (response) + { + var bytes = response.ReadFully(); + Assert.That(new Guid(bytes), Is.EqualTo(guid)); + } + } + + } +} \ No newline at end of file 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/ServiceOperationsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceOperationsTests.cs deleted file mode 100644 index 3a539cfd82f..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceOperationsTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; -using ServiceStack.WebHost.Endpoints.Utils; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class ServiceOperationsTests - { - private static ServiceOperations CreateServiceOperations(Assembly assembly, string operationNamespace) - { - var operationTypes = new List<Type>(); - foreach (var type in assembly.GetTypes()) - { - if (type.Namespace == null) continue; - if (type.Namespace.StartsWith(operationNamespace)) - { - operationTypes.Add(type); - } - } - return new ServiceOperations(operationTypes); - } - - [Test] - public void ServiceOperations_only_provides_uniquely_named_types() - { - var operations = CreateServiceOperations(typeof(GetCustomers).Assembly, typeof(GetCustomers).Namespace); - var uniqueTypeNames = new List<string>(); - foreach (var type in operations.AllOperations.Types) - { - Assert.That(!uniqueTypeNames.Contains(type.Name)); - uniqueTypeNames.Add(type.Name); - } - } - - [Test] - public void Can_load_ServiceModel_schemas() - { - var operations = CreateServiceOperations(typeof(GetCustomers).Assembly, typeof(GetCustomers).Namespace); - var schemaSet = XsdUtils.GetXmlSchemaSet(operations.AllOperations.Types); - var schemas = schemaSet.Schemas(); - Assert.IsNotNull(schemas); - } - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs new file mode 100644 index 00000000000..fa3ba9f6d48 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs @@ -0,0 +1,62 @@ +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ServiceSetup : IReturn<ServiceSetup> + { + public int Id { get; set; } + } + + public class BaseService<T> : Service + { + public virtual object Get(T dto) + { + return null; + } + } + + public class Actual : BaseService<ServiceSetup> + { + public override object Get(ServiceSetup dto) + { + dto.Id++; + return dto; + } + } + + public class ServiceSetupAppHost : AppHostHttpListenerBase + { + public ServiceSetupAppHost() : base("Service Setup Tests", typeof(Actual).Assembly) { } + public override void Configure(Container container) { } + } + + [TestFixture] + public class ServiceSetupTests + { + private const string BaseUri = "http://localhost:8001/"; + JsonServiceClient client = new JsonServiceClient(BaseUri); + private ServiceSetupAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new ServiceSetupAppHost(); + appHost.Init(); + appHost.Start(BaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_still_load_with_Abstract_Generic_BaseTypes() + { + var response = client.Get(new ServiceSetup { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(2)); + } + } +} \ No newline at end of file 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 6b5d32022db..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,283 +1,102 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> - <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> - <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>ServiceStack.WebHost.Endpoints.Tests</RootNamespace> - <AssemblyName>ServiceStack.WebHost.Endpoints.Tests</AssemblyName> - <TargetFrameworkVersion>v3.5</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> - </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>AnyCPU</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="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.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" /> - <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="protobuf-net"> - <HintPath>..\..\lib\tests\protobuf-net.dll</HintPath> - </Reference> - <Reference Include="System.Configuration" /> - </ItemGroup> - <ItemGroup> - <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="CompressionTests.cs" /> - <Compile Include="IntegrationTests\ErrorRestTests.cs" /> - <Compile Include="ProtoBufServiceTests.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="ServiceOperationsTests.cs" /> - <Compile Include="Support\Operations\GetCustomer.cs" /> - <Compile Include="Support\Types\Customer.cs" /> - </ItemGroup> - <ItemGroup> - <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.ServiceModel.Tests\ServiceStack.ServiceModel.Tests.csproj"> - <Project>{A5646013-C243-453F-A2B6-3B6870A9637D}</Project> - <Name>ServiceStack.ServiceModel.Tests</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <Content Include="..\..\lib\tests\sqlite3.dll"> - <Link>sqlite3.dll</Link> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="webpage.forbidden"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="webpage.html"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="TestExistingDir\default.html" /> - <Content Include="TestExistingDir\upload.html" /> - </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="README.md" /> - </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.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 Sdk="Microsoft.NET.Sdk.Web"> + <PropertyGroup> + <TargetFramework>net472</TargetFramework> +<!-- <TargetFramework>net6.0</TargetFramework>--> +<!-- <TargetFrameworks>net472;net6.0</TargetFrameworks>--> + <OutputType>Library</OutputType> + <AssemblyName>ServiceStack.WebHost.Endpoints.Tests</AssemblyName> + <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=" '$(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="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 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> + <Content Update="App_Data\customers.json"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + </ItemGroup> + <ItemGroup> + <None Update="TestExistingDir\default.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Update="TestExistingDir\textfile.txt"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Update="TestExistingDir\upload.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Update="webpage.forbidden"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Update="webpage.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + </ItemGroup> </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 e8182a72c87..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"> - <PropertyGroup> - <PublishUrlHistory /> - <InstallUrlHistory /> - <SupportUrlHistory /> - <UpdateUrlHistory /> - <BootstrapperUrlHistory /> - <ErrorReportUrlHistory /> - <FallbackCulture>en-US</FallbackCulture> - <VerifyUploadedFiles>false</VerifyUploadedFiles> - <ProjectView>ProjectFiles</ProjectView> - </PropertyGroup> -</Project> +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <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 01faf5d0280..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.AsyncOneWay) 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.AsyncOneWay) 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 e093229d269..125f5726fb5 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHttpHandlerFactoryTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHttpHandlerFactoryTests.cs @@ -1,61 +1,101 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.WebHost.Endpoints.Metadata; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class ServiceStackHttpHandlerFactoryTests - { - readonly Dictionary<string, Type> pathInfoMap = new Dictionary<string, Type> - { - {"Metadata", typeof(IndexMetadataHandler)}, - {"Soap11", typeof(Soap11MessageSyncReplyHttpHandler)}, - {"Soap12", typeof(Soap12MessageSyncReplyHttpHandler)}, - - {"Json/SyncReply", typeof(JsonSyncReplyHandler)}, - {"Json/AsyncOneWay", typeof(JsonAsyncOneWayHandler)}, - {"Json/Metadata", typeof(JsonMetadataHandler)}, - - {"Xml/SyncReply", typeof(XmlSyncReplyHandler)}, - {"Xml/AsyncOneWay", typeof(XmlAsyncOneWayHandler)}, - {"Xml/Metadata", typeof(XmlMetadataHandler)}, - - {"Jsv/SyncReply", typeof(JsvSyncReplyHandler)}, - {"Jsv/AsyncOneWay", typeof(JsvAsyncOneWayHandler)}, - {"Jsv/Metadata", typeof(JsvMetadataHandler)}, - - {"Soap11/Wsdl", typeof(Soap11WsdlMetadataHandler)}, - {"Soap11/Metadata", typeof(Soap11MetadataHandler)}, - - {"Soap12/Wsdl", typeof(Soap12WsdlMetadataHandler)}, - {"Soap12/Metadata", typeof(Soap12MetadataHandler)}, - }; - - [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); - Assert.That(handler.GetType(), Is.EqualTo(expectedType)); - } - } - - [Test] - public void Resolves_the_right_handler_for_case_insensitive_expexted_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)); - } - } - - - } +using System; +using System.Collections.Generic; +using NUnit.Framework; +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)}, +#if !NETCORE + {"Soap11", typeof(Soap11MessageReplyHttpHandler)}, + {"Soap12", typeof(Soap12MessageReplyHttpHandler)}, +#endif + + {"Json/Reply", typeof(JsonReplyHandler)}, + {"Json/OneWay", typeof(JsonOneWayHandler)}, + {"Json/Metadata", typeof(JsonMetadataHandler)}, + + {"Xml/Reply", typeof(XmlReplyHandler)}, + {"Xml/OneWay", typeof(XmlOneWayHandler)}, + {"Xml/Metadata", typeof(XmlMetadataHandler)}, + + {"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 + }; + + [Test] + public void Resolves_the_right_handler_for_expexted_paths() + { + foreach (var item in pathInfoMap) + { + var expectedType = item.Value; + var httpReq = new BasicHttpRequest + { + PathInfo = item.Key, + }; + var handler = HttpHandlerFactory.GetHandlerForPathInfo(httpReq, null); + Assert.That(handler.GetType(), Is.EqualTo(expectedType)); + } + } + + [Test] + 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(); + 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 new file mode 100644 index 00000000000..ce0c488998c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SharedDtoTests.cs @@ -0,0 +1,88 @@ +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + /* + * Leave commented out - this pollutes and causes many failures in other tests + */ + + //[Ignore("This isn't supported at the moment.")] + //public class SharedDtoTests + //{ + // [Route("/shareddto")] + // public class RequestDto : IReturn<ResponseDto> { } + // public class ResponseDto + // { + // public string ServiceName { get; set; } + // } + + // public class Service1 : IService + // { + // public object Get(RequestDto req) + // { + // return new ResponseDto { ServiceName = GetType().Name }; + // } + // } + + // public class Service2 : IService + // { + // public object Post(RequestDto req) + // { + // return new ResponseDto { ServiceName = GetType().Name }; + // } + // } + + // private const string ListeningOn = "http://localhost:8080/"; + + // public class AppHost + // : AppHostHttpListenerBase + // { + + // public AppHost() + // : base("Shared dto tests", typeof(Service1).Assembly) { } + + // public override void Configure(Container container) + // { + // } + // } + + // AppHost appHost; + + // [OneTimeSetUp] + // public void OnTestFixtureSetUp() + // { + // appHost = new AppHost(); + // appHost.Init(); + // appHost.Start(ListeningOn); + // } + + // [OneTimeTearDown] + // public void OnTestFixtureTearDown() + // { + // appHost.Dispose(); + // EndpointHost.ExceptionHandler = null; + // } + + // protected static IRestClient[] RestClients = + // { + // new JsonServiceClient(ListeningOn), + // new XmlServiceClient(ListeningOn), + // new JsvServiceClient(ListeningOn) + // }; + + // [Test, TestCaseSource("RestClients")] + // public void Can_call_service1(IRestClient client) + // { + // var response = client.Get(new RequestDto()); + // Assert.That(response.ServiceName, Is.EqualTo(typeof(Service1).Name)); + // } + + // [Test, TestCaseSource("RestClients")] + // public void Can_call_service2(IRestClient client) + // { + // var response = client.Post(new RequestDto()); + // Assert.That(response.ServiceName, Is.EqualTo(typeof(Service2).Name)); + // } + //} +} 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 044609c24a3..2f07106bc1d 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/DirectServiceClient.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/DirectServiceClient.cs @@ -1,226 +1,514 @@ -using System; -using System.IO; -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; - -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 = HttpMethod.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 Get<TResponse>(string relativeOrAbsoluteUrl) - { - httpReq.HttpMethod = HttpMethod.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>(string relativeOrAbsoluteUrl) - { - throw new NotImplementedException(); - } - - public TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object request) - { - throw new NotImplementedException(); - } - - public TResponse Put<TResponse>(string relativeOrAbsoluteUrl, object 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 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>(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 PostAsync<TResponse>(string relativeOrAbsoluteUrl, object 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 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(); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using ServiceStack.Host; +using ServiceStack.Testing; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support +{ + 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 f9629590c08..686aec6644b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/EndpointHandlerBaseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/EndpointHandlerBaseTests.cs @@ -1,77 +1,88 @@ -using System; -using System.Collections; -using System.Linq; -using System.Net.NetworkInformation; -using Moq; -using NUnit.Framework; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.Endpoints.Support.Tests -{ - [TestFixture] - public class EndpointHandlerBaseTests - { - class TestHandler : EndpointHandlerBase - { - public override object CreateRequest(ServiceHost.IHttpRequest request, string operationName) - { - throw new NotImplementedException(); - } - - public override object GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, object request) - { - throw new NotImplementedException(); - } - } - - [Test, TestCaseSource(typeof(EndpointHandlerBaseTests), "EndpointExpectations")] - public void GetEndpointAttributes_AcceptsUserHostAddressFormats(string format, EndpointAttributes 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"); - - Assert.AreEqual(expected | EndpointAttributes.HttpGet | EndpointAttributes.InSecure, handler.GetEndpointAttributes(request.Object)); - } - - public static IEnumerable EndpointExpectations - { - get - { - var ipv6Addresses = NetworkInterface.GetAllNetworkInterfaces() - .Where(nic => nic.NetworkInterfaceType != NetworkInterfaceType.Loopback) - .SelectMany(nic => nic.GetIPProperties() - .UnicastAddresses.Select(unicast => unicast.Address)) - .Where(address => address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6).ToList(); - - //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("fe80::100:7f:fffe%10", EndpointAttributes.LocalSubnet); - yield return new TestCaseData("[fe80::100:7f:fffe%10]:57", EndpointAttributes.LocalSubnet); - - //ipv6 loopback - yield return new TestCaseData("::1", EndpointAttributes.Localhost); - yield return new TestCaseData("[::1]:83", EndpointAttributes.Localhost); - - //ipv4 - yield return new TestCaseData("192.168.100.2", EndpointAttributes.External); - yield return new TestCaseData("192.168.100.2:47", EndpointAttributes.External); - - //ipv4 loopback - yield return new TestCaseData("127.0.0.1", EndpointAttributes.Localhost); - yield return new TestCaseData("127.0.0.1:20", EndpointAttributes.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); - } - } - } +using System; +using System.Collections; +using System.Linq; +using System.Net.NetworkInformation; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; +using ServiceStack.Testing; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Support.Tests +{ + [TestFixture] + public class EndpointHandlerBaseTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + class TestHandler : ServiceStackHandlerBase + { + } + + [Test, TestCaseSource(typeof(EndpointHandlerBaseTests), "EndpointExpectations")] + public void GetEndpointAttributes_AcceptsUserHostAddressFormats(string format, RequestAttributes expected) + { + var handler = new TestHandler(); + var request = new BasicRequest { + UserHostAddress = format, + IsSecureConnection = false, + Verb = "GET" + }; + + Assert.AreEqual(expected | RequestAttributes.HttpGet | RequestAttributes.InSecure, request.GetAttributes()); + } + + public static IEnumerable EndpointExpectations + { + get + { + var ipv6Addresses = NetworkInterface.GetAllNetworkInterfaces() + .Where(nic => nic.NetworkInterfaceType != NetworkInterfaceType.Loopback) + .SelectMany(nic => nic.GetIPProperties() + .UnicastAddresses.Select(unicast => unicast.Address)) + .Where(address => address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6).ToList(); + + //this covers all the different flavors of ipv6 address -- scoped, link local, etc + foreach (var address in ipv6Addresses) + { + 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), RequestAttributes.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", RequestAttributes.Localhost); + yield return new TestCaseData("[::1]:83", RequestAttributes.Localhost); + + //ipv4 + 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", 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", RequestAttributes.External); + yield return new TestCaseData("192.168.100.2, 192.168.0.1, 10.1.1.1", RequestAttributes.External); + } + } + } } \ No newline at end of file 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 03f77c7b38a..2d2590ad5f1 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/ExampleAppHostHttpListener.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/ExampleAppHostHttpListener.cs @@ -1,304 +1,338 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Runtime.Serialization; -using System.Threading; -using Funq; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; -using ServiceStack.Configuration; -using ServiceStack.DataAnnotations; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Tests.IntegrationTests; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host -{ - - [RestService("/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<GetFactorial> - { - public object Execute(GetFactorial request) - { - return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; - } - - public static long GetFactorial(long n) - { - return n > 1 ? n * GetFactorial(n - 1) : 1; - } - } - - [DataContract] - public class AlwaysThrows { } - - [DataContract] - public class AlwaysThrowsResponse : IHasResponseStatus - { - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class AlwaysThrowsService - : ServiceBase<AlwaysThrows> - { - protected override object Run(AlwaysThrows request) - { - throw new ArgumentException("This service always throws an error"); - } - } - - - [RestService("/movies", "POST,PUT")] - [RestService("/movies/{Id}")] - [DataContract] - public class Movie - { - public Movie() - { - this.Genres = new List<string>(); - } - - [DataMember] - [AutoIncrement] - public int Id { get; set; } - - [DataMember] - public string ImdbId { get; set; } - - [DataMember] - public string Title { get; set; } - - [DataMember] - public decimal Rating { get; set; } - - [DataMember] - public string Director { get; set; } - - [DataMember] - public DateTime ReleaseDate { get; set; } - - [DataMember] - public string TagLine { get; set; } - - [DataMember] - public List<string> Genres { get; set; } - - #region AutoGen ReSharper code, only required by tests - public bool Equals(Movie other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Equals(other.ImdbId, ImdbId) - && 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 int GetHashCode() - { - return ImdbId != null ? ImdbId.GetHashCode() : 0; - } - #endregion - } - - [DataContract] - public class MovieResponse - { - [DataMember] - public Movie Movie { get; set; } - } - - - public class MovieService : RestServiceBase<Movie> - { - public IDbConnectionFactory DbFactory { get; set; } - - /// <summary> - /// GET /movies/{Id} - /// </summary> - public override object OnGet(Movie movie) - { - return new MovieResponse { - Movie = DbFactory.Run(db => db.GetById<Movie>(movie.Id)) - }; - } - - /// <summary> - /// POST /movies - /// </summary> - public override object OnPost(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 } - } - }; - } - - /// <summary> - /// PUT /movies - /// </summary> - public override object OnPut(Movie movie) - { - DbFactory.Run(db => db.Save(movie)); - return new MovieResponse(); - } - - /// <summary> - /// DELETE /movies/{Id} - /// </summary> - public override object OnDelete(Movie request) - { - DbFactory.Run(db => db.DeleteById<Movie>(request.Id)); - return new MovieResponse(); - } - } - - - [DataContract] - [RestService("/movies", "GET")] - [RestService("/movies/genres/{Genre}")] - public class Movies - { - [DataMember] - public string Genre { get; set; } - - [DataMember] - public Movie Movie { get; set; } - } - - [DataContract] - public class MoviesResponse - { - public MoviesResponse() - { - Movies = new List<Movie>(); - } - - [DataMember] - public List<Movie> Movies { get; set; } - } - - public class MoviesService : RestServiceBase<Movies> - { - public IDbConnectionFactory DbFactory { get; set; } - - /// <summary> - /// GET /movies - /// GET /movies/genres/{Genre} - /// </summary> - public override object OnGet(Movies request) - { - var response = new MoviesResponse { - Movies = request.Genre.IsNullOrEmpty() - ? DbFactory.Run(db => db.Select<Movie>()) - : DbFactory.Run(db => db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%")) - }; - - return response; - } - } - - public class MoviesZip - { - public string Genre { get; set; } - public Movie Movie { get; set; } - } - - public class MoviesZipResponse - { - public MoviesZipResponse() - { - Movies = new List<Movie>(); - } - - public List<Movie> Movies { get; set; } - } - - public class MoviesZipService : RestServiceBase<MoviesZip> - { - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnGet(MoviesZip request) - { - return OnPost(request); - } - - public override object OnPost(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); - } - } - - - [DataContract] - [RestService("/reset-movies")] - public class ResetMovies { } - - [DataContract] - public class ResetMoviesResponse - : IHasResponseStatus - { - public ResetMoviesResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class ResetMoviesService : RestServiceBase<ResetMovies> - { +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.Configuration; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.Logging; +using ServiceStack.OrmLite; +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 + { + [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; + } + } + + 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"); + } + } + + + [Route("/all-movies", "POST,PUT")] + [Route("/all-movies/{Id}")] + [DataContract] + public class Movie + { + public Movie() + { + this.Genres = new List<string>(); + } + + [DataMember(Order = 1)] + [AutoIncrement] + 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 decimal Rating { get; set; } + + [DataMember(Order = 5)] + public string Director { get; set; } + + [DataMember(Order = 6)] + public DateTime ReleaseDate { get; set; } + + [DataMember(Order = 7)] + public string TagLine { get; set; } + + [DataMember(Order = 8)] + public List<string> Genres { get; set; } + + #region AutoGen ReSharper code, only required by tests + public bool Equals(Movie other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.ImdbId, ImdbId) + && 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 int GetHashCode() + { + return ImdbId != null ? ImdbId.GetHashCode() : 0; + } + #endregion + } + + [DataContract] + public class MovieResponse + { + [DataMember] + public Movie Movie { get; set; } + } + + + public class MovieService : Service + { + public IDbConnectionFactory DbFactory { get; set; } + + /// <summary> + /// GET /movies/{Id} + /// </summary> + public object Get(Movie movie) + { + using (var db = DbFactory.Open()) + { + return new MovieResponse { + Movie = db.SingleById<Movie>(movie.Id) + }; + } + } + + /// <summary> + /// POST /movies + /// </summary> + public object Post(Movie movie) + { + 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> + /// PUT /movies + /// </summary> + public object Put(Movie movie) + { + using (var db = DbFactory.Open()) + { + db.Save(movie); + return new MovieResponse(); + } + } + + /// <summary> + /// DELETE /movies/{Id} + /// </summary> + public object Delete(Movie request) + { + using (var db = DbFactory.Open()) + { + db.DeleteById<Movie>(request.Id); + return new MovieResponse(); + } + } + } + + + [DataContract] + [Route("/all-movies", "GET")] + [Route("/all-movies/genres/{Genre}")] + public class Movies + { + [DataMember] + public string Genre { get; set; } + + [DataMember] + public Movie Movie { get; set; } + } + + [DataContract] + public class MoviesResponse + { + public MoviesResponse() + { + Movies = new List<Movie>(); + } + + [DataMember(Order = 1)] + public List<Movie> Movies { get; set; } + } + + public class MoviesService : Service + { + /// <summary> + /// GET /movies + /// GET /movies/genres/{Genre} + /// </summary> + public object Get(Movies request) + { + var response = new MoviesResponse { + Movies = request.Genre.IsNullOrEmpty() + ? Db.Select<Movie>() + : Db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%") + }; + + return response; + } + } + + public class MoviesZip + { + public string Genre { get; set; } + public Movie Movie { get; set; } + } + + public class MoviesZipResponse + { + public MoviesZipResponse() + { + Movies = new List<Movie>(); + } + + public List<Movie> Movies { get; set; } + } + + public class MoviesZipService : Service + { + public IDbConnectionFactory DbFactory { get; set; } + + public object Get(MoviesZip request) + { + return Post(request); + } + + public Task<object> Post(MoviesZip request) + { + 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); + } + } + } + + + [DataContract] + [Route("/reset-movies")] + public class ResetMovies { } + + [DataContract] + public class ResetMoviesResponse + : IHasResponseStatus + { + public ResetMoviesResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ResetMoviesService : Service + { public static List<Movie> Top5Movies = new List<Movie> { 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"}, }, @@ -306,244 +340,237 @@ public class ResetMoviesService : RestServiceBase<ResetMovies> new Movie { ImdbId = "tt1375666", Title = "Inception", Rating = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List<string>{"Action", "Mystery", "Sci-Fi", "Thriller"}, }, new Movie { ImdbId = "tt0071562", Title = "The Godfather: Part II", Rating = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List<string> {"Crime","Drama", "Thriller"}, }, new Movie { ImdbId = "tt0060196", Title = "The Good, the Bad and the Ugly", Rating = 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<string>{"Adventure","Western"}, }, - }; - - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnPost(ResetMovies request) - { - DbFactory.Run(db => { - const bool overwriteTable = true; - db.CreateTable<Movie>(overwriteTable); - db.SaveAll(Top5Movies); - }); - - return new ResetMoviesResponse(); - } - } - - [DataContract] - public class GetHttpResult { } - - [DataContract] - public class GetHttpResultResponse - { - [DataMember] - public string Result { get; set; } - } - - public class HttpResultService : IService<GetHttpResult> - { - public object Execute(GetHttpResult request) - { - var getHttpResultResponse = new GetHttpResultResponse { Result = "result" }; - return new HttpResult(getHttpResultResponse); - } - } - - - [RestService("inbox/{Id}/responses", "GET, PUT, OPTIONS")] - public class InboxPostResponseRequest - { - public int Id { get; set; } - public List<PageElementResponseDTO> Responses { get; set; } - } - - public class InboxPostResponseRequestResponse - { - public int Id { get; set; } - public List<PageElementResponseDTO> Responses { get; set; } - } - - public class PageElementResponseDTO - { - public int PageElementId { get; set; } - public string PageElementType { get; set; } - public string PageElementResponse { get; set; } - } - - public class InboxPostResponseRequestService : ServiceBase<InboxPostResponseRequest> - { - protected override object Run(InboxPostResponseRequest request) - { - if (request.Responses == null || request.Responses.Count == 0) - { - throw new ArgumentNullException("Responses"); - } - return new InboxPostResponseRequestResponse { - Id = request.Id, - Responses = request.Responses - }; - } - } - - [RestService("inbox/{Id}/responses", "GET, PUT, OPTIONS")] - public class InboxPost - { - public bool Throw { get; set; } - public int Id { get; set; } - } - - public class InboxPostService : ServiceBase<InboxPost> - { - protected override object Run(InboxPost request) - { - if (request.Throw) - throw new ArgumentNullException("Throw"); - - return null; - } - } - - [DataContract] - [RestService("/long_running")] - public class LongRunning { } - - public class LongRunningService : ServiceBase<LongRunning> - { - protected override object Run(LongRunning request) - { - Thread.Sleep(5000); - - return "LongRunning done."; - } - } - - public class ExampleAppHostHttpListener - : AppHostHttpListenerBase - { - //private static ILog log; - - public ExampleAppHostHttpListener() - : base("ServiceStack Examples", typeof(GetFactorialService).Assembly) - { - LogManager.LogFactory = new DebugLogFactory(); - //log = LogManager.GetLogger(typeof(ExampleAppHostHttpListener)); - } - - public Action<Container> ConfigureFilter { get; set; } - - public override void Configure(Container container) - { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); - - //Signal advanced web browsers what HTTP Methods you accept - base.SetConfig(new EndpointHostConfig { + }; + + public object Post(ResetMovies request) + { + const bool overwriteTable = true; + Db.CreateTable<Movie>(overwriteTable); + Db.SaveAll(Top5Movies); + + return new ResetMoviesResponse(); + } + } + + [DataContract] + public class GetHttpResult { } + + [DataContract] + public class GetHttpResultResponse + { + [DataMember] + public string Result { get; set; } + } + + public class HttpResultService : IService + { + public object Any(GetHttpResult request) + { + var getHttpResultResponse = new GetHttpResultResponse { Result = "result" }; + return new HttpResult(getHttpResultResponse); + } + } + + + [Route("/inbox/{Id}/responses", "GET, PUT, OPTIONS")] + public class InboxPostResponseRequest + { + public int Id { get; set; } + public List<PageElementResponseDTO> Responses { get; set; } + } + + public class InboxPostResponseRequestResponse + { + public int Id { get; set; } + public List<PageElementResponseDTO> Responses { get; set; } + } + + public class PageElementResponseDTO + { + public int PageElementId { get; set; } + public string PageElementType { get; set; } + public string PageElementResponse { get; set; } + } + + public class InboxPostResponseRequestService : Service + { + public object Any(InboxPostResponseRequest request) + { + if (request.Responses == null || request.Responses.Count == 0) + { + throw new ArgumentNullException("Responses"); + } + return new InboxPostResponseRequestResponse { + Id = request.Id, + Responses = request.Responses + }; + } + } + + [Route("/inbox/{Id}/responses", "GET, PUT, OPTIONS")] + public class InboxPost + { + public bool Throw { get; set; } + public int Id { get; set; } + } + + public class InboxPostService : Service + { + public object Any(InboxPost request) + { + if (request.Throw) + throw new ArgumentNullException("Throw"); + + return null; + } + } + + [DataContract] + [Route("/long_running")] + public class LongRunning { } + + public class LongRunningService : Service + { + public object Any(LongRunning request) + { + Thread.Sleep(5000); + + return "LongRunning done."; + } + } + + public class ExampleAppHostHttpListener + : AppHostHttpListenerBase + { + //private static ILog log; + + public ExampleAppHostHttpListener() + : base("ServiceStack Examples", typeof(GetFactorialService).Assembly) + { + LogManager.LogFactory = new DebugLogFactory(); + //log = LogManager.GetLogger(typeof(ExampleAppHostHttpListener)); + } + + public Action<Container> ConfigureFilter { get; set; } + + public override void Configure(Container container) + { + //Signal advanced web browsers what HTTP Methods you accept + 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, - }); - - this.RegisterRequestBinder<CustomRequestBinder>( - httpReq => new CustomRequestBinder { IsFromBinder = true }); - - Routes - .Add<Movies>("/custom-movies", "GET") - .Add<Movies>("/custom-movies/genres/{Genre}") - .Add<Movie>("/custom-movies", "POST,PUT") - .Add<Movie>("/custom-movies/{Id}") - .Add<GetFactorial>("/fact/{ForNumber}") - .Add<MoviesZip>("/movies.zip") - .Add<GetHttpResult>("/gethttpresult") - ; - - container.Register<IResourceManager>(new ConfigurationResourceManager()); - - //var appSettings = container.Resolve<IResourceManager>(); - - container.Register(c => new ExampleConfig(c.Resolve<IResourceManager>())); - //var appConfig = container.Resolve<ExampleConfig>(); - - container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - ":memory:", false, - SqliteOrmLiteDialectProvider.Instance)); - - var resetMovies = container.Resolve<ResetMoviesService>(); - resetMovies.Post(null); - - //var movies = container.Resolve<IDbConnectionFactory>().Exec(x => x.Select<Movie>()); - //Console.WriteLine(movies.Dump()); - - if (ConfigureFilter != null) - { - ConfigureFilter(container); - } - } - } - - public class ExampleAppHostHttpListenerLongRunning - : AppHostHttpListenerLongRunningBase - { - //private static ILog log; - - public ExampleAppHostHttpListenerLongRunning() - : base("ServiceStack Examples", 500, typeof(GetFactorialService).Assembly) - { - LogManager.LogFactory = new DebugLogFactory(); - //log = LogManager.GetLogger(typeof(ExampleAppHostHttpListener)); - } - - public Action<Container> ConfigureFilter { get; set; } - - public override void Configure(Container container) - { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); - - //Signal advanced web browsers what HTTP Methods you accept - base.SetConfig(new EndpointHostConfig - { + }, + WsdlServiceNamespace = "http://www.servicestack.net/types", + DebugMode = true, + PreferredContentTypes = { MimeTypes.ProtoBuf }, + }); + + this.RegisterRequestBinder<CustomRequestBinder>( + httpReq => new CustomRequestBinder { IsFromBinder = true }); + + Routes + .Add<Movies>("/custom-movies", "GET") + .Add<Movies>("/custom-movies/genres/{Genre}") + .Add<Movie>("/custom-movies", "POST,PUT") + .Add<Movie>("/custom-movies/{Id}") + .Add<GetFactorial>("/fact/{ForNumber}") + .Add<MoviesZip>("/all-movies.zip") + .Add<GetHttpResult>("/gethttpresult") + ; + + container.Register<IAppSettings>(new AppSettings()); + + //var appSettings = container.Resolve<IResourceManager>(); + + container.Register(c => new ExampleConfig(c.Resolve<IAppSettings>())); + //var appConfig = container.Resolve<ExampleConfig>(); + + container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + var resetMovies = container.Resolve<ResetMoviesService>(); + resetMovies.Post(null); + + //var movies = container.Resolve<IDbConnectionFactory>().Exec(x => x.Select<Movie>()); + //Console.WriteLine(movies.Dump()); + + if (ConfigureFilter != null) + { + ConfigureFilter(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 ExampleAppHostHttpListenerPool : AppHostHttpListenerPoolBase + { + //private static ILog log; + + public ExampleAppHostHttpListenerPool() + : base("ServiceStack Examples", 500, typeof(GetFactorialService).Assembly) + { + LogManager.LogFactory = new DebugLogFactory(); + //log = LogManager.GetLogger(typeof(ExampleAppHostHttpListener)); + } + + public Action<Container> ConfigureFilter { get; set; } + + public override void Configure(Container container) + { + //Signal advanced web browsers what HTTP Methods you accept + 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, - }); - - this.RegisterRequestBinder<CustomRequestBinder>( - httpReq => new CustomRequestBinder { IsFromBinder = true }); - - Routes - .Add<Movies>("/custom-movies", "GET") - .Add<Movies>("/custom-movies/genres/{Genre}") - .Add<Movie>("/custom-movies", "POST,PUT") - .Add<Movie>("/custom-movies/{Id}") - .Add<GetFactorial>("/fact/{ForNumber}") - .Add<MoviesZip>("/movies.zip") - .Add<GetHttpResult>("/gethttpresult") - ; - - container.Register<IResourceManager>(new ConfigurationResourceManager()); - - //var appSettings = container.Resolve<IResourceManager>(); - - container.Register(c => new ExampleConfig(c.Resolve<IResourceManager>())); - //var appConfig = container.Resolve<ExampleConfig>(); - - container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - ":memory:", false, - SqliteOrmLiteDialectProvider.Instance)); - - var resetMovies = container.Resolve<ResetMoviesService>(); - resetMovies.Post(null); - - //var movies = container.Resolve<IDbConnectionFactory>().Exec(x => x.Select<Movie>()); - //Console.WriteLine(movies.Dump()); - - if (ConfigureFilter != null) - { - ConfigureFilter(container); - } - } - } - + }, + WsdlServiceNamespace = "http://www.servicestack.net/types", + DebugMode = true, + }); + + this.RegisterRequestBinder<CustomRequestBinder>( + httpReq => new CustomRequestBinder { IsFromBinder = true }); + + Routes + .Add<Movies>("/custom-movies", "GET") + .Add<Movies>("/custom-movies/genres/{Genre}") + .Add<Movie>("/custom-movies", "POST,PUT") + .Add<Movie>("/custom-movies/{Id}") + .Add<GetFactorial>("/fact/{ForNumber}") + .Add<MoviesZip>("/all-movies.zip") + .Add<GetHttpResult>("/gethttpresult") + ; + + 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)); + + var resetMovies = container.Resolve<ResetMoviesService>(); + resetMovies.Post(null); + + //var movies = container.Resolve<IDbConnectionFactory>().Exec(x => x.Select<Movie>()); + //Console.WriteLine(movies.Dump()); + + if (ConfigureFilter != null) + { + ConfigureFilter(container); + } + + Plugins.Add(new RequestInfoFeature()); + } + } + } \ No newline at end of file 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 ae32dc6ae9f..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/IocAppHost.cs +++ /dev/null @@ -1,96 +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); - - 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 3edd67084ba..983355e3186 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestAppHost.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestAppHost.cs @@ -1,24 +1,26 @@ -using Funq; -using ServiceStack.WebHost.Endpoints.Tests.Support.Services; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host -{ - - public interface IFoo { } - public class Foo : IFoo { } - - public class TestAppHost - : AppHostBase - { - public TestAppHost() - : base("Example Service", typeof(Nested).Assembly) - { - Instance = null; - } - - public override void Configure(Container container) - { - container.Register<IFoo>(c => new Foo()); - } - } +using System.Reflection; +using Funq; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host +{ + + public interface IFoo { } + public class Foo : IFoo { } + + public class TestAppHost + : AppHostBase + { + public TestAppHost(params Assembly[] assembliesWithServices) + : base("Example Service", + assembliesWithServices.Length > 0 ? assembliesWithServices : new[] { typeof(Nested).Assembly }) + { + Instance = null; + } + + public override void Configure(Container container) + { + container.Register<IFoo>(c => new Foo()); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs index d79c7940db6..8eb83efdaeb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs @@ -1,58 +1,55 @@ -using System; -using System.Runtime.Serialization; -using Funq; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host -{ - [DataContract] - [RestService("/login/{UserName}/{Password}")] - public class BclDto - { - [DataMember(Name = "uname")] - public string UserName { get; set; } - - [DataMember(Name = "pwd")] - public string Password { get; set; } - } - - [DataContract] - public class BclDtoResponse - { - [DataMember(Name = "uname")] - public string UserName { get; set; } - - [DataMember(Name = "pwd")] - public string Password { get; set; } - } - - public class BclDtoService : ServiceBase<BclDto> - { - protected override object Run(BclDto request) - { - return new BclDtoResponse - { - UserName = request.UserName, - Password = request.Password - }; - } - } - - public class TestConfigAppHostHttpListener - : AppHostHttpListenerBase - { - public TestConfigAppHostHttpListener() - : base("TestConfigAppHost Service", typeof(BclDto).Assembly) - { - } - - public override void Configure(Container container) - { - SetConfig(new EndpointHostConfig - { - UseBclJsonSerializers = true, - }); - } - } +using System.Runtime.Serialization; +using Funq; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host +{ + [DataContract] + [Route("/login/{UserName}/{Password}")] + public class BclDto + { + [DataMember(Name = "uname")] + public string UserName { get; set; } + + [DataMember(Name = "pwd")] + public string Password { get; set; } + } + + [DataContract] + public class BclDtoResponse + { + [DataMember(Name = "uname")] + public string UserName { get; set; } + + [DataMember(Name = "pwd")] + public string Password { get; set; } + } + + public class BclDtoService : Service + { + public object Any(BclDto request) + { + return new BclDtoResponse + { + UserName = request.UserName, + Password = request.Password + }; + } + } + + public class TestConfigAppHostHttpListener + : AppHostHttpListenerBase + { + public TestConfigAppHostHttpListener() + : base("TestConfigAppHost Service", typeof(BclDto).Assembly) + { + } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + UseBclJsonSerializers = true, + }); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs index e027a73b0a5..672b2075658 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs @@ -1,27 +1,28 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations -{ - [RestService("/customformdata")] - [DataContract] - public class CustomFormData {} - - [DataContract] - public class CustomFormDataResponse : IHasResponseStatus - { - [DataMember] - public string FirstName { get; set; } - - [DataMember] - public string Item0 { get; set; } - - [DataMember] - public string Item1Delete { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } -} +using System; +using System.Runtime.Serialization; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations +{ + [Route("/customformdata")] + [DataContract] + public class CustomFormData {} + + [DataContract] + public class CustomFormDataResponse : IHasResponseStatus + { + [DataMember] + public string FirstName { get; set; } + + [DataMember] + public string Item0 { get; set; } + + [DataMember] + public string Item1Delete { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs index 94a22b432d2..08083217010 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs @@ -1,27 +1,23 @@ -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations -{ - [RestService("/customrequestbinder")] - public class CustomRequestBinder - { - public bool IsFromBinder { get; set; } - } - - public class CustomRequestBinderResponse - { - public bool FromBinder { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - public class CustomRequestBinderService : ServiceBase<CustomRequestBinder> - { - protected override object Run(CustomRequestBinder request) - { - return new CustomRequestBinderResponse { FromBinder = request.IsFromBinder }; - } - } +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations +{ + [Route("/customrequestbinder")] + public class CustomRequestBinder + { + public bool IsFromBinder { get; set; } + } + + public class CustomRequestBinderResponse + { + public bool FromBinder { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomRequestBinderService : Service + { + public object Any(CustomRequestBinder request) + { + return new CustomRequestBinderResponse { FromBinder = request.IsFromBinder }; + } + } } \ No newline at end of file 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/RequestOfAllTypes.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfAllTypes.cs index ea63d6dba0e..9fc1a3b5675 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfAllTypes.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfAllTypes.cs @@ -87,11 +87,11 @@ public override bool Equals(object obj) && this.TimeSpan == other.TimeSpan && this.UInt == other.UInt && this.ULong == other.ULong; - } - - public override int GetHashCode() - { - return base.GetHashCode(); + } + + public override int GetHashCode() + { + return base.GetHashCode(); } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfComplexTypes.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfComplexTypes.cs index a91fbb373c9..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 { @@ -57,11 +57,11 @@ public override bool Equals(object obj) && this.StringList.EquivalentTo(other.StringList) && this.StringIntMap.EquivalentTo(other.StringIntMap) && this.RequestOfAllTypes.Equals(other.RequestOfAllTypes); - } - - public override int GetHashCode() - { - return base.GetHashCode(); + } + + public override int GetHashCode() + { + return base.GetHashCode(); } } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs index 578a9b1e8b2..b8a36ca9192 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs @@ -1,53 +1,51 @@ -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/"; - - private AppHostHttpListenerBase appHost; - - public abstract AppHostHttpListenerBase CreateListener(); - - [TestFixtureSetUp] - public virtual void TestFixtureSetUp() - { - appHost = CreateListener(); - appHost.Init(); - appHost.Start(BaseUrl); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - Dispose(); - } - - public void Dispose() - { - if (appHost == null) return; - appHost.Dispose(); - appHost = null; - } - - public void Send<TRes>(object request, Action<TRes> validate) - { - using (var xmlClient = new XmlServiceClient(BaseUrl)) - using (var jsonClient = new JsonServiceClient(BaseUrl)) - using (var jsvClient = new JsvServiceClient(BaseUrl)) - { - var xmlResponse = xmlClient.Send<TRes>(request); - validate(xmlResponse); - - var jsonResponse = jsonClient.Send<TRes>(request); - validate(jsonResponse); - - var jsvResponse = jsvClient.Send<TRes>(request); - validate(jsvResponse); - } - } - } +using System; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support +{ + public abstract class ServiceClientTestBase : IDisposable + { + protected const string BaseUrl = "http://127.0.0.1:8083/"; + + private AppHostHttpListenerBase appHost; + + public abstract AppHostHttpListenerBase CreateListener(); + + [OneTimeSetUp] + public virtual void TestFixtureSetUp() + { + appHost = CreateListener(); + appHost.Init(); + appHost.Start(BaseUrl); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + Dispose(); + } + + public void Dispose() + { + if (appHost == null) return; + appHost.Dispose(); + } + + public void Send<TRes>(object request, Action<TRes> validate) + { + using (var xmlClient = new XmlServiceClient(BaseUrl)) + using (var jsonClient = new JsonServiceClient(BaseUrl)) + using (var jsvClient = new JsvServiceClient(BaseUrl)) + { + var xmlResponse = xmlClient.Send<TRes>(request); + validate(xmlResponse); + + var jsonResponse = jsonClient.Send<TRes>(request); + validate(jsonResponse); + + var jsvResponse = jsvClient.Send<TRes>(request); + validate(jsvResponse); + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs index df74ba048ba..dff8763b6ee 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs @@ -1,24 +1,18 @@ -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - public class CustomFormDataService - : RestServiceBase<CustomFormData> // which inherits from IRequiresRequestContext - { - //Parsing: &first-name=tom&item-0=blah&item-1-delete=1 - public override object OnPost(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"] - }; - } - } - +using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + 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 new file mode 100644 index 00000000000..cab8a5d6e01 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EndpointAccessService.cs @@ -0,0 +1,76 @@ +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + public class GetsOnly { } + public class PostsOnly { } + public class PutsOnly { } + public class DeletesOnly { } + public class AnyRequest { } + public class Response { } + + [Restrict(VisibleLocalhostOnly = true)] + public class VisibleLocalhost { } + [Restrict(VisibleInternalOnly = true)] + public class VisibleInternal { } + + [Restrict(LocalhostOnly = true)] + public class LocalhostOnly { } + [Restrict(InternalOnly = true)] + public class InternalOnly { } + + public class ReturnsHttpResult { } + + public class EndpointAccessService : Service + { + public Response Get(GetsOnly request) + { + return new Response(); + } + + public Response Post(PostsOnly request) + { + return new Response(); + } + + public Response Put(PutsOnly request) + { + return new Response(); + } + + public Response Delete(DeletesOnly request) + { + return new Response(); + } + + public Response Any(AnyRequest request) + { + return new Response(); + } + + public Response Any(VisibleLocalhost request) + { + return new Response(); + } + + public Response Any(VisibleInternal request) + { + return new Response(); + } + + public Response Any(LocalhostOnly request) + { + return new Response(); + } + + public Response Any(InternalOnly request) + { + return new Response(); + } + + public HttpResult Any(ReturnsHttpResult request) + { + return new HttpResult(); + } + } + + +} \ No newline at end of file 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 e3e6f885970..e6d366e2cd6 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FileUploadService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FileUploadService.cs @@ -1,89 +1,138 @@ -using System; -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; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - [DataContract] - [RestService("/fileuploads/{RelativePath*}")] - [RestService("/fileuploads", HttpMethods.Post)] - public class FileUpload - { - [DataMember] - public string RelativePath { get; set; } - - [DataMember] - public string CustomerName { get; set; } - - [DataMember] - public int CustomerId { get; set; } - } - - [DataContract] - public class FileUploadResponse : IHasResponseStatus - { - [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; } - } - - public class FileUploadService - : RestServiceBase<FileUpload> - { - public override object OnGet(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 override object OnPost(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(), - CustomerId = request.CustomerId, - CustomerName = request.CustomerName - }; - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + [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; } + } + + [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, + 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 9f8ca9f4070..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; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - [DataContract] - public class Headers - { - [DataMember] - public string Name { 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; } - - 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 - }; - } - } - +using System; +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + [DataContract] + public class Headers + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class HeadersResponse + { + [DataMember] + public string Value { get; set; } + } + + public class HeadersService + : TestServiceBase<Headers>, IRequiresRequest + { + public IRequest Request { get; set; } + + 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 69ace9d7ddd..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] - [RestService("/hello")] //Optional: Define an alternate REST-ful url for this service - [RestService("/hello/{Name}")] - public class Hello - { - [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 }; - } - } - +using System.Runtime.Serialization; + +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 : 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 + { + 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 79b13eb38e3..0383f20a6f6 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpErrorService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpErrorService.cs @@ -1,66 +1,179 @@ -using System; -using System.IO; -using System.Net; -using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - [DataContract] - [RestService("/errors")] - [RestService("/errors/{Type}")] - [RestService("/errors/{Type}/{StatusCode}")] - [RestService("/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 - : ServiceBase<HttpError> - { - protected override object Run(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); - } - } - +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Runtime.Serialization; +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 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 f859d19f8f5..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 { - [Service(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 b2bd16e650a..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 { - [Service(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 96e2dcd2d34..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 { - [Service(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 99c2e4958e6..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 { - [Service(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 777d709dff9..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 { - [Service(RestrictAccessTo = 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 b58804b743f..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/IocService.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Generic; -using ServiceStack.ServiceHost; -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 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 void Dispose() { } } - public class AltDepDisposableProperty : IDisposable { public void Dispose() { } } - - 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; } - } - - public class IocService : IService<Ioc>, 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 Execute(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 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<IocScope>, 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 Execute(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++; - } - } - -} \ 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 d374dffd2f8..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 -{ - [Service(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 3b95396cfb4..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 -{ - [Service(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 ade529167fb..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; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - [DataContract] - public class RequestFilter - { - [DataMember] - public int StatusCode { get; set; } - - [DataMember] - public string HeaderName { get; set; } - - [DataMember] - public string HeaderValue { 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(); - } - } - +using System; +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + [DataContract] + public class RequestFilter + { + [DataMember] + public int StatusCode { get; set; } + + [DataMember] + public string HeaderName { get; set; } + + [DataMember] + public string HeaderValue { get; set; } + } + + [DataContract] + public class RequestFilterResponse + { + [DataMember] + public string Value { get; set; } + } + + 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 c168f6f564c..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 { } - [Service(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 6cc5b7b9c8a..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 { - [Service(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 cd52c25bc73..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 { - [Service(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 new file mode 100644 index 00000000000..e711449105f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestRestService.cs @@ -0,0 +1,55 @@ +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + 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 61c38363e68..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/TestBase.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support -{ - public abstract class MetadataTestBase - { - protected List<Type> ReplyOperations { get; set; } - protected List<Type> OneWayOperations { get; set; } - protected List<Type> AllOperations { get; set; } - - protected MetadataTestBase() - { - this.ReplyOperations = new[] { typeof(GetCustomer), typeof(GetCustomers) }.ToList(); - this.OneWayOperations = new[] { typeof(StoreCustomer) }.ToList(); - this.AllOperations = new[] { typeof(GetCustomerResponse), typeof(GetCustomersResponse) }.ToList(); - this.AllOperations.AddRange(ReplyOperations); - this.AllOperations.AddRange(OneWayOperations); - } - } -} \ 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 new file mode 100644 index 00000000000..947722e913c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Types/KeyAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Types +{ + /// <summary> + /// An example of a custom / domain attribute that could be applied to properties of a POCO / Request DTO. + /// If this type is added to the <typeparamref name="RouteInferenceStrategies"/><code>.AttributesToMatch</code> collection, + /// calling <typeparamref name="IServiceRoutes"/><code>.AddFromAssembly()</code> will allow + /// <typeparamref name="RouteInferenceStrategies.FromAttributes"/> to infer a custom route if its included in the + /// <typeparamref name="RouteInferenceStrategies"/> available at runtime. + /// </summary> + [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] + sealed class KeyAttribute : AttributeBase + { + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs index 10bb05871ed..3b34018491f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs @@ -1,266 +1,300 @@ -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.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - /// <summary> - /// These tests fail with Unauthorized exception when left last to run, - /// so prefixing with '_' to hoist its priority till we find out wtf is up - /// </summary> - public abstract class SyncRestClientTests : IDisposable - { - protected const string ListeningOn = "http://localhost:85/"; - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - LogManager.LogFactory = new ConsoleLogFactory(); - - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - Dispose(); - } - - public void Dispose() - { - if (appHost == null) return; - appHost.Dispose(); - appHost = null; - } - - protected abstract IRestClient CreateRestClient(); - //protected virtual IRestClient CreateRestClient() - //{ - // return new XmlServiceClient(ListeningOn); - //} - - static object[] GetFactorialRoutes = { "factorial/3", "fact/3" }; - - [TestCase("factorial/3")] - [TestCase("fact/3")] - public void Can_GET_GetFactorial_using_RestClient(string path) - { - var restClient = CreateRestClient(); - - var response = restClient.Get<GetFactorialResponse>(path); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(3))); - } - - [TestCase("movies")] - [TestCase("custom-movies")] - public void Can_GET_Movies_using_RestClient(string path) - { - var restClient = CreateRestClient(); - - var response = restClient.Get<MoviesResponse>(path); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Movies.EquivalentTo(ResetMoviesService.Top5Movies)); - } - - [TestCase("movies/1")] - [TestCase("custom-movies/1")] - public void Can_GET_single_Movie_using_RestClient(string path) - { - var restClient = CreateRestClient(); - - var response = restClient.Get<MovieResponse>(path); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Movie.Id, Is.EqualTo(1)); - } - - [TestCase("movies")] - [TestCase("custom-movies")] - public void Can_POST_to_add_new_Movie_using_RestClient(string path) - { - var restClient = CreateRestClient(); - - 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 = restClient.Post<MovieResponse>(path, 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 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); - Console.WriteLine("XML: " + toXml); - } - catch (Exception ex) - { - Console.WriteLine(ex); - throw; - } - } - - [TestCase("movies", "movies/")] - [TestCase("custom-movies", "custom-movies/")] - public void Can_DELETE_Movie_using_RestClient(string postPath, string deletePath) - { - var restClient = CreateRestClient(); - - 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 = restClient.Post<MovieResponse>(postPath, newMovie); - var createdMovie = response.Movie; - response = restClient.Delete<MovieResponse>(deletePath + createdMovie.Id); - - Assert.That(createdMovie, Is.Not.Null); - Assert.That(response.Movie, Is.Null); - } - - [Test] - public void Can_PUT_complex_type_with_custom_path() - { - var client = CreateRestClient(); - - var request = new InboxPostResponseRequest { - Id = 123, - Responses = new List<PageElementResponseDTO> { - new PageElementResponseDTO { - PageElementId = 123, - PageElementResponse = "something", - PageElementType = "Question" - } - } - }; - - var response = client.Put<InboxPostResponseRequestResponse>( - "inbox/123/responses", - request); - - Assert.That(response.Id, Is.EqualTo(request.Id)); - Assert.That(response.Responses[0].PageElementId, - Is.EqualTo(request.Responses[0].PageElementId)); - } - - [Test] - public void Does_throw_400_for_Argument_exceptions() - { - var client = CreateRestClient(); - - try - { - var response = client.Put<InboxPostResponseRequestResponse>( - "inbox/123/responses", - new InboxPostResponseRequest()); - - response.PrintDump(); - - Assert.Fail("Should throw"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo(400)); - } - } - - [Test] - public void Does_throw_400_for_Argument_exceptions_without_response_DTOs() - { - var client = CreateRestClient(); - - try - { - var response = client.Put<InboxPost>( - "inbox/123/responses", - new InboxPost { Throw = true }); - - response.PrintDump(); - - Assert.Fail("Should throw"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo(400)); - } - } - } - - [TestFixture] - public class JsonSyncRestClientTests : SyncRestClientTests - { - protected override IRestClient CreateRestClient() - { - return new JsonServiceClient(ListeningOn); - } - - [Test] - public void Can_use_response_filters() - { - var isActioncalledGlobal = false; - var isActioncalledLocal = false; - ServiceClientBase.HttpWebResponseFilter = r => isActioncalledGlobal = true; - var restClient = (JsonServiceClient)CreateRestClient(); - restClient.LocalHttpWebResponseFilter = r => isActioncalledLocal = true; - restClient.Get<MoviesResponse>("movies"); - Assert.That(isActioncalledGlobal, Is.True); - Assert.That(isActioncalledLocal, Is.True); - } - } - - [TestFixture] - public class JsvSyncRestClientTests : SyncRestClientTests - { - protected override IRestClient CreateRestClient() - { - return new JsvServiceClient(ListeningOn); - } - } - - [TestFixture] - public class XmlSyncRestClientTests : SyncRestClientTests - { - protected override IRestClient CreateRestClient() - { - return new XmlServiceClient(ListeningOn); - } - } -} +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Serialization; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + /// <summary> + /// These tests fail with Unauthorized exception when left last to run, + /// so prefixing with '_' to hoist its priority till we find out wtf is up + /// </summary> + public abstract class SyncRestClientTests : IDisposable + { + protected string ListeningOn = "http://localhost:"; + + ExampleAppHostHttpListener appHost; + + protected SyncRestClientTests(int port) + { + ListeningOn += port + "/"; + } + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + Dispose(); + } + + public void Dispose() + { + appHost.Dispose(); + } + + protected abstract IRestClient CreateRestClient(); + //protected virtual IRestClient CreateRestClient() + //{ + // return new XmlServiceClient(ListeningOn); + //} + + static object[] GetFactorialRoutes = { "factorial/3", "fact/3" }; + + [TestCase("factorial/3")] + [TestCase("fact/3")] + public void Can_GET_GetFactorial_using_RestClient(string path) + { + var restClient = CreateRestClient(); + + var response = restClient.Get<GetFactorialResponse>(path); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(3))); + } + + [TestCase("all-movies")] + [TestCase("custom-movies")] + public void Can_GET_Movies_using_RestClient(string path) + { + var restClient = CreateRestClient(); + + var response = restClient.Get<MoviesResponse>(path); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Movies.EquivalentTo(ResetMoviesService.Top5Movies)); + } + + [TestCase("all-movies/1")] + [TestCase("custom-movies/1")] + public void Can_GET_single_Movie_using_RestClient(string path) + { + var restClient = CreateRestClient(); + + var response = restClient.Get<MovieResponse>(path); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Movie.Id, Is.EqualTo(1)); + } + + [TestCase("all-movies")] + [TestCase("custom-movies")] + public void Can_POST_to_add_new_Movie_using_RestClient(string path) + { + var restClient = CreateRestClient(); + + 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<string> { "Adventure", "Drama", "Thriller" }, + }; + + var response = restClient.Post<MovieResponse>(path, 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 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 = DataContractSerializer.Instance.DeserializeFromString<MovieResponse>(xml); + var toXml = DataContractSerializer.Instance.SerializeToString(response); + Console.WriteLine("XML: " + toXml); + } + catch (Exception ex) + { + Console.WriteLine(ex); + throw; + } + } + + [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 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<string> { "Adventure", "Drama", "Thriller" }, + }; + + var response = restClient.Post<MovieResponse>(postPath, newMovie); + var createdMovie = response.Movie; + response = restClient.Delete<MovieResponse>(deletePath + createdMovie.Id); + + Assert.That(createdMovie, Is.Not.Null); + Assert.That(response.Movie, Is.Null); + } + + [Test] + public void Can_PUT_complex_type_with_custom_path() + { + var client = CreateRestClient(); + + var request = new InboxPostResponseRequest { + Id = 123, + Responses = new List<PageElementResponseDTO> { + new PageElementResponseDTO { + PageElementId = 123, + PageElementResponse = "something", + PageElementType = "Question" + } + } + }; + + var response = client.Put<InboxPostResponseRequestResponse>("inbox/123/responses", request); + + Assert.That(response.Id, Is.EqualTo(request.Id)); + Assert.That(response.Responses[0].PageElementId, + Is.EqualTo(request.Responses[0].PageElementId)); + } + + [Test] + public void Does_throw_400_for_Argument_exceptions() + { + var client = CreateRestClient(); + + try + { + var response = client.Put<InboxPostResponseRequestResponse>("inbox/123/responses", new InboxPostResponseRequest()); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(400)); + } + } + + [Test] + public void Does_throw_400_for_Argument_exceptions_without_response_DTOs() + { + var client = CreateRestClient(); + + try + { + var response = client.Put<InboxPost>("inbox/123/responses", new InboxPost { Throw = true }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(400)); + } + } + } + + [TestFixture] + public class JsonSyncRestClientTests : SyncRestClientTests + { + public JsonSyncRestClientTests() : base(8090) + { + } + + protected override IRestClient CreateRestClient() + { + return new JsonServiceClient(ListeningOn); + } + + [Test] + public void Can_use_response_filters() + { + var isActioncalledGlobal = false; + var isActioncalledLocal = false; + ServiceClientBase.GlobalResponseFilter = r => isActioncalledGlobal = true; + var restClient = (JsonServiceClient)CreateRestClient(); + 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); + + JsonHttpClient.GlobalResponseFilter = null; + } + } + + [TestFixture] + public class JsvSyncRestClientTests : SyncRestClientTests + { + public JsvSyncRestClientTests() + : base(8093) + { + } + + protected override IRestClient CreateRestClient() + { + return new JsvServiceClient(ListeningOn); + } + } + + [TestFixture] + public class XmlSyncRestClientTests : SyncRestClientTests + { + public XmlSyncRestClientTests() + : base(8094) + { + } + + protected override IRestClient CreateRestClient() + { + return new XmlServiceClient(ListeningOn); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/default.html b/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/default.html index 0c88fcb6e91..ce40780fdd3 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/default.html +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/default.html @@ -1,15 +1,15 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <div> - Default Tests/ index page - </div> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + Default Tests/ index page + </div> + </form> +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/textfile.txt b/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/textfile.txt new file mode 100644 index 00000000000..c0f66c43781 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/textfile.txt @@ -0,0 +1 @@ +123456789012345678901234567890 \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/upload.html b/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/upload.html index 2e024bdc118..ff2e0f75a03 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/upload.html +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/TestExistingDir/upload.html @@ -1,13 +1,13 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server" enctype="multipart/form-data"> - <label>Form Upload:</label> - <input type="file" value="upload" /> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server" enctype="multipart/form-data"> + <label>Form Upload:</label> + <input type="file" value="upload" /> + </form> +</body> +</html> diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs index 0710518044a..edb2da67b50 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs @@ -1,147 +1,142 @@ -using System.Collections.Generic; -using Funq; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - public class Todo - { - public int Id { get; set; } - public string Name { get; set; } - public string Content { get; set; } - public bool Done { get; set; } - - public bool Equals(Todo other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Id == Id && Equals(other.Name, Name) && Equals(other.Content, Content) && other.Done.Equals(Done); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (Todo)) return false; - return Equals((Todo) obj); - } - - public override int GetHashCode() - { - unchecked - { - int result = Id; - result = (result*397) ^ (Name != null ? Name.GetHashCode() : 0); - result = (result*397) ^ (Content != null ? Content.GetHashCode() : 0); - result = (result*397) ^ Done.GetHashCode(); - return result; - } - } - } - - [Route("/todolist")] - public class TodoList : List<Todo> - { - public TodoList() {} - public TodoList(IEnumerable<Todo> collection) : base(collection) {} - } - - public class TodoListResponse - { - public TodoList Results { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - public class TodoListService : RestServiceBase<TodoList> - { - public override object OnGet(TodoList request) - { - return new TodoListResponse { Results = request }; - } - - public override object OnPost(TodoList request) - { - return new TodoListResponse { Results = request }; - } - - public override object OnPut(TodoList request) - { - return new TodoListResponse { Results = request }; - } - - public override object OnDelete(TodoList request) - { - return new TodoListResponse { Results = request }; - } - } - - [TestFixture] - public class TodoListTests - { - private const string ListeningOn = "http://localhost:8082/"; - - public class TodoListAppHostHttpListener - : AppHostHttpListenerBase - { - - public TodoListAppHostHttpListener() - : base("TodoList Tests", typeof(TodoList).Assembly) { } - - public override void Configure(Container container) - { - } - } - - TodoListAppHostHttpListener appHost; - - readonly Todo[] Todos = new[] { - new Todo { Id = 1, Name = "Todo1", Content = "Content1", Done = false}, - new Todo { Id = 2, Name = "Todo2", Content = "Content2", Done = true}, - new Todo { Id = 3, Name = "Todo3", Content = "Content3", Done = false}, - }; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new TodoListAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - [Test] - public void Can_Send_TodoList() - { - var serviceClient = new JsonServiceClient(ListeningOn); - var response = serviceClient.Send<TodoListResponse>(new TodoList(Todos)); - Assert.That(response.Results, Is.EquivalentTo(Todos)); - } - - [Test] - public void Can_Post_TodoList() - { - var serviceClient = new JsonServiceClient(ListeningOn); - var response = serviceClient.Post<TodoListResponse>("/todolist", new TodoList(Todos)); - Assert.That(response.Results, Is.EquivalentTo(Todos)); - } - - [Test] - public void Can_Get_TodoList() - { - var serviceClient = new JsonServiceClient(ListeningOn); - var response = serviceClient.Get<TodoListResponse>("/todolist"); - Assert.That(response.Results.Count, Is.EqualTo(0)); - } - } +using System.Collections.Generic; +using Funq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.WebHost.Endpoints; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + public class Todo + { + public int Id { get; set; } + public string Name { get; set; } + public string Content { get; set; } + public bool Done { get; set; } + + public bool Equals(Todo other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Id == Id && Equals(other.Name, Name) && Equals(other.Content, Content) && other.Done.Equals(Done); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Todo)) return false; + return Equals((Todo) obj); + } + + public override int GetHashCode() + { + unchecked + { + int result = Id; + result = (result*397) ^ (Name != null ? Name.GetHashCode() : 0); + result = (result*397) ^ (Content != null ? Content.GetHashCode() : 0); + result = (result*397) ^ Done.GetHashCode(); + return result; + } + } + } + + [Route("/todolist")] + public class TodoList : List<Todo> + { + public TodoList() {} + public TodoList(IEnumerable<Todo> collection) : base(collection) {} + } + + public class TodoListResponse + { + public TodoList Results { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [DefaultRequest(typeof(TodoList))] + public class TodoListService : Service + { + public object Get(TodoList request) + { + return new TodoListResponse { Results = request }; + } + + public object Post(TodoList request) + { + return new TodoListResponse { Results = request }; + } + + public object Put(TodoList request) + { + return new TodoListResponse { Results = request }; + } + + public object Delete(TodoList request) + { + return new TodoListResponse { Results = request }; + } + } + + [TestFixture] + public class TodoListTests + { + private const string ListeningOn = "http://localhost:8082/"; + + public class TodoListAppHostHttpListener + : AppHostHttpListenerBase + { + public TodoListAppHostHttpListener() + : base("TodoList Tests", typeof(TodoList).Assembly) { } + + public override void Configure(Container container) {} + } + + TodoListAppHostHttpListener appHost; + + readonly Todo[] Todos = new[] { + new Todo { Id = 1, Name = "Todo1", Content = "Content1", Done = false}, + new Todo { Id = 2, Name = "Todo2", Content = "Content2", Done = true}, + new Todo { Id = 3, Name = "Todo3", Content = "Content3", Done = false}, + }; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new TodoListAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_Send_TodoList() + { + var serviceClient = new JsonServiceClient(ListeningOn); + var response = serviceClient.Send<TodoListResponse>(new TodoList(Todos)); + Assert.That(response.Results, Is.EquivalentTo(Todos)); + } + + [Test] + public void Can_Post_TodoList() + { + var serviceClient = new JsonServiceClient(ListeningOn); + var response = serviceClient.Post<TodoListResponse>("/todolist", new TodoList(Todos)); + Assert.That(response.Results, Is.EquivalentTo(Todos)); + } + + [Test] + public void Can_Get_TodoList() + { + var serviceClient = new JsonServiceClient(ListeningOn); + var response = serviceClient.Get<TodoListResponse>("/todolist"); + Assert.That(response.Results.Count, Is.EqualTo(0)); + } + } } \ No newline at end of file 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 new file mode 100644 index 00000000000..292e582369b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UniqueRequestTests.cs @@ -0,0 +1,170 @@ +using System.Collections.Generic; +using System.IO; +using Funq; +using NUnit.Framework; +using ServiceStack.Common; +using ServiceStack.Text; +#if !NETCORE +using ServiceStack.MiniProfiler.UI; +#endif + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/request/{Id}")] + 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 + { + public UniqueRequestAppHost() : base("Unique Request Tests", typeof(UniqueRequestService).Assembly) {} + public override void Configure(Container container) {} + } + + [TestFixture] + public class UniqueRequestTests + { + private const string BaseUri = "http://localhost:8001"; + private UniqueRequestAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new UniqueRequestAppHost(); + appHost.Init(); + appHost.Start(BaseUri + "/"); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_handle_encoded_chars() + { + var response = BaseUri.CombineWith("request/123%20456").GetStringFromUrl(); + Assert.That(response, Is.EqualTo("123 456")); + 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 47130dc7260..7f66f6a6df5 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/UserServiceValidationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UserServiceValidationTests.cs @@ -1,177 +1,175 @@ -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.WebHost.Endpoints.Tests.Support; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [RestService("/uservalidation")] - [RestService("/uservalidation/{Id}")] - public class UserValidation - { - public string FirstName { get; set; } - public string LastName { get; set; } - } - - public interface IAddressValidator - { - bool ValidAddress(string address); - } - - public class UserValidator : AbstractValidator<UserValidation>, IRequiresHttpRequest - { - 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).NotEmpty().WithMessage("Please specify a first name"); - }); - } - } - - //Not matching the naming convention ([Request DTO Name] + "Response") - public class OperationResponse - { - public UserValidation Result { get; set; } - } - - public class UserValidationService : RestServiceBase<UserValidation> - { - public override object OnGet(UserValidation request) - { - return new OperationResponse { Result = request }; - } - } - - [TestFixture] - public class UserServiceValidationTests - { - private const string ListeningOn = "http://localhost:82/"; - - public class UserAppHostHttpListener - : AppHostHttpListenerBase - { - - public UserAppHostHttpListener() - : base("Validation Tests", typeof(UserValidationService).Assembly) { } - - public override void Configure(Container container) - { - Plugins.Add(new ValidationFeature()); - container.RegisterValidators(typeof(UserValidator).Assembly); - } - } - - UserAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new UserAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - EndpointHandlerBase.ServiceManager = null; - } - - private static string ExpectedErrorCode = "ShouldNotBeEmpty"; - - protected static IServiceClient UnitTestServiceClient() - { - EndpointHandlerBase.ServiceManager = new ServiceManager(true, typeof(SecureService).Assembly); - 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<IServiceClient>[] { - () => UnitTestServiceClient(), - () => new JsonServiceClient(ListeningOn), - () => new JsvServiceClient(ListeningOn), - () => new XmlServiceClient(ListeningOn), - }; - } - } - - [Test, TestCaseSource(typeof(UserServiceValidationTests), "ServiceClients")] - public void Get_empty_request_throws_validation_exception(Func<IServiceClient> factory) - { - try - { - var client = (IRestClient)factory(); - 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)); - } - } - - public static IEnumerable RestClients - { - 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<IServiceClient>[] { - () => new JsonServiceClient(ListeningOn), - () => new JsvServiceClient(ListeningOn), - () => new XmlServiceClient(ListeningOn), - }; - } - } - - [Test, TestCaseSource(typeof(UserServiceValidationTests), "RestClients")] - public void Throws_validation_exception_even_if_AlwaysSendBasicAuthHeader_is_false(Func<IServiceClient> factory) - { - try - { - var client = (ServiceClientBase)factory(); - client.AlwaysSendBasicAuthHeader = false; - 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)); - } - } - } -} +using System; +using System.Net; +using ServiceStack.FluentValidation; +using NUnit.Framework; +using System.Collections; +using Funq; +using ServiceStack.Validation; +using ServiceStack.Web; +using ServiceStack.WebHost.Endpoints.Tests.Support; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/uservalidation")] + [Route("/uservalidation/{Id}")] + public class UserValidation + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + public interface IAddressValidator + { + bool ValidAddress(string address); + } + + public class UserValidator : AbstractValidator<UserValidation>, IRequiresRequest + { + public IAddressValidator AddressValidator { get; set; } + + public UserValidator() + { + 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 + { + public UserValidation Result { get; set; } + } + + public class UserValidationService : Service + { + public object Get(UserValidation request) + { + return new OperationResponse { Result = request }; + } + } + + [TestFixture] + public class UserServiceValidationTests + { + private const string ListeningOn = "http://localhost:1337/"; + + public class UserAppHostHttpListener + : AppHostHttpListenerBase + { + + public UserAppHostHttpListener() + : base("Validation Tests", typeof(UserValidationService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + container.RegisterValidators(typeof(UserValidator).Assembly); + } + } + + static UserAppHostHttpListener appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new UserAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + private static string ExpectedErrorCode = "ShouldNotBeEmpty"; + + 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<IServiceClient>[] { + () => UnitTestServiceClient(), + () => new JsonServiceClient(ListeningOn), + () => new JsonHttpClient(ListeningOn), + () => new JsvServiceClient(ListeningOn), + () => new XmlServiceClient(ListeningOn), + }; + } + } + + [Test, TestCaseSource(typeof(UserServiceValidationTests), "ServiceClients")] + public void Get_empty_request_throws_validation_exception(Func<IServiceClient> factory) + { + try + { + var client = (IRestClient)factory(); + 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)); + } + } + + public static IEnumerable RestClients + { + 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<IServiceClient>[] { + () => new JsonServiceClient(ListeningOn), + () => new JsonHttpClient(ListeningOn), + () => new JsvServiceClient(ListeningOn), + () => new XmlServiceClient(ListeningOn), + }; + } + } + + [Test, TestCaseSource(typeof(UserServiceValidationTests), "RestClients")] + public void Throws_validation_exception_even_if_AlwaysSendBasicAuthHeader_is_false(Func<IServiceClient> factory) + { + try + { + 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"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); + Assert.That(ex.StatusDescription, Is.EqualTo(ExpectedErrorCode)); + } + } + } +} 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 3ff2c5d19a3..55ca78bba98 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/WebServiceExceptionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/WebServiceExceptionTests.cs @@ -1,59 +1,76 @@ -using System.Runtime.Serialization; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [DataContract] - public class WithStatusResponse - { - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - [DataContract] - public class NoStatusResponse - { - } - - [TestFixture] - public class WebServiceExceptionTests - { - [Test] - public void Can_retrieve_Errors_from_Dto_WithStatusResponse() - { - var webEx = new WebServiceException - { - ResponseDto = new WithStatusResponse - { - ResponseStatus = new ResponseStatus - { - ErrorCode = "errorCode", - Message = "errorMessage", - StackTrace = "stackTrace" - } - } - }; - - Assert.That(webEx.ErrorCode, Is.EqualTo("errorCode")); - Assert.That(webEx.ErrorMessage, Is.EqualTo("errorMessage")); - Assert.That(webEx.ServerStackTrace, Is.EqualTo("stackTrace")); - } - - [Test] - public void Can_retrieve_empty_Errors_from_Dto_NoStatusResponse() - { - var webEx = new WebServiceException - { - ResponseDto = new NoStatusResponse() - }; - - Assert.That(webEx.ErrorCode, Is.Null); - Assert.That(webEx.ErrorMessage, Is.Null); - Assert.That(webEx.ServerStackTrace, Is.Null); - } - - } - +using System.Collections.Generic; +using System.Runtime.Serialization; +using NUnit.Framework; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [DataContract] + public class WithStatusResponse + { + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class NoStatusResponse + { + } + + [TestFixture] + public class WebServiceExceptionTests + { + [Test] + public void Can_retrieve_Errors_from_Dto_WithStatusResponse() + { + var webEx = new WebServiceException + { + ResponseDto = new WithStatusResponse + { + ResponseStatus = new ResponseStatus + { + ErrorCode = "errorCode", + Message = "errorMessage", + StackTrace = "stackTrace" + } + } + }; + + Assert.That(webEx.ErrorCode, Is.EqualTo("errorCode")); + Assert.That(webEx.ErrorMessage, Is.EqualTo("errorMessage")); + Assert.That(webEx.ServerStackTrace, Is.EqualTo("stackTrace")); + } + + [Test] + public void Can_retrieve_empty_Errors_from_Dto_NoStatusResponse() + { + var webEx = new WebServiceException + { + ResponseDto = new NoStatusResponse() + }; + + Assert.That(webEx.ErrorCode, Is.Null); + Assert.That(webEx.ErrorMessage, Is.Null); + 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 1e959845e13..90cec174ecb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/WsdlMetadataTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/WsdlMetadataTests.cs @@ -1,56 +1,57 @@ -using NUnit.Framework; -using ServiceStack.Logging; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints.Metadata; -using ServiceStack.WebHost.Endpoints.Tests.Support; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class WsdlMetadataTests : MetadataTestBase - { - //private static ILog log = LogManager.GetLogger(typeof(WsdlMetadataTests)); - - [Test] - public void Wsdl_state_is_correct() - { - var serviceOperations = new ServiceOperations(base.AllOperations); - var wsdlGenerator = new Soap11WsdlMetadataHandler(); - var wsdlTemplate = wsdlGenerator.GetWsdlTemplate(serviceOperations, "http://w3c.org/types", false, false, "http://w3c.org/types"); - - Assert.That(wsdlTemplate.ReplyOperationNames, Is.EquivalentTo(serviceOperations.ReplyOperations.Names)); - Assert.That(wsdlTemplate.OneWayOperationNames, Is.EquivalentTo(serviceOperations.OneWayOperations.Names)); - } - - [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, - IncludeAllTypesInAssembly = 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)); - } - - } -} \ No newline at end of file +#if !NETCORE +using NUnit.Framework; +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 : IService + { + //private static ILog log = LogManager.GetLogger(typeof(WsdlMetadataTests)); + + [Test] + public void Wsdl_state_is_correct() + { + 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() + { + 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("<?")); + } + } + + } +} +#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 new file mode 100644 index 00000000000..9baa3b59f0d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/XmlMetaDataHandlerTests.cs @@ -0,0 +1,28 @@ +using NUnit.Framework; +using ServiceStack.Metadata; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class XmlMetaDataHandlerTests + { + [Test] + public void when_creating_a_response_for_a_dto_with_no_default_constructor_the_response_is_not_empty() + { + var handler = new XmlMetadataHandler(); + var response = handler.CreateResponse(typeof(NoDefaultConstructor)); + Assert.That(response, Is.Not.Empty); + } + } + + [DataContract(Namespace = "http://schemas.servicestack.net/types")] + public class NoDefaultConstructor + { + public NoDefaultConstructor(string test) + { } + + [DataMember] + public string Value { get; set; } + } +} 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/webpage.html b/tests/ServiceStack.WebHost.Endpoints.Tests/webpage.html index 331e12ed0b4..b6cb25ffa3e 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/webpage.html +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/webpage.html @@ -1,14 +1,14 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <div> - Default index ServiceStack.WebHost.Endpoints.Tests page - </div> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + Default index ServiceStack.WebHost.Endpoints.Tests page + </div> + </form> +</body> +</html> 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 50b4285cc9e..ca3d40c7f67 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/default.css +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/default.css @@ -1,30 +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 .error .error-summary -{ - display: inline; - color: #B94A48; -} - -#facebook-signin { - margin: 50px 0 10px 0; +.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/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/_blank.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/_blank.js index 499fe114f5d..b0f97419def 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/_blank.js +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/_blank.js @@ -1,4 +1,4 @@ -(function (root) -{ - -})(window); +(function (root) +{ + +})(window); 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 9d12b39361e..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/backbone.min.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/backbone.min.js index c3ae2ff8f5d..3f0d495dc39 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/backbone.min.js +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/backbone.min.js @@ -1,33 +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<e;d++)if(c[d]&&b===c[d][0]){c[d]=null;break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,e,f=2;if(!(c=this._callbacks))return this;for(;f--;)if(b=f?a:"all",b=c[b])for(var g=0,h=b.length;g<h;g++)(d=b[g])?(e=f?Array.prototype.slice.call(arguments,1):arguments,d[0].apply(d[1]||this,e)):(b.splice(g,1),g--,h--);return this}};e.Model=function(a,b){var c;a||(a={});if(c=this.defaults)f.isFunction(c)&&(c=c.call(this)),a=f.extend({},c,a);this.attributes={}; -this._escapedAttributes={};this.cid=f.uniqueId("c");this.set(a,{silent:!0});this._changed=!1;this._previousAttributes=f.clone(this.attributes);if(b&&b.collection)this.collection=b.collection;this.initialize(a,b)};f.extend(e.Model.prototype,e.Events,{_previousAttributes:null,_changed:!1,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.attributes[a]; -return this._escapedAttributes[a]=(b==null?"":""+b).replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")},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<d;c++)this._add(a[c],b);else this._add(a,b);return this},remove:function(a,b){if(f.isArray(a))for(var c= -0,d=a.length;c<d;c++)this._remove(a[c],b);else this._remove(a,b);return this},get:function(a){if(a==null)return null;return this._byId[a.id!=null?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");this.models=this.sortBy(this.comparator);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={});this.each(this._removeReference);this._reset();this.add(a,{silent:!0});b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a||(a={});var b=this,c=a.success;a.success=function(d,f,e){b[a.add?"add":"reset"](b.parse(d,e),a);c&&c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"read",this,a)},create:function(a,b){var c=this;b||(b={});a=this._prepareModel(a,b);if(!a)return!1;var d=b.success;b.success=function(a,e,f){c.add(a,b); -d&&d(a,e,f)};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){if(a instanceof e.Model){if(!a.collection)a.collection=this}else{var c=a;a=new this.model(c,{collection:this});a.validate&&!a._performValidation(c,b)&&(a=!1)}return a},_add:function(a,b){b||(b={});a=this._prepareModel(a,b);if(!a)return!1;var c=this.getByCid(a);if(c)throw Error(["Can't add the same model to a set twice", -c.id]);this._byId[a.id]=a;this._byCid[a.cid]=a;this.models.splice(b.at!=null?b.at:this.comparator?this.sortedIndex(a,this.comparator):this.length,0,a);a.bind("all",this._onModelEvent);this.length++;b.silent||a.trigger("add",a,this,b);return a},_remove:function(a,b){b||(b={});a=this.getByCid(a)||this.get(a);if(!a)return null;delete this._byId[a.id];delete this._byCid[a.cid];this.models.splice(this.indexOf(a),1);this.length--;b.silent||a.trigger("remove",a,this,b);this._removeReference(a);return a}, -_removeReference:function(a){this==a.collection&&delete a.collection;a.unbind("all",this._onModelEvent)},_onModelEvent:function(a,b,c,d){(a=="add"||a=="remove")&&c!=this||(a=="destroy"&&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","rest","last","without","indexOf","lastIndexOf","isEmpty","groupBy"],function(a){e.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});e.Router=function(a){a||(a={});if(a.routes)this.routes=a.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var q=/:([\w\d]+)/g,r=/\*([\w\d]+)/g,s=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(e.Router.prototype,e.Events,{initialize:function(){},route:function(a, -b,c){e.history||(e.history=new e.History);f.isRegExp(a)||(a=this._routeToRegExp(a));e.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d))},this))},navigate:function(a,b){e.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(s,"\\$&").replace(q, -"([^/]*)").replace(r,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});e.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")};var j=/^#*/,t=/msie [\w.]+/,m=!1;f.extend(e.History.prototype,{interval:50,getFragment:function(a,b){if(a==null)if(this._hasPushState||b){a=window.location.pathname;var c=window.location.search;c&&(a+=c);a.indexOf(this.options.root)==0&&(a=a.substr(this.options.root.length))}else a=window.location.hash;return decodeURIComponent(a.replace(j, -""))},start:function(a){if(m)throw Error("Backbone.history has already been started");this.options=f.extend({},{root:"/"},this.options,a);this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||!window.history||!window.history.pushState);a=this.getFragment();var b=document.documentMode;if(b=t.exec(navigator.userAgent.toLowerCase())&&(!b||b<=7))this.iframe=g('<iframe src="javascript:0" tabindex="-1" />').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<c;b++){var d=n[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el){if(f.isString(this.el))this.el=g(this.el).get(0)}else{var a=this.attributes||{};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});e.Model.extend=e.Collection.extend=e.Router.extend=e.View.extend=function(a,b){var c=v(this,a,b);c.extend=this.extend;return c};var w={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a, -b,c){var d=w[a];c=f.extend({type:d,dataType:"json"},c);if(!c.url)c.url=k(b)||l();if(!c.data&&b&&(a=="create"||a=="update"))c.contentType="application/json",c.data=JSON.stringify(b.toJSON());if(e.emulateJSON)c.contentType="application/x-www-form-urlencoded",c.data=c.data?{model:c.data}:{};if(e.emulateHTTP&&(d==="PUT"||d==="DELETE")){if(e.emulateJSON)c.data._method=d;c.type="POST";c.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)}}if(c.type!=="GET"&&!e.emulateJSON)c.processData= -!1;return g.ajax(c)};var o=function(){},v=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};f.extend(d,a);o.prototype=a.prototype;d.prototype=new o;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!a||!a.url)return null;return f.isFunction(a.url)?a.url():a.url},l=function(){throw Error('A "url" property or function must be specified');},i=function(a,b,c){return function(d){a? -a(b,d,c):b.trigger("error",b,d,c)}}}).call(this); +// 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<e;d++)if(c[d]&&b===c[d][0]){c[d]=null;break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,e,f=2;if(!(c=this._callbacks))return this;for(;f--;)if(b=f?a:"all",b=c[b])for(var g=0,h=b.length;g<h;g++)(d=b[g])?(e=f?Array.prototype.slice.call(arguments,1):arguments,d[0].apply(d[1]||this,e)):(b.splice(g,1),g--,h--);return this}};e.Model=function(a,b){var c;a||(a={});if(c=this.defaults)f.isFunction(c)&&(c=c.call(this)),a=f.extend({},c,a);this.attributes={}; +this._escapedAttributes={};this.cid=f.uniqueId("c");this.set(a,{silent:!0});this._changed=!1;this._previousAttributes=f.clone(this.attributes);if(b&&b.collection)this.collection=b.collection;this.initialize(a,b)};f.extend(e.Model.prototype,e.Events,{_previousAttributes:null,_changed:!1,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.attributes[a]; +return this._escapedAttributes[a]=(b==null?"":""+b).replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")},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<d;c++)this._add(a[c],b);else this._add(a,b);return this},remove:function(a,b){if(f.isArray(a))for(var c= +0,d=a.length;c<d;c++)this._remove(a[c],b);else this._remove(a,b);return this},get:function(a){if(a==null)return null;return this._byId[a.id!=null?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");this.models=this.sortBy(this.comparator);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={});this.each(this._removeReference);this._reset();this.add(a,{silent:!0});b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a||(a={});var b=this,c=a.success;a.success=function(d,f,e){b[a.add?"add":"reset"](b.parse(d,e),a);c&&c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"read",this,a)},create:function(a,b){var c=this;b||(b={});a=this._prepareModel(a,b);if(!a)return!1;var d=b.success;b.success=function(a,e,f){c.add(a,b); +d&&d(a,e,f)};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){if(a instanceof e.Model){if(!a.collection)a.collection=this}else{var c=a;a=new this.model(c,{collection:this});a.validate&&!a._performValidation(c,b)&&(a=!1)}return a},_add:function(a,b){b||(b={});a=this._prepareModel(a,b);if(!a)return!1;var c=this.getByCid(a);if(c)throw Error(["Can't add the same model to a set twice", +c.id]);this._byId[a.id]=a;this._byCid[a.cid]=a;this.models.splice(b.at!=null?b.at:this.comparator?this.sortedIndex(a,this.comparator):this.length,0,a);a.bind("all",this._onModelEvent);this.length++;b.silent||a.trigger("add",a,this,b);return a},_remove:function(a,b){b||(b={});a=this.getByCid(a)||this.get(a);if(!a)return null;delete this._byId[a.id];delete this._byCid[a.cid];this.models.splice(this.indexOf(a),1);this.length--;b.silent||a.trigger("remove",a,this,b);this._removeReference(a);return a}, +_removeReference:function(a){this==a.collection&&delete a.collection;a.unbind("all",this._onModelEvent)},_onModelEvent:function(a,b,c,d){(a=="add"||a=="remove")&&c!=this||(a=="destroy"&&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","rest","last","without","indexOf","lastIndexOf","isEmpty","groupBy"],function(a){e.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});e.Router=function(a){a||(a={});if(a.routes)this.routes=a.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var q=/:([\w\d]+)/g,r=/\*([\w\d]+)/g,s=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(e.Router.prototype,e.Events,{initialize:function(){},route:function(a, +b,c){e.history||(e.history=new e.History);f.isRegExp(a)||(a=this._routeToRegExp(a));e.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d))},this))},navigate:function(a,b){e.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(s,"\\$&").replace(q, +"([^/]*)").replace(r,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});e.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")};var j=/^#*/,t=/msie [\w.]+/,m=!1;f.extend(e.History.prototype,{interval:50,getFragment:function(a,b){if(a==null)if(this._hasPushState||b){a=window.location.pathname;var c=window.location.search;c&&(a+=c);a.indexOf(this.options.root)==0&&(a=a.substr(this.options.root.length))}else a=window.location.hash;return decodeURIComponent(a.replace(j, +""))},start:function(a){if(m)throw Error("Backbone.history has already been started");this.options=f.extend({},{root:"/"},this.options,a);this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||!window.history||!window.history.pushState);a=this.getFragment();var b=document.documentMode;if(b=t.exec(navigator.userAgent.toLowerCase())&&(!b||b<=7))this.iframe=g('<iframe src="javascript:0" tabindex="-1" />').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<c;b++){var d=n[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el){if(f.isString(this.el))this.el=g(this.el).get(0)}else{var a=this.attributes||{};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});e.Model.extend=e.Collection.extend=e.Router.extend=e.View.extend=function(a,b){var c=v(this,a,b);c.extend=this.extend;return c};var w={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a, +b,c){var d=w[a];c=f.extend({type:d,dataType:"json"},c);if(!c.url)c.url=k(b)||l();if(!c.data&&b&&(a=="create"||a=="update"))c.contentType="application/json",c.data=JSON.stringify(b.toJSON());if(e.emulateJSON)c.contentType="application/x-www-form-urlencoded",c.data=c.data?{model:c.data}:{};if(e.emulateHTTP&&(d==="PUT"||d==="DELETE")){if(e.emulateJSON)c.data._method=d;c.type="POST";c.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)}}if(c.type!=="GET"&&!e.emulateJSON)c.processData= +!1;return g.ajax(c)};var o=function(){},v=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};f.extend(d,a);o.prototype=a.prototype;d.prototype=new o;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!a||!a.url)return null;return f.isFunction(a.url)?a.url():a.url},l=function(){throw Error('A "url" property or function must be specified');},i=function(a,b,c){return function(d){a? +a(b,d,c):b.trigger("error",b,d,c)}}}).call(this); 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 642d63e9302..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 0a10aee03dc..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)); - }); - - return function(json) { - var model = typeof json == "string" ? JSON.parse(json) : json; + 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/ServiceStack.WebHost.IntegrationTests/Content/js/login.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/login.js deleted file mode 100644 index 69ce1104646..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 06f63c3aa86..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 7eee973df44..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/underscore.min.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/underscore.min.js index 935cd2d91de..5983694cfbb 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/underscore.min.js +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/underscore.min.js @@ -1,27 +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<k;e++){if(e in a&&c.call(b,a[e],e,a)===m)break}else for(e in a)if(l.call(a,e)&&c.call(b,a[e],e,a)===m)break};b.map=function(a,c,b){var e=[];if(a==null)return e;if(t&&a.map===t)return a.map(c,b);h(a,function(a,g,G){e[e.length]=c.call(b,a,g,G)});return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var k=d!==void 0;a==null&&(a=[]);if(u&&a.reduce===u)return e&&(c=b.bind(c,e)),k?a.reduce(c,d):a.reduce(c);h(a,function(a,b,f){k?d=c.call(e,d,a,b,f):(d=a,k=!0)});if(!k)throw new TypeError("Reduce of empty array with no initial value"); -return d};b.reduceRight=b.foldr=function(a,c,d,e){a==null&&(a=[]);if(v&&a.reduceRight===v)return e&&(c=b.bind(c,e)),d!==void 0?a.reduceRight(c,d):a.reduceRight(c);a=(b.isArray(a)?a.slice():b.toArray(a)).reverse();return b.reduce(a,c,d,e)};b.find=b.detect=function(a,c,b){var e;A(a,function(a,g,f){if(c.call(b,a,g,f))return e=a,!0});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(w&&a.filter===w)return a.filter(c,b);h(a,function(a,g,f){c.call(b,a,g,f)&&(e[e.length]=a)});return e}; -b.reject=function(a,c,b){var e=[];if(a==null)return e;h(a,function(a,g,f){c.call(b,a,g,f)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=!0;if(a==null)return e;if(x&&a.every===x)return a.every(c,b);h(a,function(a,g,f){if(!(e=e&&c.call(b,a,g,f)))return m});return e};var A=b.some=b.any=function(a,c,d){c=c||b.identity;var e=!1;if(a==null)return e;if(y&&a.some===y)return a.some(c,d);h(a,function(a,b,f){if(e|=c.call(d,a,b,f))return m});return!!e};b.include=b.contains=function(a,c){var b= -!1;if(a==null)return b;if(o&&a.indexOf===o)return a.indexOf(c)!=-1;A(a,function(a){if(b=a===c)return!0});return b};b.invoke=function(a,c){var d=f.call(arguments,2);return b.map(a,function(a){return(c.call?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))return Math.max.apply(Math,a);var e={computed:-Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;b>=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;b<e.computed&&(e={value:a,computed:b})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,f){return{value:a,criteria:c.call(d,a,b,f)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?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<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return f.call(a);if(b.isArguments(a))return f.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?f.call(a,0,b):a[0]};b.rest=b.tail=function(a,b,d){return f.call(a,b==null||d?1:b)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.filter(a, -function(a){return!!a})};b.flatten=function(a){return b.reduce(a,function(a,d){if(b.isArray(d))return a.concat(b.flatten(d));a[a.length]=d;return a},[])};b.without=function(a){return b.difference(a,f.call(arguments,1))};b.uniq=b.unique=function(a,c){return b.reduce(a,function(a,e,f){if(0==f||(c===!0?b.last(a)!=e:!b.include(a,e)))a[a.length]=e;return a},[])};b.union=function(){return b.uniq(b.flatten(arguments))};b.intersection=b.intersect=function(a){var c=f.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,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<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)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(o&&a.indexOf===o)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a, -b){if(a==null)return-1;if(z&&a.lastIndexOf===z)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);d=arguments[2]||1;for(var e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};b.bind=function(a,b){if(a.bind===q&&q)return q.apply(a,f.call(arguments,1));var d=f.call(arguments,2);return function(){return a.apply(b,d.concat(f.call(arguments)))}};b.bindAll=function(a){var c=f.call(arguments,1); -c.length==0&&(c=b.functions(a));h(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 b=c.apply(this,arguments);return l.call(d,b)?d[b]:d[b]=a.apply(this,arguments)}};b.delay=function(a,b){var d=f.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(f.call(arguments,1)))};var B=function(a,b,d){var e;return function(){var f=this,g=arguments,h=function(){e=null; -a.apply(f,g)};d&&clearTimeout(e);if(d||!e)e=setTimeout(h,b)}};b.throttle=function(a,b){return B(a,b,!1)};b.debounce=function(a,b){return B(a,b,!0)};b.once=function(a){var b=!1,d;return function(){if(b)return d;b=!0;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(f.call(arguments));return b.apply(this,d)}};b.compose=function(){var a=f.call(arguments);return function(){for(var b=f.call(arguments),d=a.length-1;d>=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<a;e++)b.call(d,e)};b.mixin=function(a){h(b.functions(a),function(c){H(c,b[c]=a[c])})};var I=0;b.uniqueId=function(a){var b=I++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/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}})(); +// 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<k;e++){if(e in a&&c.call(b,a[e],e,a)===m)break}else for(e in a)if(l.call(a,e)&&c.call(b,a[e],e,a)===m)break};b.map=function(a,c,b){var e=[];if(a==null)return e;if(t&&a.map===t)return a.map(c,b);h(a,function(a,g,G){e[e.length]=c.call(b,a,g,G)});return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var k=d!==void 0;a==null&&(a=[]);if(u&&a.reduce===u)return e&&(c=b.bind(c,e)),k?a.reduce(c,d):a.reduce(c);h(a,function(a,b,f){k?d=c.call(e,d,a,b,f):(d=a,k=!0)});if(!k)throw new TypeError("Reduce of empty array with no initial value"); +return d};b.reduceRight=b.foldr=function(a,c,d,e){a==null&&(a=[]);if(v&&a.reduceRight===v)return e&&(c=b.bind(c,e)),d!==void 0?a.reduceRight(c,d):a.reduceRight(c);a=(b.isArray(a)?a.slice():b.toArray(a)).reverse();return b.reduce(a,c,d,e)};b.find=b.detect=function(a,c,b){var e;A(a,function(a,g,f){if(c.call(b,a,g,f))return e=a,!0});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(w&&a.filter===w)return a.filter(c,b);h(a,function(a,g,f){c.call(b,a,g,f)&&(e[e.length]=a)});return e}; +b.reject=function(a,c,b){var e=[];if(a==null)return e;h(a,function(a,g,f){c.call(b,a,g,f)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=!0;if(a==null)return e;if(x&&a.every===x)return a.every(c,b);h(a,function(a,g,f){if(!(e=e&&c.call(b,a,g,f)))return m});return e};var A=b.some=b.any=function(a,c,d){c=c||b.identity;var e=!1;if(a==null)return e;if(y&&a.some===y)return a.some(c,d);h(a,function(a,b,f){if(e|=c.call(d,a,b,f))return m});return!!e};b.include=b.contains=function(a,c){var b= +!1;if(a==null)return b;if(o&&a.indexOf===o)return a.indexOf(c)!=-1;A(a,function(a){if(b=a===c)return!0});return b};b.invoke=function(a,c){var d=f.call(arguments,2);return b.map(a,function(a){return(c.call?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))return Math.max.apply(Math,a);var e={computed:-Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;b>=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;b<e.computed&&(e={value:a,computed:b})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,f){return{value:a,criteria:c.call(d,a,b,f)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?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<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return f.call(a);if(b.isArguments(a))return f.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?f.call(a,0,b):a[0]};b.rest=b.tail=function(a,b,d){return f.call(a,b==null||d?1:b)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.filter(a, +function(a){return!!a})};b.flatten=function(a){return b.reduce(a,function(a,d){if(b.isArray(d))return a.concat(b.flatten(d));a[a.length]=d;return a},[])};b.without=function(a){return b.difference(a,f.call(arguments,1))};b.uniq=b.unique=function(a,c){return b.reduce(a,function(a,e,f){if(0==f||(c===!0?b.last(a)!=e:!b.include(a,e)))a[a.length]=e;return a},[])};b.union=function(){return b.uniq(b.flatten(arguments))};b.intersection=b.intersect=function(a){var c=f.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,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<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)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(o&&a.indexOf===o)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a, +b){if(a==null)return-1;if(z&&a.lastIndexOf===z)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);d=arguments[2]||1;for(var e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};b.bind=function(a,b){if(a.bind===q&&q)return q.apply(a,f.call(arguments,1));var d=f.call(arguments,2);return function(){return a.apply(b,d.concat(f.call(arguments)))}};b.bindAll=function(a){var c=f.call(arguments,1); +c.length==0&&(c=b.functions(a));h(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 b=c.apply(this,arguments);return l.call(d,b)?d[b]:d[b]=a.apply(this,arguments)}};b.delay=function(a,b){var d=f.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(f.call(arguments,1)))};var B=function(a,b,d){var e;return function(){var f=this,g=arguments,h=function(){e=null; +a.apply(f,g)};d&&clearTimeout(e);if(d||!e)e=setTimeout(h,b)}};b.throttle=function(a,b){return B(a,b,!1)};b.debounce=function(a,b){return B(a,b,!0)};b.once=function(a){var b=!1,d;return function(){if(b)return d;b=!0;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(f.call(arguments));return b.apply(this,d)}};b.compose=function(){var a=f.call(arguments);return function(){for(var b=f.call(arguments),d=a.length-1;d>=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<a;e++)b.call(d,e)};b.mixin=function(a){h(b.functions(a),function(c){H(c,b[c]=a[c])})};var I=0;b.uniqueId=function(a){var b=I++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/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/ServiceStack.WebHost.IntegrationTests/Content/js/userprofile.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/userprofile.js deleted file mode 100644 index 18e49c47703..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 500d9d8d900..83694904b79 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx +++ b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx @@ -1,217 +1,221 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ServiceStack.WebHost.IntegrationTests.Default" %> -<%@ Import Namespace="ServiceStack.Text" %> -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <title>Authentication / Validation tests</title> - <meta name="description" content=""> - <meta name="author" content=""> - - <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> - <!--[if lt IE 9]> - <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> - <![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"> - body { - padding-top: 60px; - } - </style> - </head> - - <body> - <div class="topbar"> <div class="fill"> <div class="container"> <a class="brand" href="/">Home</a> <ul class="nav"> <li class="active"><a href="#">Home</a></li> <li><a href="#about">About</a></li> <li><a href="#contact">Contact</a></li> <li><a href="api/auth/logout">Log Off</a></li> </ul> </div> </div> </div> - <div id="login" class="container"> -<h2 id="title">Authentication / Validation tests</h2> - -<div class="row"> - <div id="signin" class="span12 columns"> - <form class="span5 columns form-stacked fade-when-loading" action="api/auth/credentials" method="POST"> - <div> - <fieldset> - <legend>Sign In</legend> - - <div class="clearfix"> <label for="UserName">Email Address</label> <input id="UserName" name="UserName" type="text" value="" /> <span class="help-inline"></span> </div> - <div class="clearfix"> <label for="Password">Password</label> <input id="Password" name="Password" type="password" /> <span class="help-inline"></span> </div> - <div class="clearfix"> <div class="input"> <ul class="inputs-list"> <li> <label> <input id="RememberMe" name="RememberMe" type="checkbox" value="true" /> <span>Remember me</span> </label> </li> </ul> </div> <span class="help-block"></span> </div> - <p> - <span class="error-summary"></span> - </p> - - <p> - <button class="btn" type="submit">Sign In</button><b data-ajax="loading"></b> - or <a href="#" data-cmd="toggle:register,signin">register</a> - </p> - - <div id="facebook-signin"> - <a href="api/auth/facebook"><img src="Content/img/sign-in-with-facebook.png" alt="Sign-in with Facebook" /></a> - </div> - </fieldset> - </div> - </form> - - <div class="span4 columns"> - <h3>Become a Member</h3> - <p> - Lorem ipsum dolor sit amet, - consectetuer adipiscing elit, sed diam - 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> - </div> - - </div> -</div> -<div class="row"> - <div id="register" class="hide span12 columns"> - <form class="span8 columns form-stacked fade-when-loading" action="api/register" method="POST"> - <div> - <fieldset> - <legend>Create your member account</legend> - - <div class="clearfix"> <label for="DisplayName">DisplayName</label> <input id="DisplayName" name="DisplayName" type="text" value="" /> <span class="help-inline"></span> </div> - <div class="clearfix"> <label for="Email">Email</label> <input id="Email" name="Email" type="text" value="" /> <span class="help-inline"></span> </div> - <div class="clearfix"> <label for="Password">Password</label> <input id="Password" name="Password" type="password" /> <span class="help-inline"></span> </div> - <div class="clearfix"> <label for="ConfirmPassword">ConfirmPassword</label> <input id="ConfirmPassword" name="ConfirmPassword" type="password" /> <span class="help-inline"></span> </div> - - <p> - <small>By registering you agree to the <a href="#">Terms & Conditions</a></small> - </p> - - <span class="error-summary"></span> - - <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> - </p> - </fieldset> - </div> - </form> - </div> -</div> - -<p></p> - -<div class="alert-message success hide"><a class="close" href="#">×</a><p></p></div> - -<h3>Session Info</h3> - -<% if (UserSession.IsAuthenticated) { %> - <div class="alert-message success"> - <a class="close" href="#">×</a> - <p><strong>Contgratulations!</strong> You are authenticated</p> - </div> -<% } %> - -<pre> -<%= UserSession.Dump() %> -</pre> - -<div id="userauths"></div> -<div id="oAuthProviders"></div> - -<script type="text/javascript"> - $.getJSON("api/userauths", function(r) { - $("#userauths").html(_.jsonreport(r.results)); - $("#oAuthProviders").html(_.jsonreport(r.oAuthProviders)); - }); -</script> - - -<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; - } - } - - _.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()); - } - } - }); - }); - - _.cmdHandler({ - toggle: function (show, hide) { - clear(); - $("#" + hide).hide(); - $("#" + show).fadeIn(); - } - }); -</script> - - <h2>Test Redirect</h2> - - <form action="api/auth/credentials" method="POST"> - <div> - <fieldset> - <legend>Sign In w/ Redirect</legend> - - <div class="clearfix"> <label for="UserName">Email Address</label> <input id="Text1" name="UserName" type="text" value="" /> </div> - <div class="clearfix"> <label for="Password">Password</label> <input id="Password1" name="Password" type="password" /> </div> - <div class="clearfix"> <label for="Continue">Continue</label> <input id="Password2" name="Continue" type="text" value="http://google.com" /> </div> - <div class="clearfix"> <div class="input"> <ul class="inputs-list"> <li> <label> <input id="Checkbox1" name="RememberMe" type="checkbox" value="true" /> <span>Remember me</span> </label> </li> </ul> </div> <span class="help-block"></span> </div> - <p> - <span class="error-summary"></span> - </p> - - <p> - <button class="btn" type="submit">Sign In</button> - </p> - </fieldset> - </div> - </form> - - <footer> - <p>&copy; Company 2012</p> - </footer> - - </div> <!-- /container --> - - </body> -</html> +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ServiceStack.WebHost.IntegrationTests.Default" %> +<%@ Import Namespace="ServiceStack.Html" %> +<%@ Import Namespace="ServiceStack.Text" %> +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Authentication / Validation tests</title> + <meta name="description" content=""> + <meta name="author" content=""> + + <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> + <!--[if lt IE 9]> + <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + + <!-- Le styles --> + <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> + </head> + + <body> + <div class="topbar"> <div class="fill"> <div class="container"> <a class="brand" href="/">Home</a> <ul class="nav"> <li class="active"><a href="#">Home</a></li> <li><a href="#about">About</a></li> <li><a href="#contact">Contact</a></li> <li><a href="api/auth/logout">Log Off</a></li> </ul> </div> </div> </div> + <div id="login" class="container"> +<h2 id="title">Authentication / Validation tests</h2> + +<div class="row"> + <div id="signin" class="span12 columns"> + <form class="span5 columns form-stacked fade-when-loading" action="api/auth/credentials" method="POST"> + <div> + <fieldset> + <legend>Sign In</legend> + + <div class="clearfix"> <label for="UserName">Email Address</label> <input id="UserName" name="UserName" type="text" value="" /> <span class="help-inline"></span> </div> + <div class="clearfix"> <label for="Password">Password</label> <input id="Password" name="Password" type="password" /> <span class="help-inline"></span> </div> + <div class="clearfix"> <div class="input"> <ul class="inputs-list"> <li> <label> <input id="RememberMe" name="RememberMe" type="checkbox" value="true" /> <span>Remember me</span> </label> </li> </ul> </div> <span class="help-block"></span> </div> + <p> + <span class="error-summary"></span> + </p> + + <p> + <button class="btn" type="submit">Sign In</button><b data-ajax="loading"></b> + or <a href="#" data-click="toggle:register,signin">register</a> + </p> + + <div id="facebook-signin"> + <a href="api/auth/facebook"><img src="Content/img/sign-in-with-facebook.png" alt="Sign-in with Facebook" /></a> + </div> + </fieldset> + </div> + </form> + + <div class="span4 columns"> + <h3>Become a Member</h3> + <p> + Lorem ipsum dolor sit amet, + consectetuer adipiscing elit, sed diam + nonummy nibh euismod tincidunt ut + laoreet dolore magna aliquam erat volutpat. + </p> + <button class="btn large primary" data-click="toggle:register,signin">Register Now</button> + </div> + + </div> +</div> +<div class="row"> + <div id="register" class="hide span12 columns"> + <form class="span8 columns form-stacked fade-when-loading" action="api/register" method="POST"> + <div> + <fieldset> + <legend>Create your member account</legend> + + <div class="clearfix"> <label for="DisplayName">DisplayName</label> <input id="DisplayName" name="DisplayName" type="text" value="" /> <span class="help-inline"></span> </div> + <div class="clearfix"> <label for="Email">Email</label> <input id="Email" name="Email" type="text" value="" /> <span class="help-inline"></span> </div> + <div class="clearfix"> <label for="Password">Password</label> <input id="Password" name="Password" type="password" /> <span class="help-inline"></span> </div> + <div class="clearfix"> <label for="ConfirmPassword">ConfirmPassword</label> <input id="ConfirmPassword" name="ConfirmPassword" type="password" /> <span class="help-inline"></span> </div> + + <p> + <small>By registering you agree to the <a href="#">Terms & Conditions</a></small> + </p> + + <span class="error-summary"></span> + + <p> + <button class="btn" type="submit">Sign Up</button><b data-ajax="loading"></b> + or <a href="#" data-click="toggle:signin,register">sign in</a> + </p> + </fieldset> + </div> + </form> + </div> +</div> + +<p></p> + +<div class="alert-message success hide"><a class="close" href="#">×</a><p></p></div> + +<h3>Session Info</h3> + +<% if (UserSession.IsAuthenticated) { %> + <div class="alert-message success"> + <a class="close" href="#">×</a> + <p><strong>Contgratulations!</strong> You are authenticated</p> + </div> +<% } %> + +<pre> +<%= UserSession.Dump() %> +</pre> + +<div id="userauths"></div> +<div id="oAuthProviders"></div> + +<script type="text/javascript"> + $.getJSON("api/userauths", function (r) { + $("#userauths").html(_.jsonreport(r.results)); + $("#oAuthProviders").html(_.jsonreport(r.oAuthProviders)); + }); +</script> + + +<script type="text/javascript"> + + $(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(); + } + } + + $("#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); + } + }); + + $(document).bindHandlers({ + toggle: function (show, hide) { + $("#" + hide).hide(); + $("#" + show).fadeIn(); + } + }); +</script> + + <h2>Test Redirect</h2> + + <form action="api/auth/GoogleOpenId" method="POST"> + <p> + <button class="btn" type="submit">Sign In with Google OpenId</button> + </p> + </form> + + <form action="api/auth/OpenId" method="POST"> + <p> + <input type="text" name="OpenIdUrl" placeholder="e.g. http://{user}.myopenid.com"/> + <button class="btn" type="submit">Sign In with OpenId</button> + </p> + </form> + + <form action="api/auth/credentials" method="POST"> + <div> + <fieldset> + <legend>Sign In w/ Redirect</legend> + + <div class="clearfix"> <label for="UserName">Email Address</label> <input id="Text1" name="UserName" type="text" value="" /> </div> + <div class="clearfix"> <label for="Password">Password</label> <input id="Password1" name="Password" type="password" /> </div> + <div class="clearfix"> <label for="Continue">Continue</label> <input id="Password2" name="Continue" type="text" value="http://google.com" /> </div> + <div class="clearfix"> <div class="input"> <ul class="inputs-list"> <li> <label> <input id="Checkbox1" name="RememberMe" type="checkbox" value="true" /> <span>Remember me</span> </label> </li> </ul> </div> <span class="help-block"></span> </div> + <p> + <span class="error-summary"></span> + </p> + + <p> + <button class="btn" type="submit">Sign In</button> + </p> + </fieldset> + </div> + </form> + + <footer> + <p>&copy; Company 2012</p> + </footer> + + </div> <!-- /container --> + + </body> +</html> diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs index 5565e5e32d9..e0e1b15c37d 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs @@ -1,17 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; - -namespace ServiceStack.WebHost.IntegrationTests -{ - public partial class Default : PageBase - { - protected void Page_Load(object sender, EventArgs e) - { - - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace ServiceStack.WebHost.IntegrationTests +{ + 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 b31166d487b..db1d453bb5e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.designer.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.designer.cs @@ -1,15 +1,15 @@ -//------------------------------------------------------------------------------ -// <auto-generated> -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// </auto-generated> -//------------------------------------------------------------------------------ - -namespace ServiceStack.WebHost.IntegrationTests { - - - public partial class Default { - } -} +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace ServiceStack.WebHost.IntegrationTests { + + + public partial class Default { + } +} diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs b/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs index f28d6289eae..8cd62811529 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs @@ -1,174 +1,236 @@ -using System; -using Funq; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.Configuration; -using ServiceStack.Messaging; -using ServiceStack.MiniProfiler; -using ServiceStack.MiniProfiler.Data; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.Redis; -using ServiceStack.Redis.Messaging; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Validation; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests -{ - public class Global : System.Web.HttpApplication - { - public class AppHost - : AppHostBase - { - public AppHost() - : base("ServiceStack WebHost IntegrationTests", typeof(Reverse).Assembly) - { - } - - public override void Configure(Container container) - { - JsConfig.EmitCamelCaseNames = true; - - this.RequestFilters.Add((req, res, dto) => { - var requestFilter = dto as RequestFilter; - if (requestFilter != null) - { - res.StatusCode = requestFilter.StatusCode; - if (!requestFilter.HeaderName.IsNullOrEmpty()) - { - res.AddHeader(requestFilter.HeaderName, requestFilter.HeaderValue); - } - res.Close(); - } - - var secureRequests = dto as IRequiresSession; - if (secureRequests != null) - { - res.ReturnAuthRequired(); - } - }); - - this.Container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - "~/App_Data/db.sqlite".MapHostAbsolutePath(), - SqliteOrmLiteDialectProvider.Instance) { - ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current) - }); - - this.Container.Register<ICacheClient>(new MemoryCacheClient()); - //this.Container.Register<ICacheClient>(new BasicRedisClientManager()); - - ConfigureAuth(container); - - //this.Container.Register<ISessionFactory>( - // c => new SessionFactory(c.Resolve<ICacheClient>())); - - var dbFactory = this.Container.Resolve<IDbConnectionFactory>(); - dbFactory.Run(db => db.CreateTable<Movie>(true)); - ModelConfig<Movie>.Id(x => x.Title); - Routes - .Add<Movies>("/custom-movies", "GET, OPTIONS") - .Add<Movies>("/custom-movies/genres/{Genre}") - .Add<Movie>("/custom-movies", "POST,PUT") - .Add<Movie>("/custom-movies/{Id}") - .Add<MqHostStats>("/mqstats"); - - - var resetMovies = this.Container.Resolve<ResetMoviesService>(); - resetMovies.Post(null); - - Plugins.Add(new ValidationFeature()); - Plugins.Add(new SessionFeature()); - Plugins.Add(new ProtoBufFormat()); - - container.RegisterValidators(typeof(CustomersValidator).Assembly); - - - 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"); - - - //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" }, - }, - //EnableFeatures = onlyEnableFeatures, - DebugMode = true, //Show StackTraces for easier debugging - }); - - var redisManager = new BasicRedisClientManager(); - var mqHost = new RedisMqHost(redisManager, 2, null); - mqHost.RegisterHandler<Reverse>(this.Container.Resolve<ReverseService>().Execute); - mqHost.Start(); - - this.Container.Register((IMessageService)mqHost); - } - - //Configure ServiceStack Authentication and CustomUserSession - private void ConfigureAuth(Funq.Container container) - { - Routes - .Add<Auth>("/auth") - .Add<Auth>("/auth/{provider}") - .Add<Registration>("/register"); - - var appSettings = new AppSettings(); - - Plugins.Add(new AuthFeature(() => new CustomUserSession(), - new IAuthProvider[] { - new CredentialsAuthProvider(appSettings), - new FacebookAuthProvider(appSettings), - new TwitterAuthProvider(appSettings), - new DigestAuthProvider(appSettings), - new BasicAuthProvider(appSettings), - })); - - Plugins.Add(new RegistrationFeature()); - - container.Register<IUserAuthRepository>(c => - new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())); - - var authRepo = (OrmLiteAuthRepository)container.Resolve<IUserAuthRepository>(); - if (new AppSettings().Get("Recr eateTables", true)) - authRepo.DropAndReCreateTables(); - else - authRepo.CreateMissingTables(); - } - } - - protected void Application_Start(object sender, EventArgs e) - { - var appHost = new AppHost(); - 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(); - - var mqHost = AppHostBase.Instance.Container.TryResolve<IMessageService>(); - if (mqHost != null) - mqHost.Start(); - } - - } +using System; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; +using Funq; +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.ProtoBuf; +using ServiceStack.Redis; +using ServiceStack.Common.Tests; +using ServiceStack.DataAnnotations; +using ServiceStack.Formats; +using ServiceStack.Shared.Tests; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; +using ServiceStack.WebHost.IntegrationTests.Services; +using ServiceStack.WebHost.IntegrationTests.Tests; + +namespace ServiceStack.WebHost.IntegrationTests +{ + public class Global : System.Web.HttpApplication + { + private const bool StartMqHost = false; + + public class AppHost + : AppHostBase + { + public AppHost() + : 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) + { + IocShared.Configure(this); + + JsConfig.Init(new Text.Config { + TextCase = TextCase.CamelCase, + }); + ServiceStack.Auth.RegisterService.AllowUpdates = true; + + this.PreRequestFilters.Add((req, res) => + { + req.Items["_DataSetAtPreRequestFilters"] = true; + }); + + this.GlobalRequestFilters.Add((req, res, dto) => + { + req.Items["_DataSetAtRequestFilters"] = true; + + if (dto is RequestFilter requestFilter) + { + res.StatusCode = requestFilter.StatusCode; + if (!requestFilter.HeaderName.IsNullOrEmpty()) + { + res.AddHeader(requestFilter.HeaderName, requestFilter.HeaderValue); + } + res.Close(); + } + + 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) + }); + + this.Container.Register<ICacheClient>(new MemoryCacheClient()); + //this.Container.Register<ICacheClient>(new BasicRedisClientManager()); + + ConfigureAuth(container); + + //this.Container.Register<ISessionFactory>( + // c => new SessionFactory(c.Resolve<ICacheClient>())); + + var dbFactory = this.Container.Resolve<IDbConnectionFactory>(); + + using (var db = dbFactory.Open()) + db.DropAndCreateTable<Movie>(); + + ModelConfig<Movie>.Id(x => x.Title); + Routes + .Add<Movies>("/custom-movies", "GET, OPTIONS") + .Add<Movies>("/custom-movies/genres/{Genre}") + .Add<Movie>("/custom-movies", "POST,PUT") + .Add<Movie>("/custom-movies/{Id}") + .Add<MqHostStats>("/mqstats"); + + + 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 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!")); + + 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 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>(ExecuteMessage); + mqHost.Start(); + this.Container.Register((IMessageService)mqHost); + } + } + + //Configure ServiceStack Authentication and CustomUserSession + private void ConfigureAuth(Funq.Container container) + { + Routes + .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 GoogleAuthProvider(appSettings), + new DigestAuthProvider(appSettings), + new BasicAuthProvider(appSettings), + })); + + Plugins.Add(new RegistrationFeature()); + + container.Register<IAuthRepository>(c => + new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())); + + var authRepo = (OrmLiteAuthRepository)container.Resolve<IAuthRepository>(); + if (new AppSettings().Get("RecreateTables", true)) + authRepo.DropAndReCreateTables(); + else + authRepo.InitSchema(); + } + + public override object OnPreExecuteServiceFilter(IService service, object request, IRequest httpReq, IResponse httpRes) + { + if (service is IocScopeService) + service.InjectRequestIntoDependencies(httpReq); + return request; + } + } + + protected void Application_Start(object sender, EventArgs e) + { + var appHost = new AppHost(); + 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(); + + 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 0e5acaf630b..ef73c1d2eaf 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/PageBase.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/PageBase.cs @@ -1,81 +1,54 @@ -using System.Web.UI; -using Funq; -using ServiceStack.CacheAccess; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.WebHost.IntegrationTests.Tests; - -namespace ServiceStack.WebHost.IntegrationTests -{ - public class CustomUserSession : AuthUserSession - { - public string CustomPropety { 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); - - if (session.Email == AuthTestsBase.AdminEmail) - session.Roles.Add(RoleNames.Admin); - } - } - - public class PageBase : Page - { - private Container container; - public Container Container - { - get { return container ?? (container = Endpoints.AppHostBase.Instance.Container); } - } - - protected string SessionKey - { - get - { - var sessionId = SessionFeature.GetSessionId(); - return sessionId == null ? null : SessionFeature.GetSessionKey(sessionId); - } - } - - private CustomUserSession userSession; - protected CustomUserSession UserSession - { - get - { - if (userSession != null) return userSession; - if (SessionKey != null) - userSession = this.Cache.Get<CustomUserSession>(SessionKey); - else - SessionFeature.CreateSessionIds(); - - var unAuthorizedSession = new CustomUserSession(); - return userSession ?? (userSession = unAuthorizedSession); - } - } - - public void ClearSession() - { - userSession = null; - this.Cache.Remove(SessionKey); - } - - public new ICacheClient Cache - { - get { return Container.Resolve<ICacheClient>(); } - } - - public ISessionFactory SessionFactory - { - get { return Container.Resolve<ISessionFactory>(); } - } - - private ISession session; - public new ISession Session - { - get - { - return session ?? (session = SessionFactory.GetOrCreateSession()); - } - } - } +using System.ServiceModel.Channels; +using System.Web.UI; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Configuration; +using ServiceStack.WebHost.IntegrationTests.Tests; + +namespace ServiceStack.WebHost.IntegrationTests +{ + public class CustomUserSession : AuthUserSession + { + public string CustomProperty { get; set; } + + 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) + { + var authRepo = authService.TryResolve<IAuthRepository>(); + var userAuth = authRepo.GetUserAuth(session, tokens); + authRepo.AssignRoles(userAuth, roles: new[] { RoleNames.Admin }); + } + } + } + + public class PageBase : Page + { + /// <summary> + /// Typed UserSession + /// </summary> + private object userSession; + protected virtual TUserSession SessionAs<TUserSession>() => (TUserSession)(userSession ??= Cache.SessionAs<TUserSession>()); + + protected CustomUserSession UserSession => SessionAs<CustomUserSession>(); + + public new ICacheClient Cache => HostContext.AppHost.GetCacheClient(null); + + private ISessionFactory sessionFactory; + public virtual ISessionFactory SessionFactory => sessionFactory ?? (sessionFactory = HostContext.Resolve<ISessionFactory>()) ?? new SessionFactory(Cache); + + /// <summary> + /// Dynamic Session Bag + /// </summary> + private Caching.ISession session; + public Caching.ISession SessionBag => session ??= SessionFactory.GetOrCreateSession(); + + public void ClearSession() + { + userSession = null; + this.Cache.Remove(SessionFeature.GetSessionKey()); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs b/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs index fce86021e0b..b3b8f8a2f15 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs @@ -1,39 +1,39 @@ -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.IntegrationTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.WebHost.IntegrationTests")] -[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("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")] - -[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.IntegrationTests.Services")] - +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.IntegrationTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ServiceStack.WebHost.IntegrationTests")] +[assembly: AssemblyCopyright("Copyright (c) Microsoft 2010")] +[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("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("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 80340238fdd..a68517e612c 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj +++ b/tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj @@ -1,302 +1,358 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.30729</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{801771CD-2C19-463A-94F8-DF546825DF47}</ProjectGuid> - <ProjectTypeGuids>{349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>ServiceStack.WebHost.IntegrationTests</RootNamespace> - <AssemblyName>ServiceStack.WebHost.IntegrationTests</AssemblyName> - <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> - <FileUpgradeFlags> - </FileUpgradeFlags> - <OldToolsVersion>4.0</OldToolsVersion> - <UpgradeBackupLocation /> - <UseIISExpress>true</UseIISExpress> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>True</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>False</Optimize> - <OutputPath>bin\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - <PlatformTarget>x86</PlatformTarget> - <TreatWarningsAsErrors>True</TreatWarningsAsErrors> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> - <Optimize>True</Optimize> - <OutputPath>bin\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - <PlatformTarget>x86</PlatformTarget> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'MONOTOUCH|AnyCPU'"> - <OutputPath>bin\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <Optimize>True</Optimize> - <DebugType>pdbonly</DebugType> - <PlatformTarget>x86</PlatformTarget> - <CodeAnalysisLogFile>bin\ServiceStack.WebHost.IntegrationTests.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile> - <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression> - <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile> - <ErrorReport>prompt</ErrorReport> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - <CodeAnalysisRuleSetDirectories>;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories> - <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets> - <CodeAnalysisRuleDirectories>;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories> - <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <ItemGroup> - <Reference Include="Mono.Data.Sqlite"> - <HintPath>..\..\lib\tests\Mono.Data.Sqlite.dll</HintPath> - </Reference> - <Reference Include="protobuf-net"> - <HintPath>..\..\lib\tests\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="System" /> - <Reference Include="System.Data" /> - <Reference Include="System.Core"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Data.DataSetExtensions"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Runtime.Serialization"> - <RequiredTargetFramework>3.0</RequiredTargetFramework> - </Reference> - <Reference Include="System.ServiceModel"> - <RequiredTargetFramework>3.0</RequiredTargetFramework> - </Reference> - <Reference Include="System.Web.Extensions"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Xml.Linq"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Drawing" /> - <Reference Include="System.Web" /> - <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> - </ItemGroup> - <ItemGroup> - <Content Include="..\..\lib\tests\sqlite3.dll"> - <Link>sqlite3.dll</Link> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="Content\bootstrap.css" /> - <Content Include="Content\default.css" /> - <Content Include="Content\img\bootstrap-apple-114x114.png" /> - <Content Include="Content\img\bootstrap-apple-57x57.png" /> - <Content Include="Content\img\bootstrap-apple-72x72.png" /> - <Content Include="Content\img\favicon.ico" /> - <Content Include="Content\img\sign-in-with-facebook.png" /> - <Content Include="Content\img\sign-in-with-twitter-l.png" /> - <Content Include="Content\img\ui-bg_flat_0_aaaaaa_40x100.png" /> - <Content Include="Content\img\ui-bg_flat_75_ffffff_40x100.png" /> - <Content Include="Content\img\ui-bg_glass_55_fbf9ee_1x400.png" /> - <Content Include="Content\img\ui-bg_glass_65_ffffff_1x400.png" /> - <Content Include="Content\img\ui-bg_glass_75_dadada_1x400.png" /> - <Content Include="Content\img\ui-bg_glass_75_e6e6e6_1x400.png" /> - <Content Include="Content\img\ui-bg_glass_95_fef1ec_1x400.png" /> - <Content Include="Content\img\ui-bg_highlight-soft_75_cccccc_1x100.png" /> - <Content Include="Content\img\ui-icons_222222_256x240.png" /> - <Content Include="Content\img\ui-icons_2e83ff_256x240.png" /> - <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="Default.aspx" /> - <Content Include="user-notfound.htm" /> - <Content Include="user-default.htm" /> - <Content Include="Global.asax" /> - <Content Include="Soap11WebService.asmx" /> - <Content Include="_default.html" /> - <Content Include="TestExistingDir\default.html" /> - <Content Include="TestExistingDir\upload.html" /> - <Content Include="Web.config"> - <SubType>Designer</SubType> - </Content> - <Content Include="webpage.html" /> - </ItemGroup> - <ItemGroup> - <Compile Include="PageBase.cs"> - <SubType>ASPXCodeBehind</SubType> - </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="Services\HelloImage.cs" /> - <Compile Include="Services\IocServiceTests.cs" /> - <Compile Include="Tests\ExceptionHandlingTests.cs" /> - <Compile Include="Tests\ProtoBufServiceTests.cs" /> - <Compile Include="Services\ContentManagerOnly.cs" /> - <Compile Include="Services\ThrowsArgumentNullService.cs" /> - <Compile Include="Services\EchoMethodService.cs" /> - <Compile Include="Tests\AuthTestsBase.cs" /> - <Compile Include="Services\BatchWidgetValidationService.cs" /> - <Compile Include="Services\CachedMoviesService.cs" /> - <Compile Include="Tests\RawRequestTests.cs" /> - <Compile Include="Tests\ManageRolesTests.cs" /> - <Compile Include="Services\TestService.cs" /> - <Compile Include="Services\CustomerService.cs" /> - <Compile Include="Services\SessionService.cs" /> - <Compile Include="Services\MqHostStatsService.cs" /> - <Compile Include="Services\HttpResultsService.cs" /> - <Compile Include="Services\CustomFormDataService.cs" /> - <Compile Include="Services\GeoInfoService.cs" /> - <Compile Include="Services\ProfilerService.cs" /> - <Compile Include="Services\RouteInfoService.cs" /> - <Compile Include="Services\UserAuths.cs" /> - <Compile Include="Tests\AppHostBaseTests.cs" /> - <Compile Include="Tests\CachedServiceTests.cs" /> - <Compile Include="Tests\Config.cs" /> - <Compile Include="Tests\CsvContentTypeFilterTests.cs" /> - <Compile Include="Global.asax.cs"> - <DependentUpon>Global.asax</DependentUpon> - </Compile> - <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Services\AlwaysThrowsService.cs" /> - <Compile Include="Services\Secure.cs" /> - <Compile Include="Services\FileUploadService.cs" /> - <Compile Include="Services\MovieService.cs" /> - <Compile Include="Services\MoviesService.cs" /> - <Compile Include="Services\RequestFilter.cs" /> - <Compile Include="Services\ResetMovies.cs" /> - <Compile Include="Services\VerbMatch2Service.cs" /> - <Compile Include="Services\VerbMatch1Service.cs" /> - <Compile Include="Services\HelloService.cs" /> - <Compile Include="Services\WildCardRequestService.cs" /> - <Compile Include="Services\EchoRequestService.cs" /> - <Compile Include="Services\Rot13Service.cs" /> - <Compile Include="Services\ReverseService.cs" /> - <Compile Include="Soap11WebService.asmx.cs"> - <DependentUpon>Soap11WebService.asmx</DependentUpon> - <SubType>Component</SubType> - </Compile> - <Compile Include="Tests\CustomerServiceValidationTests.cs" /> - <Compile Include="Tests\CustomRequestDataTests.cs" /> - <Compile Include="Tests\FileUploadTests.cs" /> - <Compile Include="Tests\FilterTests.cs" /> - <Compile Include="Tests\HelloWorldRawHttpPostTests.cs" /> - <Compile Include="Tests\HelloWorldServiceClientTests.cs" /> - <Compile Include="Tests\MovieServiceTests.cs" /> - <Compile Include="Tests\RequestAndPathResolutionTests.cs" /> - <Compile Include="Tests\RequestFilterTests.cs" /> - <Compile Include="Tests\RestPathResolutionUnitTests.cs" /> - <Compile Include="Tests\RestsTestBase.cs" /> - <Compile Include="Tests\RestWebServiceTests.cs" /> - <Compile Include="Tests\SessionTests.cs" /> - <Compile Include="Tests\WebServicesTests.cs" /> - </ItemGroup> - <ItemGroup> - <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> - <WCFMetadata Include="Service References\" /> - </ItemGroup> - <ItemGroup> - <None Include="Properties\DataSources\ServiceStack.ServiceInterface.ServiceModel.ResponseStatus.datasource" /> - <None Include="README.md" /> - <None Include="webpage.forbidden" /> - </ItemGroup> - <ItemGroup> - <Folder Include="App_Data\" /> - </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> - <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.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> - --> - <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>False</AutoAssignPort> - <DevelopmentServerPort>50000</DevelopmentServerPort> - <DevelopmentServerVPath>/</DevelopmentServerVPath> - <IISUrl>http://localhost:50095/</IISUrl> - <NTLMAuthentication>False</NTLMAuthentication> - <UseCustomServer>False</UseCustomServer> - <CustomServerUrl> - </CustomServerUrl> - <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> - </WebProjectProperties> - </FlavorProperties> - </VisualStudio> - </ProjectExtensions> +<?xml version="1.0" encoding="utf-8"?> +<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> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{801771CD-2C19-463A-94F8-DF546825DF47}</ProjectGuid> + <ProjectTypeGuids>{349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ServiceStack.WebHost.IntegrationTests</RootNamespace> + <AssemblyName>ServiceStack.WebHost.IntegrationTests</AssemblyName> + <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>4.0</OldToolsVersion> + <UpgradeBackupLocation /> + <UseIISExpress>false</UseIISExpress> + <IISExpressSSLPort /> + <IISExpressAnonymousAuthentication /> + <IISExpressWindowsAuthentication /> + <IISExpressUseClassicPipelineMode /> + <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> + <DebugType>full</DebugType> + <Optimize>False</Optimize> + <OutputPath>bin\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + <PlatformTarget>AnyCPU</PlatformTarget> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>True</Optimize> + <OutputPath>bin\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + <PlatformTarget>x86</PlatformTarget> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'MONOTOUCH|AnyCPU'"> + <OutputPath>bin\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <Optimize>True</Optimize> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x86</PlatformTarget> + <CodeAnalysisLogFile>bin\ServiceStack.WebHost.IntegrationTests.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile> + <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression> + <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisRuleSetDirectories>;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories> + <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets> + <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="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.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" /> + </ItemGroup> + <ItemGroup> + <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" /> + <Content Include="Content\img\bootstrap-apple-72x72.png" /> + <Content Include="Content\img\favicon.ico" /> + <Content Include="Content\img\sign-in-with-facebook.png" /> + <Content Include="Content\img\sign-in-with-twitter-l.png" /> + <Content Include="Content\img\ui-bg_flat_0_aaaaaa_40x100.png" /> + <Content Include="Content\img\ui-bg_flat_75_ffffff_40x100.png" /> + <Content Include="Content\img\ui-bg_glass_55_fbf9ee_1x400.png" /> + <Content Include="Content\img\ui-bg_glass_65_ffffff_1x400.png" /> + <Content Include="Content\img\ui-bg_glass_75_dadada_1x400.png" /> + <Content Include="Content\img\ui-bg_glass_75_e6e6e6_1x400.png" /> + <Content Include="Content\img\ui-bg_glass_95_fef1ec_1x400.png" /> + <Content Include="Content\img\ui-bg_highlight-soft_75_cccccc_1x100.png" /> + <Content Include="Content\img\ui-icons_222222_256x240.png" /> + <Content Include="Content\img\ui-icons_2e83ff_256x240.png" /> + <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\backbone.min.js" /> + <Content Include="Content\js\jquery-1.7.1.min.js" /> + <Content Include="Content\js\jsonreport.js" /> + <Content Include="Content\js\underscore.min.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" /> + <EmbeddedResource Include="Templates\OperationControl.html" /> + <EmbeddedResource Include="Templates\HtmlFormat.html" /> + <Content Include="user-notfound.htm" /> + <Content Include="user-default.htm" /> + <Content Include="Global.asax" /> + <Content Include="Soap11WebService.asmx" /> + <Content Include="_default.html" /> + <Content Include="TestExistingDir\default.html" /> + <Content Include="TestExistingDir\upload.html" /> + <Content Include="Web.config"> + <SubType>Designer</SubType> + </Content> + <Content Include="webpage.html" /> + </ItemGroup> + <ItemGroup> + <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> + </Compile> + <Compile Include="Default.aspx.designer.cs"> + <DependentUpon>Default.aspx</DependentUpon> + </Compile> + <Compile Include="Services\CachedProtoBufEmailService.cs" /> + <Compile Include="Services\ReturnsVoidService.cs" /> + <Compile Include="Services\CustomHeadersService.cs" /> + <Compile Include="Services\EndpointAccessService.cs" /> + <Compile Include="Services\HelloImage.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> + </Compile> + <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" /> + <Compile Include="Services\ThrowsArgumentNullService.cs" /> + <Compile Include="Services\EchoMethodService.cs" /> + <Compile Include="Tests\AuthTestsBase.cs" /> + <Compile Include="Services\BatchWidgetValidationService.cs" /> + <Compile Include="Services\CachedMoviesService.cs" /> + <Compile Include="Tests\RawRequestTests.cs" /> + <Compile Include="Tests\AssertValidAccessTests.cs" /> + <Compile Include="Services\TestService.cs" /> + <Compile Include="Services\CustomerService.cs" /> + <Compile Include="Services\SessionService.cs" /> + <Compile Include="Services\MqHostStatsService.cs" /> + <Compile Include="Services\HttpResultsService.cs" /> + <Compile Include="Services\CustomFormDataService.cs" /> + <Compile Include="Services\GeoInfoService.cs" /> + <Compile Include="Services\ProfilerService.cs" /> + <Compile Include="Services\RouteTokenInfoService.cs" /> + <Compile Include="Services\UserAuths.cs" /> + <Compile Include="Tests\AppHostBaseTests.cs" /> + <Compile Include="Tests\CachedServiceTests.cs" /> + <Compile Include="Tests\Config.cs" /> + <Compile Include="Tests\CsvContentTypeFilterTests.cs" /> + <Compile Include="Global.asax.cs"> + <DependentUpon>Global.asax</DependentUpon> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Services\AlwaysThrowsService.cs" /> + <Compile Include="Services\Secure.cs" /> + <Compile Include="Services\FileUploadService.cs" /> + <Compile Include="Services\MovieService.cs" /> + <Compile Include="Services\MoviesService.cs" /> + <Compile Include="Services\RequestFilter.cs" /> + <Compile Include="Services\ResetMovies.cs" /> + <Compile Include="Services\VerbMatch2Service.cs" /> + <Compile Include="Services\VerbMatch1Service.cs" /> + <Compile Include="Services\HelloService.cs" /> + <Compile Include="Services\WildCardRequestService.cs" /> + <Compile Include="Services\EchoRequestService.cs" /> + <Compile Include="Services\Rot13Service.cs" /> + <Compile Include="Services\ReverseService.cs" /> + <Compile Include="Soap11WebService.asmx.cs"> + <DependentUpon>Soap11WebService.asmx</DependentUpon> + <SubType>Component</SubType> + </Compile> + <Compile Include="Tests\CustomerServiceValidationTests.cs" /> + <Compile Include="Tests\CustomRequestDataTests.cs" /> + <Compile Include="Tests\FileUploadTests.cs" /> + <Compile Include="Tests\FilterTests.cs" /> + <Compile Include="Tests\HelloWorldRawHttpPostTests.cs" /> + <Compile Include="Tests\HelloWorldServiceClientTests.cs" /> + <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> + <Content Include="static-root.txt" /> + <Content Include="App.config" /> + <None Include="Properties\DataSources\ServiceStack.ServiceInterface.ServiceModel.ResponseStatus.datasource" /> + <None Include="README.md" /> + <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" /> + <!-- 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> + --> + <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>False</AutoAssignPort> + <DevelopmentServerPort>50000</DevelopmentServerPort> + <DevelopmentServerVPath>/</DevelopmentServerVPath> + <IISUrl>http://localhost:50000/</IISUrl> + <NTLMAuthentication>False</NTLMAuthentication> + <UseCustomServer>False</UseCustomServer> + <CustomServerUrl> + </CustomServerUrl> + <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> + </WebProjectProperties> + </FlavorProperties> + </VisualStudio> + </ProjectExtensions> + <Import Project="$(SolutionDir)\.nuget\NuGet.targets" /> </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 b4f8133089e..35303e6febd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/AlwaysThrowsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/AlwaysThrowsService.cs @@ -1,44 +1,93 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - public class AlwaysThrows - { - [DataMember] - public string Value { 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; } - } - - public class AlwaysThrowsService - : ServiceBase<AlwaysThrows> - { - protected override object Run(AlwaysThrows request) - { - throw new NotImplementedException(GetErrorMessage(request.Value)); - } - - public static string GetErrorMessage(string value) - { - return value + " is not implemented"; - } - } +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +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; } + } + + [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] + public class AlwaysThrowsResponse + : IHasResponseStatus + { + public AlwaysThrowsResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public string Result { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class AlwaysThrowsService : Service + { + public object Any(AlwaysThrows request) + { + if (request.StatusCode.HasValue) + { + throw new HttpError( + request.StatusCode.Value, + typeof(NotImplementedException).Name, + 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) + { + return value + " is not implemented"; + } + } } \ No newline at end of file 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 35ca9a25be2..68f5c88f8ef 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/BatchWidgetValidationService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/BatchWidgetValidationService.cs @@ -1,72 +1,71 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [RestService("/BatchWidgetValidation")] - public class BatchWidgetValidationRequest - { - [DataMember] - public WidgetValidationRequest[] Batch { get; set; } - } - - [DataContract] - public class BatchWidgetValidationResponse - { - [DataMember] - public WidgetValidationResponse[] Batch { get; set; } - } - - public class BatchWidgetValidationRequestService - : IService<BatchWidgetValidationRequest> - { - public object Execute(BatchWidgetValidationRequest request) - { - throw new NotImplementedException(); - } - } - - [DataContract] - [RestService("/WidgetValidation")] - public class WidgetValidationRequest - { - [DataMember] - public int OwnerID { get; set; } - - [DataMember] - public string SellerID { get; set; } - - [DataMember] - public string WidgetNumber { get; set; } - - [DataMember] - public string Quantity { get; set; } - } - - [DataContract] - public class WidgetValidationResponse - { - [DataMember] - public string SellerWidgetNumber { get; set; } - - [DataMember] - public string MatchType { get; set; } - - [DataMember] - public decimal WidgetPrice { get; set; } - - [DataMember] - public string WidgetName { get; set; } - } - - public class WidgetValidationRequestService - : IService<WidgetValidationRequest> - { - public object Execute(WidgetValidationRequest request) - { - throw new NotImplementedException(); - } - } +using System; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/BatchWidgetValidation")] + public class BatchWidgetValidationRequest + { + [DataMember] + public WidgetValidationRequest[] Batch { get; set; } + } + + [DataContract] + public class BatchWidgetValidationResponse + { + [DataMember] + public WidgetValidationResponse[] Batch { get; set; } + } + + public class BatchWidgetValidationRequestService + : IService + { + public object Any(BatchWidgetValidationRequest request) + { + throw new NotImplementedException(); + } + } + + [DataContract] + [Route("/WidgetValidation")] + public class WidgetValidationRequest + { + [DataMember] + public int OwnerID { get; set; } + + [DataMember] + public string SellerID { get; set; } + + [DataMember] + public string WidgetNumber { get; set; } + + [DataMember] + public string Quantity { get; set; } + } + + [DataContract] + public class WidgetValidationResponse + { + [DataMember] + public string SellerWidgetNumber { get; set; } + + [DataMember] + public string MatchType { get; set; } + + [DataMember] + public decimal WidgetPrice { get; set; } + + [DataMember] + public string WidgetName { get; set; } + } + + public class WidgetValidationRequestService + : IService + { + public object Any(WidgetValidationRequest request) + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs index 887b2b32a14..723a7e99f4e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs @@ -1,38 +1,26 @@ -using System.Runtime.Serialization; -using ServiceStack.CacheAccess; -using ServiceStack.Common; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - - [DataContract] - [RestService("/cached/movies", "GET")] - [RestService("/cached/movies/genres/{Genre}")] - public class CachedMovies - { - [DataMember] - public string Genre { get; set; } - } - - public class CachedMoviesService : RestServiceBase<CachedMovies> - { - public IDbConnectionFactory DbFactory { get; set; } - - public ICacheClient CacheClient { get; set; } - - public override object OnGet(CachedMovies request) - { - var service = base.ResolveService<MoviesService>(); - - return base.RequestContext.ToOptimizedResultUsingCache( - this.CacheClient, UrnId.Create<Movies>(request.Genre ?? "all"), () => - { - return (MoviesResponse)service.Get(new Movies { Genre = request.Genre }); - }); - } - } - +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/cached/movies", "GET")] + [Route("/cached/movies/genres/{Genre}")] + public class CachedMovies + { + [DataMember] + public string Genre { get; set; } + } + + public class CachedMoviesService : Service + { + public object Get(CachedMovies request) + { + 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 }); + }); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs new file mode 100644 index 00000000000..75686dad11f --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs @@ -0,0 +1,41 @@ +using System.Runtime.Serialization; +using ServiceStack.WebHost.IntegrationTests.Tests; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/cached/protobuf")] + [Route("/cached/protobuf/{FromAddress}")] + public class CachedProtoBufEmail + { + [DataMember(Order = 1)] + public string FromAddress { get; set; } + } + + [DataContract] + [Route("/uncached/protobuf")] + [Route("/uncached/protobuf/{FromAddress}")] + public class UncachedProtoBufEmail + { + [DataMember(Order = 1)] + public string FromAddress { get; set; } + } + + class UncachedProtoBufEmailService : Service + { + public object Any(UncachedProtoBufEmail request) + { + return new ProtoBufEmail { FromAddress = request.FromAddress ?? "none" }; + } + } + + class CachedProtoBufEmailService : Service + { + public object Any(CachedProtoBufEmail request) + { + return base.Request.ToOptimizedResultUsingCache(this.Cache, + UrnId.Create<ProtoBufEmail>(request.FromAddress ?? "none"), + () => new ProtoBufEmail { FromAddress = request.FromAddress ?? "none" }); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs index a5d3f50e573..3ad9484e8d3 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs @@ -1,46 +1,44 @@ -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.IntegrationTests.Tests; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - public class ContentManagerOnly - { - public string Name { get; set; } - } - - public class ContentManagerOnlyResponse : IHasResponseStatus - { - public string Result { get; set; } - public ResponseStatus ResponseStatus { get; set; } - } - - [RequiredRole(ManageRolesTests.ContentManager)] - public class ContentManagerOnlyService : ServiceBase<ContentManagerOnly> - { - protected override object Run(ContentManagerOnly request) - { - return new ContentManagerOnlyResponse { Result = "Haz Access" }; - } - } - - public class ContentPermissionOnly - { - public string Name { get; set; } - } - - public class ContentPermissionOnlyResponse : IHasResponseStatus - { - public string Result { get; set; } - public ResponseStatus ResponseStatus { get; set; } - } - - [RequiredPermission(ManageRolesTests.ContentPermission)] - public class ContentPermissionOnlyService : ServiceBase<ContentPermissionOnly> - { - protected override object Run(ContentPermissionOnly request) - { - return new ContentPermissionOnlyResponse { Result = "Haz Access" }; - } - } +using ServiceStack.WebHost.IntegrationTests.Tests; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + public class ContentManagerOnly : IReturn<ContentManagerOnlyResponse> + { + public string Name { get; set; } + } + + public class ContentManagerOnlyResponse : IHasResponseStatus + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [RequiredRole(AssertValidAccessTests.ContentManager)] + public class ContentManagerOnlyService : Service + { + public object Any(ContentManagerOnly request) + { + return new ContentManagerOnlyResponse { Result = "Haz Access" }; + } + } + + public class ContentPermissionOnly : IReturn<ContentPermissionOnlyResponse> + { + public string Name { get; set; } + } + + public class ContentPermissionOnlyResponse : IHasResponseStatus + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [RequiredPermission(AssertValidAccessTests.ContentPermission)] + public class ContentPermissionOnlyService : Service + { + public object Any(ContentPermissionOnly request) + { + return new ContentPermissionOnlyResponse { Result = "Haz Access" }; + } + } } \ No newline at end of file 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 1423c0fa2f3..10e46375461 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomFormDataService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomFormDataService.cs @@ -1,45 +1,39 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [RestService("/customformdata")] - [DataContract] - public class CustomFormData { } - - [DataContract] - public class CustomFormDataResponse : IHasResponseStatus - { - [DataMember] - public string FirstName { get; set; } - - [DataMember] - public string Item0 { get; set; } - - [DataMember] - public string Item1Delete { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class CustomFormDataService - : RestServiceBase<CustomFormData> // which inherits from IRequiresRequestContext - { - //Parsing: &first-name=tom&item-0=blah&item-1-delete=1 - public override object OnPost(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"] - }; - } - } - +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/customformdata")] + [DataContract] + public class CustomFormData { } + + [DataContract] + public class CustomFormDataResponse : IHasResponseStatus + { + [DataMember] + public string FirstName { get; set; } + + [DataMember] + public string Item0 { get; set; } + + [DataMember] + public string Item1Delete { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + 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.IntegrationTests/Services/CustomHeadersService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomHeadersService.cs new file mode 100644 index 00000000000..65f1a8970f0 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomHeadersService.cs @@ -0,0 +1,32 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/customHeaders")] + [DataContract] + public class CustomHeaders : IReturn<CustomHeadersResponse> + { } + + [DataContract] + public class CustomHeadersResponse + { + [DataMember(Order = 1)] + public string Foo { get; set; } + [DataMember(Order = 2)] + public string Bar { get; set; } + } + + public class CustomHeadersService : Service + { + public CustomHeadersResponse Any(CustomHeaders c) + { + var response = new CustomHeadersResponse + { + Foo = Request.Headers["Foo"], + Bar = Request.Headers["Bar"] + }; + return response; + } + + } +} \ No newline at end of file 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 b75cc5a53c2..c872a60d1da 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomerService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomerService.cs @@ -1,79 +1,74 @@ -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 -{ - [RestService("/customers")] - [RestService("/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 class CustomersValidator : AbstractValidator<Customers> - { - 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).Length(20, 250); - 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; } - } - - public class CustomerService : RestServiceBase<Customers> - { - public override object OnGet(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public override object OnPost(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public override object OnPut(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public override object OnDelete(Customers request) - { - return new CustomersResponse { Result = request }; - } - } - +using System.Text.RegularExpressions; +using ServiceStack.FluentValidation; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/customers")] + [Route("/customers/{Id}")] + public class Customers : IReturn<CustomersResponse> + { + 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 class CustomersResponse + { + public Customers Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomersValidator : AbstractValidator<Customers> + { + 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).NotNull().Length(20, 250); + 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 CustomerService : 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 }; + } + } + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs index f7f7ffef29f..418ba2052a0 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs @@ -1,49 +1,47 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [RestService("/echomethod")] - public class EchoMethod - { - } - - [DataContract] - public class EchoMethodResponse - { - [DataMember] - public string Result { get; set; } - } - - public class EchoMethodService - : RestServiceBase<EchoMethod> - { - public override object OnGet(EchoMethod request) - { - return new EchoMethodResponse { Result = HttpMethods.Get }; - } - - public override object OnPost(EchoMethod request) - { - return new EchoMethodResponse { Result = HttpMethods.Post }; - } - - public override object OnPut(EchoMethod request) - { - return new EchoMethodResponse { Result = HttpMethods.Put }; - } - - public override object OnDelete(EchoMethod request) - { - return new EchoMethodResponse { Result = HttpMethods.Delete }; - } - - public override object OnPatch(EchoMethod request) - { - return new EchoMethodResponse { Result = HttpMethods.Patch }; - } - } +using System.Runtime.Serialization; +using ServiceStack.Host; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/echomethod")] + public class EchoMethod + { + } + + [DataContract] + public class EchoMethodResponse + { + [DataMember] + public string Result { get; set; } + } + + [DefaultRequest(typeof(EchoMethod))] + public class EchoMethodService : Service + { + public object Get(EchoMethod request) + { + return new EchoMethodResponse { Result = HttpMethods.Get }; + } + + public object Post(EchoMethod request) + { + return new EchoMethodResponse { Result = HttpMethods.Post }; + } + + public object Put(EchoMethod request) + { + return new EchoMethodResponse { Result = HttpMethods.Put }; + } + + public object Delete(EchoMethod request) + { + return new EchoMethodResponse { Result = HttpMethods.Delete }; + } + + public object Patch(EchoMethod request) + { + return new EchoMethodResponse { Result = HttpMethods.Patch }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs index 3eaeb7fc3d7..567eb77df21 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs @@ -1,49 +1,46 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [RestService("/echo/{Id}/{String}")] - public class EchoRequest - { - [DataMember] - public int Id { get; set; } - - [DataMember] - public string String { get; set; } - - [DataMember] - public long Long { get; set; } - - [DataMember] - public Guid Guid { get; set; } - - [DataMember] - public bool Bool { get; set; } - - [DataMember] - public DateTime DateTime { get; set; } - - [DataMember] - public double Double { get; set; } - } - - [DataContract] - public class EchoRequestResponse - { - [DataMember] - public string Result { get; set; } - } - - public class EchoRequestService - : ServiceBase<EchoRequest> - { - protected override object Run(EchoRequest request) - { - return request; - } - } +using System; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/echo/{Id}/{String}")] + public class EchoRequest + { + [DataMember] + public int Id { get; set; } + + [DataMember] + public string String { get; set; } + + [DataMember] + public long Long { get; set; } + + [DataMember] + public Guid Guid { get; set; } + + [DataMember] + public bool Bool { get; set; } + + [DataMember] + public DateTime DateTime { get; set; } + + [DataMember] + public double Double { get; set; } + } + + [DataContract] + public class EchoRequestResponse + { + [DataMember] + public string Result { get; set; } + } + + public class EchoRequestService : Service + { + public object Any(EchoRequest request) + { + return request; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs new file mode 100644 index 00000000000..4a4670da5b6 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs @@ -0,0 +1,175 @@ +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + public class GetsOnly { } + public class PostsOnly { } + public class PutsOnly { } + public class DeletesOnly { } + public class AnyRequest { } + public class Response { } + + [Restrict(VisibleLocalhostOnly = true)] + public class VisibleLocalhost { } + [Restrict(VisibleInternalOnly = true)] + public class VisibleInternal { } + + [Restrict(LocalhostOnly = true)] + public class LocalhostOnly { } + [Restrict(InternalOnly = true)] + public class InternalOnly { } + + [Restrict(RequestAttributes.Xml)] + public class XmlOnly { } + [Restrict(RequestAttributes.Json)] + public class JsonOnly { } + [Restrict(RequestAttributes.Jsv)] + public class JsvOnly { } + [Restrict(RequestAttributes.Csv)] + public class CsvOnly { } + [Restrict(RequestAttributes.ProtoBuf)] + public class ProtoBufOnly { } + [Restrict(RequestAttributes.Soap11)] + public class Soap11Only { } + [Restrict(RequestAttributes.Soap12)] + public class Soap12Only { } + [Restrict(RequestAttributes.FormatOther)] + public class OtherFormatOnly { } + + [Restrict( + RequestAttributes.InternalNetworkAccess | RequestAttributes.Json, + RequestAttributes.External | RequestAttributes.Xml)] + public class JsonInternalXmlExternal { } + + [Restrict(RequestAttributes.Secure)] + public class SslOnly { } + + [Restrict(RequestAttributes.Secure | RequestAttributes.External, + RequestAttributes.InSecure | RequestAttributes.InternalNetworkAccess)] + public class SslExternalAndInsecureInternal { } + + + public class ReturnsHttpResult + { + public int Id { get; set; } + } + + public class ReturnsHttpResultWithMarkerResult{} + public class ReturnsHttpResultWithMarker : IReturn<ReturnsHttpResultWithMarkerResult> + { + public int Id { get; set; } + } + public class ReturnsHttpResultWithResponseResponse { } + public class ReturnsHttpResultWithResponse + { + public int Id { get; set; } + } + + public class EndpointAccessService : Service + { + public Response Get(GetsOnly request) + { + return new Response(); + } + + public Response Post(PostsOnly request) + { + return new Response(); + } + + public Response Put(PutsOnly request) + { + return new Response(); + } + + public Response Delete(DeletesOnly request) + { + return new Response(); + } + + public Response Any(AnyRequest request) + { + return new Response(); + } + + public Response Any(VisibleLocalhost request) + { + return new Response(); + } + + public Response Any(VisibleInternal request) + { + return new Response(); + } + + public Response Any(LocalhostOnly request) + { + return new Response(); + } + + public Response Any(InternalOnly request) + { + return new Response(); + } + + public Response Any(XmlOnly request) + { + return new Response(); + } + + public Response Any(JsonOnly request) + { + return new Response(); + } + + public Response Any(JsvOnly request) + { + return new Response(); + } + + public Response Any(CsvOnly request) + { + return new Response(); + } + + public Response Any(ProtoBufOnly request) + { + return new Response(); + } + + public Response Any(Soap11Only request) + { + return new Response(); + } + + public Response Any(Soap12Only request) + { + return new Response(); + } + + public Response Any(OtherFormatOnly request) + { + return new Response(); + } + + public Response Any(JsonInternalXmlExternal request) + { + return new Response(); + } + + public HttpResult Any(ReturnsHttpResult request) + { + return new HttpResult(); + } + + public HttpResult Any(ReturnsHttpResultWithMarker request) + { + return new HttpResult(); + } + + public HttpResult Any(ReturnsHttpResultWithResponse request) + { + return new HttpResult(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs index 889adb805cf..3438b6fbcb5 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs @@ -1,71 +1,107 @@ -using System; -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.ServiceInterface; -using ServiceStack.Validation; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [RestService("/fileuploads/{RelativePath*}", HttpMethods.Get)] - [RestService("/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 - : RestServiceBase<FileUpload> - { - public override object OnGet(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 override object OnPost(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(), - }; - } - } - +using System; +using System.IO; +using System.Runtime.Serialization; +using System.ServiceModel.Dispatcher; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [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 8c6698c717d..f940bd7dfdf 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/GeoInfoService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/GeoInfoService.cs @@ -1,52 +1,49 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - //Request DTO - [RestService("/geoinfo")] - [DataContract] - public class GeoInfo - { - [DataMember] - public string AppToken { get; set; } - - [DataMember] - public int OrderId { get; set; } - - [DataMember] - public GeoPoint GeoCode { get; set; } - } - - [Serializable] - public class GeoPoint - { - public long t { get; set; } - public decimal latitude { get; set; } - public decimal longitude { get; set; } - } - - //Response DTO - public class GeoInfoResponse : IHasResponseStatus - { - public string Result { get; set; } - public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized - } - - public class GeoInfoService : RestServiceBase<GeoInfo> - { - public override object OnPost(GeoInfo request) - { - return new GeoInfoResponse - { - Result = "Incoming Geopoint: Latitude=" - + request.GeoCode.latitude.ToString() - + " Longitude=" - + request.GeoCode.longitude.ToString() - }; - } - } +using System; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + //Request DTO + [Route("/geoinfo")] + [DataContract] + public class GeoInfo + { + [DataMember] + public string AppToken { get; set; } + + [DataMember] + public int OrderId { get; set; } + + [DataMember] + public GeoPoint GeoCode { get; set; } + } + + [Serializable] + public class GeoPoint + { + public long t { get; set; } + public decimal latitude { get; set; } + public decimal longitude { get; set; } + } + + //Response DTO + public class GeoInfoResponse : IHasResponseStatus + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized + } + + public class GeoInfoService : Service + { + public object Post(GeoInfo request) + { + return new GeoInfoResponse + { + Result = "Incoming Geopoint: Latitude=" + + request.GeoCode.latitude.ToString() + + " Longitude=" + + request.GeoCode.longitude.ToString() + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloImage.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloImage.cs index 805cd6472cf..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 { - [RestService("/HelloImage")] + [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)) { @@ -29,12 +30,12 @@ public object Execute(HelloImage request) } } - [RestService("/HelloImage2")] + [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)) { @@ -52,11 +53,11 @@ public object Execute(HelloImage2 request) } } - [RestService("/HelloImage3")] + [Route("/HelloImage3")] 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 89ee09b7888..3679f202e1d 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloService.cs @@ -1,65 +1,71 @@ -using System.ComponentModel; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [Description("ServiceStack's Hello World web service.")] - [RestService("/hello")] - [RestService("/hello/{Name}")] - public class Hello - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class HelloResponse - { - [DataMember] - public string Result { get; set; } - } - - public class HelloService : IService<Hello> - { - public object Execute(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } - } - - public class TestFilterAttribute : ResponseFilterAttribute - { - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) - { - } - } - - [RestService("/hello2")] - [RestService("/hello2/{Name}")] - public class Hello2 - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class Hello2Response - { - [DataMember] - public string Result { get; set; } - } - - [TestFilter] - public class Hello2Service : IService<Hello2> - { - public object Execute(Hello2 request) - { - return request.Name; - } - } - - +using System.ComponentModel; +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Description("ServiceStack's Hello World web service.")] + [Route("/hello", Summary = @"Default hello service.", Notes = "Longer description for hello service.")] + [Route("/hello/{Name}", "GET", Summary = @"Says ""Hello"" to provided Name with GET.", + Notes = "Longer description of the GET method which says \"Hello\"")] + [Route("/hello/{Name}", "POST", Summary = @"Says ""Hello"" to provided Name with POST.", + Notes = "Longer description of the POST method which says \"Hello\"")] + [Route("/hello/{Name}", "PUT", Summary = @"Says ""Hello"" to provided Name with PUT.", + Notes = "Longer description of the PUT method which says \"Hello\"")] + [Route("/hello/{Name}", "DELETE", Summary = @"Says ""Hello"" to provided Name with DELETE.", + Notes = "Longer description of the DELETE method which says \"Hello\"")] + public class Hello + { + [DataMember] + [ApiMember(Name = "Name", Description = "Name Description", ParameterType = "path", + DataType = "string", IsRequired = true)] + public string Name { get; set; } + } + + [DataContract] + public class HelloResponse + { + [DataMember] + public string Result { get; set; } + } + + public class HelloService : IService + { + public object Any(Hello request) + { + return new HelloResponse { Result = "Hello, " + request.Name }; + } + } + + public class TestFilterAttribute : ResponseFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object responseDto) {} + } + + [Route("/hello2")] + [Route("/hello2/{Name}")] + public class Hello2 + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class Hello2Response + { + [DataMember] + public string Result { get; set; } + } + + [TestFilter] + public class Hello2Service : IService + { + public object Any(Hello2 request) + { + return request.Name; + } + } + + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs index ed6fe488fb5..5b4d3130c88 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs @@ -1,14 +1,10 @@ -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 { - [RestService("/httpresults")] + [Route("/httpresults")] [DataContract] public class HttpResults { @@ -32,10 +28,9 @@ public HttpResultsResponse() public ResponseStatus ResponseStatus { get; set; } } - public class HttpResultsService - : ServiceBase<HttpResults> + public class HttpResultsService : Service { - protected override object Run(HttpResults request) + public object Any(HttpResults request) { if (request.Name == "Error") throw new HttpError(HttpStatusCode.NotFound, "Error NotFound"); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/IocServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/IocServiceTests.cs deleted file mode 100644 index ceba024cc50..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 feda0584cd6..346d6e8d56e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/MovieService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/MovieService.cs @@ -1,156 +1,150 @@ -using System; -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; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - - [RestService("/movies", "POST,PUT,PATCH")] - [RestService("/movies/{Id}")] - [DataContract] - public class Movie - { - public Movie() - { - this.Genres = new List<string>(); - } - - [DataMember] - [AutoIncrement] - public int Id { get; set; } - - [DataMember] - public string ImdbId { get; set; } - - [DataMember] - public string Title { get; set; } - - [DataMember] - public decimal Rating { get; set; } - - [DataMember] - public string Director { get; set; } - - [DataMember] - public DateTime ReleaseDate { get; set; } - - [DataMember] - public string TagLine { get; set; } - - [DataMember] - public List<string> Genres { get; set; } - - #region AutoGen ReSharper code, only required by tests - public bool Equals(Movie other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Equals(other.ImdbId, ImdbId) - && 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 int GetHashCode() - { - return ImdbId != null ? ImdbId.GetHashCode() : 0; - } - #endregion - } - - [DataContract] - public class MovieResponse - { - [DataMember] - public Movie Movie { get; set; } - } - - - public class MovieService : RestServiceBase<Movie> - { - public IDbConnectionFactory DbFactory { get; set; } - - /// <summary> - /// GET /movies/{Id} - /// </summary> - public override object OnGet(Movie movie) - { - return new MovieResponse { - Movie = DbFactory.Run(db => db.GetById<Movie>(movie.Id)) - }; - } - - /// <summary> - /// POST /movies - /// </summary> - public override object OnPost(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 } - } - }; - } - - /// <summary> - /// PUT /movies - /// </summary> - public override object OnPut(Movie movie) - { - DbFactory.Run(db => db.Update(movie)); - return new MovieResponse(); - } - - /// <summary> - /// DELETE /movies/{Id} - /// </summary> - public override object OnDelete(Movie request) - { - DbFactory.Run(db => db.DeleteById<Movie>(request.Id)); - return new MovieResponse(); - } - - /// <summary> - /// PATCH /movies - /// </summary> - public override object OnPatch(Movie movie) - { - DbFactory.Run(db => { - var existingMovie = db.GetById<Movie>(movie.Id); - if (movie.Title != null) - existingMovie.Title = movie.Title; - db.Save(existingMovie); - }); - return new MovieResponse(); - } - } - +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.Serialization; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +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}")] + [DataContract] + public class Movie + { + public Movie() + { + this.Genres = new List<string>(); + } + + [DataMember(Order = 1)] + [AutoIncrement] + 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 decimal Rating { get; set; } + + [DataMember(Order = 5)] + public string Director { get; set; } + + [DataMember(Order = 6)] + public DateTime ReleaseDate { get; set; } + + [DataMember(Order = 7)] + public string TagLine { get; set; } + + [DataMember(Order = 8)] + public List<string> Genres { get; set; } + + #region AutoGen ReSharper code, only required by tests + public bool Equals(Movie other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.ImdbId, ImdbId) + && 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 int GetHashCode() + { + return ImdbId != null ? ImdbId.GetHashCode() : 0; + } + #endregion + } + + [DataContract] + public class MovieResponse + { + [DataMember] + public Movie Movie { get; set; } + } + + public class MovieService : Service + { + /// <summary> + /// GET /movies/{Id} + /// </summary> + public object Get(Movie movie) + { + return new MovieResponse { + Movie = Db.SingleById<Movie>(movie.Id) + }; + } + + /// <summary> + /// POST /movies + /// </summary> + public object Post(Movie movie) + { + 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> + /// PUT /movies + /// </summary> + public object Put(Movie movie) + { + Db.Update(movie); + return new MovieResponse(); + } + + /// <summary> + /// DELETE /movies/{Id} + /// </summary> + public object Delete(Movie request) + { + Db.DeleteById<Movie>(request.Id); + return new MovieResponse(); + } + + /// <summary> + /// PATCH /movies + /// </summary> + public object Patch(Movie movie) + { + var existingMovie = Db.SingleById<Movie>(movie.Id); + if (movie.Title != null) + existingMovie.Title = movie.Title; + Db.Save(existingMovie); + + return new MovieResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs index 361e58797ca..2fc70884833 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs @@ -1,49 +1,43 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - - [DataContract] - [RestService("/movies", "GET, OPTIONS")] - [RestService("/movies/genres/{Genre}")] - public class Movies - { - [DataMember] - public string Genre { get; set; } - - [DataMember] - public Movie Movie { get; set; } - } - - [DataContract] - public class MoviesResponse - { - [DataMember] - public List<Movie> Movies { get; set; } - } - - public class MoviesService : RestServiceBase<Movies> - { - public IDbConnectionFactory DbFactory { get; set; } - - /// <summary> - /// GET /movies - /// GET /movies/genres/{Genre} - /// </summary> - public override object OnGet(Movies request) - { - return new MoviesResponse - { - Movies = request.Genre.IsNullOrEmpty() - ? DbFactory.Run(db => db.Select<Movie>()) - : DbFactory.Run(db => db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%")) - }; - } - } - +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack.OrmLite; +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; } + + [DataMember] + public Movie Movie { get; set; } + } + + [DataContract] + public class MoviesResponse + { + [DataMember(Order = 1)] + public List<Movie> Movies { get; set; } + } + + 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 609a40fb471..e3be1f673f4 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/MqHostStatsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/MqHostStatsService.cs @@ -1,33 +1,30 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.Messaging; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - public class MqHostStats - { - [DataMember] - public string Value { get; set; } - } - - [DataContract] - public class MqHostStatsResponse - { - [DataMember] - public string Result { get; set; } - } - - public class MqHostStatsService - : ServiceBase<MqHostStats> - { - public IMessageService MessageService { get; set; } - - protected override object Run(MqHostStats request) - { - return new MqHostStatsResponse { Result = MessageService.GetStatsDescription() }; - } - } - +using System.Runtime.Serialization; +using ServiceStack.Messaging; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + public class MqHostStats + { + [DataMember] + public string Value { get; set; } + } + + [DataContract] + public class MqHostStatsResponse + { + [DataMember] + public string Result { get; set; } + } + + public class MqHostStatsService : Service + { + public IMessageService MessageService { get; set; } + + public object Any(MqHostStats request) + { + return new MqHostStatsResponse { Result = MessageService.GetStatsDescription() }; + } + } + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs index 796ef30b7ed..0d591337b7f 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs @@ -1,47 +1,44 @@ -using System.Collections.Generic; -using ServiceStack.MiniProfiler; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [RestService("/profiler", "GET")] - [RestService("/profiler/{Type}", "GET")] - public class MiniProfiler - { - public string Type { get; set; } - } - - public class MiniProfilerService : ServiceBase<MiniProfiler> - { - public IDbConnectionFactory DbFactory { get; set; } - - protected override object Run(MiniProfiler request) - { - var profiler = Profiler.Current; - - using (var db = DbFactory.OpenDbConnection()) - 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; - } - } - - using (profiler.Step("Simple Select all")) - { - return db.Select<Movie>(); - } - } - } - } +using System.Collections.Generic; +using System.Linq; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.MiniProfiler; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [ExcludeMetadata] + [Route("/profiler", "GET")] + [Route("/profiler/{Type}", "GET")] + public class MiniProfiler + { + public string Type { get; set; } + } + + public class MiniProfilerService : Service + { + public IDbConnectionFactory DbFactory { get; set; } + + public object Any(MiniProfiler request) + { + var profiler = Profiler.Current; + + using (var db = DbFactory.OpenDbConnection()) + using (profiler.Step("MiniProfiler Service")) + { + if (request.Type == "n1") + { + using (profiler.Step("N + 1 query")) + { + return db.Select<Movie>().Select(movie => db.SingleById<Movie>(movie.Id)).ToList(); + } + } + + using (profiler.Step("Simple Select all")) + { + return db.Select<Movie>(); + } + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs index 9cf07af5929..1b08d75f158 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs @@ -1,38 +1,33 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - public class RequestFilter - { - [DataMember] - public int StatusCode { get; set; } - - [DataMember] - public string HeaderName { get; set; } - - [DataMember] - public string HeaderValue { get; set; } - } - - [DataContract] - public class RequestFilterResponse - { - [DataMember] - public string Value { get; set; } - } - - public class StatusCodeService - : ServiceBase<RequestFilter>, IRequiresRequestContext - { - new public IRequestContext RequestContext { get; set; } - - protected override object Run(RequestFilter request) - { - return new RequestFilterResponse(); - } - } +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + public class RequestFilter + { + [DataMember] + public int StatusCode { get; set; } + + [DataMember] + public string HeaderName { get; set; } + + [DataMember] + public string HeaderValue { get; set; } + } + + [DataContract] + public class RequestFilterResponse + { + [DataMember] + public string Value { get; set; } + } + + public class StatusCodeService : Service + { + public object Any(RequestFilter request) + { + return new RequestFilterResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs new file mode 100644 index 00000000000..2a807219d60 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs @@ -0,0 +1,29 @@ +using System; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/req-items")] + public class RequestItems + { + } + + public class RequestItemsResponse : IHasResponseStatus + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class RequestItemsService : Service + { + public object Any(RequestItems request) + { + if (!Request.Items.ContainsKey("_DataSetAtPreRequestFilters")) + throw new InvalidOperationException("DataSetAtPreRequestFilters missing."); + + if (!Request.Items.ContainsKey("_DataSetAtRequestFilters")) + throw new InvalidOperationException("DataSetAtRequestFilters data missing."); + + return new RequestItemsResponse { Result = "MissionSuccess" }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs index 5838a9acdf0..19ef458e8d6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs @@ -1,57 +1,77 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.Serialization; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - - [DataContract] - [Description("Resets the database back to the original Top 5 movies.")] - [RestService("/reset-movies")] - public class ResetMovies { } - - [DataContract] - public class ResetMoviesResponse - : IHasResponseStatus - { - public ResetMoviesResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class ResetMoviesService : RestServiceBase<ResetMovies> - { - public static List<Movie> Top5Movies = new List<Movie> - { - 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"}, }, - new Movie { ImdbId = "tt0068646", Title = "The Godfather", Rating = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List<string> {"Crime","Drama", "Thriller"}, }, - new Movie { ImdbId = "tt1375666", Title = "Inception", Rating = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List<string>{"Action", "Mystery", "Sci-Fi", "Thriller"}, }, - new Movie { ImdbId = "tt0071562", Title = "The Godfather: Part II", Rating = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List<string> {"Crime","Drama", "Thriller"}, }, - new Movie { ImdbId = "tt0060196", Title = "The Good, the Bad and the Ugly", Rating = 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<string>{"Adventure","Western"}, }, - }; - - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnPost(ResetMovies request) - { - DbFactory.Run(db => - { - const bool overwriteTable = true; - db.CreateTable<Movie>(overwriteTable); - db.SaveAll(Top5Movies); - }); - - return new ResetMoviesResponse(); - } - } - +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Description("Resets the database back to the original Top 5 movies.")] + [Route("/reset-movies")] + public class ResetMovies : IReturn<ResetMoviesResponse> { } + + [DataContract] + public class ResetMoviesResponse : IHasResponseStatus + { + public ResetMoviesResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ResetMoviesService : Service + { + public static List<Movie> Top5Movies = new List<Movie> + { + 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"}, }, + new Movie { ImdbId = "tt0068646", Title = "The Godfather", Rating = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List<string> {"Crime","Drama", "Thriller"}, }, + new Movie { ImdbId = "tt1375666", Title = "Inception", Rating = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List<string>{"Action", "Mystery", "Sci-Fi", "Thriller"}, }, + new Movie { ImdbId = "tt0071562", Title = "The Godfather: Part II", Rating = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List<string> {"Crime","Drama", "Thriller"}, }, + new Movie { ImdbId = "tt0060196", Title = "The Good, the Bad and the Ugly", Rating = 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<string>{"Adventure","Western"}, }, + }; + + public IDbConnectionFactory DbFactory { get; set; } + + public object Post(ResetMovies request) + { + const bool overwriteTable = true; + Db.CreateTable<Movie>(overwriteTable); + Db.SaveAll(Top5Movies); + + 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 new file mode 100644 index 00000000000..306083ff42f --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReturnsVoidService.cs @@ -0,0 +1,14 @@ +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/returnsvoid")] + public class ReturnsVoid : IReturnVoid + { + public string Name { get; set; } + } + + public class ReturnsVoidService : IService + { + public void Any(ReturnsVoid request) {} + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs index dcbbd7115ca..f9644bdff17 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs @@ -1,37 +1,58 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - public class Reverse - { - [DataMember] - public string Value { get; set; } - } - - [DataContract] - public class ReverseResponse - { - [DataMember] - public string Result { get; set; } - } - - public class ReverseService - : ServiceBase<Reverse> - { - protected override object Run(Reverse request) - { - return new ReverseResponse { Result = Execute(request.Value) }; - } - - public static string Execute(string value) - { - var valueBytes = value.ToCharArray(); - Array.Reverse(valueBytes); - return new string(valueBytes); - } - } - +using System; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + public class Reverse + { + [DataMember] + public string Value { get; set; } + } + + [DataContract] + public class ReverseResponse + { + [DataMember] + 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 + : Service + { + public object Any(Reverse request) + { + return new ReverseResponse { Result = Execute(request.Value) }; + } + + public static string Execute(string value) + { + var valueBytes = value.ToCharArray(); + 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 33b45e844df..855506439d8 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/Rot13Service.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/Rot13Service.cs @@ -1,29 +1,28 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; -using ServiceStack.Text; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - public class Rot13 - { - [DataMember] - public string Value { get; set; } - } - - [DataContract] - public class Rot13Response - { - [DataMember] - public string Result { get; set; } - } - - public class Rot13Service - : ServiceBase<Rot13> - { - protected override object Run(Rot13 request) - { - return new Rot13Response { Result = request.Value.ToRot13() }; - } - } +using System.Runtime.Serialization; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + public class Rot13 + { + [DataMember] + public string Value { get; set; } + } + + [DataContract] + public class Rot13Response + { + [DataMember] + public string Result { get; set; } + } + + public class Rot13Service + : Service + { + public object Any(Rot13 request) + { + return new Rot13Response { Result = request.Value.ToRot13() }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteInfoService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteInfoService.cs deleted file mode 100644 index ebfc9919027..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")] - [RestService("/RouteInfo", "POST")] - [RestService("/RouteInfo/{AppToken}")] - [RestService("/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 : ServiceBase<RouteInfo> - { - protected override object Run(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 5ccddf557b0..c63a8bd92d8 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs @@ -1,37 +1,156 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; - -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 - : ServiceBase<Secure> - { - protected override object Run(Secure request) - { - throw new UnauthorizedAccessException("You shouldn't be able to see this"); - } - } +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +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; } + } + + [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"); + } + + 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 5badbc4875d..9f9780eb9cd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionService.cs @@ -1,65 +1,41 @@ -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 - { - public int Counter { get; set; } - } - - [RestService("/session")] - public class Session - { - public string Value { get; set; } - } - - public class SessionResponse - { - public CustomSession Typed { get; set; } - public CustomSession UnTyped { get; set; } - } - - public class SessionService - : ServiceBase<Session> - { - //public ISessionFactory SessionFactory { get; set; } - - //private ISession session; - //public ISession Session - //{ - // get - // { - // return session ?? (session = - // SessionFactory.GetOrCreateSession( - // new HttpRequestWrapper(null, HttpContext.Current.Request), - // new HttpResponseWrapper(HttpContext.Current.Response) - // )); - // } - //} - - protected override object Run(Session request) - { - var untyped = Session["untyped"] as CustomSession ?? new CustomSession(); - var typed = Session.Get<CustomSession>("typed") ?? new CustomSession(); - - untyped.Counter++; - typed.Counter++; - - Session["untyped"] = untyped; - Session.Set("typed", typed); - - var response = new SessionResponse { - Typed = typed, - UnTyped = untyped, - }; - - return response; - } - } +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + public class CustomSession + { + public int Counter { get; set; } + } + + [Route("/session")] + public class Session + { + public string Value { get; set; } + } + + public class SessionResponse + { + public CustomSession Typed { get; set; } + public CustomSession UnTyped { get; set; } + } + + public class SessionService : Service + { + public object Any(Session request) + { + var untyped = SessionBag["untyped"] as CustomSession ?? new CustomSession(); + var typed = SessionBag.Get<CustomSession>("typed") ?? new CustomSession(); + + untyped.Counter++; + typed.Counter++; + + SessionBag["untyped"] = untyped; + SessionBag.Set("typed", typed); + + var response = new SessionResponse { + Typed = typed, + UnTyped = untyped, + }; + + return response; + } + } } \ No newline at end of file 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 new file mode 100644 index 00000000000..933ce51267b --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/SwaggerTestService.cs @@ -0,0 +1,328 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Net; +using System.Runtime.Serialization; +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")] + [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] + [ApiAllowableValues("ColorDesc", typeof(MyColorDesc))] //Enum + [DataMember] + public MyColorDesc ColorDesc { 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<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 cec583ee917..63bb5b60d6c 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/TestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/TestService.cs @@ -1,35 +1,33 @@ -using System.ComponentModel; -using System.Runtime.Serialization; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [Description("ServiceStack's Test World web service.")] - [RestService("/test")] - [RestService("/test/{Name}")] - public class Test - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class TestResponse - { - [DataMember] - public string Result { get; set; } - } - - public class TestService : IService<Test> - { - public object Execute(Test request) - { - var client = new Soap12ServiceClient("http://localhost/ServiceStack.WebHost.IntegrationTests/api/"); - var response = client.Send<HelloResponse>(new Hello { Name = request.Name }); - return new TestResponse { Result = response.Result }; - } - } - +using System.ComponentModel; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Description("ServiceStack's Test World web service.")] + [Route("/test")] + [Route("/test/{Name}")] + public class Test + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class TestResponse + { + [DataMember] + public string Result { get; set; } + } + + public class TestService : IService + { + 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 }); + return new TestResponse { Result = response.Result }; + } + } + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs index d10b4f913a1..bc46cf128db 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs @@ -1,41 +1,37 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [RestService("/throwsargumentnull")] - [DataContract] - public class ThrowsArgumentNull - { - [DataMember] - public string Value { get; set; } - } - - [DataContract] - public class ThrowsArgumentNullResponse - : IHasResponseStatus - { - public ThrowsArgumentNullResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public string Result { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class ThrowsArgumentNullService - : ServiceBase<ThrowsArgumentNull> - { - protected override object Run(ThrowsArgumentNull request) - { - throw new ArgumentNullException("Name"); - } - } +using System; +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/throwsargumentnull")] + [DataContract] + public class ThrowsArgumentNull + { + [DataMember] + public string Value { get; set; } + } + + [DataContract] + public class ThrowsArgumentNullResponse + : IHasResponseStatus + { + public ThrowsArgumentNullResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public string Result { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ThrowsArgumentNullService : Service + { + public object Any(ThrowsArgumentNull request) + { + throw new ArgumentNullException("Name"); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs index 50ca32f8547..a59267d1089 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs @@ -1,44 +1,39 @@ -using System.Collections.Generic; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [RestService("/userauths")] - public class UserAuths - { - public int[] Ids { get; set; } - } - - public class UserAuthsResponse : IHasResponseStatus - { - public UserAuthsResponse() - { - this.Results = new List<UserAuth>(); - this.OAuthProviders = new List<UserOAuthProvider>(); - } - - public List<UserAuth> Results { get; set; } - - public List<UserOAuthProvider> 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 : ServiceBase<UserAuths> - { - public IDbConnectionFactory DbFactory { get; set; } - - protected override object Run(UserAuths request) - { - return new UserAuthsResponse { - Results = DbFactory.Run(db => db.Select<UserAuth>()), - OAuthProviders = DbFactory.Run(db => db.Select<UserOAuthProvider>()), - }; - } - } +using System.Collections.Generic; +using ServiceStack.Auth; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/userauths")] + public class UserAuths + { + public int[] Ids { get; set; } + } + + public class UserAuthsResponse : IHasResponseStatus + { + public UserAuthsResponse() + { + this.Results = new List<UserAuth>(); + this.OAuthProviders = new List<UserAuthDetails>(); + } + + public List<UserAuth> Results { 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 : Service + { + public object Any(UserAuths request) + { + return new UserAuthsResponse { + Results = Db.Select<UserAuth>(), + OAuthProviders = Db.Select<UserAuthDetails>(), + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs index eff0b0b99b4..6ed8c9716c6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs @@ -1,57 +1,56 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [RestService("/VerbMatch", "GET,DELETE")] - [RestService("/VerbMatch/{Name}", "GET,DELETE")] - public class VerbMatch1 - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class VerbMatch1Response - { - [DataMember] - public string Result { get; set; } - } - - public class VerbMatch1Service : IService<VerbMatch1>, IRestService<VerbMatch1> - { - public object Execute(VerbMatch1 request) - { - throw new NotImplementedException(); - } - - public object Get(VerbMatch1 request) - { - return new VerbMatch1Response { Result = HttpMethods.Get }; - } - - public object Post(VerbMatch1 request) - { - return new VerbMatch1Response { Result = HttpMethods.Post }; - } - - public object Put(VerbMatch1 request) - { - return new VerbMatch1Response { Result = HttpMethods.Put }; - } - - public object Delete(VerbMatch1 request) - { - return new VerbMatch1Response { Result = HttpMethods.Delete }; - } - - public object Patch(VerbMatch1 request) - { - return new VerbMatch1Response { Result = HttpMethods.Patch }; - } - } - +using System; +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/VerbMatch", "GET,DELETE")] + [Route("/VerbMatch/{Name}", "GET,DELETE")] + public class VerbMatch1 + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class VerbMatch1Response + { + [DataMember] + public string Result { get; set; } + } + + public class VerbMatch1Service : IService + { + public object Any(VerbMatch1 request) + { + throw new NotImplementedException(); + } + + public object Get(VerbMatch1 request) + { + return new VerbMatch1Response { Result = HttpMethods.Get }; + } + + public object Post(VerbMatch1 request) + { + return new VerbMatch1Response { Result = HttpMethods.Post }; + } + + public object Put(VerbMatch1 request) + { + return new VerbMatch1Response { Result = HttpMethods.Put }; + } + + public object Delete(VerbMatch1 request) + { + return new VerbMatch1Response { Result = HttpMethods.Delete }; + } + + public object Patch(VerbMatch1 request) + { + return new VerbMatch1Response { Result = HttpMethods.Patch }; + } + } + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs index fb77e35ae5b..8b88342e814 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs @@ -1,57 +1,56 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [RestService("/VerbMatch", "POST,PUT,PATCH")] - [RestService("/VerbMatch/{Name}", "POST,PUT,PATCH")] - public class VerbMatch2 - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class VerbMatch2Response - { - [DataMember] - public string Result { get; set; } - } - - public class VerbMatch2Service : IService<VerbMatch2>, IRestService<VerbMatch2> - { - public object Execute(VerbMatch2 request) - { - throw new NotImplementedException(); - } - - public object Get(VerbMatch2 request) - { - return new VerbMatch2Response { Result = HttpMethods.Get }; - } - - public object Post(VerbMatch2 request) - { - return new VerbMatch2Response { Result = HttpMethods.Post }; - } - - public object Put(VerbMatch2 request) - { - return new VerbMatch2Response { Result = HttpMethods.Put }; - } - - public object Delete(VerbMatch2 request) - { - return new VerbMatch2Response { Result = HttpMethods.Delete }; - } - - public object Patch(VerbMatch2 request) - { - return new VerbMatch2Response { Result = HttpMethods.Patch }; - } - } - +using System; +using System.Runtime.Serialization; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/VerbMatch", "POST,PUT,PATCH")] + [Route("/VerbMatch/{Name}", "POST,PUT,PATCH")] + public class VerbMatch2 + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class VerbMatch2Response + { + [DataMember] + public string Result { get; set; } + } + + public class VerbMatch2Service : IService + { + public object Any(VerbMatch2 request) + { + throw new NotImplementedException(); + } + + public object Get(VerbMatch2 request) + { + return new VerbMatch2Response { Result = HttpMethods.Get }; + } + + public object Post(VerbMatch2 request) + { + return new VerbMatch2Response { Result = HttpMethods.Post }; + } + + public object Put(VerbMatch2 request) + { + return new VerbMatch2Response { Result = HttpMethods.Put }; + } + + public object Delete(VerbMatch2 request) + { + return new VerbMatch2Response { Result = HttpMethods.Delete }; + } + + public object Patch(VerbMatch2 request) + { + return new VerbMatch2Response { Result = HttpMethods.Patch }; + } + } + } \ No newline at end of file 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 e84749758d9..889d28b89f2 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/WildCardRequestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/WildCardRequestService.cs @@ -1,41 +1,48 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - [DataContract] - [RestService("/wildcard/{Id}/{Path}/{Action}")] - [RestService("/wildcard/{Id}/{RemainingPath*}")] - public class WildCardRequest - { - [DataMember] - public int Id { get; set; } - - [DataMember] - public string Path { get; set; } - - [DataMember] - public string RemainingPath { get; set; } - - [DataMember] - public string Action { get; set; } - } - - [DataContract] - public class WildCardRequestResponse - { - [DataMember] - public string Result { get; set; } - } - - public class WildCardRequestService - : ServiceBase<WildCardRequest> - { - protected override object Run(WildCardRequest request) - { - return request; - } - } +using System.Runtime.Serialization; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [DataContract] + [Route("/wildcard/{Id}/{Path}/{Action}")] + [Route("/wildcard/{Id}/{RemainingPath*}")] + public class WildCardRequest + { + [DataMember] + public int Id { get; set; } + + [DataMember] + public string Path { get; set; } + + [DataMember] + public string RemainingPath { get; set; } + + [DataMember] + public string Action { get; set; } + } + + [DataContract] + public class WildCardRequestResponse + { + [DataMember] + public string Result { get; set; } + } + + [Route("/path/{Tail*}")] + public class BasicWildcard + { + public string Tail { get; set; } + } + + public class WildCardRequestService : Service + { + public object Get(WildCardRequest request) + { + return request; + } + + public object Get(BasicWildcard request) + { + return request; + } + } } \ No newline at end of file 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/Soap11WebService.asmx.cs b/tests/ServiceStack.WebHost.IntegrationTests/Soap11WebService.asmx.cs index 0a1d57b7ca9..30b801d13cb 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Soap11WebService.asmx.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Soap11WebService.asmx.cs @@ -1,30 +1,30 @@ -using System.ComponentModel; -using System.Web.Services; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests -{ - /// <summary> - /// Summary description for Soap11WebService - /// </summary> - [WebService(Namespace = "http://schemas.servicestack.net/types")] - [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] - [ToolboxItem(false)] - // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. - // [System.Web.Script.Services.ScriptService] - public class Soap11WebService : System.Web.Services.WebService - { - - [WebMethod] - public string HelloWorld() - { - return "Hello World"; - } - - [WebMethod] - public ReverseResponse Reverse(Reverse request) - { - return new ReverseService().Execute(request) as ReverseResponse; - } - } -} +using System.ComponentModel; +using System.Web.Services; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests +{ + /// <summary> + /// Summary description for Soap11WebService + /// </summary> + [WebService(Namespace = "http://schemas.servicestack.net/types")] + [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] + [ToolboxItem(false)] + // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. + // [System.Web.Script.Services.ScriptService] + public class Soap11WebService : System.Web.Services.WebService + { + + [WebMethod] + public string HelloWorld() + { + return "Hello World"; + } + + [WebMethod] + public ReverseResponse Reverse(Reverse request) + { + return new ReverseService().Any(request) as ReverseResponse; + } + } +} diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx b/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx new file mode 100644 index 00000000000..e489660c587 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx @@ -0,0 +1,18 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Test.aspx.cs" Inherits="ServiceStack.WebHost.IntegrationTests.Subpages.Test" %> +<%@ Import Namespace="ServiceStack.Html" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> + <%=ServiceStack.MiniProfiler.Profiler.RenderIncludes(null, null, null, null, false, null).AsRaw() %> +</head> +<body> + <form id="form1" runat="server"> + <div> + Test Page + </div> + </form> +</body> +</html> diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx.cs b/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx.cs new file mode 100644 index 00000000000..a8c9a412b17 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.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 ServiceStack.WebHost.IntegrationTests.Subpages +{ + public partial class Test : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx.designer.cs b/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx.designer.cs new file mode 100644 index 00000000000..2d68c7d14f9 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Subpages/Test.aspx.designer.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace ServiceStack.WebHost.IntegrationTests.Subpages { + + + public partial class Test { + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} 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/default.html b/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/default.html index 0c88fcb6e91..ce40780fdd3 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/default.html +++ b/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/default.html @@ -1,15 +1,15 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <div> - Default Tests/ index page - </div> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + Default Tests/ index page + </div> + </form> +</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 2e024bdc118..3a6e1d1d0ed 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/upload.html +++ b/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/upload.html @@ -1,13 +1,13 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server" enctype="multipart/form-data"> - <label>Form Upload:</label> - <input type="file" value="upload" /> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server" enctype="multipart/form-data"> + <label>Form Upload:</label> + <input type="file" value="upload" /> + </form> +</body> +</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 ff842978b11..922f67ede89 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AppHostBaseTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AppHostBaseTests.cs @@ -1,44 +1,40 @@ -using System.Net; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - /// <summary> - /// Note: These tests don't test ServiceStack when its mounted at /api - /// </summary> - [TestFixture] - public class AppHostBaseTests - { - private const string BasePath = Config.AbsoluteBaseUri; - - [Test] - public void Root_path_redirects_to_metadata_page() - { - var html = Config.ServiceStackBaseUri.DownloadUrl(); - Assert.That(html.Contains("The following operations are supported.")); - } - - [Test] - public void Can_download_webpage_html_page() - { - var html = (BasePath + "webpage.html").DownloadUrl(); - 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_3_on_page_with_non_whitelisted_extension() - { - var webRes = (BasePath + "api/webpage.forbidden").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); - } - - } +using System.Net; +using NUnit.Framework; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class AppHostBaseTests + { + private const string BasePath = Config.AbsoluteBaseUri; + + [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() + { + var html = (BasePath + "webpage.html").GetStringFromUrl(); + Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); + } + + [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_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 2655c14c8b1..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 - { - private const string BaseUri = Config.ServiceStackBaseUri; - public const string AdminEmail = "admin@servicestack.com"; - private const string AdminPassword = "E8828A3E26884CE0B345D0D2DFED358A"; - - 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<RegistrationResponse>(registration); - } - catch (WebServiceException ex) - { - Console.WriteLine("Error while creating Admin User: " + ex.Message); - Console.WriteLine(ex.ResponseDto.Dump()); - } - return registration; - } - - public JsonServiceClient Login(string userName, string password) - { - var client = new JsonServiceClient(BaseUri); - client.Send<AuthResponse>(new Auth { - UserName = userName, - Password = password, - RememberMe = true, - }); - - return client; - } - - public JsonServiceClient AuthenticateWithAdminUser() - { - var registration = CreateAdminUser(); - var adminServiceClient = new JsonServiceClient(BaseUri); - adminServiceClient.Send<AuthResponse>(new Auth { - UserName = registration.UserName, - Password = registration.Password, - RememberMe = true, - }); - - 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())); - } - - } - +using System; +using System.Net; +using NUnit.Framework; +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"; + + private IServiceClient serviceClient; + public IServiceClient ServiceClient + { + get + { + return serviceClient ?? (serviceClient = new JsonServiceClient(BaseUri)); + } + } + + 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 Authenticate + { + UserName = userName, + Password = password, + RememberMe = true, + }); + + return client; + } + + 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; + } + + 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 new file mode 100644 index 00000000000..61ba99b6bd3 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/BinarySerializedTests.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Text; +using NUnit.Framework; +using ServiceStack.ProtoBuf; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class BinarySerializedTests + { + private string RandomString(int Length) + { + var rnd = new Random(); + var tmp = new StringBuilder(); + for (Int64 i = 0; i < Length; i++) + { + tmp.Append(Convert.ToChar(((byte)rnd.Next(254))).ToString()); + } + return Convert.ToBase64String(tmp.ToString().ToUtf8Bytes()); + } + + [Test] + public void Can_serialize_RandomString() + { + var rand = RandomString(32); + using (var ms = new MemoryStream()) + { + global::ProtoBuf.Serializer.Serialize(ms, rand); + ms.Position = 0; + var fromBytes = global::ProtoBuf.Serializer.Deserialize<string>(ms); + + Assert.That(rand, Is.EqualTo(fromBytes)); + } + } + + [Test] + public void Can_call_cached_WebService_with_Protobuf() + { + var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); + + try + { + var fromEmail = RandomString(32); + var response = client.Post<ProtoBufEmail>("/cached/protobuf", new CachedProtoBufEmail + { + FromAddress = fromEmail + }); + + Assert.That(response.FromAddress, Is.EqualTo(fromEmail)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void Can_call_WebService_with_Protobuf() + { + //new ProtoBufServiceTests().Can_Send_ProtoBuf_request(); + + var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); + + try + { + var fromEmail = RandomString(32); + var response = client.Post<ProtoBufEmail>("/cached/protobuf", new UncachedProtoBufEmail + { + FromAddress = fromEmail + }); + + Assert.That(response.FromAddress, Is.EqualTo(fromEmail)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs index b32b83aa0bb..0b86f46665d 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs @@ -1,35 +1,58 @@ -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [TestFixture] - public class CachedServiceTests - { - protected IRestClient CreateNewServiceClient() - { - return new JsonServiceClient(Config.ServiceStackBaseUri); - } - - [Test] - public void Can_call_Cached_WebService() - { - var client = CreateNewServiceClient(); - - var response = client.Get<MoviesResponse>("/cached/movies"); - - Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); - } - - [Test] - public void Can_call_Cached_WebService_with_JSONP() - { - var url = Config.ServiceStackBaseUri.CombineWith("/cached/movies?callback=cb"); - var jsonp = url.DownloadJsonFromUrl(); - Assert.That(jsonp.StartsWith("cb(")); - } - } +using NUnit.Framework; +using ServiceStack.Common; +using ServiceStack.ProtoBuf; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class CachedServiceTests + { + [OneTimeSetUp] + public void OnBeforeEachTest() + { + var jsonClient = new JsonServiceClient(Config.ServiceStackBaseUri); + jsonClient.Post<ResetMoviesResponse>("reset-movies", new ResetMovies()); + } + + [Test] + public void Can_call_Cached_WebService_with_JSON() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get<MoviesResponse>("/cached/movies"); + + Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + } + + [Test] + public void Can_call_Cached_WebService_with_ProtoBuf() + { + var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get<MoviesResponse>("/cached/movies"); + + Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + } + + [Test] + public void Can_call_Cached_WebService_with_ProtoBuf_without_compression() + { + var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); + client.DisableAutoCompression = true; + client.Get<MoviesResponse>("/cached/movies"); + var response2 = client.Get<MoviesResponse>("/cached/movies"); + + Assert.That(response2.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + } + + [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(")); + } + } } \ 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 8150465474c..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 const string AbsoluteBaseUri = "http://localhost:50000/"; - public const string ServiceStackBaseUri = AbsoluteBaseUri + "api"; - } +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + 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 2a977c2d579..9e1ff066d18 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CsvContentTypeFilterTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CsvContentTypeFilterTests.cs @@ -1,132 +1,124 @@ -using System; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [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); - } - - [SetUp] - public void SetUp() - { - // make sure that movies db is not modified - RestsTestBase.GetWebResponse(HttpMethods.Post, ServiceClientBaseUri + "reset-movies", ContentType.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); - - 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(ServiceClientBaseUri + "csv/syncreply/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 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_SyncReply_Path_and_alternate_XML_Accept_Header() - { - var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "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)); - 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; - - 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(ServiceClientBaseUri + "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(ServiceClientBaseUri + "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); - } - - } -} \ No newline at end of file +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +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 + "/"; + + 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", MimeTypes.Xml, 0); + } + + [Test] + public async Task Can_download_movies_in_Csv() + { + var client = new CsvServiceClient(ServiceClientBaseUri); + + var response = await client.GetAsync<MoviesResponse>(new Movies()); + + Assert.That(response, Is.Not.Null, "No response received"); + } + + [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(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], 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_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(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], 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_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(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], 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 = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/reply/Hello?Name=World!"); + + 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 = res.ReadToEnd(); + var lf = Environment.NewLine; + Assert.That(csv, Is.EqualTo("Result{0}\"Hello, World!\"{0}".Fmt(lf))); + + 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 = MimeTypes.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 = res.ReadToEnd(); + var lf = Environment.NewLine; + Assert.That(csv, Is.EqualTo("Result{0}\"Hello, World!\"{0}".Fmt(lf))); + + Console.WriteLine(csv); + } + + } +} diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs new file mode 100644 index 00000000000..12a8710718e --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs @@ -0,0 +1,42 @@ +using NUnit.Framework; +using ServiceStack.ProtoBuf; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class CustomHeadersTests + { + [Test] + public void GetRequest() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + client.Headers.Add("Foo", "abc123"); + var response = client.Get(new CustomHeaders()); + Assert.That(response.Foo, Is.EqualTo("abc123")); + Assert.That(response.Bar, Is.Null); + } + + [Test] + public void PostRequest() + { + var client = new XmlServiceClient(Config.ServiceStackBaseUri); + client.Headers.Add("Bar", "abc123"); + client.Headers.Add("Foo", "xyz"); + var response = client.Post(new CustomHeaders()); + Assert.That(response.Bar, Is.EqualTo("abc123")); + Assert.That(response.Foo, Is.EqualTo("xyz")); + } + + [Test] + public void Delete() + { + var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); + client.Headers.Add("Bar", "abc123"); + client.Headers.Add("Foo", "xyz"); + var response = client.Delete(new CustomHeaders()); + Assert.That(response.Bar, Is.EqualTo("abc123")); + Assert.That(response.Foo, Is.EqualTo("xyz")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomRequestDataTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomRequestDataTests.cs index dcf07e94f4d..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.Net; -using System.Web; -using NUnit.Framework; -using ServiceStack.Common.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; - - 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(); - - 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.Fail(errorResponse); - } - } - - } +using System.IO; +using System.Net; +using NUnit.Framework; +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 = MimeTypes.FormUrlEncoded; + + 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 = errorWebResponse.ReadToEnd(); + + 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 54d1c1d5dec..2966f00c770 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomerServiceValidationTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomerServiceValidationTests.cs @@ -1,119 +1,119 @@ -using System.Collections; -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; - - private string[] ExpectedPostErrorFields = new[] { - "Id", - "LastName", - "FirstName", - "Company", - "Address", - "Postcode", - }; - - private string[] ExpectedPostErrorCodes = new[] { - "NotEqual", - "ShouldNotBeEmpty", - "NotEmpty", - "NotNull", - "Length", - "Predicate", - }; - - 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", - }; - } - - 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<CustomersResponse>(new Customers()); - response.PrintDump(); - 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(IRestClient client) - { - try - { - var response = client.Get<CustomersResponse>("/Customers"); - response.PrintDump(); - 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(IServiceClient client) - { - var response = client.Send<CustomersResponse>(validRequest); - Assert.That(response.ResponseStatus, Is.Null); - } - - } - +using System.Collections; +using System.Linq; +using System.Net; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class CustomerServiceValidationTests + { + private const string ListeningOn = Config.ServiceStackBaseUri; + + private string[] ExpectedPostErrorFields = new[] { + "Id", + "LastName", + "FirstName", + "Company", + "Address", + "Postcode", + }; + + private string[] ExpectedPostErrorCodes = new[] { + "NotEqual", + "ShouldNotBeEmpty", + "NotEmpty", + "NotNull", + "NotNull", //Length returns true if null + "Predicate", + }; + + 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", + }; + } + + 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()); + 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(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(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); + } + + } + } \ 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 09e28bc3de8..4c6458ed256 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ExceptionHandlingTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ExceptionHandlingTests.cs @@ -1,42 +1,36 @@ using System; using System.Net; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.ServiceInterface; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; using NUnit.Framework; -using Funq; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [RestService("/users")] + [Route("/users")] public class User { } public class UserResponse : IHasResponseStatus { public ResponseStatus ResponseStatus { get; set; } } - public class UserService : RestServiceBase<User> + public class UserService : Service { - public override object OnGet(User request) + public object Get(User request) { return new HttpError(System.Net.HttpStatusCode.BadRequest, "CanNotExecute", "Failed to execute!"); } - public override object OnPost(User request) + public object Post(User request) { throw new HttpError(System.Net.HttpStatusCode.BadRequest, "CanNotExecute", "Failed to execute!"); } - public override object OnDelete(User request) + public object Delete(User request) { throw new HttpError(System.Net.HttpStatusCode.Forbidden, "CanNotExecute", "Failed to execute!"); } - public override object OnPut(User request) + public object Put(User request) { throw new ArgumentException(); } @@ -52,9 +46,9 @@ public class ExceptionWithResponseStatusResponse { public ResponseStatus ResponseStatus { get; set; } } - public class ExceptionWithResponseStatusService : ServiceBase<ExceptionWithResponseStatus> + public class ExceptionWithResponseStatusService : Service { - protected override object Run(ExceptionWithResponseStatus request) + public object Any(ExceptionWithResponseStatus request) { throw new CustomException(); } @@ -62,33 +56,71 @@ protected override object Run(ExceptionWithResponseStatus request) public class ExceptionNoResponseStatus { } public class ExceptionNoResponseStatusResponse { } - public class ExceptionNoResponseStatusService : ServiceBase<ExceptionNoResponseStatus> + public class ExceptionNoResponseStatusService : Service { - protected override object Run(ExceptionNoResponseStatus request) + public object Any(ExceptionNoResponseStatus request) { throw new CustomException(); } } public class ExceptionNoResponseDto { } - public class ExceptionNoResponseDtoService : ServiceBase<ExceptionNoResponseDto> + public class ExceptionNoResponseDtoService : Service { - protected override object Run(ExceptionNoResponseDto request) + public object Any(ExceptionNoResponseDto request) { throw new CustomException(); } } + 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) @@ -163,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] @@ -172,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 } } @@ -190,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("{}")); } } @@ -207,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.EqualTo("")); + 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 3c3e7800429..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"); - - 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; - - Stream memStream = new System.IO.MemoryStream(); - - 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 header = string.Format(headerTemplate, "upload", fileInfo.Name, MimeTypes.GetMimeType(fileInfo.Name)); - - - - byte[] headerbytes = System.Text.Encoding.ASCII.GetBytes(header); - - 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); - - using (var fs = fileInfo.OpenRead()) - { - fs.WriteTo(memStream); - } - - memStream.Write(boundarybytes, 0, boundarybytes.Length); - - - //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); - - //memStream.Write(boundarybytes, 0, boundarybytes.Length); - - - httpWebRequest.ContentLength = memStream.Length; - - 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(); - - return httpWebRequest.GetResponse(); - } - - [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)); - }); - } - - [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(); - - var webResponse = webRequest.GetResponse(); - var actualContents = new StreamReader(webResponse.GetResponseStream()).ReadToEnd(); - - Assert.That(webResponse.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadForm.Name))); - Assert.That(actualContents, Is.EqualTo(expectedContents)); - } - - } +using System; +using System.IO; +using System.Net; +using NUnit.Framework; +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"); + + 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(); + + 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 header = string.Format(headerTemplate, "upload", fileInfo.Name, MimeTypes.GetMimeType(fileInfo.Name)); + + + + byte[] headerbytes = System.Text.Encoding.ASCII.GetBytes(header); + + 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); + + using (var fs = fileInfo.OpenRead()) + { + fs.WriteTo(memStream); + } + + memStream.Write(boundarybytes, 0, boundarybytes.Length); + + + //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); + + //memStream.Write(boundarybytes, 0, boundarybytes.Length); + + + httpWebRequest.ContentLength = memStream.Length; + + 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(); + + return httpWebRequest.GetResponse(); + } + + [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 = 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 = uploadForm.OpenRead().ReadToEnd(); + + var webResponse = webRequest.GetResponse(); + var actualContents = webResponse.ReadToEnd(); + + 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 e24ca24894a..2c689867cf2 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/FilterTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/FilterTests.cs @@ -1,19 +1,19 @@ -using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.ServiceClient.Web; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [TestFixture] - public class FilterTests - { - [Test] - public void Can_call_service_returning_string() - { - var response = Config.ServiceStackBaseUri.CombineWith("hello2/world") - .DownloadJsonFromUrl(); - - Assert.That(response, Is.EqualTo("world")); - } - } +using NUnit.Framework; +using ServiceStack.Common; +using ServiceStack.Text; + +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(); + + 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 be8fb8d360c..6eb040299c1 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldRawHttpPostTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldRawHttpPostTests.cs @@ -1,53 +1,51 @@ -using System; -using System.IO; -using System.Net; -using NUnit.Framework; - -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"; - - 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!\"}")); - } - } - - [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 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 System; +using System.IO; +using System.Net; +using NUnit.Framework; + +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"; + + 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()) + { + 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"; + + 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()) + { + 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 8aa1d9ce9bb..b2f5eb0bfcd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldServiceClientTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldServiceClientTests.cs @@ -1,80 +1,69 @@ -using System; -using System.Collections; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [TestFixture] - public class HelloWorldServiceClientTests - { - 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) - }; - } - } - - public static IEnumerable RestClients - { - get - { - return new IRestClient[] { - new JsonServiceClient(Config.ServiceStackBaseUri), - new JsvServiceClient(Config.ServiceStackBaseUri), - new XmlServiceClient(Config.ServiceStackBaseUri), - }; - } - } - - [Test, TestCaseSource("ServiceClients")] - public void Sync_Call_HelloWorld_with_Sync_ServiceClients_on_PreDefined_Routes(IServiceClient client) - { - var response = client.Send<HelloResponse>(new Hello { Name = "World!" }); - - Assert.That(response.Result, Is.EqualTo("Hello, World!")); - } - - [Test, TestCaseSource("RestClients")] - public void 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)); - - Assert.That(response.Result, Is.EqualTo("Hello, World!")); - } - - [Test, TestCaseSource("RestClients")] - public void Sync_Call_HelloWorld_with_RestClients_on_UserDefined_Routes(IRestClient client) - { - var response = client.Get<HelloResponse>("/hello/World!"); - - Assert.That(response.Result, Is.EqualTo("Hello, World!")); - } - - [Test, TestCaseSource("RestClients")] - public void 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")); - - Thread.Sleep(TimeSpan.FromSeconds(1)); - - Assert.That(response.Result, Is.EqualTo("Hello, World!")); - } - } +using System.Collections; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class HelloWorldServiceClientTests + { + 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) + }; + } + } + + public static IEnumerable RestClients + { + get + { + return new IRestClient[] { + new JsonServiceClient(Config.ServiceStackBaseUri), + new JsvServiceClient(Config.ServiceStackBaseUri), + new XmlServiceClient(Config.ServiceStackBaseUri), + }; + } + } + + [Test, TestCaseSource("ServiceClients")] + public void Sync_Call_HelloWorld_with_Sync_ServiceClients_on_PreDefined_Routes(IServiceClient client) + { + var response = client.Send<HelloResponse>(new Hello { Name = "World!" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test, TestCaseSource("RestClients")] + public async Task Async_Call_HelloWorld_with_ServiceClients_on_PreDefined_Routes(IServiceClient client) + { + var response = await client.SendAsync<HelloResponse>(new Hello { Name = "World!" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test, TestCaseSource("RestClients")] + public void Sync_Call_HelloWorld_with_RestClients_on_UserDefined_Routes(IRestClient client) + { + var response = client.Get<HelloResponse>("/hello/World!"); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test, TestCaseSource("RestClients")] + public async Task Async_Call_HelloWorld_with_Async_ServiceClients_on_UserDefined_Routes(IServiceClient client) + { + var response = await client.GetAsync<HelloResponse>("/hello/World!"); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + } } \ No newline at end of file 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 8137bf14903..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ManageRolesTests.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -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<RegistrationResponse>(newUserRegistration); - - return newUserRegistration; - } - - - [Test] - public void Cannot_assign_roles_with_normal_user() - { - var newUser = RegisterNewUser(autoLogin: true); - - try - { - var response = ServiceClient.Send<AssignRolesResponse>( - 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.Unauthorized)); - //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<AssignRolesResponse>( - 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<AssignRolesResponse>( - new AssignRoles { - UserName = newUser.UserName, - Roles = new List<string> { RoleName1, RoleName2 }, - Permissions = new List<string> { Permission1, Permission2 } - }); - - var response = client.Send<UnAssignRolesResponse>( - 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<ContentManagerOnlyResponse>(new ContentManagerOnly()); - Assert.Fail("Should not be allowed - no roles"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); - } - - var client = AuthenticateWithAdminUser(); - - client.Send<AssignRolesResponse>( - new AssignRoles { - UserName = newUser.UserName, - Roles = new List<string> { RoleName1 }, - }); - - var newUserClient = Login(newUser.UserName, newUser.Password); - - try - { - newUserClient.Send<ContentManagerOnlyResponse>(new ContentManagerOnly()); - Assert.Fail("Should not be allowed - wrong roles"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); - } - - var assignResponse = client.Send<AssignRolesResponse>( - new AssignRoles { - UserName = newUser.UserName, - Roles = new List<string> { ContentManager }, - }); - - Assert.That(assignResponse.AllRoles, Is.EquivalentTo(new[] { RoleName1, ContentManager })); - - var response = newUserClient.Send<ContentManagerOnlyResponse>(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<ContentPermissionOnlyResponse>(new ContentPermissionOnly()); - Assert.Fail("Should not be allowed - no permissions"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Permissions")); - } - - var client = AuthenticateWithAdminUser(); - - client.Send<AssignRolesResponse>( - new AssignRoles { - UserName = newUser.UserName, - Permissions = new List<string> { RoleName1 }, - }); - - var newUserClient = Login(newUser.UserName, newUser.Password); - - try - { - newUserClient.Send<ContentPermissionOnlyResponse>(new ContentPermissionOnly()); - Assert.Fail("Should not be allowed - wrong permissions"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Permissions")); - } - - var assignResponse = client.Send<AssignRolesResponse>( - new AssignRoles { - UserName = newUser.UserName, - Permissions = new List<string> { ContentPermission }, - }); - - Assert.That(assignResponse.AllPermissions, Is.EquivalentTo(new[] { RoleName1, ContentPermission })); - - var response = newUserClient.Send<ContentPermissionOnlyResponse>(new ContentPermissionOnly()); - - Assert.That(response.Result, Is.EqualTo("Haz Access")); - } - - } -} \ 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 6fe5f1638b9..6e3288d8fe6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/MovieServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/MovieServiceTests.cs @@ -1,120 +1,116 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceModel.Serialization; -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).ToUniversalTime(), - 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)); - } - } - - } - +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.OrmLite; +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:", 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 99faa28bd59..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 NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -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 : ServiceBase<ProtoBufEmail> - { - protected override object Run(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); - } - } - - } +using System; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +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 : Service + { + public object Any(ProtoBufEmail request) + { + 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 f4a8aedf0f5..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 NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.Text; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.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 - { - [Test] - public void Can_POST_raw_request() - { - var rawData = "<<(( 'RAW_DATA' ))>>"; - var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; - var json = requestUrl.PutToUrl(rawData, ContentType.PlainText, 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.PutToUrl(rawData, ContentType.PlainText, ContentType.Json); - var response = json.FromJson<RawRequestResponse>(); - Assert.That(response.Result, Is.EqualTo(rawData)); - } - - } - +using System.IO; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [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 3440e33e823..a41207220f1 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestAndPathResolutionTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestAndPathResolutionTests.cs @@ -1,47 +1,47 @@ -using NUnit.Framework; -using ServiceStack.ServiceInterface.Testing; -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) { } - - [SetUp] - public void OnBeforeTest() - { - 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_case_insensitive_request() - { - var request = (EchoRequest)ExecutePath("/xml/syncreply/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")); - } - } +using NUnit.Framework; +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) { } + + [SetUp] + public void OnBeforeTest() + { + base.OnBeforeEachTest(); + } + + [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/reply/echorequest"); + Assert.That(request, Is.Not.Null); + } + + [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 76add421f18..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; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [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"); - - 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()); - - 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\"")); - } - } - - - [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"); - - 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)); - } - } - } +using System.Net; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [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/reply/RequestFilter?StatusCode=401"); + + 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/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 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\"")); + } + } + + + [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 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 0524f73e7e6..2273837ec0a 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestPathResolutionUnitTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestPathResolutionUnitTests.cs @@ -1,130 +1,142 @@ -using Funq; -using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceInterface.Testing; -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)); - } - - [Test] - public void Can_call_WildCardRequest_with_alternate_matching_WildCard_defined() - { - var request = (WildCardRequest)GetRequest("/wildcard/1/aPath/edit"); - Assert.That(request.Id, Is.EqualTo(1)); - Assert.That(request.Path, Is.EqualTo("aPath")); - Assert.That(request.Action, Is.EqualTo("edit")); - 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")); - } - - } +using NUnit.Framework; +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)); + } + + [Test] + public void Can_get_empty_BasicWildcard() + { + var request = GetRequest<BasicWildcard>("/path"); + Assert.That(request.Tail, Is.Null); + request = GetRequest<BasicWildcard>("/path/"); + Assert.That(request.Tail, Is.Null); + request = GetRequest<BasicWildcard>("/path/a"); + Assert.That(request.Tail, Is.EqualTo("a")); + request = GetRequest<BasicWildcard>("/path/a/b/c"); + Assert.That(request.Tail, Is.EqualTo("a/b/c")); + } + + [Test] + public void Can_call_WildCardRequest_with_alternate_matching_WildCard_defined() + { + var request = (WildCardRequest)GetRequest("/wildcard/1/aPath/edit"); + Assert.That(request.Id, Is.EqualTo(1)); + Assert.That(request.Path, Is.EqualTo("aPath")); + Assert.That(request.Action, Is.EqualTo("edit")); + 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")); + } + + } } \ 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 d176b9eee9c..b3e56ff3346 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestWebServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestWebServiceTests.cs @@ -1,200 +1,201 @@ -using System; -using System.IO; -using System.Net; -using System.Text; -using NUnit.Framework; -using ServiceStack.Common.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; - } - } - - } - +using System; +using System.IO; +using System.Net; +using System.Text; +using NUnit.Framework; +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", 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 66d1995fe01..16dca0dc814 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestsTestBase.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestsTestBase.cs @@ -1,182 +1,181 @@ -using System; -using System.IO; -using System.Net; -using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.Logging; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -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; - } - - } +using System; +using System.IO; +using System.Net; +using NUnit.Framework; +using ServiceStack.Common.Tests; +using ServiceStack.Host; +using ServiceStack.Logging; +using ServiceStack.Text; +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 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 ba0dd88fb67..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 NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Messaging; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [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())); - } - } +using System; +using System.IO; +using System.Web; +using NUnit.Framework; +using ServiceStack.Testing; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [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())); + } + + [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/Soap11AddServiceReferenceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/Soap11AddServiceReferenceTests.cs index 5d5d5ba773f..0449aa160d8 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/Soap11AddServiceReferenceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/Soap11AddServiceReferenceTests.cs @@ -1,60 +1,60 @@ -using System; -using System.ServiceModel; -using NUnit.Framework; -using ServiceStack.Text; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [TestFixture] - public class Soap11AddServiceReferenceTests - { - private const string EndpointUri = "http://localhost/ServiceStack.WebHost.IntegrationTests/ServiceStack/Soap11"; - private Soap11ServiceReference.ISyncReply client; - - [SetUp] - public void OnBeforeEachTest() - { - //Generated proxy when using 'Add Service Reference' on the EndpointUri above. - //Thank WCF for the config ugliness - client = new Soap11ServiceReference.SyncReplyClient( - new BasicHttpBinding - { - MaxReceivedMessageSize = int.MaxValue, - HostNameComparisonMode = HostNameComparisonMode.StrongWildcard - }, - new EndpointAddress(EndpointUri)); - } - - private const string TestString = "ServiceStack"; - - [Test] - public void Does_Execute_ReverseService() - { - var response = client.Reverse(TestString); - var expectedValue = ReverseService.Execute(TestString); - Assert.That(response, Is.EqualTo(expectedValue)); - } - - [Test] - public void Does_Execute_Rot13Service() - { - var response = client.Rot13(TestString); - var expectedValue = TestString.ToRot13(); - Assert.That(response, Is.EqualTo(expectedValue)); - } - - [Test] - public void Can_Handle_Exception_from_AlwaysThrowService() - { - string result; - var responseStatus = client.AlwaysThrows(out result, TestString); - - var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); - Assert.That(responseStatus.ErrorCode, - Is.EqualTo(typeof(NotImplementedException).Name)); - Assert.That(responseStatus.Message, Is.EqualTo(expectedError)); - } - - } +using System; +using System.ServiceModel; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class Soap11AddServiceReferenceTests + { + private const string EndpointUri = "http://localhost/ServiceStack.WebHost.IntegrationTests/ServiceStack/Soap11"; + private Soap11ServiceReference.ISyncReply client; + + [SetUp] + public void OnBeforeEachTest() + { + //Generated proxy when using 'Add Service Reference' on the EndpointUri above. + //Thank WCF for the config ugliness + client = new Soap11ServiceReference.SyncReplyClient( + new BasicHttpBinding + { + MaxReceivedMessageSize = int.MaxValue, + HostNameComparisonMode = HostNameComparisonMode.StrongWildcard + }, + new EndpointAddress(EndpointUri)); + } + + private const string TestString = "ServiceStack"; + + [Test] + public void Does_Execute_ReverseService() + { + var response = client.Reverse(TestString); + var expectedValue = ReverseService.Execute(TestString); + Assert.That(response, Is.EqualTo(expectedValue)); + } + + [Test] + public void Does_Execute_Rot13Service() + { + var response = client.Rot13(TestString); + var expectedValue = TestString.ToRot13(); + Assert.That(response, Is.EqualTo(expectedValue)); + } + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowService() + { + string result; + var responseStatus = client.AlwaysThrows(out result, TestString); + + var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); + Assert.That(responseStatus.ErrorCode, + Is.EqualTo(typeof(NotImplementedException).Name)); + Assert.That(responseStatus.Message, Is.EqualTo(expectedError)); + } + + } } \ 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 new file mode 100644 index 00000000000..d1853119d1e --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/UniqueRequestTests.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [Route("/request/{Id}")] + 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.ServiceStackBaseUri; + + [Test] + [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(); + Assert.That(response, Is.EqualTo("123%20456")); + response = BaseUri.CombineWith("request/123%7C456").GetStringFromUrl(); + 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 5b794069b94..51fa69b2939 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs @@ -1,130 +1,270 @@ -using System; -using System.Net; -using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support; -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) { } - - [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> - /// 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(true, typeof(ReverseService).Assembly); - 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); - } - } - +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.Common.Tests; +using ServiceStack.Text; +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) { } + + [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() + { + var client = CreateNewServiceClient(); + if (client is DirectServiceClient) return; + var response = client.Send<RequestItemsResponse>(new RequestItems { }); + Assert.That(response.Result, Is.EqualTo("MissionSuccess")); + } + } + + + /// <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 6cc5d14d6b6..f53c77b66e5 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Web.config +++ b/tests/ServiceStack.WebHost.IntegrationTests/Web.config @@ -1,131 +1,104 @@ -<?xml version="1.0"?> -<configuration> - <configSections> - <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> - <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> - <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> - <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> - <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/> - <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> - <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> - <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> - </sectionGroup> - </sectionGroup> - </sectionGroup> - </configSections> - <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.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 - during development. - --> - <compilation debug="true"> - <assemblies> - <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> - <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> - <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> - </assemblies> - </compilation> - <!-- - 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> - --> - <customErrors mode="Off"></customErrors> - - <pages> - <controls> - <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - </controls> - </pages> - <httpHandlers> - <remove verb="*" path="*.asmx"/> - <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/> - - <!--<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*"/>--> - </httpHandlers> - <httpModules> - <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - </httpModules> - </system.web> - <system.codedom> - <compilers> - <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <providerOption name="CompilerVersion" value="v3.5"/> - <providerOption name="WarnAsError" value="false"/> - </compiler> - </compilers> - </system.codedom> - <!-- - 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"/> - <modules> - <remove name="ScriptModule"/> - <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - </modules> - <handlers> - <remove name="WebServiceHandlerFactory-Integrated"/> - <remove name="ScriptHandlerFactory"/> - <remove name="ScriptHandlerFactoryAppServices"/> - <remove name="ScriptResource"/> - <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - - <!--<add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>--> - </handlers> - </system.webServer> - <runtime> - <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" appliesTo="v2.0.50727"><dependentAssembly> - <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/> - <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/> - <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> - </dependentAssembly> - </assemblyBinding></runtime> -</configuration> +<?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"> + <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> + <!-- + 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.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" /> + <!-- + 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> + --> + <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> + <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 index 5847155592b..0374bc6727e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/_default.html +++ b/tests/ServiceStack.WebHost.IntegrationTests/_default.html @@ -1,52 +1,52 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <div> - Default index ServiceStack.WebHost.IntegrationTests page - </div> - </form> - - <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script> - <script type="text/javascript"> - $(function () { - - var dt = new Date(); - var etime = dt.getTime(); - - var jdata = { - "AppToken": "TEST123", - "OrderId": 1, - "GeoCode": { - "t": etime, - "latitude": 32.81434, - "longitude": -80.3432221 - } - }; - - $.ajax({ - url: "geoinfo", - type: "POST", - contentType: "application/json", - accept: "application/json", - dataType: "json", - data: JSON.stringify(jdata), - success: function (data) { - //alert(data.Result); - } - }); - - // $.post("geoinfo", JSON.stringify(jdata), - // function (data) { - // alert(data.Result); - // }, - // "json"); - - }); - </script> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + Default index ServiceStack.WebHost.IntegrationTests page + </div> + </form> + + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script> + <script type="text/javascript"> + $(function () { + + var dt = new Date(); + var etime = dt.getTime(); + + var jdata = { + "AppToken": "TEST123", + "OrderId": 1, + "GeoCode": { + "t": etime, + "latitude": 32.81434, + "longitude": -80.3432221 + } + }; + + $.ajax({ + url: "geoinfo", + type: "POST", + contentType: "application/json", + accept: "application/json", + dataType: "json", + data: JSON.stringify(jdata), + success: function (data) { + //alert(data.Result); + } + }); + + // $.post("geoinfo", JSON.stringify(jdata), + // function (data) { + // alert(data.Result); + // }, + // "json"); + + }); + </script> +</body> +</html> 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/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/user-default.htm b/tests/ServiceStack.WebHost.IntegrationTests/user-default.htm index b1f81e3b227..b60004b0042 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/user-default.htm +++ b/tests/ServiceStack.WebHost.IntegrationTests/user-default.htm @@ -1,14 +1,14 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <h1> - User - Default index page - </h1> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <h1> + User - Default index page + </h1> + </form> +</body> +</html> diff --git a/tests/ServiceStack.WebHost.IntegrationTests/user-notfound.htm b/tests/ServiceStack.WebHost.IntegrationTests/user-notfound.htm index 9482ec9a0c3..f08005636ee 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/user-notfound.htm +++ b/tests/ServiceStack.WebHost.IntegrationTests/user-notfound.htm @@ -1,14 +1,14 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <h1> - 404 Not Found - </h1> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <h1> + 404 Not Found + </h1> + </form> +</body> +</html> diff --git a/tests/ServiceStack.WebHost.IntegrationTests/webpage.html b/tests/ServiceStack.WebHost.IntegrationTests/webpage.html index 331e12ed0b4..b6cb25ffa3e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/webpage.html +++ b/tests/ServiceStack.WebHost.IntegrationTests/webpage.html @@ -1,14 +1,14 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" > -<head runat="server"> - <title></title> -</head> -<body> - <form id="form1" runat="server"> - <div> - Default index ServiceStack.WebHost.Endpoints.Tests page - </div> - </form> -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + Default index ServiceStack.WebHost.Endpoints.Tests page + </div> + </form> +</body> +</html> diff --git a/tests/ServiceStack.WebHostApp/AppHost.cs b/tests/ServiceStack.WebHostApp/AppHost.cs deleted file mode 100644 index d0d2b831806..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 fad4ec35172..00000000000 --- a/tests/ServiceStack.WebHostApp/ServiceStack.WebHostApp.csproj +++ /dev/null @@ -1,114 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <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> - </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.Web" /> - <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> - </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> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> - <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>43492</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 7aad6cade3b..00000000000 --- a/tests/ServiceStack.WebHostApp/web.config +++ /dev/null @@ -1,103 +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> - <configSections> - </configSections> - <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"> - <assemblies> - <add assembly="System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <add assembly="System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <add assembly="System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <add assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> - </assemblies> - </compilation> - <!-- - 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> - --> - <pages> - <controls> - <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> - <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> - </controls> - </pages> - <httpHandlers> - <remove verb="*" path="*.asmx" /> - <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> - <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> - <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false" /> - <!-- ServiceStack: Required for MONO --> - <add path="api*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" /> - </httpHandlers> - </system.web> - <system.codedom> - <compilers> - <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <providerOption name="CompilerVersion" value="v3.5" /> - <providerOption name="WarnAsError" value="false" /> - </compiler> - </compilers> - </system.codedom> - <!-- - 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 xmlns="urn:schemas-microsoft-com:asm.v1" appliesTo="v2.0.50727"> - <dependentAssembly> - <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35" /> - <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35" /> - <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" /> - </dependentAssembly> - </assemblyBinding> - </runtime> - <appSettings> - </appSettings> - <connectionStrings> - </connectionStrings> -</configuration>