diff --git a/MR3/Castle.MonoRail.sln b/MR3/Castle.MonoRail.sln index 0ff9961d..e0427f57 100644 --- a/MR3/Castle.MonoRail.sln +++ b/MR3/Castle.MonoRail.sln @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ComponentsPerScope.fsx = ComponentsPerScope.fsx ListAllExports.fsx = ListAllExports.fsx rails thoughts.txt = rails thoughts.txt + rakefile.rb = rakefile.rb TODO.txt = TODO.txt EndProjectSection EndProject @@ -36,14 +37,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestingSites", "TestingSite EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{60349639-F39F-4556-8898-E64AEC0B22A4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensibility", "Extensibility", "{2F740D6F-95A0-44EE-8E2C-33EC3761EC25}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Castle.Extensibility", "..\..\Extensibility\src\Castle.Extensibility\Castle.Extensibility.fsproj", "{10FDDA68-3450-4179-819A-248D9D628454}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Castle.Extensibility.Windsor", "..\..\Extensibility\src\Castle.Extensibility.Windsor\Castle.Extensibility.Windsor.fsproj", "{6A43A495-8E52-4AF7-AFE3-51CA88900B18}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Castle.Extensibility.Services.FSStorage", "..\..\Extensibility\src\Castle.Extensibility.Services.FSStorage\Castle.Extensibility.Services.FSStorage.fsproj", "{FF8A9176-C810-4DA8-8470-DC925B2DEC3E}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Castle.MonoRail.Integration.Tests", "tests\Castle.MonoRail.Integration.Tests\Castle.MonoRail.Integration.Tests.csproj", "{A9D55E13-01F2-49B5-97C7-336E44B218F4}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSiteForIntegration", "tests\WebSiteForIntegration\WebSiteForIntegration.csproj", "{B3C51C43-5E58-4CEE-8F02-9CFD3981BCCF}" @@ -56,6 +49,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OData", "OData", "{1FDBC6CA EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.OData", "Extensions\OData\3rd\odata\System.Data.OData.csproj", "{34B74905-DF66-4BF7-958B-62C50ED1203C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComposableHostWebSite", "tests\ComposableHostWebSite\ComposableHostWebSite.csproj", "{A5388E06-87EF-4894-B22A-4716839A165C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BundledWebSite1", "tests\BundledWebSite1\BundledWebSite1.csproj", "{F70E9E7E-9955-42E6-B14F-7981EBD3F389}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Castle.MonoRail.Extension.OData.Integration.Tests", "Extensions\OData\tests\Castle.MonoRail.Extension.OData.Integration.Tests\Castle.MonoRail.Extension.OData.Integration.Tests.csproj", "{7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ODataTestWebSite", "Extensions\OData\tests\ODataTestWebSite\ODataTestWebSite.csproj", "{B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -382,96 +383,6 @@ Global {FB716680-F72C-4A77-84C9-C5A3A30DD909}.Release|Mixed Platforms.Build.0 = Release|x86 {FB716680-F72C-4A77-84C9-C5A3A30DD909}.Release|x86.ActiveCfg = Release|x86 {FB716680-F72C-4A77-84C9-C5A3A30DD909}.Release|x86.Build.0 = Release|x86 - {10FDDA68-3450-4179-819A-248D9D628454}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Debug|Any CPU.Build.0 = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Debug|x86.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.MONO28-Release|x86.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Release|Any CPU.Build.0 = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.NET40-Release|x86.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Release|Any CPU.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Release|Any CPU.Build.0 = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {10FDDA68-3450-4179-819A-248D9D628454}.Release|x86.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Debug|x86.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.MONO28-Release|x86.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Release|Any CPU.Build.0 = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.NET40-Release|x86.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Release|Any CPU.Build.0 = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {6A43A495-8E52-4AF7-AFE3-51CA88900B18}.Release|x86.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Debug|x86.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.MONO28-Release|x86.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Release|Any CPU.Build.0 = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.NET40-Release|x86.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Release|Any CPU.Build.0 = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E}.Release|x86.ActiveCfg = Release|Any CPU {A9D55E13-01F2-49B5-97C7-336E44B218F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A9D55E13-01F2-49B5-97C7-336E44B218F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {A9D55E13-01F2-49B5-97C7-336E44B218F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -622,6 +533,126 @@ Global {34B74905-DF66-4BF7-958B-62C50ED1203C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {34B74905-DF66-4BF7-958B-62C50ED1203C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {34B74905-DF66-4BF7-958B-62C50ED1203C}.Release|x86.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Debug|x86.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.MONO28-Release|x86.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Release|Any CPU.Build.0 = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.NET40-Release|x86.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Release|Any CPU.Build.0 = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A5388E06-87EF-4894-B22A-4716839A165C}.Release|x86.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Debug|x86.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.MONO28-Release|x86.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Release|Any CPU.Build.0 = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.NET40-Release|x86.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Release|Any CPU.Build.0 = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F70E9E7E-9955-42E6-B14F-7981EBD3F389}.Release|x86.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Debug|x86.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.MONO28-Release|x86.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Release|Any CPU.Build.0 = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.NET40-Release|x86.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Release|Any CPU.Build.0 = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0}.Release|x86.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Debug|x86.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Debug|Any CPU.Build.0 = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Debug|x86.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Release|Any CPU.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Release|Any CPU.Build.0 = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Release|Mixed Platforms.Build.0 = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.MONO28-Release|x86.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Debug|Any CPU.Build.0 = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Debug|x86.ActiveCfg = Debug|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Release|Any CPU.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Release|Any CPU.Build.0 = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Release|Mixed Platforms.Build.0 = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.NET40-Release|x86.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Release|Any CPU.Build.0 = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -629,17 +660,18 @@ Global GlobalSection(NestedProjects) = preSolution {84BCA422-D499-44A4-8AD3-5039238B77BE} = {382D966B-30DE-4849-ADBB-7286C248B287} {A0731A18-51AF-43FE-9CB5-C13F870DC1BA} = {382D966B-30DE-4849-ADBB-7286C248B287} + {B3C51C43-5E58-4CEE-8F02-9CFD3981BCCF} = {382D966B-30DE-4849-ADBB-7286C248B287} + {A5388E06-87EF-4894-B22A-4716839A165C} = {382D966B-30DE-4849-ADBB-7286C248B287} + {F70E9E7E-9955-42E6-B14F-7981EBD3F389} = {382D966B-30DE-4849-ADBB-7286C248B287} {D0F1F4F2-48B0-4C46-83E4-8909C92846C9} = {60349639-F39F-4556-8898-E64AEC0B22A4} {A9D55E13-01F2-49B5-97C7-336E44B218F4} = {60349639-F39F-4556-8898-E64AEC0B22A4} - {B3C51C43-5E58-4CEE-8F02-9CFD3981BCCF} = {60349639-F39F-4556-8898-E64AEC0B22A4} {8DF9E981-2558-4EFD-A455-5459F36A9B03} = {FF1223B6-11F6-4EDB-AC3E-5DDF93B23C96} {FB716680-F72C-4A77-84C9-C5A3A30DD909} = {FF1223B6-11F6-4EDB-AC3E-5DDF93B23C96} {51FC792E-69D3-41C4-937E-4ABAC181D918} = {FF1223B6-11F6-4EDB-AC3E-5DDF93B23C96} - {10FDDA68-3450-4179-819A-248D9D628454} = {2F740D6F-95A0-44EE-8E2C-33EC3761EC25} - {6A43A495-8E52-4AF7-AFE3-51CA88900B18} = {2F740D6F-95A0-44EE-8E2C-33EC3761EC25} - {FF8A9176-C810-4DA8-8470-DC925B2DEC3E} = {2F740D6F-95A0-44EE-8E2C-33EC3761EC25} {702F84E9-CAD2-4B64-A4C5-F915BAD4A729} = {1FDBC6CA-942F-45B1-B841-B0808D16E1DE} {EBA1D22A-F8D5-4884-9297-2C10AD2663E7} = {1FDBC6CA-942F-45B1-B841-B0808D16E1DE} {34B74905-DF66-4BF7-958B-62C50ED1203C} = {1FDBC6CA-942F-45B1-B841-B0808D16E1DE} + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0} = {1FDBC6CA-942F-45B1-B841-B0808D16E1DE} + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD} = {1FDBC6CA-942F-45B1-B841-B0808D16E1DE} EndGlobalSection EndGlobal diff --git a/MR3/ConsoleApplication1/.gitignore b/MR3/ConsoleApplication1/.gitignore deleted file mode 100644 index 8f99b635..00000000 --- a/MR3/ConsoleApplication1/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/ConsoleApplication1/ -/ConsoleApplication1/** diff --git a/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceSet.cs b/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceSet.cs index 9d954ad6..c5066739 100644 --- a/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceSet.cs +++ b/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceSet.cs @@ -14,154 +14,155 @@ namespace System.Data.Services.Providers { - #region Namespaces. - using System; - using System.Data.OData; - using System.Diagnostics; - #endregion Namespaces. - - /// - /// Class to keep information about a resource set. - /// - /// - /// Custom providers can choose to use it as is or derive from it - /// in order to flow provider-specific data. - /// - [DebuggerDisplay("{Name}: {ResourceType}")] + #region Namespaces. + + using System; + using System.Data.OData; + using System.Diagnostics; + + #endregion Namespaces. + + /// + /// Class to keep information about a resource set. + /// + /// + /// Custom providers can choose to use it as is or derive from it + /// in order to flow provider-specific data. + /// + [DebuggerDisplay("{Name}: {ResourceType}")] #if INTERNAL_DROP internal class ResourceSet : ODataAnnotatable #else - public class ResourceSet : ODataAnnotatable + public class ResourceSet : ODataAnnotatable #endif - { - #region Fields - /// - /// Reference to resource type that this resource set is a collection of. - /// - private readonly ResourceType elementType; - - /// - /// Name of the resource set. - /// - private readonly string name; - - /// - /// Is true, if the resource set is fully initialized and validated. No more changes can be made once its set to readonly. - /// - private bool isReadOnly; - - /// Is true, if key properties should be ordered as per declared order when used for constructing OrderBy queries. - /// Otherwise the default alphabetical order is used. - private bool useMetadataKeyOrder; - #endregion Fields - - #region Constructors - /// - /// Constructs a new ResourceSet instance using the specified name and ResourceType instance. - /// - /// name of the resource set. - /// Reference to clr type that this resource set is a collection of. - public ResourceSet(string name, ResourceType elementType) - { - ExceptionUtils.CheckArgumentStringNotNullOrEmpty(name, "name"); - ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); - - if (elementType.ResourceTypeKind != ResourceTypeKind.EntityType) - { - throw new ArgumentException(Strings.ResourceSet_ResourceSetMustBeAssociatedWithEntityType); - } - - this.name = name; - this.elementType = elementType; - } - #endregion Constructors - - #region Properties - /// - /// Name of the resource set. - /// - public string Name - { - get { return this.name; } - } - - /// - /// Reference to resource type that this resource set is a collection of. - /// - public ResourceType ResourceType - { - get { return this.elementType; } - } - - /// - /// PlaceHolder to hold custom state information about resource set. - /// - public object CustomState - { - get - { - return this.GetCustomState(); - } - - set - { - this.SetCustomState(value); - } - } - - /// - /// Returns true, if this container has been set to read only. Otherwise returns false. - /// - public bool IsReadOnly - { - get { return this.isReadOnly; } - } - - /// - /// Is true, if key properties should be ordered as per declared order when used for constructing OrderBy queries. - /// Otherwise the default alphabetical order is used. - /// - public bool UseMetadataKeyOrder - { - get - { - return this.useMetadataKeyOrder; - } - - set - { - this.ThrowIfSealed(); - this.useMetadataKeyOrder = value; - } - } - #endregion Properties - - #region Methods - /// - /// Sets the resource set to readonly mode. resource sets cannot be updated once this property is set. - /// - public void SetReadOnly() - { - // If its already set to readonly, then its a no-op - if (this.isReadOnly) - { - return; - } - - this.elementType.SetReadOnly(); - this.isReadOnly = true; - } - - /// - /// Checks if the resource set is sealed. If not, it throws an InvalidOperationException. - /// - private void ThrowIfSealed() - { - if (this.isReadOnly) - { - throw new InvalidOperationException(Strings.ResourceSet_Sealed(this.Name)); - } - } - #endregion Methods - } -} + { + #region Fields + + /// + /// Reference to resource type that this resource set is a collection of. + /// + private readonly ResourceType elementType; + + /// + /// Name of the resource set. + /// + private readonly string name; + + /// + /// Is true, if the resource set is fully initialized and validated. No more changes can be made once its set to readonly. + /// + private bool isReadOnly; + + /// Is true, if key properties should be ordered as per declared order when used for constructing OrderBy queries. + /// Otherwise the default alphabetical order is used. + private bool useMetadataKeyOrder; + + #endregion Fields + + #region Constructors + + /// + /// Constructs a new ResourceSet instance using the specified name and ResourceType instance. + /// + /// name of the resource set. + /// Reference to clr type that this resource set is a collection of. + public ResourceSet(string name, ResourceType elementType) + { + ExceptionUtils.CheckArgumentStringNotNullOrEmpty(name, "name"); + ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); + + if (elementType.ResourceTypeKind != ResourceTypeKind.EntityType) + { + throw new ArgumentException(Strings.ResourceSet_ResourceSetMustBeAssociatedWithEntityType); + } + + this.name = name; + this.elementType = elementType; + } + + #endregion Constructors + + #region Properties + + /// + /// Name of the resource set. + /// + public string Name + { + get { return this.name; } + } + + /// + /// Reference to resource type that this resource set is a collection of. + /// + public ResourceType ResourceType + { + get { return this.elementType; } + } + + /// + /// PlaceHolder to hold custom state information about resource set. + /// + public object CustomState + { + get { return this.GetCustomState(); } + + set { this.SetCustomState(value); } + } + + /// + /// Returns true, if this container has been set to read only. Otherwise returns false. + /// + public bool IsReadOnly + { + get { return this.isReadOnly; } + } + + /// + /// Is true, if key properties should be ordered as per declared order when used for constructing OrderBy queries. + /// Otherwise the default alphabetical order is used. + /// + public bool UseMetadataKeyOrder + { + get { return this.useMetadataKeyOrder; } + + set + { + this.ThrowIfSealed(); + this.useMetadataKeyOrder = value; + } + } + + #endregion Properties + + #region Methods + + /// + /// Sets the resource set to readonly mode. resource sets cannot be updated once this property is set. + /// + public void SetReadOnly() + { + // If its already set to readonly, then its a no-op + if (this.isReadOnly) + { + return; + } + + this.elementType.SetReadOnly(); + this.isReadOnly = true; + } + + /// + /// Checks if the resource set is sealed. If not, it throws an InvalidOperationException. + /// + private void ThrowIfSealed() + { + if (this.isReadOnly) + { + throw new InvalidOperationException(Strings.ResourceSet_Sealed(this.Name)); + } + } + + #endregion Methods + } +} \ No newline at end of file diff --git a/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceType.cs b/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceType.cs index efe864b2..9404d155 100644 --- a/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceType.cs +++ b/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ResourceType.cs @@ -39,10 +39,12 @@ public class ResourceType : ODataAnnotatable #endif { #region Fields. + /// /// Empty list of properties. /// - internal static readonly ReadOnlyCollection EmptyProperties = new ReadOnlyCollection(new ResourceProperty[0]); + internal static readonly ReadOnlyCollection EmptyProperties = + new ReadOnlyCollection(new ResourceProperty[0]); /// /// ResourceTypeKind for the type that this structure represents. @@ -128,9 +130,11 @@ public class ResourceType : ODataAnnotatable /// True if the EPM info was initialized for this type. /// private bool epmInfoInitialized; + #endregion Fields. #region Constructors. + /// /// Constructs a new instance of Astoria type using the specified clr type. /// @@ -160,7 +164,8 @@ public class ResourceType : ODataAnnotatable if (baseType != null && baseType.ResourceTypeKind != resourceTypeKind) { throw new ArgumentException( - Strings.ResourceType_InvalidResourceTypeKindInheritance(resourceTypeKind.ToString(), baseType.ResourceTypeKind.ToString()), + Strings.ResourceType_InvalidResourceTypeKindInheritance(resourceTypeKind.ToString(), + baseType.ResourceTypeKind.ToString()), "resourceTypeKind"); } @@ -238,19 +243,18 @@ internal ResourceType(Type type, ResourceTypeKind resourceTypeKind, string names this.baseType = baseType; } } + #endregion Constructors. #region Properties. + /// /// True if the resource type includes a default stream. /// public bool IsMediaLinkEntry { [DebuggerStepThrough] - get - { - return this.isMediaLinkEntry; - } + get { return this.isMediaLinkEntry; } set { @@ -296,27 +300,27 @@ public ResourceTypeKind ResourceTypeKind /// public ReadOnlyCollection Properties { - get - { - return this.InitializeProperties(); - } + get { return this.InitializeProperties(); } } /// /// List of properties declared on this type. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("DataWeb.Usage", "AC0014:DoNotHandleProhibitedExceptionsRule", Justification = "always rethrows the exception")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("DataWeb.Usage", "AC0014:DoNotHandleProhibitedExceptionsRule", + Justification = "always rethrows the exception")] public ReadOnlyCollection PropertiesDeclaredOnThisType { get { - ReadOnlyCollection readOnlyProperties = this.propertiesDeclaredOnThisType as ReadOnlyCollection; + ReadOnlyCollection readOnlyProperties = + this.propertiesDeclaredOnThisType as ReadOnlyCollection; if (readOnlyProperties == null) { // This method will call the virtual method, if that's not been called yet and add the list of properties // returned by the virtual method to the properties collection. this.GetPropertiesDeclaredOnThisType(); - readOnlyProperties = new ReadOnlyCollection(this.propertiesDeclaredOnThisType ?? ResourceType.EmptyProperties); + readOnlyProperties = + new ReadOnlyCollection(this.propertiesDeclaredOnThisType ?? ResourceType.EmptyProperties); if (!this.isReadOnly) { @@ -397,7 +401,9 @@ public ReadOnlyCollection ETagProperties { if (this.etagProperties == null) { - ReadOnlyCollection etag = new ReadOnlyCollection(this.Properties.Where(p => p.IsOfKind(ResourcePropertyKind.ETag)).ToList()); + ReadOnlyCollection etag = + new ReadOnlyCollection( + this.Properties.Where(p => p.IsOfKind(ResourcePropertyKind.ETag)).ToList()); if (!this.isReadOnly) { return etag; @@ -449,10 +455,7 @@ public bool IsAbstract public bool IsOpenType { [DebuggerStepThrough] - get - { - return this.isOpenType; - } + get { return this.isOpenType; } set { @@ -474,10 +477,7 @@ public bool IsOpenType public bool CanReflectOnInstanceType { [DebuggerStepThrough] - get - { - return this.canReflectOnInstanceType; - } + get { return this.canReflectOnInstanceType; } set { @@ -491,15 +491,9 @@ public bool CanReflectOnInstanceType /// public object CustomState { - get - { - return this.GetCustomState(); - } + get { return this.GetCustomState(); } - set - { - this.SetCustomState(value); - } + set { this.SetCustomState(value); } } /// @@ -522,9 +516,11 @@ internal IEnumerable NamedStreams return this.Properties.Where(p => p.IsOfKind(ResourcePropertyKind.Stream)); } } + #endregion Properties. #region Methods. + /// /// Get a ResourceType representing a primitive type given a .NET System.Type object. /// @@ -550,7 +546,8 @@ public static ResourceType GetPrimitiveResourceType(Type type) /// /// The of a single item in the multiValue. /// A object representing a multiValue of the specified items. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704", Justification = "MultiValue is a Name")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704", Justification = "MultiValue is a Name") + ] public static MultiValueResourceType GetMultiValueResourceType(ResourceType itemType) { ExceptionUtils.CheckArgumentNotNull(itemType, "itemType"); @@ -601,8 +598,8 @@ public void AddEntityPropertyMappingAttribute(EntityPropertyMappingAttribute att epm.OwnEpmAttributes.Add(attribute); } - public IEnumerable OwnEpmAttributes - { + public IEnumerable OwnEpmAttributes + { get { EpmResourceTypeAnnotation epm = this.Epm(); @@ -611,7 +608,7 @@ public IEnumerable OwnEpmAttributes return Enumerable.Empty(); } return epm.OwnEpmAttributes; - } + } } /// @@ -784,7 +781,7 @@ private static int ResourcePropertyComparison(ResourceProperty a, ResourceProper private static void CheckResourceTypeKind(ResourceTypeKind kind, string parameterName) { if (kind < ResourceTypeKind.EntityType || - kind > ResourceTypeKind.MultiValue) + kind > ResourceTypeKind.MultiValue) { throw new ArgumentException(Strings.General_InvalidEnumValue(kind.GetType().Name), parameterName); } @@ -848,7 +845,8 @@ private void AddPropertyImplementation(ResourceProperty property) { if (resourceProperty.Name == property.Name) { - throw new InvalidOperationException(Strings.ResourceType_PropertyWithSameNameAlreadyExists(resourceProperty.Name, this.FullName)); + throw new InvalidOperationException(Strings.ResourceType_PropertyWithSameNameAlreadyExists(resourceProperty.Name, + this.FullName)); } } @@ -862,7 +860,8 @@ private void AddPropertyImplementation(ResourceProperty property) } // NamedStream cannot be used as key or etag (you cannot create a property with a mixed flag that contains stream) - Debug.Assert(!property.IsOfKind(ResourcePropertyKind.Key) && !property.IsOfKind(ResourcePropertyKind.ETag), "NamedStream property kind must be used alone"); + Debug.Assert(!property.IsOfKind(ResourcePropertyKind.Key) && !property.IsOfKind(ResourcePropertyKind.ETag), + "NamedStream property kind must be used alone"); Debug.Assert(!property.CanReflectOnInstanceTypeProperty, "NamedStream properties must not be able to reflect"); } else @@ -879,9 +878,12 @@ private void AddPropertyImplementation(ResourceProperty property) throw new InvalidOperationException(Strings.ResourceType_KeyPropertiesOnlyOnEntityTypes); } - Debug.Assert(property.ResourceType.ResourceTypeKind == ResourceTypeKind.Primitive, "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); - Debug.Assert(!property.IsOfKind(ResourcePropertyKind.ETag), "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); - Debug.Assert(property.IsOfKind(ResourcePropertyKind.Primitive), "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); + Debug.Assert(property.ResourceType.ResourceTypeKind == ResourceTypeKind.Primitive, + "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); + Debug.Assert(!property.IsOfKind(ResourcePropertyKind.ETag), + "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); + Debug.Assert(property.IsOfKind(ResourcePropertyKind.Primitive), + "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); } if (property.IsOfKind(ResourcePropertyKind.ETag)) @@ -891,12 +893,16 @@ private void AddPropertyImplementation(ResourceProperty property) throw new InvalidOperationException(Strings.ResourceType_ETagPropertiesOnlyOnEntityTypes); } - Debug.Assert(property.ResourceType.ResourceTypeKind == ResourceTypeKind.Primitive, "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); - Debug.Assert(property.IsOfKind(ResourcePropertyKind.Primitive), "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); - Debug.Assert(!property.IsOfKind(ResourcePropertyKind.Key), "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); + Debug.Assert(property.ResourceType.ResourceTypeKind == ResourceTypeKind.Primitive, + "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); + Debug.Assert(property.IsOfKind(ResourcePropertyKind.Primitive), + "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); + Debug.Assert(!property.IsOfKind(ResourcePropertyKind.Key), + "This check must have been done in ResourceProperty.ValidatePropertyParameters method"); } - Debug.Assert(property.ResourceType != GetPrimitiveResourceType(typeof(System.IO.Stream)), "Non NamedStream resource using Stream type"); + Debug.Assert(property.ResourceType != GetPrimitiveResourceType(typeof (System.IO.Stream)), + "Non NamedStream resource using Stream type"); } this.propertiesDeclaredOnThisType.Add(property); @@ -934,7 +940,8 @@ private void GetPropertiesDeclaredOnThisType() /// private void ValidateType() { - Debug.Assert(this.isLoadPropertiesMethodCalled && this.IsReadOnly, "This method must be invoked only if LoadPropertiesDeclaredOnThisType has been called and the type is set to ReadOnly"); + Debug.Assert(this.isLoadPropertiesMethodCalled && this.IsReadOnly, + "This method must be invoked only if LoadPropertiesDeclaredOnThisType has been called and the type is set to ReadOnly"); if (this.BaseType != null) { @@ -1009,6 +1016,7 @@ private void MarkEpmInfoInitialized() epm.EpmTargetTree.Validate(); } } + #endregion Methods. } } \ No newline at end of file diff --git a/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ServiceOperation.cs b/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ServiceOperation.cs index 2bcc6a07..ce5823cb 100644 --- a/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ServiceOperation.cs +++ b/MR3/Extensions/OData/3rd/odata/System/Data/Services/Providers/ServiceOperation.cs @@ -14,287 +14,283 @@ namespace System.Data.Services.Providers { - #region Namespaces. - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Data.OData; - using System.Diagnostics; - #endregion Namespaces. - - /// - /// Use this class to represent a custom service operation. - /// + #region Namespaces. + + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Data.OData; + using System.Diagnostics; + + #endregion Namespaces. + + /// + /// Use this class to represent a custom service operation. + /// #if !SILVERLIGHT && !WINDOWS_PHONE - [DebuggerVisualizer("ServiceOperation={Name}")] + [DebuggerVisualizer("ServiceOperation={Name}")] #endif #if INTERNAL_DROP internal class ServiceOperation : ODataAnnotatable #else - public class ServiceOperation : ODataAnnotatable + public class ServiceOperation : ODataAnnotatable #endif - { - /// - /// HTTP method the service operation responds to. - /// - private readonly string method; - - /// - /// In-order parameters for this operation. - /// - private readonly ReadOnlyCollection parameters; - - /// - /// Kind of result expected from this operation. - /// - private readonly ServiceOperationResultKind resultKind; - - /// - /// Type of element of the method result. - /// - private readonly ResourceType resultType; - - /// - /// Empty parameter collection. - /// - private static ReadOnlyCollection emptyParameterCollection = new ReadOnlyCollection(new ServiceOperationParameter[0]); - - /// - /// MIME type specified on primitive results, possibly null. - /// - private string mimeType; - - /// - /// Entity set from which entities are read, if applicable. - /// - private ResourceSet resourceSet; - - /// - /// Name of the service operation. - /// - private string name; - - /// - /// Is true, if the service operation is set to readonly i.e. fully initialized and validated. No more changes can be made, - /// after the service operation is set to readonly. - /// - private bool isReadOnly; - - /// - /// Initializes a new instance. - /// - /// name of the service operation. - /// Kind of result expected from this operation. - /// Type of element of the method result. - /// EntitySet of the result expected from this operation. - /// Protocol (for example HTTP) method the service operation responds to. - /// In-order parameters for this operation. - public ServiceOperation( - string name, - ServiceOperationResultKind resultKind, - ResourceType resultType, - ResourceSet resultSet, - string method, - IEnumerable parameters) - { - ExceptionUtils.CheckArgumentStringNotNullOrEmpty(name, "name"); - CheckServiceOperationResultKind(resultKind, "resultKind"); - ExceptionUtils.CheckArgumentStringNotNullOrEmpty(method, "method"); - - if ((resultKind == ServiceOperationResultKind.Void && resultType != null) || - (resultKind != ServiceOperationResultKind.Void && resultType == null)) - { - throw new ArgumentException(Strings.ServiceOperation_ResultTypeAndKindMustMatch("resultKind", "resultType", ServiceOperationResultKind.Void)); - } - - if ((resultType == null || resultType.ResourceTypeKind != ResourceTypeKind.EntityType) && resultSet != null) - { - throw new ArgumentException(Strings.ServiceOperation_ResultSetMustBeNull("resultSet", "resultType")); - } - - if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.EntityType && (resultSet == null || !resultSet.ResourceType.IsAssignableFrom(resultType))) - { - throw new ArgumentException(Strings.ServiceOperation_ResultTypeAndResultSetMustMatch("resultType", "resultSet")); - } - - if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.MultiValue) - { - throw new ArgumentException(Strings.ServiceOperation_InvalidResultType(resultType.FullName)); - } - - if (method != HttpConstants.HttpMethodGet && method != HttpConstants.HttpMethodPost) - { - throw new ArgumentException(Strings.ServiceOperation_NotSupportedProtocolMethod(method, name)); - } - - this.name = name; - this.resultKind = resultKind; - this.resultType = resultType; - this.resourceSet = resultSet; - this.method = method; - if (parameters == null) - { - this.parameters = ServiceOperation.emptyParameterCollection; - } - else - { - this.parameters = new ReadOnlyCollection(new List(parameters)); - HashSet paramNames = new HashSet(StringComparer.Ordinal); - foreach (ServiceOperationParameter p in this.parameters) - { - if (!paramNames.Add(p.Name)) - { - throw new ArgumentException(Strings.ServiceOperation_DuplicateParameterName(p.Name), "parameters"); - } - } - } - } - - /// - /// Protocol (for example HTTP) method the service operation responds to. - /// - public string Method - { - get { return this.method; } - } - - /// - /// MIME type specified on primitive results, possibly null. - /// - public string MimeType - { - get - { - return this.mimeType; - } - - set - { - this.ThrowIfSealed(); - if (String.IsNullOrEmpty(value)) - { - throw new InvalidOperationException(Strings.ServiceOperation_MimeTypeCannotBeEmpty(this.Name)); - } - - if (!HttpUtils.IsValidMediaTypeName(value)) - { - throw new InvalidOperationException(Strings.ServiceOperation_MimeTypeNotValid(value, this.Name)); - } - - this.mimeType = value; - } - } - - /// - /// Name of the service operation. - /// - public string Name - { - get { return this.name; } - } - - /// - /// Returns all the parameters for the given service operations. - /// - public ReadOnlyCollection Parameters - { - get { return this.parameters; } - } - - /// - /// Kind of result expected from this operation. - /// - public ServiceOperationResultKind ResultKind - { - get { return this.resultKind; } - } - - /// - /// Element of result type. - /// - /// - /// Note that if the method returns an IEnumerable<string>, - /// this property will be typeof(string). - /// - public ResourceType ResultType - { - get { return this.resultType; } - } - - /// - /// PlaceHolder to hold custom state information about service operation. - /// - public object CustomState - { - get - { - return this.GetCustomState(); - } - - set - { - this.SetCustomState(value); - } - } - - /// - /// Returns true, if this service operation has been set to read only. Otherwise returns false. - /// - public bool IsReadOnly - { - get { return this.isReadOnly; } - } - - /// - /// Entity set from which entities are read (possibly null). - /// - public ResourceSet ResourceSet - { - get { return this.resourceSet; } - } - - /// - /// Set this service operation to readonly. - /// - public void SetReadOnly() - { - if (this.isReadOnly) - { - return; - } - - foreach (ServiceOperationParameter parameter in this.Parameters) - { - parameter.SetReadOnly(); - } - - this.isReadOnly = true; - } - - /// - /// Check whether the given value for ServiceOperationResultKind is valid. If not, throw argument exception. - /// - /// value for ServiceOperationResultKind - /// name of the parameter - /// if the value is not valid. - private static void CheckServiceOperationResultKind(ServiceOperationResultKind kind, string parameterName) - { - if (kind < ServiceOperationResultKind.DirectValue || - kind > ServiceOperationResultKind.Void) - { - throw new ArgumentException(Strings.General_InvalidEnumValue(kind.GetType().Name), parameterName); - } - } - - /// - /// Throws an InvalidOperationException if this service operation is already set to readonly. - /// - private void ThrowIfSealed() - { - if (this.isReadOnly) - { - throw new InvalidOperationException(Strings.ServiceOperation_Sealed(this.Name)); - } - } - } -} + { + /// + /// HTTP method the service operation responds to. + /// + private readonly string method; + + /// + /// In-order parameters for this operation. + /// + private readonly ReadOnlyCollection parameters; + + /// + /// Kind of result expected from this operation. + /// + private readonly ServiceOperationResultKind resultKind; + + /// + /// Type of element of the method result. + /// + private readonly ResourceType resultType; + + /// + /// Empty parameter collection. + /// + private static ReadOnlyCollection emptyParameterCollection = + new ReadOnlyCollection(new ServiceOperationParameter[0]); + + /// + /// MIME type specified on primitive results, possibly null. + /// + private string mimeType; + + /// + /// Entity set from which entities are read, if applicable. + /// + private ResourceSet resourceSet; + + /// + /// Name of the service operation. + /// + private string name; + + /// + /// Is true, if the service operation is set to readonly i.e. fully initialized and validated. No more changes can be made, + /// after the service operation is set to readonly. + /// + private bool isReadOnly; + + /// + /// Initializes a new instance. + /// + /// name of the service operation. + /// Kind of result expected from this operation. + /// Type of element of the method result. + /// EntitySet of the result expected from this operation. + /// Protocol (for example HTTP) method the service operation responds to. + /// In-order parameters for this operation. + public ServiceOperation( + string name, + ServiceOperationResultKind resultKind, + ResourceType resultType, + ResourceSet resultSet, + string method, + IEnumerable parameters) + { + ExceptionUtils.CheckArgumentStringNotNullOrEmpty(name, "name"); + CheckServiceOperationResultKind(resultKind, "resultKind"); + ExceptionUtils.CheckArgumentStringNotNullOrEmpty(method, "method"); + + if ((resultKind == ServiceOperationResultKind.Void && resultType != null) || + (resultKind != ServiceOperationResultKind.Void && resultType == null)) + { + throw new ArgumentException(Strings.ServiceOperation_ResultTypeAndKindMustMatch("resultKind", "resultType", + ServiceOperationResultKind.Void)); + } + + if ((resultType == null || resultType.ResourceTypeKind != ResourceTypeKind.EntityType) && resultSet != null) + { + throw new ArgumentException(Strings.ServiceOperation_ResultSetMustBeNull("resultSet", "resultType")); + } + + if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.EntityType && + (resultSet == null || !resultSet.ResourceType.IsAssignableFrom(resultType))) + { + throw new ArgumentException(Strings.ServiceOperation_ResultTypeAndResultSetMustMatch("resultType", "resultSet")); + } + + if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.MultiValue) + { + throw new ArgumentException(Strings.ServiceOperation_InvalidResultType(resultType.FullName)); + } + + if (method != HttpConstants.HttpMethodGet && method != HttpConstants.HttpMethodPost) + { + throw new ArgumentException(Strings.ServiceOperation_NotSupportedProtocolMethod(method, name)); + } + + this.name = name; + this.resultKind = resultKind; + this.resultType = resultType; + this.resourceSet = resultSet; + this.method = method; + if (parameters == null) + { + this.parameters = ServiceOperation.emptyParameterCollection; + } + else + { + this.parameters = new ReadOnlyCollection(new List(parameters)); + HashSet paramNames = new HashSet(StringComparer.Ordinal); + foreach (ServiceOperationParameter p in this.parameters) + { + if (!paramNames.Add(p.Name)) + { + throw new ArgumentException(Strings.ServiceOperation_DuplicateParameterName(p.Name), "parameters"); + } + } + } + } + + /// + /// Protocol (for example HTTP) method the service operation responds to. + /// + public string Method + { + get { return this.method; } + } + + /// + /// MIME type specified on primitive results, possibly null. + /// + public string MimeType + { + get { return this.mimeType; } + + set + { + this.ThrowIfSealed(); + if (String.IsNullOrEmpty(value)) + { + throw new InvalidOperationException(Strings.ServiceOperation_MimeTypeCannotBeEmpty(this.Name)); + } + + if (!HttpUtils.IsValidMediaTypeName(value)) + { + throw new InvalidOperationException(Strings.ServiceOperation_MimeTypeNotValid(value, this.Name)); + } + + this.mimeType = value; + } + } + + /// + /// Name of the service operation. + /// + public string Name + { + get { return this.name; } + } + + /// + /// Returns all the parameters for the given service operations. + /// + public ReadOnlyCollection Parameters + { + get { return this.parameters; } + } + + /// + /// Kind of result expected from this operation. + /// + public ServiceOperationResultKind ResultKind + { + get { return this.resultKind; } + } + + /// + /// Element of result type. + /// + /// + /// Note that if the method returns an IEnumerable<string>, + /// this property will be typeof(string). + /// + public ResourceType ResultType + { + get { return this.resultType; } + } + + /// + /// PlaceHolder to hold custom state information about service operation. + /// + public object CustomState + { + get { return this.GetCustomState(); } + + set { this.SetCustomState(value); } + } + + /// + /// Returns true, if this service operation has been set to read only. Otherwise returns false. + /// + public bool IsReadOnly + { + get { return this.isReadOnly; } + } + + /// + /// Entity set from which entities are read (possibly null). + /// + public ResourceSet ResourceSet + { + get { return this.resourceSet; } + } + + /// + /// Set this service operation to readonly. + /// + public void SetReadOnly() + { + if (this.isReadOnly) + { + return; + } + + foreach (ServiceOperationParameter parameter in this.Parameters) + { + parameter.SetReadOnly(); + } + + this.isReadOnly = true; + } + + /// + /// Check whether the given value for ServiceOperationResultKind is valid. If not, throw argument exception. + /// + /// value for ServiceOperationResultKind + /// name of the parameter + /// if the value is not valid. + private static void CheckServiceOperationResultKind(ServiceOperationResultKind kind, string parameterName) + { + if (kind < ServiceOperationResultKind.DirectValue || + kind > ServiceOperationResultKind.Void) + { + throw new ArgumentException(Strings.General_InvalidEnumValue(kind.GetType().Name), parameterName); + } + } + + /// + /// Throws an InvalidOperationException if this service operation is already set to readonly. + /// + private void ThrowIfSealed() + { + if (this.isReadOnly) + { + throw new InvalidOperationException(Strings.ServiceOperation_Sealed(this.Name)); + } + } + } +} \ No newline at end of file diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Api.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Api.fs index 0560a44d..2985327a 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Api.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Api.fs @@ -1,4 +1,18 @@ - +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + namespace Castle.MonoRail open System @@ -16,6 +30,7 @@ namespace Castle.MonoRail let mutable _containerName = containerName let _entities = List() + let _entSeq : EntitySetConfig seq = upcast _entities let _resourcetypes = lazy ( let rts = ResourceMetadataBuilder.build(_schemaNs, _entities) rts |> Seq.iter (fun rt -> rt.SetReadOnly() ) @@ -23,7 +38,8 @@ namespace Castle.MonoRail let _resourcesets = lazy ( _resourcetypes.Force() |> Seq.filter (fun rt -> rt.ResourceTypeKind = ResourceTypeKind.EntityType && (_entities |> Seq.exists (fun e -> e.EntityName === rt.Name) ) ) - |> Seq.map (fun rt -> (let rs = ResourceSet(rt.Name, rt) + |> Seq.map (fun rt -> (let name = (_entSeq |> Seq.find(fun e -> e.TargetType = rt.InstanceType)).EntitySetName + let rs = ResourceSet(name, rt) rs.SetReadOnly() rs )) |> box :?> ResourceSet seq) @@ -32,14 +48,14 @@ namespace Castle.MonoRail member x.SchemaNamespace with get() = schemaNamespace member x.ContainerName with get() = containerName - member x.EntitySet<'a>(entityName:string, source:IQueryable<'a>) = + member x.EntitySet<'a>(entitySetName:string, source:IQueryable<'a>) = if _resourcesets.IsValueCreated then raise(InvalidOperationException("Model is frozen since ResourceSets were built")) - let cfg = EntitySetConfigurator(entityName, source) + let entityType = typeof<'a> + let cfg = EntitySetConfigurator(entitySetName, entityType.Name, source) _entities.Add cfg cfg - member x.Entities : EntitySetConfig seq = upcast _entities - + member x.Entities = _entSeq member internal x.ResourceSets = _resourcesets.Force() member internal x.ResourceTypes = _resourcetypes.Force() member internal x.GetResourceType(name) = @@ -48,10 +64,13 @@ namespace Castle.MonoRail member internal x.GetResourceSet(name) = x.ResourceSets |> Seq.tryFind (fun rs -> StringComparer.OrdinalIgnoreCase.Equals( rs.Name, name ) ) - member internal x.GetQueryable(name) = - match _entities |> Seq.tryFind (fun e -> StringComparer.OrdinalIgnoreCase.Equals(e.EntityName, name)) with + member internal x.GetQueryable(rs:ResourceSet) = + match _entities |> Seq.tryFind (fun e -> StringComparer.OrdinalIgnoreCase.Equals(e.EntitySetName, rs.Name)) with | Some e -> e.Source | _ -> null + member internal x.GetRelatedResourceSet(rt:ResourceType) = + x.ResourceSets + |> Seq.tryFind (fun rs -> rs.ResourceType = rt ) interface IDataServiceMetadataProvider with member x.ContainerNamespace = x.SchemaNamespace diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/AstLinqTranslator.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/AstLinqTranslator.fs new file mode 100644 index 00000000..15a26945 --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/AstLinqTranslator.fs @@ -0,0 +1,185 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData + +open System +open System.Linq +open System.Linq.Expressions +open System.Collections +open System.Collections.Generic +open System.Collections.Specialized +open System.Data.OData +open System.Data.Services.Providers + + +module AstLinqTranslator = + + type This = static member Assembly = typeof.Assembly + + let typed_select_methodinfo = + let m = This.Assembly.GetType("Castle.MonoRail.Extension.OData.AstLinqTranslator").GetMethod("typed_select") + System.Diagnostics.Debug.Assert(m <> null, "Could not get typed_select methodinfo") + m + + let typed_queryable_filter_methodinfo = + let m = This.Assembly.GetType("Castle.MonoRail.Extension.OData.AstLinqTranslator").GetMethod("typed_queryable_filter") + System.Diagnostics.Debug.Assert(m <> null, "Could not get typed_queryable_filter methodinfo") + m + + let typed_queryable_orderby_methodinfo = + let m = This.Assembly.GetType("Castle.MonoRail.Extension.OData.AstLinqTranslator").GetMethod("typed_queryable_orderby") + System.Diagnostics.Debug.Assert(m <> null, "Could not get typed_queryable_orderby methodinfo") + m + + let select_by_key (rt:ResourceType) (source:IQueryable) (key:string) = + // for now support for a single key + let keyProp = Seq.head rt.KeyProperties + + let keyVal = + // weak!! + System.Convert.ChangeType(key, keyProp.ResourceType.InstanceType) + + let rtType = rt.InstanceType + let ``method`` = typed_select_methodinfo.MakeGenericMethod([|rtType|]) + let result = ``method``.Invoke(null, [|source; keyVal; keyProp|]) + if result = null then failwithf "Lookup of entity %s for key %s failed." rt.Name key + result + + let apply_queryable_filter (rt:ResourceType) (items:IQueryable) (ast:QueryAst) = + let rtType = rt.InstanceType + let ``method`` = typed_queryable_filter_methodinfo.MakeGenericMethod([|rtType|]) + ``method``.Invoke(null, [|items; ast|]) + + let apply_queryable_orderby (rt:ResourceType) (items:IQueryable) (ast:OrderByAst seq) = + let rtType = rt.InstanceType + let ``method`` = typed_queryable_orderby_methodinfo.MakeGenericMethod([|rtType|]) + ``method``.Invoke(null, [|items; ast|]) + + let typed_select<'a> (source:IQueryable) (key:obj) (keyProp:ResourceProperty) = + let typedSource = source :?> IQueryable<'a> + let parameter = Expression.Parameter(source.ElementType, "element") + let e = Expression.Property(parameter, keyProp.Name) + + let bExp = Expression.Equal(e, Expression.Constant(key)) + let exp = Expression.Lambda(bExp, [parameter]) :?> Expression> + typedSource.FirstOrDefault(exp) + + + let internal build_linq_exp_tree (paramType:Type) (ast:QueryAst) = + + let parameter = Expression.Parameter(paramType, "element") + + let rec build_tree (node) : Expression = + match node with + | Element -> upcast parameter + | Null -> upcast Expression.Constant(null) + | Literal (t, v) -> upcast Expression.Constant(v, t) + + | PropertyAccess (s, prop, rt) -> + let target = build_tree s + upcast Expression.Property(target, prop) + + | UnaryExp (e, op, rt) -> + let exp = build_tree e + match op with + | UnaryOp.Negate -> upcast Expression.Negate (exp) + | UnaryOp.Not -> upcast Expression.Not (exp) + | UnaryOp.Cast -> upcast Expression.Convert(exp, rt.InstanceType) + // | UnaryOp.IsOf -> upcast Expression.TypeIs + | _ -> failwithf "Unsupported unary op %O" op + + | BinaryExp (l, r, op, rt) -> + let leftExp = build_tree l + let rightExp = build_tree r + match op with + | BinaryOp.Eq -> upcast Expression.Equal(leftExp, rightExp) + | BinaryOp.Neq -> upcast Expression.NotEqual(leftExp, rightExp) + | BinaryOp.Add -> upcast Expression.Add(leftExp, rightExp) + | BinaryOp.And -> upcast Expression.And(leftExp, rightExp) + | BinaryOp.Or -> upcast Expression.Or(leftExp, rightExp) + | BinaryOp.Mul -> upcast Expression.Multiply(leftExp, rightExp) + | BinaryOp.Div -> upcast Expression.Divide(leftExp, rightExp) + | BinaryOp.Mod -> upcast Expression.Modulo(leftExp, rightExp) + | BinaryOp.Sub -> upcast Expression.Subtract(leftExp, rightExp) + | BinaryOp.LessT -> upcast Expression.LessThan(leftExp, rightExp) + | BinaryOp.GreatT -> upcast Expression.GreaterThan(leftExp, rightExp) + | BinaryOp.LessET -> upcast Expression.LessThanOrEqual(leftExp, rightExp) + | BinaryOp.GreatET -> upcast Expression.GreaterThanOrEqual(leftExp, rightExp) + + | _ -> failwithf "Unsupported binary op %O" op + + | _ -> failwithf "Unsupported node %O" node + + let exp = build_tree ast + (exp, parameter) + + // a predicate is a Func + let build_linq_exp_predicate<'a> (paramType:Type) (ast:QueryAst) = + let rootExp, parameter = build_linq_exp_tree paramType ast + Expression.Lambda(rootExp, [parameter]) :?> Expression> + + let build_linq_exp_lambda (paramType:Type) (ast:QueryAst) = + let rootExp, parameter = build_linq_exp_tree paramType ast + Expression.Lambda(rootExp, [parameter]) + + (* + // a member access is a Func + let build_linq_exp_memberaccess<'a> (paramType:Type) (ast:QueryAst) = + let rootExp, parameter = build_linq_exp_tree paramType ast + Expression.Lambda(rootExp, [parameter]) :?> Expression> + *) + + let typed_queryable_filter<'a> (source:IQueryable) (ast:QueryAst) : IQueryable = + let typedSource = source :?> IQueryable<'a> + let orExp = build_linq_exp_predicate<'a> source.ElementType ast + let exp : Expression = upcast Expression.Quote( orExp ) + let where = Expression.Call(typeof, "Where", [|source.ElementType|], [|source.Expression; exp|]) + typedSource.Provider.CreateQuery(where) + + + let typed_queryable_orderby<'a> (source:IQueryable) (nodes:OrderByAst seq) : IQueryable = + // let typedSource = source :?> IQueryable<'a> + let elemType = typeof<'a> + let isFirstCall = ref true + + let applyOrder (source:IQueryable) node = + let build_lambda ast : Expression * Type = + let exp = build_linq_exp_lambda elemType ast + let retType = exp.Body.Type + upcast Expression.Quote exp, retType + let asc, desc = + if !isFirstCall + then "OrderBy", "OrderByDescending" + else "ThenBy", "ThenByDescending" + isFirstCall := false + + let exp, retType, op = + match node with + | OrderByAst.Asc ast -> + let exp, retType = build_lambda ast + exp, retType, asc + | OrderByAst.Desc ast -> + let exp, retType = build_lambda ast + exp, retType, desc + | _ -> failwith "Unsupported node" + + source.Provider.CreateQuery( Expression.Call(typeof, op, [|source.ElementType; retType|], [|source.Expression; exp|]) ) + + // applies expression, which returns a "new" + // queryable, which is then used on the next call + nodes |> Seq.fold (fun source c -> applyOrder source c ) source + + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Castle.MonoRail.Extension.OData.fsproj b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Castle.MonoRail.Extension.OData.fsproj index 7e9ec099..d73b9a45 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Castle.MonoRail.Extension.OData.fsproj +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Castle.MonoRail.Extension.OData.fsproj @@ -34,8 +34,17 @@ --keyfile:..\..\..\..\buildscripts\CastleKey.snk + + ..\..\..\..\lib\FParsec.dll + + + ..\..\..\..\lib\FParsecCS.dll + + + ..\..\..\..\lib\Newtonsoft.Json.dll + ..\..\..\..\lib\System.ComponentModel.Composition.Codeplex.dll @@ -52,15 +61,23 @@ + + - + + + + + - + + + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Configurators.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Configurators.fs new file mode 100644 index 00000000..11a17622 --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Configurators.fs @@ -0,0 +1,82 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.OData + + open System + open System.Collections.Generic + open System.Data.OData + open System.Data.Services.Providers + open System.Data.Services.Common + open System.Linq + open System.Linq.Expressions + open System.Reflection + + + [] + type EntitySetConfig(entitySetName:string, entityName:string, source, targetType:Type) = + let _entMapAttrs : List = List() + let _customPropInfo = Dictionary() + let mutable _entityName = entityName + member x.TargetType = targetType + member x.EntitySetName : string = entitySetName + member x.EntityName with get() = _entityName and set(v) = _entityName <- v + member x.Source : IQueryable = source + member internal x.EntityPropertyAttributes : List = _entMapAttrs + member internal x.CustomPropConfig = _customPropInfo + + and [] + PropConfigurator(mappedType:Type) = + class + abstract member GetValue : instance:obj * source:obj -> obj + abstract member SetValue : instance:obj * value:obj -> unit + member x.MappedType = mappedType + end + + and TypedPropConfigurator<'TSource,'TTarget> + (getter:Func<'TSource, 'TTarget>, + setter:Func<'TTarget, 'TSource>) = + class + inherit PropConfigurator(typeof<'TTarget>) + + override x.GetValue(instance, source) = + null + + override x.SetValue(instance, value) = + () + end + + and EntitySetConfigurator<'a>(entitySetName, entityName, source:IQueryable<'a>) = + inherit EntitySetConfig(entitySetName, entityName, source, typeof<'a>) + + member x.TypedSource = source + + member x.AddAttribute( att:EntityPropertyMappingAttribute ) = + x.EntityPropertyAttributes.Add att + x + + member x.WithEntityName(name) = + x.EntityName <- name + x + + member x.ForProperty<'TSource,'TTarget>(propSelector:Expression>, + getter:Func<'TSource, 'TTarget>, + setter:Func<'TTarget, 'TSource>) = + let propInfo = RefHelpers.lastpropinfo_from_exp(propSelector) + if propInfo = null then raise(ArgumentException()) + let config = TypedPropConfigurator(getter, setter) + x.CustomPropConfig.[propInfo] <- config + x + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Constants.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Constants.fs index 06a1beaf..fe097a12 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Constants.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Constants.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData open System.Data.OData open System.Text.RegularExpressions diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ControllerActionOperation.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ControllerActionOperation.fs new file mode 100644 index 00000000..4d4fcc5a --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ControllerActionOperation.fs @@ -0,0 +1,42 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData + + open System + open System.Collections.Generic + open System.Data.OData + open System.Data.Services.Providers + open System.Data.Services.Common + open System.Linq + open System.Linq.Expressions + open System.Reflection + open Castle.MonoRail.OData + open Castle.MonoRail.Extension.OData + open Castle.MonoRail.Hosting.Mvc + open Castle.MonoRail.Hosting.Mvc.Typed + + + [] + type ControllerActionOperation(rt:ResourceType, actionName:string) = + member x.ResourceType = rt + member x.Name = actionName + + + type internal SubControllerInfo = { + creator : Func; + desc : TypedControllerDescriptor; + } with + static member Empty = { creator = null; desc = null } \ No newline at end of file diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.AssemblyInfo.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.AssemblyInfo.fs index 927e05bc..bd674810 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.AssemblyInfo.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.AssemblyInfo.fs @@ -1,4 +1,18 @@ - +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + module AssemblyLevelDeclarations open System.Reflection diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.fs new file mode 100644 index 00000000..f091977f --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Internal.fs @@ -0,0 +1,27 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +module InternalUtils + + open System + open System.Reflection + open System.Collections.Generic + + + let getEnumerableElementType (possibleEnumerableType:Type) = + let found = possibleEnumerableType.FindInterfaces(TypeFilter(fun t o -> (o :?> Type).IsAssignableFrom(t)), typedefof>) + if found.Length = 0 + then None + else Some(found.[0].GetGenericArguments().[0]) diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataController.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataController.fs index ce0d1549..0ae07f6b 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataController.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataController.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail open System open System.Collections @@ -15,15 +30,13 @@ open Castle.MonoRail.Extension.OData - - - /// Entry point for exposing EntitySets through OData [] type ODataController<'T when 'T :> ODataModel>(model:'T) = - + let _provider = model :> IDataServiceMetadataProvider let _wrapper = DataServiceMetadataProviderWrapper(_provider) + let _services : Ref = ref null let resolveHttpOperation (httpMethod) = match httpMethod with @@ -33,41 +46,76 @@ | SegmentProcessor.HttpDelete -> SegmentOp.Delete | _ -> failwithf "Unsupported http method %s" httpMethod - // returns a function able execute a action (param to fun) - // on the controller associated with the entity type - let resource_controller_creator (services:IServiceRegistry) (entityType:Type) (routeMatch:RouteMatch) (context:HttpContextBase) paramCallback = - // todo: caching - let template = typedefof> - let concrete = template.MakeGenericType([|entityType|]) - let spec = PredicateControllerCreationSpec(fun t -> concrete.IsAssignableFrom(t)) - let prototype = services.ControllerProvider.CreateController(spec) - if prototype <> null then - let executor = services.ControllerExecutorProvider.CreateExecutor(prototype) - System.Diagnostics.Debug.Assert ( executor <> null && executor :? ODataEntitySubControllerExecutor ) - + let _executors = List() + let _invoker_cache = Dictionary bool -> IList -> RouteMatch -> HttpContextBase -> obj>() + // action isCollection params route context result + + let get_action_invoker rt = + let create_controller_prototype (rt:ResourceType) = + let creator = model.GetControllerCreator (rt) + if creator <> null + then creator.Invoke() + else null + + // we will have issues with object models with self referencies + // a better implementation would "consume" the items used, taking them off the list + let tryResolveParamValue (paramType:Type) isCollection (parameters:IList) = + let entryType = + + if isCollection then + match InternalUtils.getEnumerableElementType paramType with + | Some t -> t + | _ -> paramType + elif paramType.IsGenericType then + paramType.GetGenericArguments().[0] + else paramType + + match parameters |> Seq.tryFind (fun (ptype, _) -> ptype = entryType || entryType.IsAssignableFrom(ptype)) with + | Some (_, value) -> + // param is Model + if paramType.IsGenericType && paramType.GetGenericTypeDefinition() = typedefof> + then Activator.CreateInstance ((typedefof>).MakeGenericType(paramType.GetGenericArguments()), [|value|]) + else // entryType <> paramType && paramType.IsAssignableFrom(entryType) then + value + | _ -> null + + // returns a function able to invoke actions + let create_executor_fn (rt:ResourceType) prototype = + let executor = (!_services).ControllerExecutorProvider.CreateExecutor(prototype) + Diagnostics.Debug.Assert ( executor <> null && executor :? ODataEntitySubControllerExecutor ) + _executors.Add executor let odataExecutor = executor :?> ODataEntitySubControllerExecutor - odataExecutor.GetParameterCallback <- Func(paramCallback) - (fun action -> let result = executor.Execute(action, prototype, routeMatch, context) - // if the return is an empty result, we treat it as null - if result <> null && result :? EmptyResult - then (null, true) else (result, true)) - else (fun _ -> (null, false)) - - let tryResolveParamValue (paramType:Type) isCollection (rt:ResourceType) (value:obj) = - let entryType = - let found = paramType.FindInterfaces(TypeFilter(fun t o -> (o :?> Type).IsAssignableFrom(t)), typedefof>) - if found.Length = 0 - then paramType - else found.[0].GetGenericArguments().[0] - - // if param is Model - if paramType.IsGenericType && paramType.GetGenericTypeDefinition() = typedefof> - then - Activator.CreateInstance ((typedefof>).MakeGenericType(paramType.GetGenericArguments()), [|value|]) - elif paramType.IsAssignableFrom(entryType) then - value + (fun action isCollection parameters routeMatch context -> + let callback = Func(fun ptype -> tryResolveParamValue ptype isCollection parameters) + odataExecutor.GetParameterCallback <- callback + executor.Execute(action, prototype, routeMatch, context)) + let succ, existing = _invoker_cache.TryGetValue rt + if succ then existing + else + let prototype = create_controller_prototype rt + let executor = create_executor_fn rt prototype + _invoker_cache.[rt] <- executor + executor + + let invoke_action rt action parameters route context = + let invoker = get_action_invoker (rt) + invoker action parameters route context + + let invoke_controller (action:string) isCollection (rt:ResourceType) parameters optional route context = + if model.SupportsAction(rt, action) then + let result = invoke_action rt action isCollection parameters route context + if result = null || ( result <> null && result :? EmptyResult ) + // if the action didn't return anything meaningful, we consider it a success + then true + // else, the action took over, and we should therefore end our execution + else false else - null + // if we couldnt run the action, then the results + // depends on whether the call was optional or not + if optional then true else false + + let clean_up = + _executors |> Seq.iter (fun exec -> (exec :> IDisposable).Dispose() ) member x.Model = model member internal x.MetadataProvider = _provider @@ -75,7 +123,13 @@ member x.Process(services:IServiceRegistry, httpMethod:string, greedyMatch:string, routeMatch:RouteMatch, context:HttpContextBase) = + + + _services := services + + model.SetServiceRegistry services + let request = context.Request let response = context.Response response.AddHeader("DataServiceVersion", "2.0") @@ -83,61 +137,83 @@ let writer = response.Output let qs = request.Url.Query let baseUri = routeMatch.Uri - let requestContentType = request.ContentType - - let invoke_controller (action:string) isCollection (rt:ResourceType) o optional = - let paramCallback = fun (t:Type) -> tryResolveParamValue t isCollection rt o - let actionExecutor = resource_controller_creator services rt.InstanceType routeMatch context paramCallback - let result, executed = actionExecutor action - - if not optional && not executed then - failwith "Non existent controller or action not found. Entity: %O action: %s. Make sure there's a controller inheriting from ODataEntitySubController" rt.InstanceType action - else - if result = null then true - else - // todo: execute result? - false + let requestContentType, reqEncoding = + if request.ContentType.IndexOf(";", StringComparison.Ordinal) <> -1 then + let content = request.ContentType.Split([|';'|]).[0] + content, request.ContentEncoding + else request.ContentType, request.ContentEncoding + + let negotiate_content (isSingle) = + let supported = + if isSingle + then [|"application/atom+xml";"application/json";"application/xml";"text/plain"|] + else [|"application/atom+xml";"application/json"|] + services.ContentNegotiator.ResolveBestContentType (request.AcceptTypes, supported) + + let invoke action isColl (rt:ResourceType) (parameters:(Type*obj) seq) value isOptional = + let newParams = List(parameters) + if value <> null then + newParams.Add (rt.InstanceType, value) + invoke_controller action isColl rt newParams isOptional routeMatch context let callbacks = { - accessSingle = Func(fun rt o -> invoke_controller "Access" false rt o true); - accessMany = Func(fun rt o -> invoke_controller "AccessMany" true rt o true); - create = Func(fun rt o -> invoke_controller "Create" false rt o false); - update = Func(fun rt o -> invoke_controller "Update" false rt o false); - remove = Func(fun rt o -> invoke_controller "Remove" false rt o false); - } + authorize = Func(fun rt ps o -> invoke "Authorize" false rt ps o true); + authorizeMany = Func(fun rt ps o -> invoke "AuthorizeMany" true rt ps o true); + view = Func(fun rt ps o -> invoke "View" false rt ps o true); + viewMany = Func(fun rt ps o -> invoke "ViewMany" true rt ps o true); + create = Func(fun rt ps o -> invoke "Create" false rt ps o false); + update = Func(fun rt ps o -> invoke "Update" false rt ps o false); + remove = Func(fun rt ps o -> invoke "Remove" false rt ps o false); + operation = Action(fun rt ps action -> invoke action false rt ps null false |> ignore); + negotiateContent = Func(negotiate_content) + } + let requestParams = { - model = model; - provider = x.MetadataProvider; - wrapper = x.MetadataProviderWrapper; - contentType = requestContentType; - contentEncoding = request.ContentEncoding; - input = request.InputStream; - baseUri = baseUri; - accept = request.AcceptTypes; - } + model = model; + provider = x.MetadataProvider; + wrapper = x.MetadataProviderWrapper; + contentType = requestContentType; + contentEncoding = reqEncoding; + input = request.InputStream; + baseUri = baseUri; + accept = request.AcceptTypes; + } let responseParams = { - contentType = null ; - contentEncoding = response.ContentEncoding; - writer = writer; - httpStatus = 200; - } + contentType = null ; + contentEncoding = response.ContentEncoding; + writer = writer; + httpStatus = 200; + httpStatusDesc = "OK"; + location = null; + } try - let op = resolveHttpOperation httpMethod - let segments = SegmentParser.parse (greedyMatch, qs, model) - - SegmentProcessor.Process op segments callbacks requestParams responseParams - - if not <| String.IsNullOrEmpty responseParams.contentType then - response.ContentType <- responseParams.contentType - if responseParams.contentEncoding <> null then - response.ContentEncoding <- responseParams.contentEncoding - - EmptyResult.Instance - + try + let op = resolveHttpOperation httpMethod + let segments, meta, metaquery = SegmentParser.parse (greedyMatch, request.QueryString, model, baseUri) + + SegmentProcessor.Process op segments meta metaquery request.QueryString callbacks requestParams responseParams + + if responseParams.httpStatus <> 200 then + response.StatusCode <- responseParams.httpStatus + response.StatusDescription <- responseParams.httpStatusDesc + if not <| String.IsNullOrEmpty responseParams.contentType then + response.ContentType <- responseParams.contentType + if responseParams.contentEncoding <> null then + response.ContentEncoding <- responseParams.contentEncoding + if responseParams.location <> null then + response.AddHeader("Location", responseParams.location) + + EmptyResult.Instance + + finally + clean_up with | :? HttpException as ht -> reraise() | exc -> + + reraise() + // todo: instead of raising, we should serialize error e write it back // TODO: use responseContentType to resolve output mime type @@ -157,13 +233,12 @@ (* - - Resource not found for the segment 'People'. + + Resource not found for the segment 'People'. *) // if html, let the exception filters handle it, otherwise, let it bubble to asp.net - reraise() diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubController.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubController.fs new file mode 100644 index 00000000..f2d7f42a --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubController.fs @@ -0,0 +1,51 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail + + open System + open System.Linq + open System.Collections + open System.Collections.Generic + + /// Entry point for exposing EntitySets through OData + [] + type IODataEntitySubController<'TEntity when 'TEntity : not struct> = + interface + (* + member x.Authorize(ent:'TEntity) = + EmptyResult.Instance + + member x.Authorize(ents:IEnumerable<'TEntity>) = + EmptyResult.Instance + + member x.View(ent:'TEntity) = + EmptyResult.Instance + + member x.ViewAll(ents:IEnumerable<'TEntity>) = + EmptyResult.Instance + + member x.Post_Create(ent:'TEntity) = + EmptyResult.Instance + + member x.Put_Update(ent:'TEntity) = + EmptyResult.Instance + + member x.Delete_Remove(ent:'TEntity) = + EmptyResult.Instance + *) + end + + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubControllerExecutor.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubControllerExecutor.fs index 664445e6..f3543d8f 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubControllerExecutor.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataEntitySubControllerExecutor.fs @@ -1,14 +1,17 @@ -namespace Castle.MonoRail - - /// Entry point for exposing EntitySets through OData - [] - type ODataEntitySubController<'TEntity when 'TEntity : not struct>() = - class - // view - // create - // update - // delete - end +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. namespace Castle.MonoRail.Extension.OData @@ -101,7 +104,7 @@ namespace Castle.MonoRail.Extension.OData } let isSubController = baseTypes - |> Seq.exists (fun t -> t.IsGenericType && typedefof>.IsAssignableFrom( t.GetGenericTypeDefinition() )) + |> Seq.exists (fun t -> t.IsGenericType && typedefof>.IsAssignableFrom( t.GetGenericTypeDefinition() )) if isSubController then let exp = _execFactory.CreateExport() diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataModel.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataModel.fs new file mode 100644 index 00000000..09f39ee9 --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ODataModel.fs @@ -0,0 +1,166 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail + + open System + open System.Collections.Generic + open System.Data.OData + open System.Data.Services.Providers + open System.Linq + open Castle.MonoRail.OData + open Castle.MonoRail.Extension.OData + open Castle.MonoRail.Hosting.Mvc + open Castle.MonoRail.Hosting.Mvc.Typed + + + /// Access point to entities to be exposed by a single odata endpoint + type ODataModel(schemaNamespace, containerName) = + + let mutable _schemaNs = schemaNamespace + let mutable _containerName = containerName + let _serviceRegistry : Ref = ref null + + let _entities = List() + let _entSeq : EntitySetConfig seq = upcast _entities + + let _resourcetypes = lazy ( let rts = ResourceMetadataBuilder.build(_schemaNs, _entities) + rts |> Seq.iter (fun rt -> rt.SetReadOnly() ) + rts.ToList() |> box :?> ResourceType seq ) + + let _resourcesets = lazy ( _resourcetypes.Force() + |> Seq.filter (fun rt -> rt.ResourceTypeKind = ResourceTypeKind.EntityType && (_entities |> Seq.exists (fun e -> e.EntityName === rt.Name) ) ) + |> Seq.map (fun rt -> (let name = (_entSeq |> Seq.find(fun e -> e.TargetType = rt.InstanceType)).EntitySetName + let rs = ResourceSet(name, rt) + rs.SetReadOnly() + rs )) + |> box :?> ResourceSet seq) + + let _rt2ControllerCreator : Ref> = ref null + + member x.SchemaNamespace with get() = schemaNamespace + member x.ContainerName with get() = containerName + + member x.EntitySet<'a>(entitySetName:string, source:IQueryable<'a>) = + if _resourcesets.IsValueCreated then raise(InvalidOperationException("Model is frozen since ResourceSets were built")) + let entityType = typeof<'a> + let cfg = EntitySetConfigurator(entitySetName, entityType.Name, source) + _entities.Add cfg + cfg + + member x.Entities = _entSeq + member internal x.ResourceSets = _resourcesets.Force() + member internal x.ResourceTypes = _resourcetypes.Force() + member internal x.GetResourceType(name) = + x.ResourceTypes + |> Seq.tryFind (fun rs -> StringComparer.OrdinalIgnoreCase.Equals( rs.Name, name ) ) + member internal x.GetResourceSet(name) = + x.ResourceSets + |> Seq.tryFind (fun rs -> StringComparer.OrdinalIgnoreCase.Equals( rs.Name, name ) ) + member internal x.GetQueryable(rs:ResourceSet) = + match _entities |> Seq.tryFind (fun e -> StringComparer.OrdinalIgnoreCase.Equals(e.EntitySetName, rs.Name)) with + | Some e -> e.Source + | _ -> null + member internal x.GetRelatedResourceSet (rt:ResourceType) = + x.ResourceSets + |> Seq.tryFind (fun rs -> rs.ResourceType = rt) + + member internal x.SupportsAction (rt:ResourceType, name:string) = + if !_rt2ControllerCreator <> null then + let succ, info = (!_rt2ControllerCreator).TryGetValue rt + succ && info.desc.HasAction name + else false + + member internal x.GetControllerCreator (rt:ResourceType) = + if !_rt2ControllerCreator <> null then + let succ, info = (!_rt2ControllerCreator).TryGetValue rt + if succ then info.creator + else null + else null + + member internal x.GetNestedOperation (rt:ResourceType, name:string) : ControllerActionOperation = + if !_rt2ControllerCreator <> null then + let succ, info = (!_rt2ControllerCreator).TryGetValue rt + if succ && info.desc.HasAction name // TODO: should use HTTP VERB to narrow options + then ControllerActionOperation(rt, name) + else null + else null + + member internal x.SetServiceRegistry(services:IServiceRegistry) = + + if _serviceRegistry.Value = null then + _serviceRegistry := services + + let resolve_subcontrollerinfo (entityType:Type) = + let template = typedefof> + let concrete = template.MakeGenericType([|entityType|]) + let spec = PredicateControllerCreationSpec(fun t -> concrete.IsAssignableFrom(t)) + let creator = services.ControllerProvider.CreateController(spec) + if creator <> null then + let prototype = creator.Invoke() :?> TypedControllerPrototype + { creator = creator; desc = prototype.Descriptor :?> TypedControllerDescriptor } + else + SubControllerInfo.Empty + + let build_subcontrollers_map () = + let dict = Dictionary() + _resourcetypes.Force() + |> Seq.map (fun rt -> rt, resolve_subcontrollerinfo rt.InstanceType) + |> Seq.filter (fun t -> snd t <> SubControllerInfo.Empty) + |> Seq.iter (fun t -> dict.Add (fst t, snd t)) + dict + + _rt2ControllerCreator := build_subcontrollers_map () + + + interface IDataServiceMetadataProvider with + member x.ContainerNamespace = x.SchemaNamespace + member x.ContainerName = x.ContainerName + member x.ResourceSets = x.ResourceSets + member x.Types = x.ResourceTypes + member x.ServiceOperations = + // we dont support ops yet + Seq.empty + member x.GetDerivedTypes(resType) = + // we dont support hierarchies yet + Seq.empty + member x.HasDerivedTypes(resType) = + // we dont support hierarchies yet + false + member x.TryResolveResourceSet(name, rtToReturn) = + match x.GetResourceSet(name) with + | Some rt -> rtToReturn <- rt; true + | None -> false + member x.TryResolveResourceType(name, rtToReturn) = + match x.GetResourceType(name) with + | Some rt -> rtToReturn <- rt; true + | None -> false + member x.TryResolveServiceOperation(name, opToReturn) = + // we dont support ops yet + false + member x.GetResourceAssociationSet(resSet, resType, property) = + let targetResType = property.ResourceType + match x.ResourceSets |> Seq.tryFind (fun rs -> targetResType.InstanceType.IsAssignableFrom(rs.ResourceType.InstanceType)) with + | Some containerResSet -> + ResourceAssociationSet(resType.Name + "_" + property.Name, + ResourceAssociationSetEnd(resSet, resType, property), + ResourceAssociationSetEnd(containerResSet, targetResType, null)) + | _ -> null + + + + + + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/QueryExpressionParser.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/QueryExpressionParser.fs new file mode 100644 index 00000000..6cd3ba00 --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/QueryExpressionParser.fs @@ -0,0 +1,457 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData + +open System +open System.Collections +open System.Collections.Specialized +open System.Collections.Generic +open System.Data.OData +open System.Data.Services.Providers +open System.Linq +open System.Linq.Expressions +open System.Text +open System.Globalization +open System.Web +open Castle.MonoRail +open FParsec +open FParsec.Primitives +open FParsec.CharParsers + + +type BinaryOp = + | And = 0 + | Or = 1 + | Eq = 2 + | Neq = 3 + | Mul = 4 + | Div = 5 + | Mod = 6 + | Add = 7 + | Sub = 8 + | LessT = 9 + | GreatT = 10 + | LessET = 11 + | GreatET= 12 + +type UnaryOp = + | Negate = 0 + | Not = 1 + | Cast = 2 + // | IsOf + +type EdmPrimitives = + | Null = 0 + | Binary = 1 + | Boolean = 2 + | Byte = 3 + | DateTime = 4 + | Decimal = 5 + | Double = 6 + | Single = 7 + | Guid = 8 + | Int16 = 9 + | Int32 = 10 + | Int64 = 11 + | SByte = 12 + | SString = 13 + | Time = 14 + | String = 15 + | DateTimeOffset = 16 + + +type Exp = + | All + | Identifier of string + | Element + | Literal of EdmPrimitives * string * obj + | MemberAccess of Exp * Exp // string * (string list) option + | Unary of UnaryOp * Exp + | Binary of Exp * BinaryOp * Exp + // | MethodCall + // | Cast + // | IsOf + // | FuncCall + with + member x.ToStringTree() = + let b = StringBuilder() + let rec print (n) (level:int) = + b.AppendLine() |> ignore + for x in 1..level do b.Append(" ") |> ignore + match n with + | Identifier f -> b.Append (sprintf "Id %s" f) |> ignore + | Element -> b.Append (sprintf "Element") |> ignore + | Literal (t,s,v) -> + if v = null + then b.Append (sprintf "Literal %O [%s]" t s ) |> ignore + else + if v :? DateTime then + let dt = v :?> DateTime + b.Append (sprintf "Literal %O [%O]" t (dt.ToString(CultureInfo.InvariantCulture))) |> ignore + else b.Append (sprintf "Literal %O [%O]" t v ) |> ignore + + | MemberAccess (ex,n) -> + b.Append (sprintf "MemberAccess " ) |> ignore + print ex (level + 1) + print n (level + 1) + | Unary (op,ex) -> + b.Append (sprintf "Unary %O " op) |> ignore + print ex (level + 1) + | Binary (ex1, op, ex2) -> + b.Append (sprintf "Binary %O " op) |> ignore + print ex1 (level + 1) + print ex2 (level + 1) + | _ -> failwithf "Unsupported node type? Need to update this match, dude" + print x 1 + b.ToString() + + +type OrderByExp = + | Asc of Exp + | Desc of Exp + + +// rename to queryparser instead? +module QueryExpressionParser = + begin + (* + OData/Operator Precedence + Grouping (x) parenExpression, boolParenExpression + Primary x/m memberExpression + Primary x(...) methodCallExpression, boolMethodCallExpression + Unary -x negateExpression + Unary not x notExpression + Unary cast(T), cast(x, T) castExpression + Multiplicative x mul y mulExpression + Multiplicative x div y divExpression + Multiplicative x mod y modExpression + Additive x add y addExpression + Additive x sub y subExpression + Relational/ttesting x lt y ltExpression + Relational/ttesting x gt y gtExpression + Relational/ttesting x le y leExpression + Relational/ttesting x ge y geExpression + Relational/ttesting isof(T), isof(x, T) isofExpression + Equality x eq y eqExpression + Equality x ne y neExpression + Conditional AND x and y andExpression + Conditional OR x or y orExpression + + *) + + // Rewrites the tree to be rooted with MemberAccess(Element instead) + // not ideal, but couldnt get fparsec to produce the desired tree + let rec rebuildMemberAccessTree exp = + match exp with + | MemberAccess (r, arg) -> MemberAccess(rebuildMemberAccessTree r, arg) + | Identifier i -> MemberAccess(Exp.Element, exp) + | _ -> failwithf "Not supposed to traverse any other node type, but got into %O" exp + + let ws = spaces + // let nospace = preturn () + let pc c = ws >>. pchar c + let pstr s = ws >>. pstring s + let pstrCI s = ws >>. pstringCI s + let lparen = pstring "(" >>. ws + let rparen = pstring ")" >>. ws + let opp = new OperatorPrecedenceParser<_,_,_>() + let ida = identifier(IdentifierOptions()) + let entity = ws >>. ida .>> manyChars (noneOf "/") + let squote = pstring "'" + let shyphen = pstring "-" + let scolon = pstring ":" + + // Address MemberAccess(element, PriceAddress) + // Address/Name MemberAccess(MemberAccess(element, Address), Name) + // Address/Name/Length MemberAccess(MemberAccess(MemberAccess(element, Address), Name), Length) + let combine = stringReturn "/" (fun x y -> Exp.MemberAccess(x, y)) + let idAsExp = ida .>> ws |>> (fun id -> Exp.Identifier(id)) + let star = pchar '*' .>> ws |>> (fun _ -> Exp.Identifier("*")) + let memberAccessExp = chainl1 (idAsExp) (combine) + let selMemberAccessExp = chainl1 (idAsExp <|> star) (combine) + + let sign = pstr "-" <|>% "" + + let nullLiteral = pstr "null" .>> ws |>> fun _ -> Exp.Literal(EdmPrimitives.Null, null, null) + + // guidUriLiteral= "guid" SQUOTE guidLiteral SQUOTE + // guidLiteral = 8*HEXDIG "-" 4*HEXDIG "-" 4*HEXDIG "-" 12*HEXDIG + // 80749f18-d2f1-47e5-b1d0-4169c10125b5 + let guidLiteral = pstring "guid" .>> squote >>. + pipe5 + (manyMinMaxSatisfy 8 8 isHex .>> shyphen) + (manyMinMaxSatisfy 4 4 isHex .>> shyphen) + (manyMinMaxSatisfy 4 4 isHex .>> shyphen) + (manyMinMaxSatisfy 4 4 isHex .>> shyphen) + (manyMinMaxSatisfy 12 12 isHex) + (fun v1 v2 v3 v4 v5 -> sprintf "%s-%s-%s-%s-%s" v1 v2 v3 v4 v5) .>> squote .>> ws + |>> fun g -> Exp.Literal(EdmPrimitives.Guid, null, Guid.Parse(g)) + + let toInt v = Int32.Parse(v) + + // year "-" month "-" day + let datePart = pipe3 + (manyMinMaxSatisfy 4 4 isDigit .>> shyphen |>> toInt) + (manyMinMaxSatisfy 1 2 isDigit .>> shyphen |>> toInt) + (manyMinMaxSatisfy 1 2 isDigit |>> toInt) + (fun year month day -> DateTime(year, month, day)) + + // [":" second ["." nanoSeconds]] + let secondsNanoPart = opt ( pchar ':' >>. + (manyMinMaxSatisfy 1 2 isDigit |>> toInt) .>>. + (opt (pchar '.' >>. manyMinMaxSatisfy 1 7 isDigit |>> toInt))) + |>> fun (sec) -> + match sec with + | Some (secs, nano) -> + match nano with | Some n -> (secs, n) | _ -> (secs, 0) + | _ -> (0,0) + + // hour ":" minute [":" second ["." nanoSeconds]] + let timePart = pipe3 (manyMinMaxSatisfy 1 2 isDigit .>> scolon |>> toInt) + (manyMinMaxSatisfy 1 2 isDigit |>> toInt) + secondsNanoPart + ( fun hour minute secs -> DateTime(1999, 1, 1, hour, minute, fst secs, snd secs)) + + + // dateTimeLiteral = year "-" month "-" day "T" hour ":" minute [":" second ["." nanoSeconds]] + let datetimeLiteral = pstring "datetime" .>> squote >>. + pipe2 (datePart .>> pchar 'T') timePart + (fun date time -> DateTime(date.Year, date.Month, date.Day, time.Hour, time.Minute, time.Second, time.Millisecond)) .>> squote .>> ws + |>> fun g -> Exp.Literal(EdmPrimitives.DateTime, null, g) + + let signedIntPart = (sign .>>. many1Chars digit) |>> fun (s,v) -> Single.Parse(s + v) + let optDecimalPart = (pchar '.' >>. many1Chars digit |>> fun v -> Single.Parse("0." + v)) + <|>% 0.0f + let decimalPart = (pchar '.' >>. many1Chars digit |>> fun v -> Single.Parse("0." + v)) + + let intLiteral = (sign .>>. many1Chars digit) .>> ws + |>> fun (c,v) -> Exp.Literal(EdmPrimitives.Int32, null, Int32.Parse(c + v)) + let int64Literal = (sign .>>. many1Chars digit .>> pstringCI "l") .>> ws + |>> fun (c,v) -> Exp.Literal(EdmPrimitives.Int64, null, Int64.Parse(c + v)) + + // decimalUriLiteral = decimalLiteral ("M"/"m") + // decimalLiteral = sign 1*29DIGIT ["." 1*29DIGIT] + let decLiteral = pipe3 signedIntPart optDecimalPart (pstringCI "m") + (fun i d _ -> (decimal) (i + d)) .>> ws + |>> fun d -> Exp.Literal(EdmPrimitives.Decimal, null, d) + + (* + singleLiteral = nonDecimalPoint + / nonExp + / exp + / nan + / negativeInfinity + / postiveInfinity + nonDecimalPoint = sign 1*8DIGIT + nonExpDecimal = sign *DIGIT "." *DIGIT + expDecimal = sign 1*DIGIT "." 8DIGIT ("e" / "E") sign 1*2DIGIT + *) + let singleLiteral = ((attempt(pipe2 signedIntPart decimalPart (fun i d -> (float32) (i + d)))) + <|> (signedIntPart .>> pstrCI "f" |>> fun i -> (float32) i) ) .>> ws + |>> fun d -> Exp.Literal(EdmPrimitives.Single, null, d) + + (* + doubleLiteral = nonDecimalPoint + / nonExp + / exp + / nan + / negativeInfinity + / postiveInfinity + ("D" / "d") + nonDecimalPoint = sign 1*17DIGIT + nonExpDecimal = sign* DIGIT "." *DIGIT + expDecimal = sign 1*DIGIT "." 16DIGIT ("e" / "E") sign 1*3DIGIT + *) + let doubleLiteral = pipe3 signedIntPart optDecimalPart (pstringCI "d") + (fun i d _ -> (float) (i + d)) .>> ws + |>> fun d -> Exp.Literal(EdmPrimitives.Double, null, d) + + let stringLiteral = between (pc '\'') (pchar '\'') + (many1Chars (noneOf "'")) .>> ws |>> fun en -> Exp.Literal(EdmPrimitives.SString, en, null) + + let boolLiteral = (pstr "true" <|> pstr "false") .>> ws |>> fun v -> Exp.Literal(EdmPrimitives.Boolean, v, null) + let binaryLiteral = (pstr "X" <|> pstrCI "binary") >>. squote >>. (many1Chars hex) .>> squote .>> ws + |>> fun v -> Exp.Literal(EdmPrimitives.Binary, v, null) + + let literalExp = choice [ + nullLiteral + binaryLiteral + datetimeLiteral + guidLiteral + attempt(decLiteral) + attempt(doubleLiteral) + attempt(singleLiteral) + attempt(int64Literal) + intLiteral + stringLiteral + boolLiteral + ] + + let tryBetweenParens p = lparen >>? (p .>>? rparen) + + let exp = opp.ExpressionParser + let memberAccess = memberAccessExp |>> rebuildMemberAccessTree + let selMemberAccess = memberAccessExp |>> rebuildMemberAccessTree + let units = literalExp <|> tryBetweenParens exp <|> memberAccess + + opp.TermParser <- units + + let term = exp .>> eof + + let expandExp = sepBy1 memberAccess (pc ',' .>> ws) + + let orderbyTerm = memberAccess .>>. + ( pstringCI "asc" |>> (fun _ -> "asc") <|> pstringCI "desc" |>> (fun _ -> "desc") <|>% "asc") + |>> fun (m,o) -> if o = "asc" then OrderByExp.Asc(m) else OrderByExp.Desc(m) + + let orderByUnit = sepBy1 orderbyTerm (pc ',' .>> ws) + + // ShipCountry , Else [asc|desc] + // ShipCountry ne 'France' desc + // "=" [WSP] commonExpression [WSP] [asc / desc] + // *( "," [WSP] commonExpression [WSP] [asc / desc]) + let orderby = orderByUnit .>> eof + + + // $select=CustomerID,CompanyName,Address + // select=CustomerID,Orders + // select=CustomerID,Orders & $expand=Orders/OrderDetails + // $select= * + // $select=CustomerID,Orders/* & $expand=Orders/OrderDetails + let selectTerm = (pc '*' .>> ws |>> fun _ -> Exp.All) <|> selMemberAccessExp + let selectExp = (sepBy1 selectTerm (pc ',' .>> ws)) .>> eof + + + + opp.AddOperator(InfixOperator("and", ws, 1 , Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.And, y))) + opp.AddOperator(InfixOperator("or", ws, 2 , Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.Or, y))) + + opp.AddOperator(InfixOperator("eq", ws, 3 , Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.Eq, y))) + opp.AddOperator(InfixOperator("ne", ws, 4 , Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.Neq, y))) + + opp.AddOperator(InfixOperator("lt" , ws, 5, Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.LessT, y))) + opp.AddOperator(InfixOperator("gt" , ws, 6, Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.GreatT, y))) + opp.AddOperator(InfixOperator("le" , ws, 7, Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.LessET, y))) + opp.AddOperator(InfixOperator("ge" , ws, 8, Associativity.Right, fun x y -> Exp.Binary(x, BinaryOp.GreatET, y))) + // opp.AddOperator(PrefixOperator("isof",nospace, 70, false, fun x -> Exp.Unary(UnaryOp.IsOf, x)) + + opp.AddOperator(InfixOperator("add", ws, 9, Associativity.Left, fun x y -> Exp.Binary(x, BinaryOp.Add, y))) + opp.AddOperator(InfixOperator("sub", ws, 10, Associativity.Left, fun x y -> Exp.Binary(x, BinaryOp.Sub, y))) + + opp.AddOperator(InfixOperator("mul", ws, 11, Associativity.Left, fun x y -> Exp.Binary(x, BinaryOp.Mul, y))) + opp.AddOperator(InfixOperator("div", ws, 12, Associativity.Left, fun x y -> Exp.Binary(x, BinaryOp.Div, y))) + opp.AddOperator(InfixOperator("mod", ws, 13, Associativity.Left, fun x y -> Exp.Binary(x, BinaryOp.Mod, y))) + + opp.AddOperator(PrefixOperator("-", ws, 14, false, fun x -> Exp.Unary(UnaryOp.Negate, x))) + opp.AddOperator(PrefixOperator("not", ws, 15, false, fun x -> Exp.Unary(UnaryOp.Not, x))) + // opp.AddOperator(PrefixOperator("cast", nospace, 100, false, fun x -> Exp.Unary(UnaryOp.Cast, x)) + + let internal parse (original:string) p = + match run p original with + | Success(result, _, _) -> result + | Failure(errorMsg, _, _) -> (raise(ArgumentException(errorMsg))) + + let parse_orderby (original:string) = + parse original orderby |> Array.ofList + + let parse_filter (original:string) = + parse original term + + let parse_expand (original:string) = + parse original expandExp |> Array.ofList + + let parse_select (original:string) = + parse original selectExp |> Array.ofList + + end + +(* +isofExpression = "isof" [WSP] "("[[WSP] commonExpression [WSP] ","][WSP]stringLiteral [WSP] ")" +castExpression = "cast" [WSP] "("[[WSP] commonExpression [WSP] ","][WSP]stringLiteral [WSP] ")" +boolCastExpression = "cast" [WSP] "("[[WSP] commonExpression [WSP] ","][WSP] "Edm.Boolean" [WSP] ")" + +methodCallExpression = boolMethodExpression + / indexOfMethodCallExpression + / replaceMethodCallExpression + / toLowerMethodCallExpression + / toUpperMethodCallExpression + / trimMethodCallExpression + / substringMethodCallExpression + / concatMethodCallExpression + / lengthMethodCallExpression + / yearMethodCallExpression + / monthMethodCallExpression + / dayMethodCallExpression + / hourMethodCallExpression + / minuteMethodCallExpression + / secondMethodCallExpression + / roundMethodCallExpression + / floorMethodCallExpression + / ceilingMethodCallExpression + +boolMethodExpression = endsWithMethodCallExpression + / startsWithMethodCallExpression + / substringOfMethodCallExpression + +endsWithMethodCallExpression = "endswith" [WSP] + "(" [WSP] commonexpression [WSP] + "," [WSP] commonexpression [WSP] ")" +indexOfMethodCallExpression = "indexof" [WSP] + "(" [WSP] commonexpression [WSP] + "," [WSP] commonexpression [WSP] ")" +replaceMethodCallExpression = "replace" [WSP] + "(" [WSP] commonexpression [WSP] + "," [WSP] commonexpression [WSP] + "," [WSP] commonexpression [WSP] ")" +startsWithMethodCallExpression = "startswith" [WSP] + "(" [WSP] commonexpression [WSP] + "," [WSP] commonexpression [WSP] ")" +toLowerMethodCallExpression = "tolower" [WSP] + "(" [WSP] commonexpression [WSP] ")" +toUpperMethodCallExpression = "toupper" [WSP] + "(" [WSP] commonexpression [WSP] ")" +trimMethodCallExpression = "trim" [WSP] + "(" [WSP] commonexpression [WSP] ")" +substringMethodCallExpression = "substring" [WSP] + "(" [WSP] commonexpression [WSP] + [ "," [WSP] commonexpression [WSP] ] ")" +substringOfMethodCallExpression = "substringof" [WSP] + "(" [WSP] commonexpression [WSP] + [ "," [WSP] commonexpression [WSP] ] ")" +concatMethodCallExpression = "concat" [WSP] + "(" [WSP] commonexpression [WSP] + [ "," [WSP] commonexpression [WSP] ] ")" +lengthMethodCallExpression = "length" [WSP] + "(" [WSP] commonexpression [WSP] ")" +yearMethodCallExpression = "year" [WSP] + "(" [WSP] commonexpression [WSP] ")" +monthMethodCallExpression = "month" [WSP] + "(" [WSP] commonexpression [WSP] ")" +dayMethodCallExpression = "day" [WSP] + "(" [WSP] commonexpression [WSP] ")" +hourMethodCallExpression = "hour" [WSP] + "(" [WSP] commonexpression [WSP] ")" +minuteMethodCallExpression = "minute" [WSP] + "(" [WSP] commonexpression [WSP] ")" +secondMethodCallExpression = "second" [WSP] + "(" [WSP] commonexpression [WSP] ")" +roundMethodCallExpression = "round" [WSP] + "(" [WSP] commonexpression [WSP] ")" +floorMethodCallExpression = "floor" [WSP] + "(" [WSP] commonexpression [WSP] ")" +ceilingMethodCallExpression = "ceiling" [WSP] + "(" [WSP] commonexpression [WSP] ")" +*) \ No newline at end of file diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/QuerySemanticAnalysis.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/QuerySemanticAnalysis.fs new file mode 100644 index 00000000..c78208c1 --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/QuerySemanticAnalysis.fs @@ -0,0 +1,303 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData + +open System +open System.Collections +open System.Collections.Specialized +open System.Collections.Generic +open System.Data.OData +open System.Data.Services.Providers +open System.Linq +open System.Linq.Expressions +open System.Text +open System.Reflection +open System.Web +open Castle.MonoRail +open FParsec +open FParsec.Primitives +open FParsec.CharParsers + + +type QueryAst = + | Element + | Null + | Literal of Type * obj + | PropertyAccess of QueryAst * PropertyInfo * ResourceType + | BinaryExp of QueryAst * QueryAst * BinaryOp * ResourceType + | UnaryExp of QueryAst * UnaryOp * ResourceType + with + member x.GetExpType(root:ResourceType) = + match x with + | Element -> root.InstanceType + | Null -> typeof + | Literal (t,_) -> t + | PropertyAccess (_,_,rt) -> rt.InstanceType + | UnaryExp (_,_,rt) -> rt.InstanceType + | BinaryExp (_,_,_,rt) -> rt.InstanceType + + // member x.IsDecimal() + + member x.ToStringTree() = + let b = StringBuilder() + let rec print (n) (level:int) = + b.AppendLine() |> ignore + for x in 1..level do b.Append(" ") |> ignore + match n with + | Null -> b.Append (sprintf "Null") |> ignore + | Element -> b.Append (sprintf "Element") |> ignore + | Literal (t,v) -> b.Append (sprintf "Literal %s [%O]" t.Name v) |> ignore + | PropertyAccess (ex,pinfo,rt) -> + b.Append (sprintf "PropertyAccess [%s] = %s" pinfo.Name rt.FullName) |> ignore + print ex (level + 1) + + | UnaryExp (ex,op,rt) -> + b.Append (sprintf "Unary %O %s" op rt.FullName) |> ignore + print ex (level + 1) + + | BinaryExp (ex1,ex2,op,rt) -> + b.Append (sprintf "Binary %O %s" op rt.FullName) |> ignore + print ex1 (level + 1) + print ex2 (level + 1) + + | _ -> failwithf "Unsupported node type? Need to update this match, dude" + print x 1 + b.ToString() + +type OrderByAst = + | Nothing + | Asc of QueryAst + | Desc of QueryAst + +module QuerySemanticAnalysis = + begin + + // recursively process the raw exp tree transforming it + // into a QueryAst bound to types and RTs + let rec private r_analyze e (rt:ResourceType) = + match e with + | Exp.Element -> QueryAst.Element, rt + | Exp.Literal (edm, v, o) -> + let literal = + match edm with + | EdmPrimitives.Null -> QueryAst.Null + | EdmPrimitives.SString -> QueryAst.Literal (typeof, v) + | EdmPrimitives.Int16 -> QueryAst.Literal (typeof, o) + | EdmPrimitives.Int32 -> QueryAst.Literal (typeof, o) + | EdmPrimitives.Int64 -> QueryAst.Literal (typeof, o) + | EdmPrimitives.Single -> QueryAst.Literal (typeof, o) + | EdmPrimitives.Decimal -> QueryAst.Literal (typeof, o) + | EdmPrimitives.Double -> QueryAst.Literal (typeof, o) + | EdmPrimitives.DateTime -> QueryAst.Literal (typeof, o) + | EdmPrimitives.Boolean -> QueryAst.Literal (typeof, Convert.ToBoolean(v)) + | EdmPrimitives.Guid -> QueryAst.Literal (typeof, o) + | _ -> failwithf "Unsupported edm primitive type %O" edm + + match literal with + | QueryAst.Literal (t,v) -> literal, ResourceType.GetPrimitiveResourceType(t) + | QueryAst.Null -> literal, null + | _ -> failwith "What kind of literal is that?!" + + | Exp.MemberAccess (ex, id) -> + let name = + match id with + | Identifier i -> i + | _ -> failwith "Only Identifier nodes are supported as the rhs of a MemberAccess node" + + let get_prop (name:string) (rt:ResourceType) = + match rt.Properties |> Seq.tryFind (fun p -> p.Name === name) with + | Some p -> p + | _ -> failwith "Property not found?" + + let root, nestedRt = r_analyze ex rt + + // rt.InstanceType.GetProperty(p.Name, BindingFlags.Public ||| BindingFlags.Instance) + let prop = get_prop name nestedRt + let propInfo = nestedRt.InstanceType.GetProperty(prop.Name, BindingFlags.Public ||| BindingFlags.Instance) + + QueryAst.PropertyAccess(root, propInfo, prop.ResourceType), prop.ResourceType + + + | Exp.Binary (ex1, op, ex2) -> + + let texp1, t1 = r_analyze ex1 rt + let texp2, t2 = r_analyze ex2 rt + + // Unary Numeric promotions + // A data service MAY support unary numeric promotions for the negation operator + // (negateExpression common expressions). Unary promotions consist of converting + // operands of type Edm.Byte or Edm.Int16 to Edm.Int32 and of type Edm.Single to Edm.Double. + + // Binary Numeric promotions + // If supported, binary numeric promotion SHOULD implicitly convert both operands to a + // common type and, in the case of the nonrelational operators, also become the return type. + // If supported, a data service SHOULD support binary numeric promotion for the following + // Entity Data Model (EDM) primitive types + + let cast_exp (exp:QueryAst) targetType = + // * If binary numeric promotion is supported, a data service SHOULD use a castExpression to + // promote an operand to the target type. + if exp.GetExpType(rt) = targetType + then exp + else QueryAst.UnaryExp(exp, UnaryOp.Cast, ResourceType.GetPrimitiveResourceType(targetType)) + + let convert_to_bool (e1:QueryAst) (e2:QueryAst) = + if e1.GetExpType(rt) <> typeof || e2.GetExpType(rt) <> typeof then + let newe1 = + if e1.GetExpType(rt) = typeof + then QueryAst.UnaryExp(e1, UnaryOp.Cast, ResourceType.GetPrimitiveResourceType(typeof)) + else e1 + let newe2 = + if e2.GetExpType(rt) = typeof + then QueryAst.UnaryExp(e2, UnaryOp.Cast, ResourceType.GetPrimitiveResourceType(typeof)) + else e2 + newe1, newe2 + else e1, e2 + + let binary_numeric_promote (e1:QueryAst) (e2:QueryAst) originalRt = + // If supported, binary numeric promotion SHOULD consist of the application of the + // following rules in the order specified: + // * If either operand is of type Edm.Decimal, the other operand is converted + // to Edm.Decimal unless it is of type Edm.Single or Edm.Double. + // * Otherwise, if either operand is Edm.Double, the other operand is converted to type Edm.Double. + // * Otherwise, if either operand is Edm.Single, the other operand is converted to type Edm.Single. + // * Otherwise, if either operand is Edm.Int64, the other operand is converted to type Edm.Int64. + // * Otherwise, if either operand is Edm.Int32, the other operand is converted to type Edm.Int32 + // * Otherwise, if either operand is Edm.Int16, the other operand is converted to type Edm.Int16. + + if e1.GetExpType(rt) = typeof || e2.GetExpType(rt) = typeof then + cast_exp e1 typeof, cast_exp e2 typeof, ResourceType.GetPrimitiveResourceType (typeof) + + elif e1.GetExpType(rt) = typeof || e2.GetExpType(rt) = typeof then + cast_exp e1 typeof, cast_exp e2 typeof, ResourceType.GetPrimitiveResourceType (typeof) + + elif e1.GetExpType(rt) = typeof || e2.GetExpType(rt) = typeof then + cast_exp e1 typeof, cast_exp e2 typeof, ResourceType.GetPrimitiveResourceType (typeof) + + elif e1.GetExpType(rt) = typeof || e2.GetExpType(rt) = typeof then + cast_exp e1 typeof, cast_exp e2 typeof, ResourceType.GetPrimitiveResourceType (typeof) + + elif e1.GetExpType(rt) = typeof || e2.GetExpType(rt) = typeof then + cast_exp e1 typeof, cast_exp e2 typeof, ResourceType.GetPrimitiveResourceType (typeof) + + elif e1.GetExpType(rt) = typeof || e2.GetExpType(rt) = typeof then + cast_exp e1 typeof, cast_exp e2 typeof, ResourceType.GetPrimitiveResourceType (typeof) + + else e1, e2, originalRt + + let assert_isnumeric (t:Type) = + //t.IsPrimitive && + () + + let newExp1, newExp2, eqRt = + match op with + | BinaryOp.And + | BinaryOp.Or -> + // suports booleans + let new1, new2 = convert_to_bool texp1 texp2 + new1, new2, ResourceType.GetPrimitiveResourceType(typeof) + + | BinaryOp.Add + | BinaryOp.Mul + | BinaryOp.Div + | BinaryOp.Mod + | BinaryOp.Sub -> + // suports decimal, double single int32 and int64 + // need to promote members if necessary + let new1, new2, newRt = binary_numeric_promote texp1 texp2 t1 + assert_isnumeric (newRt.InstanceType) + assert_isnumeric (new1.GetExpType(rt)) + assert_isnumeric (new2.GetExpType(rt)) + new1, new2, newRt + + | BinaryOp.Neq + | BinaryOp.Eq + | BinaryOp.LessT + | BinaryOp.GreatT + | BinaryOp.LessET + | BinaryOp.GreatET -> + // suports double single int32 int64 string datetime guid binary + let boolRt = ResourceType.GetPrimitiveResourceType(typeof) + let new1, new2, newRt = binary_numeric_promote texp1 texp2 boolRt + new1, new2, boolRt + + | _ -> failwith "Unknown binary operation" + + QueryAst.BinaryExp(newExp1, newExp2, op, eqRt), eqRt + + | Exp.Unary (op, exp) -> + + let exp1, expRt = r_analyze exp rt + + let newExp, eqRt = + match op with + | UnaryOp.Negate -> + // suports decimal, double single int32 and int64 + // need to promote members if necessary + exp1, expRt + + | UnaryOp.Not -> + // suports bool only + exp1, ResourceType.GetPrimitiveResourceType(typeof) + + // TODO: isofExpression + // TODO: cast + | _ -> failwith "Unknown unary operation" + + QueryAst.UnaryExp(newExp, op, eqRt), eqRt + + | _ -> failwithf "Unsupported exp type %O" e + + + let analyze_and_convert (exp:Exp) (rt:ResourceType) : QueryAst = + + let newTree, _ = r_analyze exp rt + newTree + + let analyze_and_convert_orderby (exps:OrderByExp[]) (rt:ResourceType) : OrderByAst seq = + + let convert exp = + match exp with + | OrderByExp.Asc e -> let ast, _ = r_analyze e rt in OrderByAst.Asc(ast) + | OrderByExp.Desc e -> let ast, _ = r_analyze e rt in OrderByAst.Desc(ast) + | _ -> failwithf "Unsupported OrderByExp type %O" exp + + exps |> Seq.map convert + + let analyze_and_convert_expand (exps:Exp[]) (rt:ResourceType) (properties:HashSet) = + + let rec resolve_property ast (rt:ResourceType) = + match ast with + | QueryAst.Element -> + rt + | QueryAst.PropertyAccess (source, name, res) -> + let target = resolve_property source rt + let prop = target.Properties |> Seq.find (fun p -> p.Name = name.Name) + properties.Add prop |> ignore + res + | _ -> failwithf "Unsupported QueryAst type %O" ast + + let properties = HashSet() + + let convert exp = + let ast, _ = r_analyze exp rt + resolve_property ast rt + + exps |> Seq.iter (fun e -> convert e |> ignore) + + + end + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ResourceMetadataBuilder.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ResourceMetadataBuilder.fs index 31188c8b..e107a3d6 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ResourceMetadataBuilder.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/ResourceMetadataBuilder.fs @@ -1,38 +1,17 @@ - -namespace Castle.MonoRail.OData - - open System - open System.Collections.Generic - open System.Data.OData - open System.Data.Services.Providers - open System.Data.Services.Common - open System.Linq - open System.Linq.Expressions - open System.Reflection - - [] - type EntitySetConfig(entityName, source, targetType:Type) = - let _entMapAttrs : List = List() - member x.TargetType = targetType - member x.EntityName : string = entityName - member x.Source : IQueryable = source - member internal x.EntityPropertyAttributes : List = _entMapAttrs - - - and EntitySetConfigurator<'a>(entityName, source:IQueryable<'a>) = - inherit EntitySetConfig(entityName, source, typeof<'a>) - - member x.TypedSource = source - - member x.AddAttribute( att:EntityPropertyMappingAttribute ) = - //let memberAccess = exp.Body :?> MemberExpression - //let prop = memberAccess.Member :?> PropertyInfo - //let res, list = x.EntityPropertyAttributes.TryGetValue prop - //if res - //then list.Add att - //else x.EntityPropertyAttributes.[prop] <- List([att]) - x.EntityPropertyAttributes.Add att - +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. namespace Castle.MonoRail.Extension.OData @@ -62,7 +41,7 @@ namespace Castle.MonoRail.Extension.OData let private resolve_resourceTypeKind_based_on_properties (entType:Type) = let hasKeyOrNonPrimitives = entType.GetProperties(PropertiesBindingFlags) - |> Seq.exists (fun p -> p.IsDefined(typeof, true) || not <| is_primitive p.PropertyType) + |> Seq.exists (fun p -> p.IsDefined(typeof, true)) if hasKeyOrNonPrimitives then ResourceTypeKind.EntityType else ResourceTypeKind.ComplexType @@ -76,7 +55,6 @@ namespace Castle.MonoRail.Extension.OData then pType.GetGenericArguments().[0] else null - let rec private resolveRT (pType) (knownTypes:Dictionary) (builderFn) = // maybe it's a primitive let resourceType = ResourceType.GetPrimitiveResourceType(pType) @@ -103,7 +81,6 @@ namespace Castle.MonoRail.Extension.OData then Some(result, false) else None - let private resolve_propertKind (resource:ResourceType) (propertyInfo:PropertyInfo) (isCollection) = if resource.ResourceTypeKind = ResourceTypeKind.Primitive then @@ -122,35 +99,40 @@ namespace Castle.MonoRail.Extension.OData failwithf "Unsupported resource type (kind) for property" - let private build_property (resource:ResourceType) (prop:PropertyInfo) (knownTypes:Dictionary) builderFn = + let private build_property (resource:ResourceType) (prop:PropertyInfo) (knownTypes:Dictionary) + (customPropMapping:Dictionary<_,_>) builderFn = if not prop.DeclaringType.IsInterface && prop.CanRead && prop.GetIndexParameters().Length = 0 then - let propType = prop.PropertyType - match resolveRT propType knownTypes builderFn with + let propType = + let succ, config : bool * PropConfigurator = customPropMapping.TryGetValue(prop) + if not succ then prop.PropertyType + else config.MappedType + + match resolveRT propType knownTypes builderFn with | Some (resolvedType, isColl) -> - let kind = resolve_propertKind resolvedType prop isColl + let kind = resolve_propertKind resolvedType prop isColl let resProp = ResourceProperty(prop.Name, kind, resolvedType) resource.AddProperty resProp | _ -> () let private build_properties (resource:ResourceType) (knownTypes:Dictionary) (type2CustomName:Dictionary) - resourceBuilderFn (entType:Type) = + customPropMapping resourceBuilderFn (entType:Type) = entType.GetProperties(PropertiesBindingFlags) - |> Seq.iter (fun prop -> build_property resource prop knownTypes resourceBuilderFn) + |> Seq.iter (fun prop -> build_property resource prop knownTypes customPropMapping resourceBuilderFn) let rec private build_resource_type schemaNs (knownTypes:Dictionary) (type2CustomName:Dictionary) - (entMapAttributes:List) (entType:Type) = + (entMapAttributes:List) customPropMapping (entType:Type) = if entType.IsValueType || not entType.IsVisible || entType.IsArray || entType.IsPointer || entType.IsCOMObject || entType.IsInterface || entType = typeof || entType = typeof || entType = typeof || entType = typeof || entType = typeof || entType = typeof || entType.IsEnum then null - elif knownTypes.ContainsKey(entType) then + elif knownTypes.ContainsKey(entType) then knownTypes.[entType] - else + else // note: no support for hierarchies of resource types yet let kind = resolve_resourceTypeKind_based_on_properties entType @@ -159,13 +141,14 @@ namespace Castle.MonoRail.Extension.OData knownTypes.[entType] <- resource entMapAttributes |> Seq.iter (fun e -> resource.AddEntityPropertyMappingAttribute e) - build_properties resource knownTypes type2CustomName (build_resource_type schemaNs knownTypes type2CustomName entMapAttributes) entType + build_properties resource knownTypes type2CustomName customPropMapping (build_resource_type schemaNs knownTypes type2CustomName entMapAttributes customPropMapping) entType resource /// Asserts that the return from build_resource_type is non null and EntityType - let private build_entity_resource schemaNs (config:EntitySetConfig) (knownTypes) (type2CustomName) = - let resource = build_resource_type schemaNs knownTypes type2CustomName config.EntityPropertyAttributes config.TargetType + let private build_entity_resource schemaNs (config:EntitySetConfig) propMappings (knownTypes) (type2CustomName) = + + let resource = build_resource_type schemaNs knownTypes type2CustomName config.EntityPropertyAttributes propMappings config.TargetType if resource = null || resource.ResourceTypeKind <> ResourceTypeKind.EntityType then failwithf "Expecting an entity to be constructed from %O but instead got something else" config.TargetType @@ -173,13 +156,21 @@ namespace Castle.MonoRail.Extension.OData let build(schemaNs:string, configs:EntitySetConfig seq) = + // aggregates the custom mapping for all properties + let propMappings = + let dict = Dictionary() + configs + |> Seq.collect (fun c -> c.CustomPropConfig) + |> Seq.iter (fun kv -> dict.[kv.Key] <- kv.Value) + dict + let type2CustomName = Enumerable.ToDictionary(configs, (fun (c:EntitySetConfig) -> c.TargetType), (fun (c:EntitySetConfig) -> c.EntityName)) let knownTypes = Dictionary() - configs |> Seq.iter (fun c -> build_entity_resource schemaNs c knownTypes type2CustomName) + configs |> Seq.iter (fun c -> build_entity_resource schemaNs c propMappings knownTypes type2CustomName) knownTypes.Values |> box :?> ResourceType seq diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentParser.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentParser.fs index 677f7869..fe3a2ff2 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentParser.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentParser.fs @@ -1,24 +1,45 @@ - +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + namespace Castle.MonoRail.Extension.OData open System open System.Collections +open System.Collections.Specialized open System.Collections.Generic open System.Data.OData open System.Data.Services.Providers open System.Linq +open System.Linq.Expressions open System.Web open Castle.MonoRail -type EntityDetails = { +type EntityAccessInfo = { + RawPathSegment : string; + Uri : Uri; mutable ManyResult : IQueryable; mutable SingleResult : obj; + ResSet : ResourceSet; ResourceType : ResourceType; Name : string; - Key : string + Key : string; } -type PropertyAccessDetails = { +type PropertyAccessInfo = { + RawPathSegment : string; + Uri : Uri; mutable ManyResult : IEnumerable; mutable SingleResult : obj; ResourceType : ResourceType; @@ -27,31 +48,169 @@ type PropertyAccessDetails = { } type MetaSegment = + | Nothing | Metadata - | Batch | Count | Value - | Links of UriSegment[] + // | Links // of UriSegment[] + | Batch + +and MetaQuerySegment = + | Nothing | Format of string | Skip of int | Top of int - | OrderBy of string[] - | Expand of string[] - | Select of string[] - | InlineCount + | OrderBy of string + | Expand of string + | Select of string + | InlineCount of string | Filter of string and UriSegment = - | Meta of MetaSegment - | ServiceDirectory - | EntitySet of EntityDetails - | EntityType of EntityDetails - | ComplexType of PropertyAccessDetails - | PropertyAccessSingle of PropertyAccessDetails - | PropertyAccessCollection of PropertyAccessDetails - | ServiceOperation + // | Links | Nothing - + | ServiceDirectory + | EntitySet of EntityAccessInfo + | EntityType of EntityAccessInfo + | ComplexType of PropertyAccessInfo + | PropertyAccessSingle of PropertyAccessInfo + | PropertyAccessCollection of PropertyAccessInfo + | RootServiceOperation + | ActionOperation of ControllerActionOperation + + +(* + Uri Syntax spec. See ms-odata.pdf, section 2.2.3.1 + ================================================== + +serviceRoot = *( "/" segment-nz ) ; section 3.3 of [RFC3986] + ; segment-nz = the non empty sequence of characters + ; outside the set of URI reserved + ; characters as specified in [RFC3986] + +pathPrefix = *( "/" segment-nz ) ; zero or more URI path segments + +resourcePath = "/" + ( ([entityContainer "."] entitySet) + / serviceOperation-collEt + [ paren ] [ navPath ] [ count ] + ) + / serviceOperation + +paren = "()" + +serviceOperation = serviceOperation-et + / serviceOperation-collCt + / serviceOperation-ct + / serviceOperation-collPrim + / serviceOperation-prim [ value ] + +count = "/$count" + +navPath = "("keyPredicate")" [navPath-options] + +navPath-options = [ navPath-np / propertyPath / propertyPath-ct / value ] + +navPath-np = "/" + ( ("$links" / entityNavProperty ) + / (entityNavProperty-es [ paren ] [ navPath ]) + / (entityNavProperty-et [ navPath-options ]) + ) + +entityNavProperty = (entityNavProperty-es [ paren ]) + / entityNavProperty-et + +propertyPath = "/" entityProperty [ value ] +propertyPath-ct = 1 * ("/" entityComplexProperty) [ propertyPath ] + +keyPredicate = keyPredicate-single + / keyPredicate-cmplx + +keyPredicate-single = 1*DIGIT ; section B.1 of [RFC5234] + / ([1*unreserved] "’" 1*unreserved "’") ; section 2.3 of [RFC3986] + / 1*(HEXDIG HEXDIG)) ; section B.1 of [RFC5234] + +keyPredicate-cmplx = entityProperty "=" keyPredicate-single + ["," keyPredicate-cmplx] + +value = "/$value" + +queryOptions = sysQueryOption ; see section 2.2.3.6.1 + / customQueryOption ; section 2.2.3.6.2 + / serviceOpParam ; see section 2.2.3.6.3 + *("&"(sysQueryOption / serviceOpParam / customQueryOption)) + +sysQueryOption = expandQueryOp + / filterQueryOp + / orderbyQueryOp + / skipQueryOp + / topQueryOp + / formatQueryOp + / countQueryOp + / selectQueryOp + / skiptokenQueryOp + +customQueryOption = *pchar ; section 3.3 of [RFC3986] +expandQueryOp = ; see section 2.2.3.6.1.3 +filterQueryOp = ; see section 2.2.3.6.1.4 +orderbyQueryOp = ; see section 2.2.3.6.1.6 +skipQueryOp = ; see section 2.2.3.6.1.7 +serviceOpParam = ; see section 2.2.3.6.3 +topQueryOp = ; see section 2.2.3.6.1.8 +formatQueryOp = ; see section 2.2.3.6.1.5 +countQueryOp = ; see section 2.2.3.6.1.10 +selectQueryOp = ; see section 2.2.3.6.1.11 +skiptokenQueryOp = ; see section 2.2.3.6.1.9 + +;Note: The semantic meaning, relationship to Entity Data Model +; (EDM) constructs and additional URI construction +; constraints for the following grammar rules are further +; defined in (section 2.2.3.4) and (section 2.2.3.5) +; See [MC-CSDL] for further scoping rules regarding the value +; of each of the rules below + +entityContainer = *pchar ; section 3.3 of [RFC3986] + ; the name of an Entity Container in the EDM model + +entitySet = *pchar ; section 3.3 of [RFC3986] + ; the name of an Entity Set in the EDM model + +entityType = *pchar ; section 3.3 of [RFC3986] + ; the name of an Entity Type in the EDM model + +entityProperty = *pchar ; section 3.3 of [RFC3986] + ; the name of a property (of type EDMSimpleType) on an + ; Entity Type in the EDM + ; model associated with the data service + +entityComplexProperty = *pchar ; section 3.3 of [RFC3986] + ; the name of a property (of type ComplexType) on an + ; Entity Type in the EDM + ; model associated with the data service + +entityNavProperty-es= *pchar ; section 3.3 of [RFC3986] + ; the name of a Navigation Property on an Entity Type in + ; the EDM model associated with the data service. The + ; Navigation Property MUST identify an Entity Set. + +entityNavProperty-et= *pchar ; section 3.3 of [RFC3986] + ; the name of a Navigation Property on an Entity Type + ; in the EDM model associated with the data service. + ; The Navigation Property MUST identify an entity. + +serviceOperation-collEt = *pchar ; section 3.3 of [RFC3986] + ; the name of a Function Import in the EDM model which returns a + ; collection of entities from the same Entity Set + +serviceOperation-et = *pchar ; section 3.3 of [RFC3986] + ; the name of a Function Import which returns a single Entity + ; Type instance + +serviceOperation-collCt = *pchar ; section 3.3 of [RFC3986] + ; the name of a Function Import which returns a collection of + ; Complex Type [MC-CSDL] instances. Each member of the + ; collection is of the same type. +*) module SegmentParser = begin @@ -93,11 +252,16 @@ module SegmentParser = then Some(arg) else None - let (|RootOperationAccess|_|) (model:ODataModel) (arg:string) = + let (|RootOperationAccess|_|) (model:ODataModel) (arg:string) = None - let (|OperationAccess|_|) (rt:ResourceType option) (arg:string) = - None + let (|OperationAccess|_|) (model:ODataModel) (rt:ResourceType option) (arg:string) = + if rt.IsNone then None + else + let op = model.GetNestedOperation(rt.Value, arg) + if op = null + then None + else Some(op) let (|PropertyAccess|_|) (rt:ResourceType option) (arg:string) = let name, key = @@ -114,7 +278,7 @@ module SegmentParser = let (|EntityTypeAccess|_|) (model:ODataModel) (arg:string) = match arg with | SegmentWithKey (name, key) -> - match model.GetResourceType(name) with + match model.GetResourceSet(name) with | Some rt -> Some(rt, name, key) | _ -> None | _ -> None @@ -122,60 +286,147 @@ module SegmentParser = let (|EntitySetAccess|_|) (model:ODataModel) (arg:string) = match arg with | SegmentWithoutKey name -> - match model.GetResourceType(name) with - | Some rt -> Some(rt, name) + match model.GetResourceSet(name) with + | Some rs -> Some(rs, name) | _ -> None | _ -> None - + + let internal process_first (firstSeg:string) model (svcUri:Uri) (resourceType:Ref) (meta:Ref) = + match firstSeg with + | "" -> + UriSegment.ServiceDirectory + | Meta m -> // todo: semantic validation + Diagnostics.Debug.Assert (!meta = MetaSegment.Nothing) + meta := m + UriSegment.Nothing + + | RootOperationAccess model o -> + UriSegment.RootServiceOperation + + // todo: support for: + // | OperationAccess within ResourceType + + | EntitySetAccess model (rs, name) -> + resourceType := rs.ResourceType + UriSegment.EntitySet({ Uri=Uri(svcUri, name); RawPathSegment=firstSeg; ResSet = rs; + ResourceType = !resourceType; Name = name; Key = null; + SingleResult = null; ManyResult = null; }) + + | EntityTypeAccess model (rs, name, key) -> + resourceType := rs.ResourceType + UriSegment.EntityType({ Uri=Uri(svcUri, firstSeg); RawPathSegment=firstSeg; ResSet = rs; + ResourceType = !resourceType; Name = name; Key = key; + SingleResult = null; ManyResult = null; }) + + | _ -> raise(HttpException(400, "First segment of uri could not be parsed")) + + + let internal build_segment_for_property kind (baseUri:Uri) (rawSegment:string) (prop:ResourceProperty) key = + match kind with + | ResourcePropertyKind.Primitive -> + // todo: assert key is null + let info = { Uri=Uri(baseUri, rawSegment); RawPathSegment=rawSegment; ResourceType=prop.ResourceType; + Property=prop; Key = null; SingleResult = null; ManyResult = null } + UriSegment.PropertyAccessSingle(info) + + | ResourcePropertyKind.ComplexType -> + // todo: assert key is null + let info = { Uri=Uri(baseUri, rawSegment); RawPathSegment=rawSegment; ResourceType=prop.ResourceType; + Property=prop; Key = null; SingleResult = null; ManyResult = null } + UriSegment.ComplexType(info) + + | ResourcePropertyKind.ResourceReference -> + let info = { Uri=Uri(baseUri, rawSegment); RawPathSegment=rawSegment; ResourceType=prop.ResourceType; + Property=prop; Key = key; SingleResult = null; ManyResult = null } + UriSegment.PropertyAccessSingle(info) + + | ResourcePropertyKind.ResourceSetReference -> + if key = null then + let info = { Uri=Uri(baseUri, rawSegment); RawPathSegment=rawSegment; ResourceType=prop.ResourceType; + Property=prop; Key = null; SingleResult = null; ManyResult = null } + UriSegment.PropertyAccessCollection(info) + else + let info = { Uri=Uri(baseUri, rawSegment); RawPathSegment=rawSegment; ResourceType=prop.ResourceType; + Property=prop; Key = key; SingleResult = null; ManyResult = null } + UriSegment.PropertyAccessSingle(info) + + | _ -> raise(HttpException(500, "Unsupported property kind for segment ")) + + let partition_qs_parameters (qs:NameValueCollection) = + let odataParams, ordinaryParams = + let odata, ordinary = + qs.AllKeys + |> List.ofSeq |> List.partition (fun k -> k.StartsWith("$", StringComparison.Ordinal)) + let ordinaryParams = NameValueCollection(StringComparer.OrdinalIgnoreCase) + ordinary |> List.iter (fun i -> ordinaryParams.[i] <- qs.[i]) + let odataparms = NameValueCollection(StringComparer.OrdinalIgnoreCase) + odata |> List.iter (fun i -> odataparms.[i] <- qs.[i]) + odataparms, ordinary + odataParams, ordinaryParams + // we also need to parse QS // ex url/Suppliers?$filter=Address/City eq 'Redmond' - let public parse(path:string, qs:string, model:ODataModel) : UriSegment[] = - - let rec parse_segment (all:UriSegment list) (previous:UriSegment) (contextRT:ResourceType option) (rawSegments:string[]) (index:int) : UriSegment[] = + let parse(path:string, qs:NameValueCollection, model:ODataModel, svcUri:Uri) : UriSegment[] * MetaSegment * MetaQuerySegment[] = + + let odataParams, ordinaryParams = partition_qs_parameters qs + + // tracks the meta we will discover later + let meta = ref MetaSegment.Nothing + + // tracks the last segment where (is a collection type = true) + let lastCollAccessSegment : Ref = ref UriSegment.Nothing + + // this rec function parses all segments but the first + let rec parse_segment (all:UriSegment list) (previous:UriSegment) + (contextRT:ResourceType option) (rawSegments:string[]) (index:int) : UriSegment[] = - // check for empty is temporary, should find better solution if index < rawSegments.Length && (rawSegments.[index] <> String.Empty && index <= rawSegments.Length - 1) then let rawSegment = rawSegments.[index] let resourceType : Ref = ref null + let baseUri = + match previous with + | UriSegment.EntitySet d + | UriSegment.EntityType d -> Uri(d.Uri.AbsoluteUri + "/") + | UriSegment.PropertyAccessCollection d + | UriSegment.PropertyAccessSingle d -> Uri(d.Uri.AbsoluteUri + "/") + | _ -> svcUri let newSegment = match rawSegment with | Meta m -> - // todo: semantic validation - UriSegment.Meta(m) - | OperationAccess contextRT o -> UriSegment.ServiceOperation + // todo: semantic validation + // (e.g. at this point, $metadata is not accepted) + Diagnostics.Debug.Assert (!meta = MetaSegment.Nothing) + meta := m + UriSegment.Nothing + + | OperationAccess model contextRT o -> + UriSegment.ActionOperation(o) | PropertyAccess contextRT (prop, key) -> resourceType := prop.ResourceType - match prop.Kind with | ResourcePropKind kind -> - match kind with - | ResourcePropertyKind.Primitive -> - // todo: assert key is null - UriSegment.PropertyAccessSingle({ ResourceType=prop.ResourceType; Property=prop; Key = null; SingleResult = null; ManyResult = null }) - - | ResourcePropertyKind.ComplexType -> - // todo: assert key is null - UriSegment.ComplexType({ ResourceType=prop.ResourceType; Property=prop; Key = null; SingleResult = null; ManyResult = null }) + build_segment_for_property kind baseUri rawSegment prop key + | _ -> raise(HttpException(500, "Unsupported property kind for segment ")) - | ResourcePropertyKind.ResourceReference -> - UriSegment.PropertyAccessSingle({ ResourceType=prop.ResourceType; Property=prop; Key = key; SingleResult = null; ManyResult = null }) + | _ -> raise(HttpException(400, "Segment does not match a property or operation")) + + match newSegment with + | UriSegment.EntitySet _ + | UriSegment.PropertyAccessCollection _ -> + lastCollAccessSegment := newSegment + | _ -> () - | ResourcePropertyKind.ResourceSetReference -> - if key = null then - UriSegment.PropertyAccessCollection({ ResourceType=prop.ResourceType; Property=prop; Key = null; SingleResult = null; ManyResult = null }) - else - UriSegment.PropertyAccessSingle({ ResourceType=prop.ResourceType; Property=prop; Key = key; SingleResult = null; ManyResult = null }) + let rt = if !resourceType <> null then Some(!resourceType) else None - | _ -> raise(HttpException(500, "Unsupported property kind for segment ")) - | _ -> raise(HttpException(500, "Unsupported property kind for segment ")) - | _ -> raise(HttpException(400, "Segment does not match a property or operation")) + let newList = + all @ (if newSegment = UriSegment.Nothing then [] else [newSegment]) - parse_segment (all @ [newSegment]) newSegment (if !resourceType <> null then Some(!resourceType) else None) rawSegments (index + 1) - else - all |> Array.ofList + parse_segment newList newSegment rt rawSegments (index + 1) + + else all |> Array.ofList let normalizedPath = if path.StartsWith("/", StringComparison.Ordinal) @@ -186,67 +437,31 @@ module SegmentParser = let firstSeg = rawSegments.[0] let resourceType : Ref = ref null - let segment = - match firstSeg with - | "" -> - UriSegment.ServiceDirectory - | Meta m -> - // todo: semantic validation - UriSegment.Meta(m) - | RootOperationAccess model o -> - UriSegment.ServiceOperation - | EntitySetAccess model (rt, name) -> - resourceType := rt - UriSegment.EntitySet({ ResourceType = rt; Name = name; Key = null; SingleResult = null; ManyResult = null }) - | EntityTypeAccess model (rt, name, key) -> - resourceType := rt - UriSegment.EntityType({ ResourceType = rt; Name = name; Key = key; SingleResult = null; ManyResult = null }) - | _ -> raise(HttpException(400, "First segment of uri could not be parsed")) - - parse_segment [segment] segment (if !resourceType <> null then Some(!resourceType) else None) rawSegments 1 - - - - (* - http://services.odata.org/OData/OData.svc/Categories - Identifies all Categories Collection. - Is described by the Entity Set named "Categories" in the service metadata document. - http://services.odata.org/OData/OData.svc/Categories(1) - Identifies a single Category Entry with key value 1. - Is described by the Entity Type named "Categories" in the service metadata document. - http://services.odata.org/OData/OData.svc/Categories(1)/Name - Identifies the Name property of the Categories Entry with key value 1. - Is described by the Property named "Name" on the "Categories" Entity Type in the service metadata document. - http://services.odata.org/OData/OData.svc/Categories(1)/Products - Identifies the collection of Products associated with Category Entry with key value 1. - Is described by the Navigation Property named "Products" on the "Category" Entity Type in the service metadata document. - http://services.odata.org/OData/OData.svc/Categories(1)/Products/$count - Identifies the number of Product Entries associated with Category 1. - Is described by the Navigation Property named "Products" on the "Category" Entity Type in the service metadata document. - http://services.odata.org/OData/OData.svc/Categories(1)/Products(1)/Supplier/Address/City - Identifies the City of the Supplier for Product 1 which is associated with Category 1. - Is described by the Property named "City" on the "Address" Complex Type in the service metadata document. - http://services.odata.org/OData/OData.svc/Categories(1)/Products(1)/Supplier/Address/City/$value - Same as the URI above, but identifies the "raw value" of the City property. - http://services.odata.org/OData/OData.svc/Categories(1)/$links/Products - Identifies the set of Products related to Category 1. - Is described by the Navigation Property named "Products" on the "Category" Entity Type in the associated service metadata document. - http://services.odata.org/OData/OData.svc/Products(1)/$links/Category - Identifies the Category related to Product 1. - Is described by the Navigation Property named "Category" on the "Product" Entity Type in the associated service metadata document. - *) - - -// need to process segments from an endpoint -// Example localhost/vpath/odata.svc/Products(1)/Categories - -// http://odata.research.microsoft.com/FAQ.aspx -// http://services.odata.org/%28S%28zjtwckq5iumy0qno2wbf413y%29%29/OData/OData.svc/ - -// http://odata.netflix.com/v2/Catalog/ -// http://odata.netflix.com/v2/Catalog/$metadata -// http://odata.netflix.com/v2/Catalog/Movies - -// http://vancouverdataservice.cloudapp.net/v1/ - - end \ No newline at end of file + // first segment is a special situation + let segment = process_first firstSeg model svcUri resourceType meta + + // calls the parser + let uriSegments = parse_segment [segment] segment (if !resourceType <> null then Some(!resourceType) else None) rawSegments 1 + + // process odata query parameters, if any + let metaQuerySegments = + let list = List() + for key in odataParams.Keys do + let value = odataParams.[key] + match key with + | "$filter" -> MetaQuerySegment.Filter (value) + | "$orderby" -> MetaQuerySegment.OrderBy (value) + | "$top" -> MetaQuerySegment.Top (Int32.Parse(value)) + | "$skip" -> MetaQuerySegment.Skip (Int32.Parse(value)) + | "$expand" -> MetaQuerySegment.Expand (value) + | "$format" -> MetaQuerySegment.Format (value) + | "$inlinecount"-> MetaQuerySegment.InlineCount (value) + | "$select" -> MetaQuerySegment.Select (value) + | _ -> failwithf "special query parameter is not supported: %s (note that these parameters are case sensitive)" key + |> list.Add + list |> Array.ofSeq + + uriSegments, !meta, metaQuerySegments + + end + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentProcessor.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentProcessor.fs index d4608d8d..f64983f8 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentProcessor.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/SegmentProcessor.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData open System open System.IO @@ -6,6 +21,7 @@ open System.Linq open System.Linq.Expressions open System.Collections open System.Collections.Generic +open System.Collections.Specialized open System.Data.OData open System.Data.Services.Providers open System.ServiceModel.Syndication @@ -13,6 +29,7 @@ open System.Text open System.Xml open System.Xml.Linq open Castle.MonoRail +open Castle.MonoRail.Extension.OData.Serialization // http://msdn.microsoft.com/en-us/library/dd233205.aspx @@ -24,12 +41,24 @@ type SegmentOp = // | Merge = 5 type ProcessorCallbacks = { - accessSingle : Func; - accessMany : Func; - create : Func; - update : Func; - remove : Func; -} + authorize : Func; + authorizeMany : Func; + view : Func; + viewMany : Func; + create : Func; + update : Func; + remove : Func; + operation : Action; + negotiateContent : Func; +} with + member x.Auth (rt, parameters, item) = x.authorize.Invoke(rt, parameters, item) + member x.Auth (rt, parameters, item) = x.authorizeMany.Invoke(rt, parameters, item) + member x.View (rt, parameters, item) = x.view.Invoke(rt, parameters, item) + member x.View (rt, parameters, item) = x.viewMany.Invoke(rt, parameters, item) + member x.Create (rt, parameters, item) = x.create.Invoke(rt, parameters, item) + member x.Update (rt, parameters, item) = x.update.Invoke(rt, parameters, item) + member x.Remove (rt, parameters, item) = x.remove.Invoke(rt, parameters, item) + member x.Operation (rt, parameters, action) = x.operation.Invoke(rt, parameters, action) type RequestParameters = { model : ODataModel; @@ -47,18 +76,18 @@ type ResponseParameters = { mutable contentEncoding : Encoding; writer : TextWriter; mutable httpStatus : int; -} - -type ResponseToSend = { - mutable QItems : IQueryable; - mutable EItems : IEnumerable; - mutable SingleResult : obj; - ResType : ResourceType; + mutable httpStatusDesc : string; + mutable location : string; } module SegmentProcessor = begin - let internal emptyResponse = { QItems = null; EItems = null; SingleResult = null; ResType = null } + type ResponseParameters with + member x.SetStatus(code:int, desc:string) = + x.httpStatus <- code + x.httpStatusDesc <- desc + + let internal emptyResponse = { QItems = null; SingleResult = null; ResType = null; FinalResourceUri=null; ResProp = null; PropertiesToExpand = HashSet() } let (|HttpGet|HttpPost|HttpPut|HttpDelete|HttpMerge|HttpHead|) (arg:string) = match arg.ToUpperInvariant() with @@ -70,47 +99,38 @@ module SegmentProcessor = | "GET" -> HttpGet | _ -> failwithf "Could not understand method %s" arg - type This = static member Assembly = typeof.Assembly - - let typed_select_methodinfo = - let m = This.Assembly.GetType("Castle.MonoRail.Extension.OData.SegmentProcessor").GetMethod("typed_select") - System.Diagnostics.Debug.Assert(m <> null, "Could not get typed_select methodinfo") - m - - let typed_select<'a> (source:IQueryable) (key:obj) (keyProp:ResourceProperty) = - let typedSource = source :?> IQueryable<'a> - let parameter = Expression.Parameter(source.ElementType, "element") - let e = Expression.Property(parameter, keyProp.Name) - let bExp = Expression.Equal(e, Expression.Constant(key)) - let exp = Expression.Lambda(bExp, [parameter]) :?> Expression> - typedSource.FirstOrDefault(exp) - - let private select_by_key (rt:ResourceType) (source:IQueryable) (key:string) = - - // for now support for a single key - let keyProp = Seq.head rt.KeyProperties - let keyVal = - // weak!! - System.Convert.ChangeType(key, keyProp.ResourceType.InstanceType) + let private assert_entitytype_without_entityset op (rt:ResourceType) (model:ODataModel) = + if rt.ResourceTypeKind <> ResourceTypeKind.EntityType then + failwithf "Unsupported operation %O" op + match model.GetRelatedResourceSet(rt) with + | Some rs -> failwithf "Unsupported operation %O" op + | _ -> () - let rtType = rt.InstanceType - let ``method`` = typed_select_methodinfo.MakeGenericMethod([|rtType|]) - let result = ``method``.Invoke(null, [|source; keyVal; keyProp|]) - if result = null then failwithf "Lookup of entity %s for key %s failed." rt.Name key - result - let internal serialize_result (items:IEnumerable) (item:obj) (rt:ResourceType) (request:RequestParameters) (response:ResponseParameters) = - let s = SerializerFactory.Create(response.contentType) + let internal serialize_result (formatOverrider:string) (reply:ResponseToSend) + (request:RequestParameters) (response:ResponseParameters) (containerUri:Uri) = - if items <> null then - s.SerializeMany (request.baseUri, rt, items, response.writer, response.contentEncoding) - else - s.SerializeSingle (request.baseUri, rt, item, response.writer, response.contentEncoding) + response.contentType <- + if formatOverrider <> null then + match formatOverrider.ToLowerInvariant() with + | "json" -> MediaTypes.JSon + | "xml" -> MediaTypes.Xml + | "atom" -> MediaTypes.Atom + | "simplejson" -> MediaTypes.JSon; + | _ -> failwithf "Unsupported format value %O" formatOverrider + else response.contentType + + let wrapper = request.wrapper + let s = SerializerFactory.Create(response.contentType, formatOverrider, + wrapper, request.baseUri, containerUri, + reply.ResType, reply.PropertiesToExpand, + response.writer, response.contentEncoding ) + Diagnostics.Debug.Assert( s <> null ) + s.Serialize reply let internal deserialize_input (rt:ResourceType) (request:RequestParameters) = let s = DeserializerFactory.Create(request.contentType) - s.DeserializeSingle (rt, new StreamReader(request.input), request.contentEncoding) let internal get_property_value (container:obj) (property:ResourceProperty) = @@ -123,124 +143,242 @@ module SegmentProcessor = value - let internal process_collection_property op container (p:PropertyAccessDetails) (previous:UriSegment) hasMoreSegments (model:ODataModel) (shouldContinue:Ref) = + let internal process_collection_property op container (p:PropertyAccessInfo) (previous:UriSegment) hasMoreSegments + (model:ODataModel) (callbacks:ProcessorCallbacks) + (request:RequestParameters) (response:ResponseParameters) parameters + (shouldContinue:Ref) = System.Diagnostics.Debug.Assert ((match previous with | UriSegment.Nothing -> false | _ -> true), "cannot be root") if op = SegmentOp.View || (hasMoreSegments && op = SegmentOp.Update) then let value = (get_property_value container p.Property ) :?> IEnumerable - //if intercept_many op value p.ResourceType shouldContinue then + // if callbacks.accessMany.Invoke(p.ResourceType, value) then p.ManyResult <- value + { ResType = p.ResourceType; + QItems = value.AsQueryable(); SingleResult = null; + FinalResourceUri = p.Uri; ResProp = p.Property; PropertiesToExpand = HashSet() } + // else emptyResponse + else match op with - | SegmentOp.Update -> - // deserialize - // process - // result - raise(NotImplementedException("Update for property not supported yet")) + | SegmentOp.Create -> + + assert_entitytype_without_entityset op p.ResourceType model + + let input = deserialize_input p.ResourceType request + + let succ= callbacks.create.Invoke(p.ResourceType, parameters, input) + if succ then + response.SetStatus(201, "Created") + // we dont have enough data to build it + // response.location <- Uri(request.baseUri, p.Uri.OriginalString + "(" + key + ")").AbsoluteUri + + p.SingleResult <- input + + { ResType = p.ResourceType; + QItems = null; SingleResult = input; + FinalResourceUri = p.Uri; ResProp = null; PropertiesToExpand = HashSet() } + else + shouldContinue := false + emptyResponse + | _ -> failwithf "Unsupported operation %O" op - let internal process_item_property op container (p:PropertyAccessDetails) (previous:UriSegment) hasMoreSegments (model:ODataModel) (shouldContinue:Ref) = + let internal process_item_property op container (p:PropertyAccessInfo) (previous:UriSegment) hasMoreSegments + (model:ODataModel) (callbacks:ProcessorCallbacks) (shouldContinue:Ref) + (requestParams:RequestParameters) (response:ResponseParameters) parameters = System.Diagnostics.Debug.Assert ((match previous with | UriSegment.Nothing -> false | _ -> true), "cannot be root") - if op = SegmentOp.View || (hasMoreSegments && op = SegmentOp.Update) then + let auth_item (item:obj) = + let succ = callbacks.Auth(p.ResourceType, parameters, item) + if not succ then shouldContinue := false + succ + + let get_property_value () = let propValue = get_property_value container p.Property - if p.Key <> null then - let collAsQueryable = (propValue :?> IEnumerable).AsQueryable() - let value = select_by_key p.ResourceType collAsQueryable p.Key - //if intercept_single op value p.ResourceType shouldContinue then - p.SingleResult <- value + let finalVal = + if p.Key <> null then + let collAsQueryable = (propValue :?> IEnumerable).AsQueryable() + let value = AstLinqTranslator.select_by_key p.ResourceType collAsQueryable p.Key + value + else propValue + if auth_item finalVal + then finalVal + else null + + if op = SegmentOp.View || hasMoreSegments then + + let singleResult = get_property_value () + + if singleResult <> null then + if not hasMoreSegments && not <| callbacks.View(p.ResourceType, parameters, singleResult) then + shouldContinue := false else - //if intercept_single op propValue p.ResourceType shouldContinue then - p.SingleResult <- propValue + shouldContinue := false + + if !shouldContinue then + p.SingleResult <- singleResult + { ResType = p.ResourceType; + QItems = null; SingleResult = singleResult; + FinalResourceUri = p.Uri; ResProp = p.Property; PropertiesToExpand = HashSet() } + else emptyResponse + else + System.Diagnostics.Debug.Assert (not hasMoreSegments) + match op with | SegmentOp.Update -> - // if primitive... - raise(NotImplementedException("Update for property not supported yet")) + + if p.Property.IsOfKind(ResourcePropertyKind.Primitive) then + // if primitive... + raise(NotImplementedException("Update for property is not supported yet")) - // | SegmentOp.Delete -> is the property a relationship? should delete through a $link instead - | _ -> () + elif p.Property.IsOfKind(ResourcePropertyKind.ResourceSetReference) || + p.Property.IsOfKind(ResourcePropertyKind.ResourceReference) then + + // only supported for the case below, otherwise one should use $link instead + assert_entitytype_without_entityset op p.ResourceType model + let finalValue = get_property_value () - let internal process_entityset op (d:EntityDetails) (previous:UriSegment) hasMoreSegments - (model:ODataModel) (callbacks:ProcessorCallbacks) (shouldContinue:Ref) requestParams = - System.Diagnostics.Debug.Assert ((match previous with | UriSegment.Nothing -> true | _ -> false), "must be root") + if callbacks.update.Invoke(p.ResourceType, parameters, finalValue) then + response.SetStatus(204, "No Content") - // System.Diagnostics.Debug.Assert (not hasMoreSegments) + emptyResponse + + else failwithf "Operation not supported for this entity type" + + | SegmentOp.Delete -> + + if p.Property.IsOfKind(ResourcePropertyKind.Primitive) then + failwithf "Cannot delete a primitive value in a property" + + elif p.Property.IsOfKind(ResourcePropertyKind.ResourceSetReference) || + p.Property.IsOfKind(ResourcePropertyKind.ResourceReference) then + + // only supported for the case below, otherwise one should use $link instead + assert_entitytype_without_entityset op p.ResourceType model + + let finalValue = get_property_value () + + if callbacks.remove.Invoke(p.ResourceType, parameters, finalValue) then + response.SetStatus(204, "No Content") + + emptyResponse + + else failwithf "Operation not supported for this resource type" + + | _ -> failwithf "Operation not supported for this resource type" + + + let internal process_entityset op (d:EntityAccessInfo) (previous:UriSegment) hasMoreSegments + (model:ODataModel) (callbacks:ProcessorCallbacks) (shouldContinue:Ref) + (request:RequestParameters) (response:ResponseParameters) parameters = + System.Diagnostics.Debug.Assert ((match previous with | UriSegment.Nothing -> true | _ -> false), "must be root") + + let get_values () = + let value = model.GetQueryable (d.ResSet) + if not <| callbacks.Auth(d.ResourceType, parameters, value) then + shouldContinue := false; null + else value match op with | SegmentOp.View -> // acceptable next segments: $count, $orderby, $top, $skip, $format, $inlinecount - let value = model.GetQueryable (d.Name) - if callbacks.accessMany.Invoke(d.ResourceType, value) then - d.ManyResult <- value - { ResType = d.ResourceType; QItems = value; EItems = null; SingleResult = null } - else - shouldContinue := false - emptyResponse + let values = get_values () + d.ManyResult <- values - | SegmentOp.Create -> - System.Diagnostics.Debug.Assert (not hasMoreSegments) + if values <> null then + if not hasMoreSegments && not <| callbacks.View( d.ResourceType, parameters, values ) then + shouldContinue := false - let item = deserialize_input d.ResourceType requestParams + // remember: this ! is not NOT, it's a de-ref + if !shouldContinue then + { ResType = d.ResourceType; QItems = values; SingleResult = null; FinalResourceUri = d.Uri; ResProp = null; PropertiesToExpand = HashSet() } + else emptyResponse - if callbacks.create.Invoke(d.ResourceType, item) then - () - else - shouldContinue := false - - emptyResponse - | SegmentOp.Update -> + | SegmentOp.Create -> System.Diagnostics.Debug.Assert (not hasMoreSegments) - // deserialize - // process - // result - emptyResponse - | SegmentOp.Delete -> - System.Diagnostics.Debug.Assert (not hasMoreSegments) - // process - // result - emptyResponse + let item = deserialize_input d.ResourceType request + + let succ = callbacks.Create(d.ResourceType, parameters, item) + if succ then + response.SetStatus(201, "Created") + // not enough info to build location + // response.location <- Uri(request.baseUri, d.Uri.OriginalString + "(" + key + ")").AbsoluteUri + + { ResType = d.ResourceType; + QItems = null; SingleResult = item; + FinalResourceUri = d.Uri; ResProp = null; PropertiesToExpand = HashSet() } + else + shouldContinue := false + emptyResponse | _ -> failwithf "Unsupported operation %O" op - let internal process_entitytype op (d:EntityDetails) (previous:UriSegment) hasMoreSegments (model:ODataModel) (shouldContinue:Ref) stream = + let internal process_entityset_single op (d:EntityAccessInfo) (previous:UriSegment) hasMoreSegments + (model:ODataModel) (callbacks:ProcessorCallbacks) (shouldContinue:Ref) + (request:RequestParameters) (response:ResponseParameters) parameters = System.Diagnostics.Debug.Assert ((match previous with | UriSegment.Nothing -> true | _ -> false), "must be root") - if op = SegmentOp.View || (hasMoreSegments && op = SegmentOp.Update) then - System.Diagnostics.Debug.Assert (not (op = SegmentOp.Delete), "should not be delete") + let auth_item (item:obj) = + let succ = callbacks.Auth(d.ResourceType, parameters, item) + if not succ then shouldContinue := false + succ + + let get_single_result () = + let wholeSet = model.GetQueryable (d.ResSet) + let singleResult = AstLinqTranslator.select_by_key d.ResourceType wholeSet d.Key + if auth_item singleResult + then singleResult + else null + + if op = SegmentOp.View || hasMoreSegments then + if not hasMoreSegments then Diagnostics.Debug.Assert (not (op = SegmentOp.Delete), "should not be delete") + + let singleResult = get_single_result () - // if there are more segments, consider this a read - let wholeSet = model.GetQueryable (d.Name) - let singleResult = select_by_key d.ResourceType wholeSet d.Key - //if intercept_single op singleResult d.ResourceType shouldContinue then d.SingleResult <- singleResult - { ResType = d.ResourceType; QItems = null; EItems = null; SingleResult = singleResult } + if singleResult <> null then + if not hasMoreSegments && not <| callbacks.View(d.ResourceType, parameters, singleResult) then + shouldContinue := false + else + shouldContinue := false + + if !shouldContinue then + { ResType = d.ResourceType; QItems = null; SingleResult = singleResult; FinalResourceUri = d.Uri; ResProp = null; PropertiesToExpand = HashSet() } + else emptyResponse - else + else match op with | SegmentOp.Update -> - // deserialize - // process - // result - emptyResponse + // runs auth + let single = get_single_result() + if single <> null then + // todo: shouldn't it deserialize into 'single'? + let item = deserialize_input d.ResourceType request + let succ = callbacks.Update(d.ResourceType, parameters, item) + if succ + then response.SetStatus(204, "No Content") + else shouldContinue := false | SegmentOp.Delete -> // http://www.odata.org/developers/protocols/operations#DeletingEntries // Entries are deleted by executing an HTTP DELETE request against a URI that points at the Entry. // If the operation executed successfully servers should return 200 (OK) with no response body. - - // process - // result - emptyResponse + let single = get_single_result() + if single <> null then + if callbacks.Remove(d.ResourceType, parameters, single) then + response.SetStatus(204, "No Content") + else shouldContinue := false | _ -> failwithf "Unsupported operation %O at this level" op + emptyResponse let internal serialize_directory op hasMoreSegments (previous:UriSegment) writer baseUri metadataProviderWrapper (response:ResponseParameters) = @@ -254,9 +392,8 @@ module SegmentProcessor = | _ -> failwithf "Unsupported operation %O at this level" op - let internal serialize_metadata op hasMoreSegments (previous:UriSegment) writer baseUri metadataProviderWrapper (response:ResponseParameters) = + let internal serialize_metadata op (previous:UriSegment) writer baseUri metadataProviderWrapper (response:ResponseParameters) = System.Diagnostics.Debug.Assert ((match previous with | UriSegment.Nothing -> true | _ -> false), "must be root") - System.Diagnostics.Debug.Assert (not hasMoreSegments, "needs to be the only segment") match op with | SegmentOp.View -> @@ -264,25 +401,42 @@ module SegmentProcessor = MetadataSerializer.serialize (writer, metadataProviderWrapper, response.contentEncoding) | _ -> failwithf "Unsupported operation %O at this level" op - let internal resolveResponseContentType (segments:UriSegment[]) (acceptTypes:string[]) = - match segments |> Array.tryPick (fun s -> match s with | UriSegment.Meta m -> (match m with | MetaSegment.Format f -> Some(f) | _ -> None ) | _ -> None) with - | Some f -> - match f.ToLowerInvariant() with - | "atom" -> "application/atom+xml" - | "xml" -> "application/xml" - | "json" -> "application/json" - | _ -> f - | _ -> - // should be more sophisticate than this.. - if acceptTypes = null || acceptTypes.Length = 0 - then "application/atom+xml" // defaults to atom - else - if acceptTypes |> Array.exists (fun at -> at.StartsWith("*/*", StringComparison.OrdinalIgnoreCase) ) - then "application/atom+xml" - else acceptTypes.[0] + let private process_operation_value (previous:UriSegment) (result:ResponseToSend) (response:ResponseParameters) = + if result = emptyResponse || result.SingleResult = null + || result.ResProp = null + || not <| result.ResProp.IsOfKind(ResourcePropertyKind.Primitive) then + raise(InvalidOperationException("$value can only operate if a previous segment produced a primitive value")) + + // change the response type + response.contentType <- "text/plain" + + // return the exact same result as the previous + result + + let private apply_filter (response:ResponseToSend) (rawExpression:string) = + let ast = QueryExpressionParser.parse_filter rawExpression + let typedAst = QuerySemanticAnalysis.analyze_and_convert ast response.ResType + + if response.QItems <> null then + response.QItems <- AstLinqTranslator.apply_queryable_filter response.ResType response.QItems typedAst :?> IQueryable + + let private apply_orderby (response:ResponseToSend) (rawExpression:string) = + let exps = QueryExpressionParser.parse_orderby rawExpression + let typedNodes = QuerySemanticAnalysis.analyze_and_convert_orderby exps response.ResType - let public Process (op:SegmentOp) (segments:UriSegment[]) (callbacks:ProcessorCallbacks) (request:RequestParameters) (response:ResponseParameters) = + if response.QItems <> null then + response.QItems <- AstLinqTranslator.apply_queryable_orderby response.ResType response.QItems typedNodes :?> IQueryable + + let private apply_expand (response:ResponseToSend) (rawExpression:string) = + let exps = QueryExpressionParser.parse_expand rawExpression + QuerySemanticAnalysis.analyze_and_convert_expand exps response.ResType response.PropertiesToExpand + + let public Process (op:SegmentOp) + (segments:UriSegment[]) (meta:MetaSegment) (metaQueries:MetaQuerySegment[]) + (ordinaryParams:NameValueCollection) + (callbacks:ProcessorCallbacks) + (request:RequestParameters) (response:ResponseParameters) = // missing support for operations, value, filters, links, batch, ... @@ -295,80 +449,103 @@ module SegmentProcessor = // in case of exception, serialized error is sent let model = request.model - let stream = request.input let baseUri = request.baseUri let writer = response.writer - do response.contentType <- resolveResponseContentType segments request.accept + let parameters = List() + let lastSegment = segments.[segments.Length - 1] - let rec rec_process (index:int) (previous:UriSegment) (result:ResponseToSend) = + let rec rec_process (index:int) (previous:UriSegment) (result:ResponseToSend) = let shouldContinue = ref true if index < segments.Length then - let container, prevRt = + let container, prevRt, containerUri = match previous with - | UriSegment.EntityType d -> d.SingleResult, d.ResourceType + | UriSegment.EntityType d -> d.SingleResult, d.ResourceType, d.Uri | UriSegment.ComplexType d - | UriSegment.PropertyAccessSingle d -> d.SingleResult, d.ResourceType - | _ -> null, null + | UriSegment.PropertyAccessSingle d -> d.SingleResult, d.ResourceType, d.Uri + | _ -> null, null, null + + // builds list of contextual parameters. used when calling back controllers + if container <> null then parameters.Add (prevRt.InstanceType, container) let hasMoreSegments = index + 1 < segments.Length let segment = segments.[index] let toSerialize = match segment with - | UriSegment.Meta m -> - match m with - | MetaSegment.Metadata -> - serialize_metadata op hasMoreSegments previous writer baseUri request.wrapper response - emptyResponse - | _ -> failwithf "Unsupported meta instruction %O" m - | UriSegment.ServiceDirectory -> serialize_directory op hasMoreSegments previous writer baseUri request.wrapper response emptyResponse - | UriSegment.ServiceOperation -> - () + | UriSegment.ActionOperation actionOp -> + callbacks.Operation(actionOp.ResourceType, parameters, actionOp.Name) + // it's understood that the action took care of the result emptyResponse + | UriSegment.RootServiceOperation -> emptyResponse + | UriSegment.EntitySet d -> - process_entityset op d previous hasMoreSegments model callbacks shouldContinue request + process_entityset op d previous hasMoreSegments model callbacks shouldContinue request response parameters | UriSegment.EntityType d -> - process_entitytype op d previous hasMoreSegments model shouldContinue stream + process_entityset_single op d previous hasMoreSegments model callbacks shouldContinue request response parameters | UriSegment.PropertyAccessCollection d -> - process_collection_property op container d previous hasMoreSegments model shouldContinue - emptyResponse + process_collection_property op container d previous hasMoreSegments model callbacks request response parameters shouldContinue | UriSegment.ComplexType d | UriSegment.PropertyAccessSingle d -> - process_item_property op container d previous hasMoreSegments model shouldContinue - emptyResponse + process_item_property op container d previous hasMoreSegments model callbacks shouldContinue request response parameters | _ -> Unchecked.defaultof - // if !shouldContinue then - rec_process (index+1) segment toSerialize - // else + if !shouldContinue + then rec_process (index+1) segment toSerialize + else result else result - // process segments recursively. + let result = + // process segments recursively. + let navResult = rec_process 0 UriSegment.Nothing emptyResponse + match meta with + | MetaSegment.Nothing -> + navResult + | MetaSegment.Metadata -> + serialize_metadata op lastSegment writer baseUri request.wrapper response + emptyResponse + | MetaSegment.Value -> + process_operation_value lastSegment navResult response + | _ -> failwithf "Unsupported meta instruction %O" meta + + let formatOverrider : Ref = ref null + + // I'm starting to think that ordering may be important here: + // select > expand > everything else + for metaQuery in metaQueries do + match metaQuery with + | MetaQuerySegment.Select exp -> + () + | MetaQuerySegment.Filter exp -> + apply_filter result exp + | MetaQuerySegment.OrderBy exp -> + apply_orderby result exp + | MetaQuerySegment.Expand exp -> + apply_expand result exp + | MetaQuerySegment.Format fmt -> + formatOverrider := fmt + | MetaQuerySegment.InlineCount cf -> + () + | MetaQuerySegment.Skip howMany -> + () + | MetaQuerySegment.Top count -> + () + | _ -> failwithf "Unsupported metaQuery instruction %O" metaQuery + // we ultimately need to serialize a result back - let result = rec_process 0 UriSegment.Nothing emptyResponse - if result <> emptyResponse then - let items : IEnumerable = - if result.QItems <> null - then upcast result.QItems - else result.EItems - let item = result.SingleResult - let rt = result.ResType - - serialize_result items item rt request response - - () - + if response.contentType = null then + response.contentType <- callbacks.negotiateContent.Invoke( result.SingleResult <> null ) + serialize_result !formatOverrider result request response result.FinalResourceUri end diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Atom.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Atom.fs index f923b872..b7d09959 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Atom.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Atom.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization open System open System.Collections @@ -21,35 +36,13 @@ module AtomSerialization = let private linkRelResource = Uri("http://schemas.microsoft.com/ado/2007/08/dataservices/related/") let private categoryScheme = "http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" - - type System.Data.Services.Providers.ResourceProperty - with - member x.GetValue(instance:obj) = - let prop = instance.GetType().GetProperty(x.Name) - prop.GetValue(instance, null) - member x.GetValueAsStr(instance:obj) = - let prop = instance.GetType().GetProperty(x.Name) - let value = prop.GetValue(instance, null) - // XmlConvert.ToString(value) - if value = null - then null - else value.ToString() - - type System.Data.Services.Providers.ResourceType - with - member x.PathWithKey(instance:obj) = - let keyValue = - if x.KeyProperties.Count = 1 - then x.KeyProperties.[0].GetValueAsStr(instance) - else failwith "Composite keys are not supported" - sprintf "%s(%s)" x.Name keyValue - - + /// The content of a SyndicationItem can be anything that inherits from SyndicationContent + /// This class exposes one that is based entries, like a dictionary type ContentDict (items:(string*string*obj) seq) = inherit SyndicationContent() let _items = List(items) - let rec write_primitive_prop (writer:XmlWriter) name typename (value:obj) = + let rec write_property_value (writer:XmlWriter) name typename (value:obj) = writer.WriteStartElement (name, "http://schemas.microsoft.com/ado/2007/08/dataservices") if typename <> "Edm.String" then @@ -67,141 +60,257 @@ module AtomSerialization = new () = ContentDict(Seq.empty) + /// Adds an entry to the content. value may be null member x.Add(name, typename, value) = _items.Add( (name, typename, value) ) member internal x.InternalWrite (writer, name) = - _items |> Seq.iter (fun (name,typename,value) -> write_primitive_prop writer name typename value) + _items |> Seq.iter (fun (name,typename,value) -> write_property_value writer name typename value) override x.Type = "application/xml" override x.Clone() = upcast ContentDict(_items) override x.WriteContentsTo (writer) = if _items.Count > 0 then writer.WriteStartElement("properties", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") - _items |> Seq.iter (fun (name,typename,value) -> write_primitive_prop writer name typename value) + _items |> Seq.iter (fun (name,typename,value) -> write_property_value writer name typename value) writer.WriteEndElement() - let rec private build_content_from_properties (relResUri:Uri) instance (rt:ResourceType) (item:SyndicationItem) = - let content = ContentDict() - let skipContent = ref false - - for prop in rt.Properties do - let otherRt = prop.ResourceType - skipContent := false - - let atts = rt.OwnEpmAttributes |> Seq.filter (fun epm -> epm.SourcePath = prop.Name) - - for att in atts do - skipContent := not att.KeepInContent - match att.TargetSyndicationItem with - // todo, lots of extra cases - | SyndicationItemProperty.Title -> - item.Title <- TextSyndicationContent (prop.GetValueAsStr(instance)) - | _ -> () - - if prop.IsOfKind ResourcePropertyKind.ResourceReference then - // - item.Links.Add (SyndicationLink(Uri(relResUri.OriginalString + "/" + prop.Name, UriKind.Relative), - linkRelResource.AbsoluteUri + otherRt.Name, - otherRt.Name, - "application/atom+xml;type=entry", 0L)) - - - elif prop.IsOfKind ResourcePropertyKind.ResourceSetReference then - // - item.Links.Add (SyndicationLink(Uri(relResUri.OriginalString + "/" + prop.Name, UriKind.Relative), - linkRelResource.AbsoluteUri + otherRt.Name, - otherRt.Name, - "application/atom+xml;type=feed", 0L)) - - - elif prop.IsOfKind ResourcePropertyKind.ComplexType then - // ... - - let innerinstance = prop.GetValue(instance) - let inner = build_content_from_properties relResUri innerinstance otherRt item - content.Add (prop.Name, prop.ResourceType.FullName, inner) - - elif prop.IsOfKind ResourcePropertyKind.Primitive && not !skipContent then - content.Add (prop.Name, prop.ResourceType.FullName, (prop.GetValue(instance))) - - content - - - let internal build_item (instance) (baseUri:Uri) (rt:ResourceType) addNs = - (* - - - - - - - 0 - 1992-01-01T00:00:00 - - 4 - 2.5 - - *) - let item = SyndicationItem() - let relResUri = Uri(rt.PathWithKey(instance), UriKind.Relative) - let fullResUri = Uri(baseUri, relResUri) - - if addNs then - item.AttributeExtensions.Add (qualifiedDataWebPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices") - item.AttributeExtensions.Add (qualifiedDataWebMetadataPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") - - item.BaseUri <- baseUri - // item.AttributeExtensions.Add (qualifiedDataWebPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices") - // item.AttributeExtensions.Add (qualifiedDataWebMetadataPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") - - item.Title <- TextSyndicationContent(String.Empty) - item.Id <- fullResUri.AbsoluteUri - item.Links.Add(SyndicationLink(relResUri, "edit", rt.InstanceType.Name, null, 0L)) - - item.Authors.Add emptyPerson - - item.Categories.Add(SyndicationCategory(rt.Namespace + "." + rt.InstanceType.Name, categoryScheme, null)) - - item.Content <- build_content_from_properties relResUri instance rt item + /// Custom serializer for Atom. + /// Mapped properties of the entity type are written in the content element as + /// properties in the dataservice namespace. + type AtomSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) as self = + class + inherit Serializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) - item + let _xmlWriter = SerializerCommons.create_xmlwriter writer enc + let rec build_content_from_properties (relResUri:Uri) instance (rt:ResourceType) (item:SyndicationItem) = + let content = ContentDict() + let skipContent = ref false - let internal write_items (baseUri:Uri) (rt:ResourceType) (items:IEnumerable) (writer:TextWriter) (enc:Encoding) = - let resUri = Uri(rt.Name, UriKind.Relative) + for prop in rt.Properties do + let otherRt = prop.ResourceType + skipContent := false + + let atts = rt.OwnEpmAttributes |> Seq.filter (fun epm -> epm.SourcePath = prop.Name) - let syndicationItems = - let lst = List() - for item in items do - lst.Add (build_item item baseUri rt false) - lst + for att in atts do + skipContent := not att.KeepInContent + match att.TargetSyndicationItem with + // todo: lots of extra cases + | SyndicationItemProperty.Title -> + item.Title <- TextSyndicationContent (prop.GetValueAsStr(instance)) + | _ -> () - let feed = SyndicationFeed(syndicationItems) + if prop.IsOfKind ResourcePropertyKind.ResourceReference then - feed.BaseUri <- baseUri - feed.AttributeExtensions.Add (qualifiedDataWebPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices") - feed.AttributeExtensions.Add (qualifiedDataWebMetadataPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") + let link = SyndicationLink(Uri(relResUri.OriginalString + "/" + prop.Name, UriKind.Relative), + linkRelResource.AbsoluteUri + otherRt.Name, + otherRt.Name, "application/atom+xml;type=entry", 0L) - feed.Title <- TextSyndicationContent(rt.Name) - feed.Id <- Uri(baseUri, resUri).AbsoluteUri - - // temporary - feed.LastUpdatedTime <- DateTimeOffset.MinValue + if self.ShouldExpand prop then + () + // + // + // - feed.Links.Add(SyndicationLink(Uri(rt.Name, UriKind.Relative), "self", rt.Name, null, 0L)) + item.Links.Add link + + elif prop.IsOfKind ResourcePropertyKind.ResourceSetReference then + + // + let link = SyndicationLink(Uri(relResUri.OriginalString + "/" + prop.Name, UriKind.Relative), + linkRelResource.AbsoluteUri + otherRt.Name, + otherRt.Name, + "application/atom+xml;type=feed", 0L) + + if self.ShouldExpand prop then + () + // + // + // + // + // + + item.Links.Add link + + elif prop.IsOfKind ResourcePropertyKind.ComplexType then + // ... + // todo: add case for collection of complex types + + match InternalUtils.getEnumerableElementType prop.ResourceType.InstanceType with + | Some elementType -> + let innerContent = ContentDict() + let elements = prop.GetValue(instance) :?> IEnumerable + // start Properties + for element in elements do + let contentElement = build_content_from_properties relResUri element otherRt item + innerContent.Add ("element", prop.ResourceType.FullName, contentElement) + // end Properties + content.Add (prop.Name, prop.ResourceType.FullName, innerContent) + + | _ -> + let innerinstance = prop.GetValue(instance) + let inner = build_content_from_properties relResUri innerinstance otherRt item + content.Add (prop.Name, prop.ResourceType.FullName, inner) + + elif prop.IsOfKind ResourcePropertyKind.Primitive && not !skipContent then + let originalVal = (prop.GetValue(instance)) + if originalVal <> null then + let strVal = XmlSerialization.to_xml_string prop.ResourceType.InstanceType originalVal + content.Add (prop.Name, prop.ResourceType.FullName, strVal) + else + content.Add (prop.Name, prop.ResourceType.FullName, null) + content + + let build_item (instance) addNs appendKey = + let item = SyndicationItem() + let resourceSet = wrapper.ResourceSets |> Seq.tryFind (fun rs -> rs.ResourceType = rt) + + if addNs then + item.BaseUri <- serviceBaseUri + item.AttributeExtensions.Add (qualifiedDataWebPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices") + item.AttributeExtensions.Add (qualifiedDataWebMetadataPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") + + item.Title <- TextSyndicationContent(String.Empty) + + let resourceUri = + match resourceSet with + | Some rs -> + // for this case, we always want to append the key + Uri(serviceBaseUri, rs.Name + rt.GetKey(instance)) + | _ -> + System.Diagnostics.Debug.Assert (containerUri <> null) + if appendKey + then Uri(containerUri.AbsoluteUri + rt.GetKey(instance)) + else containerUri + let relativeUri = serviceBaseUri.MakeRelativeUri(resourceUri) + + item.Id <- resourceUri.AbsoluteUri + + item.Links.Add(SyndicationLink(relativeUri, "edit", rt.InstanceType.Name, null, 0L)) + item.Authors.Add emptyPerson + item.Categories.Add(SyndicationCategory(rt.Namespace + "." + rt.InstanceType.Name, categoryScheme, null)) + item.Content <- build_content_from_properties relativeUri instance rt item + item + + let build_feed (items:IEnumerable) = + let rootUri = if containerUri <> null then containerUri else serviceBaseUri + let resourceSet = wrapper.ResourceSets |> Seq.tryFind (fun rs -> rs.ResourceType = rt) + + System.Diagnostics.Debug.Assert (rootUri <> null) + + let syndicationItems = + let lst = List() + for item in items do + lst.Add (build_item item false true) + lst + + let feed = SyndicationFeed(syndicationItems) + + feed.BaseUri <- serviceBaseUri + feed.AttributeExtensions.Add (qualifiedDataWebPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices") + feed.AttributeExtensions.Add (qualifiedDataWebMetadataPrefix, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") + + feed.Title <- TextSyndicationContent(rt.Name) + feed.Id <- rootUri.AbsoluteUri - let xmlWriter = SerializerCommons.create_xmlwriter writer enc - feed.GetAtom10Formatter().WriteTo( xmlWriter ) - xmlWriter.Flush() - - let internal write_item (baseUri:Uri) (rt:ResourceType) (item:obj) (writer:TextWriter) (enc:Encoding) = - let syndicationItem = build_item item baseUri rt true - - let xmlWriter = SerializerCommons.create_xmlwriter writer enc - syndicationItem.GetAtom10Formatter().WriteTo( xmlWriter ) - xmlWriter.Flush() + let selfLink = + match resourceSet with + | Some rs -> Uri(rs.Name, UriKind.Relative) + | _ -> containerUri + + feed.Links.Add(SyndicationLink(selfLink, "self", rt.Name, null, 0L)) + feed + + override x.SerializeMany(items) = + let feed = build_feed items + feed.GetAtom10Formatter().WriteTo _xmlWriter + _xmlWriter.Flush() + + override x.SerializeSingle(item) = + let item = build_item item true false + item.GetAtom10Formatter().WriteTo _xmlWriter + _xmlWriter.Flush() + + override x.SerializeProperty(prop:ResourceProperty, value) = + raise(NotImplementedException()) + + end + + + let private get_string_value (reader:XmlReader) = + let doContinue = ref true + let buffer = StringBuilder() + while !doContinue && reader.Read() do + match reader.NodeType with + | XmlNodeType.SignificantWhitespace | XmlNodeType.CDATA | XmlNodeType.Text -> + buffer.Append reader.Value |> ignore + | XmlNodeType.Comment | XmlNodeType.Whitespace -> () + | XmlNodeType.EndElement -> doContinue := false + | _ -> failwithf "Unexpected token parsing element value" + buffer.ToString() + + let private populate_properties (reader:XmlReader) (rt:ResourceType) (instance:obj) = + + while reader.ReadToElement() do + let doContinue = ref true + + while !doContinue do + if reader.NodeType = XmlNodeType.None then + doContinue := false + + elif reader.NodeType <> XmlNodeType.Element then + doContinue := true + reader.Skip() + else + match rt.Properties |> Seq.tryFind (fun p -> p.Name = reader.LocalName) with + | Some prop -> + let value : obj = + let rawStringVal = + let att = reader.GetAttribute("null", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") + if att = null || XmlConvert.ToBoolean(att) = false then + if reader.IsEmptyElement + then String.Empty + else get_string_value reader + else null + + if rawStringVal <> null then + match prop.ResourceType.ResourceTypeKind with + | ResourceTypeKind.Primitive -> + let targetType = + let nulType = Nullable.GetUnderlyingType(prop.ResourceType.InstanceType) + if nulType = null then prop.ResourceType.InstanceType + else nulType + + if targetType = typeof then rawStringVal :> obj + elif targetType = typeof then XmlConvert.ToInt32 rawStringVal |> box + elif targetType = typeof then XmlConvert.ToInt16 rawStringVal |> box + elif targetType = typeof then XmlConvert.ToInt64 rawStringVal |> box + elif targetType = typeof then XmlConvert.ToByte rawStringVal |> box + elif targetType = typeof then XmlConvert.ToBoolean rawStringVal |> box + elif targetType = typeof then XmlConvert.ToDateTime (rawStringVal, XmlDateTimeSerializationMode.RoundtripKind) |> box + elif targetType = typeof then XmlConvert.ToDecimal rawStringVal |> box + elif targetType = typeof then XmlConvert.ToSingle rawStringVal |> box + else null + + | ResourceTypeKind.ComplexType -> failwithf "complex type support needs to be implemented" + | ResourceTypeKind.EntityType -> failwithf "entity type is not a supported property type" + | _ -> failwithf "Unsupported type" + + else null + + prop.SetValue(instance, value) + + doContinue := reader.Read() + + | _ -> + // could not find property: should this be an error? + doContinue := false let internal read_item (rt:ResourceType) (reader:TextReader) (enc:Encoding) = let reader = SerializerCommons.create_xmlreader reader enc @@ -209,30 +318,33 @@ module AtomSerialization = fmt.ReadFrom(reader) let item = fmt.Item + let instance = Activator.CreateInstance rt.InstanceType + let content = + if item.Content :? XmlSyndicationContent + then item.Content :?> XmlSyndicationContent + else null + + // todo: remapping of atom attributes for prop in rt.PropertiesDeclaredOnThisType do // rt.OwnEpmAttributes () - Activator.CreateInstance rt.InstanceType + if content <> null then + let reader = content.GetReaderAtContent() + reader.ReadStartElement ("content", "http://www.w3.org/2005/Atom") + if reader.IsStartElement ("properties", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") then + reader.ReadStartElement("properties", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") + populate_properties reader rt instance - let internal read_feed (rt:ResourceType) (reader:TextReader) (enc:Encoding) = - raise(NotImplementedException()) + instance - let CreateDeserializer () = + let CreateDeserializer = { new Deserializer() with override x.DeserializeMany (rt, reader, enc) = - read_feed rt reader enc + raise(NotImplementedException()) override x.DeserializeSingle (rt, reader, enc) = read_item rt reader enc } - let CreateSerializer () = - { new Serializer() with - override x.SerializeMany(baseUri, rt, items, writer, enc) = - write_items baseUri rt items writer enc - override x.SerializeSingle(baseUri, rt, item, writer, enc) = - write_item baseUri rt item writer enc - } - end diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Factory.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Factory.fs index a322d7f7..81c3539e 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Factory.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Factory.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization open System open System.Xml @@ -6,36 +21,39 @@ open System.Xml type SerializerFactory() = - static member Create(contentType:string) : Serializer = + static member Create(contentType:string, overriding:string, wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) : Serializer = match contentType.ToLowerInvariant() with | "application/atom+xml" -> - AtomSerialization.CreateSerializer() + upcast AtomSerialization.AtomSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) | "application/json" -> - JSonSerialization.CreateSerializer() - - | "application/xml" - | "text/xml" -> - XmlSerialization.CreateSerializer() - - | _ -> failwithf "unsupported content type %s" contentType + let useSimplerFormat = overriding === "simplejson" + upcast JSonSerialization.JsonSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc, useSimplerFormat) + + | "text/xml" + | "application/xml" -> + upcast XmlSerialization.XmlSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) + + | "text/plain" -> + upcast PlainTextSerialization.PlainTextSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) + | _ -> failwithf "unsupported content type %s" contentType type DeserializerFactory() = static member Create(contentType:string) : Deserializer = - match contentType.ToLowerInvariant() with | "application/atom+xml" -> - AtomSerialization.CreateDeserializer() - + AtomSerialization.CreateDeserializer + | "application/json" -> - JSonSerialization.CreateDeserializer() - + JSonSerialization.CreateDeserializer + | "application/xml" | "text/xml" -> XmlSerialization.CreateDeserializer() - - | _ -> failwithf "unsupported content type %s" contentType \ No newline at end of file + + | _ -> failwithf "unsupported content type %s" contentType + diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Json.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Json.fs index 7f02ad0e..05105f54 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Json.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Json.fs @@ -1,13 +1,264 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization open System +open System.Collections +open System.Collections.Generic +open System.Linq open System.Xml +open System.IO +open System.Text +open System.ServiceModel.Syndication +open System.Data.OData +open System.Data.Services.Providers +open System.Data.Services.Common +open Newtonsoft.Json + + module JSonSerialization = begin - let CreateDeserializer () = null + let private set_up (writer:JsonTextWriter) = + writer.DateFormatHandling <- DateFormatHandling.IsoDateFormat + writer.Formatting <- Formatting.Indented + writer.IndentChar <- '\t' + writer.Indentation <- 1 + + + type JsonSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc, useSimplerFormat:bool) as self = + class + inherit Serializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) + + let jwriter = new JsonTextWriter(writer) + + do + set_up jwriter + + let write_meta (uri:Uri) (rt:ResourceType) = + if not useSimplerFormat then + jwriter.WritePropertyName "__metadata" + jwriter.WriteStartObject() + if uri <> null then + jwriter.WritePropertyName "uri" + jwriter.WriteValue uri.AbsoluteUri + jwriter.WritePropertyName "type" + jwriter.WriteValue rt.FullName + jwriter.WriteEndObject() + + let rec write_primitive_and_complex_properties (instance) (uri:Uri) (rt:ResourceType) = + + for prop in rt.Properties do + let otherRt = prop.ResourceType + + if prop.IsOfKind ResourcePropertyKind.ComplexType then + // todo: add case for collection of complex types + + jwriter.WritePropertyName prop.Name + + // TODO: is collection? + // if prop.ResourceType.InstanceType.IsColl then + + let innerinstance = prop.GetValue(instance) + + write_complextype innerinstance uri otherRt + + elif prop.IsOfKind ResourcePropertyKind.Primitive then + + jwriter.WritePropertyName prop.Name + + let originalVal = prop.GetValue(instance) + + jwriter.WriteValue originalVal + + + and write_ref_properties (instance) (uri:Uri) (rt:ResourceType) = + + for prop in rt.Properties do + let otherRt = prop.ResourceType + + if prop.IsOfKind ResourcePropertyKind.ResourceReference || prop.IsOfKind ResourcePropertyKind.ResourceSetReference then + jwriter.WritePropertyName prop.Name + if not useSimplerFormat then jwriter.WriteStartObject () + + // spec wise, we need to output additional metadata in the end (after the properties) + // to reference the associations used for the expanded properties, but I'm skipping that for now + + if self.ShouldExpand (prop) then + if prop.IsOfKind ResourcePropertyKind.ResourceSetReference then + if not useSimplerFormat then jwriter.WritePropertyName "results" + + let innerItems = prop.GetValue(instance) :?> IEnumerable + if innerItems <> null then + write_set (Uri(uri.AbsoluteUri + "/" + prop.Name)) prop.ResourceType innerItems true + else + jwriter.WriteStartArray () + jwriter.WriteEndArray () + else + if not useSimplerFormat then jwriter.WritePropertyName "result" + + let inner = prop.GetValue(instance) + if inner <> null then + write_js_item inner (Uri(uri.AbsoluteUri + "/" + prop.Name)) prop.ResourceType true + else + jwriter.WriteNull() + + else + if not useSimplerFormat then + jwriter.WritePropertyName "__deferred" + jwriter.WriteStartObject () + jwriter.WritePropertyName "uri" + jwriter.WriteValue (uri.AbsoluteUri + "/" + prop.Name) + jwriter.WriteEndObject () + else + jwriter.WriteStartObject () + jwriter.WriteEndObject () + + + if not useSimplerFormat then jwriter.WriteEndObject () + + + and write_complextype (instance) (uri:Uri) (rt:ResourceType) = + + if instance = null then + jwriter.WriteNull() + else + jwriter.WriteStartObject() + write_meta null rt + write_primitive_and_complex_properties instance uri rt + jwriter.WriteEndObject() + + + and write_js_item (instance) (containerUri:Uri) (rt:ResourceType) appendKey = + jwriter.WriteStartObject() + + let resourceSet = wrapper.ResourceSets |> Seq.tryFind (fun rs -> rs.ResourceType = rt) + let resourceUri = + match resourceSet with + | Some rs -> + // for this case, we always want to append the key + Uri(serviceBaseUri, rs.Name + rt.GetKey(instance)) + | _ -> + System.Diagnostics.Debug.Assert (containerUri <> null) + if appendKey + then Uri(containerUri.AbsoluteUri + rt.GetKey(instance)) + else containerUri + + write_meta resourceUri rt + write_primitive_and_complex_properties instance resourceUri rt + write_ref_properties instance resourceUri rt + + jwriter.WriteEndObject() + + and write_set (containerUri:Uri) (rt:ResourceType) (items:IEnumerable) appendKey = + + jwriter.WriteStartArray() + + for item in items do + write_js_item item containerUri rt appendKey + + jwriter.WriteEndArray() + + let wrap_in_d (f) = + if not useSimplerFormat then + jwriter.WriteStartObject() + jwriter.WritePropertyName "d" + + f() + + if not useSimplerFormat then + jwriter.WriteEndObject() + + override x.SerializeMany(items) = + wrap_in_d (fun _ -> write_set containerUri rt items true ) + + override x.SerializeSingle(item) = + wrap_in_d (fun _ -> write_js_item item containerUri rt false ) + + override x.SerializeProperty(prop:ResourceProperty, value) = + + let write_d () = + jwriter.WriteStartObject() + jwriter.WritePropertyName prop.Name + jwriter.WriteValue value + jwriter.WriteEndObject() + + wrap_in_d (fun _ -> write_d () ) + + end + + + + let internal read_item (rt:ResourceType) (reader:TextReader) (enc:Encoding) = + + use jsonReader = new JsonTextReader(reader) + let instance = Activator.CreateInstance rt.InstanceType + + // { "d": { Prop: a, Prop2: 2 } } + // { Prop: a, Prop2: 2 } + + let getToPropertyStart () = + let doContinue = ref true + while !doContinue && jsonReader.Read() do + if jsonReader.TokenType = JsonToken.PropertyName && jsonReader.Value.ToString() <> "d" then + doContinue := false + + getToPropertyStart() + + let doContinue = ref true + while !doContinue do + if jsonReader.TokenType = JsonToken.PropertyName then + match rt.Properties |> Seq.tryFind (fun p -> p.Name = jsonReader.Value.ToString()) with + | Some prop -> + jsonReader.Read() |> ignore + // todo: assert is not comment or property name + + let value = jsonReader.Value + + if prop.IsOfKind (ResourcePropertyKind.Primitive) then + + let sanitizedVal = Convert.ChangeType(value, prop.ResourceType.InstanceType) + + prop.SetValue(instance, sanitizedVal) + + elif prop.IsOfKind (ResourcePropertyKind.ComplexType) then + + () + else + () + + doContinue := jsonReader.Read() + + | _ -> + // could not find property: should this be an error? + doContinue := false + + else + doContinue := jsonReader.Read() + + instance - let CreateSerializer () = null + let CreateDeserializer = + { + new Deserializer() with + override x.DeserializeMany (rt, reader, enc) = + raise(NotImplementedException()) + override x.DeserializeSingle (rt, reader, enc) = + read_item rt reader enc + } end diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Metadata.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Metadata.fs index 85457bb1..013fe511 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Metadata.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.Metadata.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization open System open System.Collections.Generic @@ -43,6 +58,7 @@ module AtomServiceDocSerializer = end // used when /$metadata is accessed with GET +// see http://msdn.microsoft.com/en-us/library/bb399292.aspx module MetadataSerializer = begin @@ -54,15 +70,27 @@ module MetadataSerializer = static member EpmNsPrefix = "FC_NsPrefix" static member EpmNsUri = "FC_NsUri" - let private associationSetsCache = Dictionary() - let private associationTypesCache = Dictionary() - let private get_associationtype_lookupname (rt:ResourceType) (prop:ResourceProperty) = rt.Name + if prop <> null then "_" + prop.Name else "" + let private get_associationtype_name (end1:ResourceType) (prop1:ResourceProperty) (end2:ResourceType) (prop2:ResourceProperty) = + end1.Name + "_" + prop1.Name + + (* + let actualend1 = if prop1 <> null then end1 else end2 + let actualend2 = if actualend1 = end1 + then (if prop2 <> null then end2 else null) + else null + actualend1.Name + "_" + prop1.Name + + if actualend2 <> null + then "_" + actualend2.Name + "_" + prop2.Name + else "" + *) + + (* let private get_associationtype_name (association:ResourceAssociationSet) = let end1 = if association.End1.ResourceProperty <> null then association.End1 else association.End2 let end2 = if end1 = association.End1 @@ -72,6 +100,7 @@ module MetadataSerializer = if end2 <> null then "_" + end2.ResourceType.Name + "_" + end2.ResourceProperty.Name else "" + *) // http://msdn.microsoft.com/en-us/library/dd942559%28v=prot.10%29.aspx let write_epm_properties (xmlWriter:XmlWriter) skipSourcePath removePrefix (items:EntityPropertyMappingAttribute seq) = @@ -138,7 +167,7 @@ module MetadataSerializer = items |> Seq.iter write_epm_attributes - let private write_property (xmlWriter:XmlWriter) (resRt:ResourceType) (property:ResourceProperty) = + let private write_property (xmlWriter:XmlWriter) (resRt:ResourceType) (property:ResourceProperty) (associationTypesCache:Dictionary) = let write_facets () = let pType = property.Type @@ -152,7 +181,7 @@ module MetadataSerializer = |> Seq.filter (fun epm -> (Array.get (epm.SourcePath.Split([|'/'|])) 0) = property.Name) |> write_epm_properties xmlWriter skipSourcePath removePrefix - if (property.ResourceType.ResourceTypeKind = ResourceTypeKind.Primitive) then + if property.ResourceType.ResourceTypeKind = ResourceTypeKind.Primitive then xmlWriter.WriteStartElement("Property") xmlWriter.WriteAttributeString("Name", property.Name) xmlWriter.WriteAttributeString("Type", property.ResourceType.FullName) @@ -166,7 +195,7 @@ module MetadataSerializer = write_epm_attributes false - elif (property.Kind = ResourcePropertyKind.ComplexType) then + elif property.Kind = ResourcePropertyKind.ComplexType then xmlWriter.WriteStartElement("Property") xmlWriter.WriteAttributeString("Name", property.Name) @@ -188,17 +217,14 @@ module MetadataSerializer = xmlWriter.WriteAttributeString("Relationship", assocType.FullName) xmlWriter.WriteAttributeString("FromRole", typeend.Name) xmlWriter.WriteAttributeString("ToRole", otherside.Name) - xmlWriter.WriteEndElement() - () - - let private write_properties (writer:XmlWriter) (resRt:ResourceType) = + let private write_properties (writer:XmlWriter) (resRt:ResourceType) (associationTypesCache:Dictionary) = resRt.PropertiesDeclaredOnThisType - |> Seq.iter (fun p -> write_property writer resRt p) + |> Seq.iter (fun p -> write_property writer resRt p associationTypesCache) - let private write_entity (writer:XmlWriter) (resRt:ResourceType) = + let private write_entity (writer:XmlWriter) (resRt:ResourceType) (associationTypesCache:Dictionary) = let write_key () = writer.WriteStartElement("Key") @@ -209,7 +235,7 @@ module MetadataSerializer = writer.WriteEndElement() writer.WriteStartElement("EntityType") - writer.WriteAttributeString("Name", XmlConvert.EncodeName(resRt.Name)) + writer.WriteAttributeString("Name", XmlConvert.EncodeName(resRt.InstanceType.Name)) if resRt.IsAbstract || resRt.BaseType <> null then raise(NotImplementedException("Abstract/Inheritance for ResourceTypes is not supported")) if resRt.IsOpenType then raise(NotImplementedException("OpenTypes aren't supported")) @@ -222,26 +248,26 @@ module MetadataSerializer = write_epm_properties writer false false resRt.OwnEpmAttributes // resRt.InheritedEpmInfo write_key () - write_properties writer resRt + write_properties writer resRt associationTypesCache writer.WriteEndElement() - let private write_complex (writer:XmlWriter) (resRt:ResourceType) = + let private write_complex (writer:XmlWriter) (resRt:ResourceType) (associationTypesCache:Dictionary) = writer.WriteStartElement("ComplexType") - writer.WriteAttributeString("Name", XmlConvert.EncodeName(resRt.Name)) - write_properties writer resRt + writer.WriteAttributeString("Name", XmlConvert.EncodeName(resRt.InstanceType.Name)) + write_properties writer resRt associationTypesCache writer.WriteEndElement() - let private write_type (writer:XmlWriter) (resRt:ResourceType) = + let private write_type (writer:XmlWriter) (resRt:ResourceType) (associationTypesCache:Dictionary) = if resRt.ResourceTypeKind = ResourceTypeKind.EntityType then - write_entity writer resRt + write_entity writer resRt associationTypesCache else - write_complex writer resRt - + write_complex writer resRt associationTypesCache - - let private prepare (wrapper:DataServiceMetadataProviderWrapper) = + let private prepare (wrapper:DataServiceMetadataProviderWrapper) + (associationSetsCache:Dictionary) + (associationTypesCache:Dictionary) = - let get_main_association (rs:ResourceSetWrapper) (rt:ResourceType) (prop:ResourceProperty) = + let get_res_association_set (rs:ResourceSetWrapper) (rt:ResourceType) (prop:ResourceProperty) = let key = rs.Name + "_" + rt.FullName + "_" + prop.Name let r, association = associationSetsCache.TryGetValue key @@ -255,124 +281,145 @@ module MetadataSerializer = let associationSet = wrapper.GetResourceAssociationSet(wrapper.ValidateResourceSet(associationEnd.ResourceSet), associationEnd.ResourceType, associationEnd.ResourceProperty) if associationSet = null || association.Name <> associationSet.Name then raise(InvalidOperationException("Invalid bi-directional assocation")) - + let key2 = sprintf "%s_%s_%s" associationEnd.ResourceSet.Name associationEnd.ResourceProperty.ResourceType.FullName associationEnd.ResourceProperty.Name + associationSetsCache.Add (key2, association) + (* let key2 = if associationEnd.ResourceProperty <> null then sprintf "%s_%s_%s" associationEnd.ResourceSet.Name associationEnd.ResourceProperty.ResourceType.FullName associationEnd.ResourceProperty.Name else sprintf "%s_Null_%s_%s" associationEnd.ResourceSet.Name rt.FullName prop.Name associationSetsCache.Add (key2, association) + *) associationSetsCache.Add (key, association) association - let get_association_type (association:ResourceAssociationSet) (rs:ResourceSetWrapper) (rt:ResourceType) (prop:ResourceProperty) = - let associationTypes = associationTypesCache - let name = get_associationtype_name association + let get_association_type (association:ResourceAssociationSet) (rs:ResourceSetWrapper) + (rt:ResourceType) (prop:ResourceProperty) = + + let lookupName = get_associationtype_lookupname rt prop + if not <| associationTypesCache.ContainsKey lookupName then + failwithf "Since RT associations are processed first, it was expected that the association name %s would already be created by now. However, it wasn't." lookupName + else associationTypesCache.[lookupName] + + let build_association_info (rs:ResourceSetWrapper) (rt:ResourceType) (prop:ResourceProperty) = + let association = get_res_association_set rs rt prop + if association <> null then + association.ResourceAssociationType <- get_association_type association rs rt prop + + let populate_association_set (rs:ResourceSetWrapper) = + let rt = rs.ResourceType + rt.PropertiesDeclaredOnThisType + |> Seq.filter (fun p -> p.ResourceType.ResourceTypeKind = ResourceTypeKind.EntityType) + |> Seq.iter (fun p -> build_association_info rs rt p) + + let ensure_association_type_exists (rt:ResourceType) (prop:ResourceProperty) = + let end1 = rt + let end2 = prop.ResourceType + let otherProp = + match end2.PropertiesDeclaredOnThisType |> Seq.tryPick (fun p -> if p.ResourceType = end1 then Some(p) else None) with + | Some p -> p + | _ -> null + + let name = get_associationtype_name end1 prop end2 otherProp let lookupName = get_associationtype_lookupname rt prop - if not <| associationTypes.ContainsKey lookupName then - let bidirectional = association.End1.ResourceProperty <> null && association.End2.ResourceProperty <> null + if not <| associationTypesCache.ContainsKey lookupName then + let bidirectional = otherProp <> null let end1Name, end2Name = if not bidirectional then - if association.End1.ResourceProperty <> null + if otherProp = null then rt.Name, prop.Name else prop.Name, rt.Name else - (get_associationtype_lookupname association.End1.ResourceType association.End1.ResourceProperty), - (get_associationtype_lookupname association.End2.ResourceType association.End2.ResourceProperty) + (get_associationtype_lookupname end1 prop), + (get_associationtype_lookupname end2 otherProp) + let resourceAssociationType = ResourceAssociationType( name, rt.Namespace, - new ResourceAssociationTypeEnd(end1Name, association.End1.ResourceType, association.End1.ResourceProperty, association.End2.ResourceProperty), - new ResourceAssociationTypeEnd(end2Name, association.End2.ResourceType, association.End2.ResourceProperty, association.End1.ResourceProperty)) - associationTypes.Add (lookupName, resourceAssociationType) - if bidirectional then - let otherside = association.GetRelatedResourceAssociationSetEnd (rs, rt, prop) - let name = get_associationtype_lookupname otherside.ResourceType otherside.ResourceProperty - associationTypes.Add (name, resourceAssociationType) - resourceAssociationType - else - associationTypes.[lookupName] - - + new ResourceAssociationTypeEnd(end1Name, end1, prop, otherProp), + new ResourceAssociationTypeEnd(end2Name, end2, otherProp, prop)) + associationTypesCache.Add (lookupName, resourceAssociationType) - let build_association_info (rs:ResourceSetWrapper) (rt:ResourceType) (prop:ResourceProperty) = - let association = get_main_association rs rt prop - - if association <> null then - association.ResourceAssociationType <- get_association_type association rs rt prop - - () + if bidirectional then + let name = get_associationtype_lookupname end2 otherProp + if not <| associationTypesCache.ContainsKey name then + associationTypesCache.Add (name, ResourceAssociationType(name, rt.Namespace, resourceAssociationType.End2, resourceAssociationType.End1)) - let populate_association (rs:ResourceSetWrapper) = - let rt = rs.ResourceType + let populate_association_types (rt:ResourceType) = rt.PropertiesDeclaredOnThisType |> Seq.filter (fun p -> p.ResourceType.ResourceTypeKind = ResourceTypeKind.EntityType) - |> Seq.iter (fun p -> build_association_info rs rt p) - - wrapper.ResourceSets |> Seq.iter populate_association - () + |> Seq.iter (fun p -> ensure_association_type_exists rt p) - let private write_associations (writer:XmlWriter) = + wrapper.ResourceTypes |> Seq.iter populate_association_types + wrapper.ResourceSets |> Seq.iter populate_association_set - let write_association (association:ResourceAssociationType) = - let write_association_end (``end``:ResourceAssociationTypeEnd) = - writer.WriteStartElement "End" - writer.WriteAttributeString ("Role", ``end``.Name) - writer.WriteAttributeString ("Type", ``end``.ResourceType.FullName) - writer.WriteAttributeString ("Multiplicity", ``end``.Multiplicity) - writer.WriteEndElement() - writer.WriteStartElement "Association" - writer.WriteAttributeString("Name", association.Name) - write_association_end association.End1 - write_association_end association.End2 - writer.WriteEndElement () - associationTypesCache.Values |> Seq.iter write_association - - let private write_entitycontainer (writer:XmlWriter) (wrapper:DataServiceMetadataProviderWrapper) = + let public serialize(writer:TextWriter, wrapper:DataServiceMetadataProviderWrapper, enc:Encoding) = + let xmlWriter = SerializerCommons.create_xmlwriter writer enc - let write_entity (rs:ResourceSetWrapper) = - writer.WriteStartElement "EntitySet" - writer.WriteAttributeString ("Name", rs.Name) - writer.WriteAttributeString ("EntityType", rs.ResourceType.FullName) - writer.WriteEndElement() + let associationSetsCache = Dictionary() + let associationTypesCache = Dictionary() - let write_association (association:ResourceAssociationSet) = + prepare wrapper associationSetsCache associationTypesCache - let write_end (``end``:ResourceAssociationTypeEnd) (aSetEnd:ResourceAssociationSetEnd) = - writer.WriteStartElement "End" - writer.WriteAttributeString ("Role", ``end``.Name) - writer.WriteAttributeString ("EntitySet", aSetEnd.ResourceSet.Name) + let write_associations (writer:XmlWriter) = + + let write_association_type (association:ResourceAssociationType) = + let write_association_end (``end``:ResourceAssociationTypeEnd) = + writer.WriteStartElement "End" + writer.WriteAttributeString ("Role", ``end``.Name) + writer.WriteAttributeString ("Type", ``end``.ResourceType.Namespace + "." + ``end``.ResourceType.InstanceType.Name) + writer.WriteAttributeString ("Multiplicity", ``end``.Multiplicity) + writer.WriteEndElement() + + writer.WriteStartElement "Association" + writer.WriteAttributeString("Name", association.Name) + write_association_end association.End1 + if association.End2.Name <> association.End1.Name then + write_association_end association.End2 writer.WriteEndElement () - writer.WriteStartElement "AssociationSet" - writer.WriteAttributeString ("Name", association.Name) - writer.WriteAttributeString("Association", association.ResourceAssociationType.FullName) - let associationTypeEnd1 = association.ResourceAssociationType.GetResourceAssociationTypeEnd(association.End1.ResourceType, association.End1.ResourceProperty) - let associationTypeEnd2 = association.ResourceAssociationType.GetResourceAssociationTypeEnd(association.End2.ResourceType, association.End2.ResourceProperty) - write_end associationTypeEnd1 association.End1 - write_end associationTypeEnd2 association.End2 - writer.WriteEndElement () - - writer.WriteStartElement "EntityContainer" - writer.WriteAttributeString ("Name", (XmlConvert.EncodeName(wrapper.ContainerName))) - writer.WriteAttributeString ("m", "IsDefaultEntityContainer", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata", "true") + associationTypesCache.Values |> Seq.iter write_association_type + + let write_entitycontainer (writer:XmlWriter) (wrapper:DataServiceMetadataProviderWrapper) = - wrapper.ResourceSets |> Seq.iter write_entity - associationSetsCache.Values |> Seq.iter write_association - // write service operations + let write_entity (rs:ResourceSetWrapper) = + writer.WriteStartElement "EntitySet" + writer.WriteAttributeString ("Name", rs.Name) + writer.WriteAttributeString ("EntityType", rs.ResourceType.Namespace + "." + rs.ResourceType.InstanceType.Name) + writer.WriteEndElement() - writer.WriteEndElement () + let write_association_set (association:ResourceAssociationSet) = + + let write_end (``end``:ResourceAssociationTypeEnd) (aSetEnd:ResourceAssociationSetEnd) = + if ``end`` <> null && aSetEnd.ResourceSet <> null then + writer.WriteStartElement "End" + writer.WriteAttributeString ("Role", ``end``.Name) + writer.WriteAttributeString ("EntitySet", aSetEnd.ResourceSet.Name) + writer.WriteEndElement () + + writer.WriteStartElement "AssociationSet" + writer.WriteAttributeString ("Name", association.Name) + writer.WriteAttributeString("Association", association.ResourceAssociationType.FullName) + let associationTypeEnd1 = association.ResourceAssociationType.GetResourceAssociationTypeEnd(association.End1.ResourceType, association.End1.ResourceProperty) + let associationTypeEnd2 = association.ResourceAssociationType.GetResourceAssociationTypeEnd(association.End2.ResourceType, association.End2.ResourceProperty) + write_end associationTypeEnd1 association.End1 + write_end associationTypeEnd2 association.End2 + writer.WriteEndElement () - () + writer.WriteStartElement "EntityContainer" + writer.WriteAttributeString ("Name", (XmlConvert.EncodeName(wrapper.ContainerName))) + writer.WriteAttributeString ("m", "IsDefaultEntityContainer", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata", "true") - let public serialize(writer:TextWriter, wrapper:DataServiceMetadataProviderWrapper, enc:Encoding) = - let xmlWriter = SerializerCommons.create_xmlwriter writer enc + wrapper.ResourceSets |> Seq.iter write_entity + associationSetsCache.Values |> Seq.iter write_association_set + // write service operations - prepare(wrapper) + writer.WriteEndElement () xmlWriter.WriteStartElement("edmx", "Edmx", "http://schemas.microsoft.com/ado/2007/06/edmx") xmlWriter.WriteAttributeString("Version", "1.0") @@ -386,7 +433,7 @@ module MetadataSerializer = xmlWriter.WriteAttributeString("xmlns", "m", null, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") wrapper.ResourceTypes - |> Seq.iter (fun rs -> write_type xmlWriter rs ) + |> Seq.iter (fun rs -> write_type xmlWriter rs associationTypesCache) write_associations xmlWriter diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainTextSerialization.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainTextSerialization.fs new file mode 100644 index 00000000..6c42de0a --- /dev/null +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainTextSerialization.fs @@ -0,0 +1,46 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization + +open System +open System.IO +open System.Xml +open System.Data.Services.Providers + +module PlainTextSerialization = + begin + + type PlainTextSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) = + class + inherit Serializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) + + let write_primitive_value (rt:ResourceType) (prop:ResourceProperty) value (writer:TextWriter) = + if value = null + then writer.Write "null" + else writer.Write (value.ToString()) + + override x.SerializeMany(items) = + raise(NotImplementedException()) + + override x.SerializeSingle(item) = + raise(NotImplementedException()) + + override x.SerializeProperty(prop:ResourceProperty, value) = + write_primitive_value rt prop value writer + + end + + end \ No newline at end of file diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainXml.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainXml.fs index 3bc6021a..43499c41 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainXml.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.PlainXml.fs @@ -1,12 +1,92 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization open System open System.Xml +open System.Data.Services.Providers + module XmlSerialization = begin - let CreateDeserializer () = null + let internal to_xml_string (valType:Type) (originalVal:obj) = + let targetType = + let nulType = Nullable.GetUnderlyingType(valType) + if nulType = null then valType else nulType + + System.Diagnostics.Debug.Assert( originalVal <> null ) + + if targetType = typeof then string(originalVal) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> bool) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> float) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> double) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> int8) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> int16) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> int32) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> int64) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> DateTime, XmlDateTimeSerializationMode.RoundtripKind) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> decimal) + elif targetType = typeof then Convert.ToBase64String(originalVal :?> byte[]) + elif targetType = typeof then XmlConvert.ToString(originalVal :?> byte) + else raise(InvalidOperationException("primitive value conversion to its xml representation is not supported. " + valType.FullName)) + + let internal write_primitive_value (rt:ResourceType) (prop:ResourceProperty) value (writer:XmlWriter) = + let name = prop.Name + + writer.WriteStartElement (name, "http://schemas.microsoft.com/ado/2007/08/dataservices") + + let typename = rt.FullName + + if typename <> "Edm.String" then + writer.WriteAttributeString ("type", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata", typename) + + if value = null + then writer.WriteAttributeString("null", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata", "true") + else writer.WriteString(value.ToString()) + + writer.WriteEndElement() + + let private write_primitive (rt:ResourceType) (prop:ResourceProperty) (value:obj) (txtwriter) (enc) = + use writer = SerializerCommons.create_xmlwriter (txtwriter) enc + write_primitive_value rt prop value writer + + + type XmlSerializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) = + class + inherit Serializer(wrapper, serviceBaseUri, containerUri, rt, propertiesToExpand, writer, enc) + + override x.SerializeMany(items) = + raise(NotImplementedException()) + + override x.SerializeSingle(item) = + raise(NotImplementedException()) + + override x.SerializeProperty(prop:ResourceProperty, value) = + write_primitive rt prop value writer enc - let CreateSerializer () = null + end + + let CreateDeserializer () = + { new Deserializer() with + override x.DeserializeMany (rt, reader, enc) = + // read_feed rt reader enc + raise(NotImplementedException()) + override x.DeserializeSingle (rt, reader, enc) = + // read_item rt reader enc + raise(NotImplementedException()) + } - end \ No newline at end of file + end diff --git a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.fs b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.fs index 3798c757..e51c5506 100644 --- a/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.fs +++ b/MR3/Extensions/OData/src/Castle.MonoRail.Extension.ODataFs/Serialization/Serialization.fs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Serialization open System open System.Collections @@ -13,6 +28,15 @@ open System.Data.OData open System.Data.Services.Providers +type ResponseToSend = { + mutable QItems : IQueryable; + mutable SingleResult : obj; + ResType : ResourceType; + FinalResourceUri : Uri; + ResProp : ResourceProperty; + PropertiesToExpand : HashSet; +} + [] type Deserializer() = class @@ -21,15 +45,118 @@ type Deserializer() = end [] -type Serializer() = - class - abstract member SerializeMany : baseUri:Uri * rt:ResourceType * items:IEnumerable * writer:TextWriter * enc:Encoding -> unit - abstract member SerializeSingle : baseUri:Uri * rt:ResourceType * items:obj * writer:TextWriter * enc:Encoding -> unit +type Serializer(wrapper:DataServiceMetadataProviderWrapper, serviceBaseUri:Uri, containerUri:Uri, rt:ResourceType, + propertiesToExpand:HashSet, writer:TextWriter, enc:Encoding) = + + abstract member SerializeMany : items:IEnumerable -> unit + abstract member SerializeSingle : item:obj -> unit + abstract member SerializeProperty : prop:ResourceProperty * value:obj -> unit + + member x.ShouldExpand (property:ResourceProperty) = propertiesToExpand.Contains property + + member x.Serialize (response:ResponseToSend) = + let items : IQueryable = response.QItems + let item = response.SingleResult + let rt = response.ResType + + if items <> null then + x.SerializeMany (items) + elif response.ResProp <> null && response.ResProp.IsOfKind(ResourcePropertyKind.Primitive) then + x.SerializeProperty (response.ResProp, item) + else + x.SerializeSingle (item) + + +(* +[] +type SerializerStructure() = + class + inherit Serializer() + + member x.ShouldExpand (property:ResourceProperty) = + false + + member x.WriteItems () = + // ProcessSkipTop ? + // ProcessSkipToken ? + () + + member x.WriteItem () = + () + + member x.WriteProperty () = + () + + member x.InternalWriteItems () = + () + + member x.InternalWriteItem () = + () + + member x.InternalProperty () = + () + end +*) + +[] module SerializerCommons = begin + + type XmlReader with + member x.ReadToElement() = + let doCont = ref true + let isElement = ref false + while !doCont do + match x.NodeType with + | XmlNodeType.None | XmlNodeType.ProcessingInstruction + | XmlNodeType.Comment | XmlNodeType.Whitespace + | XmlNodeType.XmlDeclaration -> + () + | XmlNodeType.Text -> + if String.IsNullOrEmpty x.Value || x.Value.Trim().Length <> 0 + then isElement := false; doCont := false + | XmlNodeType.Element -> + isElement := true; doCont := false + | _ -> + isElement := false; doCont := false + if !doCont then doCont := x.Read() + !isElement + + type ResourceProperty + with + member x.GetValue(instance:obj) = + let prop = instance.GetType().GetProperty(x.Name) + prop.GetValue(instance, null) + member x.GetValueAsStr(instance:obj) = + let prop = instance.GetType().GetProperty(x.Name) + let value = prop.GetValue(instance, null) + if value = null + then null + else value.ToString() + member x.SetValue(instance:obj, value:obj) = + let prop = instance.GetType().GetProperty(x.Name) + prop.SetValue(instance, value, null) + + type ResourceType + with + member x.GetKey (instance:obj) = + let keyValue = + if x.KeyProperties.Count = 1 + then x.KeyProperties.[0].GetValueAsStr(instance) + else failwith "Composite keys are not supported" + sprintf "(%s)" keyValue + (* + member x.PathWithKey(instance:obj) = + let keyValue = + if x.KeyProperties.Count = 1 + then x.KeyProperties.[0].GetValueAsStr(instance) + else failwith "Composite keys are not supported" + sprintf "%s(%s)" x.Name keyValue + *) + let internal create_xmlwriter(writer:TextWriter) (encoding) = let settings = XmlWriterSettings(CheckCharacters = false, ConformanceLevel = ConformanceLevel.Fragment, @@ -43,4 +170,5 @@ module SerializerCommons = let internal create_xmlreader(reader:TextReader) (encoding) = let settings = XmlReaderSettings() XmlReader.Create(reader, settings) - end \ No newline at end of file + end + diff --git a/MR3/WebApplication1/.gitignore b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/.gitignore similarity index 100% rename from MR3/WebApplication1/.gitignore rename to MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/.gitignore diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/AggRootModelAtomTestCase.cs b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/AggRootModelAtomTestCase.cs new file mode 100644 index 00000000..6d9411fe --- /dev/null +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/AggRootModelAtomTestCase.cs @@ -0,0 +1,121 @@ +namespace Castle.MonoRail.Extension.OData.Integration.Tests +{ + using System; + using System.IO; + using System.Net; + using Castle.MonoRail.Integration.Tests; + using FluentAssertions; + using NUnit.Framework; + + [TestFixture, Category("Integration")] + public class ActionResultsIntegrationAtomTestCase : BaseServerTest + { + public ActionResultsIntegrationAtomTestCase() + { + this.WebSiteFolder = "ODataTestWebSite"; + } + + [Test] + public void Post_Repository_ExpectsSuccessfulCreation() + { + var req = (HttpWebRequest) WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories"))); + // var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); + req.Accept = "application/atom+xml"; + req.ContentType = "application/atom+xml"; + req.Method = "POST"; + var reqWriter = new StreamWriter(req.GetRequestStream()); + // todo: write Repository in atom + + reqWriter.Write( +@" + + + + + repo1 + + + "); + reqWriter.Flush(); + + var reply = (HttpWebResponse)req.GetResponse(); + reply.StatusCode.Should().Be(HttpStatusCode.Created); + reply.ContentType.Should().Be("application/atom+xml; charset=utf-8"); + var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); + + Console.WriteLine(replyContent); + } + + [Test] + public void Post_Branch_ExpectsSuccessfulCreation() + { + var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories(1)/Branches"))); + // var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); + req.Accept = "application/atom+xml"; + req.ContentType = "application/atom+xml"; + req.Method = "POST"; + var reqWriter = new StreamWriter(req.GetRequestStream()); + // todo: write Repository in atom + + reqWriter.Write( +@" + + + 2012-04-20T06:29:23Z + + + + + + branch1 + + + "); + reqWriter.Flush(); + + var reply = (HttpWebResponse)req.GetResponse(); + reply.StatusCode.Should().Be(HttpStatusCode.Created); + reply.ContentType.Should().Be("application/atom+xml; charset=utf-8"); + var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); + + Console.WriteLine(replyContent); + } + + [Test] + public void Post_Revision_ExpectsSuccessfulCreation() + { + var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories(1)/Branches(100)/Revisions"))); + // var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); + req.Accept = "application/atom+xml"; + req.ContentType = "application/atom+xml"; + req.Method = "POST"; + var reqWriter = new StreamWriter(req.GetRequestStream()); + // todo: write Repository in atom + + reqWriter.Write( +@" + + + 2012-04-20T06:29:23Z + + + + + + file1 + 123 + + + "); + reqWriter.Flush(); + + var reply = (HttpWebResponse)req.GetResponse(); + reply.StatusCode.Should().Be(HttpStatusCode.Created); + reply.ContentType.Should().Be("application/atom+xml; charset=utf-8"); + var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); + + Console.WriteLine(replyContent); + + } + } +} diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/AggRootModelJsonTestCase.cs b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/AggRootModelJsonTestCase.cs new file mode 100644 index 00000000..bab865c3 --- /dev/null +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/AggRootModelJsonTestCase.cs @@ -0,0 +1,144 @@ +namespace Castle.MonoRail.Extension.OData.Integration.Tests +{ + using System; + using System.IO; + using System.Net; + using Castle.MonoRail.Integration.Tests; + using FluentAssertions; + using NUnit.Framework; + + [TestFixture, Category("Integration")] + public class ActionResultsIntegrationJsonTestCase : BaseServerTest + { + public ActionResultsIntegrationJsonTestCase() + { + this.WebSiteFolder = "ODataTestWebSite"; + } + + [Test] + public void Post_Repository_ExpectsSuccessfulCreation() + { + var req = (HttpWebRequest) WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories"))); + // var req = (HttpWebRequest) WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); + + req.Accept = "application/json"; + req.ContentType = "application/json"; + req.Method = "POST"; + var reqWriter = new StreamWriter(req.GetRequestStream()); + + reqWriter.Write( +@"{ + ""d"": { + ""Name"": ""Repo 2"" + } +}"); + reqWriter.Flush(); + + var reply = (HttpWebResponse)req.GetResponse(); + reply.StatusCode.Should().Be(HttpStatusCode.Created); + reply.ContentType.Should().Be("application/json; charset=utf-8"); + var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); + + Console.WriteLine(replyContent); + } + + [Test] + public void Post_Repository_SimplerJSon_ExpectsSuccessfulCreation() + { + var req = (HttpWebRequest) WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories"))); + // var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); + + req.Accept = "application/json"; + req.ContentType = "application/json"; + req.Method = "POST"; + var reqWriter = new StreamWriter(req.GetRequestStream()); + + reqWriter.Write( +@"{ + + ""Name"": ""Repo 2"" + +}"); + reqWriter.Flush(); + + var reply = (HttpWebResponse)req.GetResponse(); + reply.StatusCode.Should().Be(HttpStatusCode.Created); + reply.ContentType.Should().Be("application/json; charset=utf-8"); + var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); + + Console.WriteLine(replyContent); + } + +// [Test] +// public void Post_Branch_ExpectsSuccessfulCreation() +// { +// var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories(1)/Branches"))); + // var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); +// req.Accept = "application/atom+xml"; +// req.ContentType = "application/atom+xml"; +// req.Method = "POST"; +// var reqWriter = new StreamWriter(req.GetRequestStream()); + // todo: write Repository in atom +// +// reqWriter.Write( +//@" +// +// +// 2012-04-20T06:29:23Z +// +// +// +// +// +// branch1 +// +// +// "); +// reqWriter.Flush(); +// +// var reply = (HttpWebResponse)req.GetResponse(); +// reply.StatusCode.Should().Be(HttpStatusCode.Created); +// reply.ContentType.Should().Be("application/atom+xml; charset=utf-8"); +// var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); +// +// Console.WriteLine(replyContent); +// } +// +// [Test] +// public void Post_Revision_ExpectsSuccessfulCreation() +// { +// var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(BuildUrl("/models/RootModel/Repositories(1)/Branches(100)/Revisions"))); + // var req = (HttpWebRequest)WebRequest.CreateDefault(new Uri("http://localhost:2740/models/RootModel/Repositories")); +// req.Accept = "application/atom+xml"; +// req.ContentType = "application/atom+xml"; +// req.Method = "POST"; +// var reqWriter = new StreamWriter(req.GetRequestStream()); + // todo: write Repository in atom +// +// reqWriter.Write( +//@" +// +// +// 2012-04-20T06:29:23Z +// +// +// +// +// +// file1 +// 123 +// +// +// "); +// reqWriter.Flush(); +// +// var reply = (HttpWebResponse)req.GetResponse(); +// reply.StatusCode.Should().Be(HttpStatusCode.Created); +// reply.ContentType.Should().Be("application/atom+xml; charset=utf-8"); +// var replyContent = new StreamReader(reply.GetResponseStream()).ReadToEnd(); +// +// Console.WriteLine(replyContent); +// +// } + } +} diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/Castle.MonoRail.Extension.OData.Integration.Tests.csproj b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/Castle.MonoRail.Extension.OData.Integration.Tests.csproj new file mode 100644 index 00000000..c6cc94f8 --- /dev/null +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/Castle.MonoRail.Extension.OData.Integration.Tests.csproj @@ -0,0 +1,78 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {7AB66D00-A3FB-4B04-BA2D-4C60F0C0B6C0} + Library + Properties + Castle.MonoRail.Extension.OData.Integration.Tests + Castle.MonoRail.Extension.OData.Integration.Tests + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\tests\lib\CassiniDev4-lib.dll + + + ..\..\..\..\tests\lib\FluentAssertions.dll + + + ..\..\..\..\tests\lib\nunit.framework.dll + + + + + + + + + + + + + + + + + {8C35651E-A56E-4771-95CA-E312AA318538} + Castle.MonoRail + + + {A9D55E13-01F2-49B5-97C7-336E44B218F4} + Castle.MonoRail.Integration.Tests + + + {B0D83F48-B4B4-4F6B-867F-B9D91FAE7DAD} + ODataTestWebSite + + + + + \ No newline at end of file diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/Properties/AssemblyInfo.cs b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..b1a2cf8f --- /dev/null +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Integration.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("Castle.MonoRail.Extension.OData.Integration.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Castle.MonoRail.Extension.OData.Integration.Tests")] +[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("4c651b0e-62a7-4301-9840-c9d514ef3b44")] + +// 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/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AstLinqTranslatorTestCase.cs b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AstLinqTranslatorTestCase.cs new file mode 100644 index 00000000..0e875902 --- /dev/null +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AstLinqTranslatorTestCase.cs @@ -0,0 +1,377 @@ +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Tests +{ + using System; + using System.Collections.Generic; + using System.ComponentModel.DataAnnotations; + using System.Data.Services.Providers; + using System.Linq; + using System.Linq.Expressions; + using FluentAssertions; + using NUnit.Framework; + + [TestFixture] + public class AstLinqTranslatorTestCase + { + private StubModel _model; + private ResourceType _catalogRt; + private List _catalogs; + + [SetUp] + public void Init() + { + _catalogs = new List + { + new Catalog2() { Id = 1, Name = "catalog 1", IsPublished = false, Owner = new User2() { Email = "email1@m.com", Name = "Mary"} }, + new Catalog2() { Id = 2, Name = "catalog 2", IsPublished = true , Owner = new User2() { Email = "email2@m.com", Name = "John"} }, + new Catalog2() { Id = 3, Name = "catalog 3", IsPublished = false, Owner = new User2() { Email = "email3@m.com", Name = "Jeff"} }, + new Catalog2() { Id = 4, Name = "catalog 4", IsPublished = true , Owner = new User2() { Email = "email4@m.com", Name = "Andrew"} }, + new Catalog2() { Id = 5, Name = "catalog 5", IsPublished = false, Owner = new User2() { Email = "email5@m.com", Name = "Mary"} }, + }; + + _model = new StubModel( + m => m.EntitySet("catalogs", _catalogs.AsQueryable()) + ); + + _catalogRt = _model.GetResourceType("Catalog2").Value; + } + + private Expression> BuildLinqExpressionPredicate(string expression, ResourceType rt) + { + var exp = QueryExpressionParser.parse_filter(expression); + // Console.WriteLine(exp4.ToStringTree()); + + var tree = QuerySemanticAnalysis.analyze_and_convert(exp, rt); + //Console.WriteLine(tree.ToStringTree()); + + return AstLinqTranslator.build_linq_exp_predicate(typeof(T), tree); + } + + private static IQueryable ApplyOrderByExpression(IQueryable source, string expression, ResourceType rt) + { + var exp = QueryExpressionParser.parse_orderby(expression); + // Console.WriteLine(exp4.ToStringTree()); + var tree = QuerySemanticAnalysis.analyze_and_convert_orderby(exp, rt); + // Console.WriteLine(tree.ToStringTree()); + return AstLinqTranslator.typed_queryable_orderby(source, tree) as IQueryable; + } + + [Test] + public void OrderBy_Asc_StringProperty() + { + var result = ApplyOrderByExpression(_catalogs.AsQueryable(), "Name", _catalogRt); + result.Should().NotBeNull(); + var names = result.Select(c => c.Name); + var expected = _catalogs.OrderBy(c => c.Name).Select(c => c.Name); + names.Should().Equal(expected); + } + + [Test] + public void OrderBy_Desc_StringProperty() + { + var result = ApplyOrderByExpression(_catalogs.AsQueryable(), "Name desc", _catalogRt); + result.Should().NotBeNull(); + var names = result.Select(c => c.Name); + var expected = _catalogs.OrderByDescending(c => c.Name).Select(c => c.Name); + names.Should().Equal(expected); + } + + [Test] + public void OrderBy_Asc_Int32Property() + { + var result = ApplyOrderByExpression(_catalogs.AsQueryable(), "Id", _catalogRt); + result.Should().NotBeNull(); + var resultElems = result.Select(c => c.Id); + var expected = _catalogs.OrderBy(c => c.Id).Select(c => c.Id); + resultElems.Should().Equal(expected); + } + + [Test] + public void OrderBy_Desc_Int32Property() + { + var result = ApplyOrderByExpression(_catalogs.AsQueryable(), "Id desc", _catalogRt); + result.Should().NotBeNull(); + var resultElems = result.Select(c => c.Id); + var expected = _catalogs.OrderByDescending(c => c.Id).Select(c => c.Id); + resultElems.Should().Equal(expected); + } + + [Test] + public void OrderBy_Asc_StringProperty_AndThen_Desc_Int32Property() + { + var result = ApplyOrderByExpression(_catalogs.AsQueryable(), "Name, Id desc", _catalogRt); + result.Should().NotBeNull(); + var names = result.Select(c => c.Name); + var expected = _catalogs.OrderBy(c => c.Name).ThenByDescending(c => c.Id).Select(c => c.Name); + names.Should().Equal(expected); + } + + + [Test] + public void Property_Eq_String() + { + var exp = BuildLinqExpressionPredicate("Name eq 'catalog 1'", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(1); + results.ElementAt(0).Name.Should().Be("catalog 1"); + } + + [Test] + public void NestedProperty_Eq_String() + { + var exp = BuildLinqExpressionPredicate("Owner/Name eq 'Mary'", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(2); + results.Where(c => c.Owner.Name == "Mary").Should().HaveCount(2); + } + + [Test] + public void Property_Eq_Int32() + { + var exp = BuildLinqExpressionPredicate("Id eq 1", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(1); + results.ElementAt(0).Name.Should().Be("catalog 1"); + } + + [Test] + public void Property_Eq_Bool() + { + var exp = BuildLinqExpressionPredicate("IsPublished eq true", _catalogRt); + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(2); + + exp = BuildLinqExpressionPredicate("IsPublished eq false", _catalogRt); + results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count - 2); + } + + [Test] + public void BinaryNumericPromotion_Property_Eq_Int64() + { + var exp = BuildLinqExpressionPredicate("Id eq 1L", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(1); + results.ElementAt(0).Name.Should().Be("catalog 1"); + } + + [Test] + public void BinaryNumericPromotion_Property_Eq_Single() + { + var exp = BuildLinqExpressionPredicate("Id eq 1.0", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(1); + results.ElementAt(0).Name.Should().Be("catalog 1"); + } + + [Test] + public void Property_Ne_Int32() + { + var exp = BuildLinqExpressionPredicate("Id ne 1", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count - 1); + } + + [Test] + public void Property_Ne_NegateOfInt32() + { + var exp = BuildLinqExpressionPredicate("Id ne -1", _catalogRt); + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count); + + exp = BuildLinqExpressionPredicate("-Id ne 1", _catalogRt); + results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count); + } + + [Test] + public void Property_Ne_NegateOfSingle() + { + var exp = BuildLinqExpressionPredicate("Id ne -1.0", _catalogRt); + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count); + } + + [Test] + public void Property_Eq_Not() + { + var exp = BuildLinqExpressionPredicate("not (Id eq 1)", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count - 1); + } + + [Test] + public void Property_GreaterThan() + { + var exp = BuildLinqExpressionPredicate("Id gt 1", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count - 1); + } + + [Test] + public void Property_GreaterEqualThan() + { + var exp = BuildLinqExpressionPredicate("Id ge 1", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(_catalogs.Count); + } + + [Test] + public void Property_LessThan() + { + var exp = BuildLinqExpressionPredicate("Id lt 1", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(0); + } + + [Test] + public void Property_LessEqualThan() + { + var exp = BuildLinqExpressionPredicate("Id le 1", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(1); + } + + + [Test] + public void Property_GreaterThan_And_Eq() + { + var exp = BuildLinqExpressionPredicate("Id gt 1 and Name eq 'catalog 2'", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(1); + } + + [Test] + public void Property_GreaterThan_Or_Eq() + { + var exp = BuildLinqExpressionPredicate("Id eq 2 or Name eq 'catalog 1'", _catalogRt); + + var results = _catalogs.Where(exp.Compile()); + results.Count().Should().Be(2); + } + + private readonly string[] numericOps = new[] { "sub", "add", "mul", "div", "mod" }; + private readonly string[] relationalOps = new[] { "lt", "gt", "le", "ge" }; + private readonly string[] eqOps = new[] { "eq", "ne" }; + private readonly string[][] numericTypes = new[] + { + new [] { "Edm.Int32", "2", "PropInt32" }, + new [] { "Edm.Int64", "3L", "PropInt64" }, + new [] { "Edm.Decimal", "4m", "PropDec" }, + new [] { "Edm.Double", "5.0D", "PropSingle" }, + new [] { "Edm.Single", "6F", "PropDouble" }, + }; + + [Test] + public void EqualityOps_On_NumericTypes_Properties() + { + foreach (var op in eqOps) + foreach (var left in numericTypes) + foreach (var right in numericTypes) + { + var rawEx = left[2] + " " + op + " " + right[2]; + var exp = BuildLinqExpressionPredicate(rawEx, _catalogRt); + var results = _catalogs.Where(exp.Compile()); + results.Count(); + } + } + + [Test] + public void RelationalsOps_On_NumericTypes_Properties() + { + foreach (var op in relationalOps) + foreach (var left in numericTypes) + foreach (var right in numericTypes) + { + var rawEx = left[2] + " " + op + " " + right[2]; + var exp = BuildLinqExpressionPredicate(rawEx, _catalogRt); + var results = _catalogs.Where(exp.Compile()); + results.Count(); + } + } + + [Test] + public void NumericOps_On_NumericTypes_Properties() + { + foreach (var op in numericOps) + foreach (var left in numericTypes) + foreach (var right in numericTypes) + { + var rawEx = left[2] + " eq " + left[2] + " " + op + " " + right[2]; + var exp = BuildLinqExpressionPredicate(rawEx, _catalogRt); + var f = exp.Compile(); + } + } + + [Test] + public void NumericOps_On_NumericTypes_Literal() + { + foreach (var op in numericOps) + foreach (var left in numericTypes) + foreach (var right in numericTypes) + { + var rawEx = left[2] + " eq " + left[1] + " " + op + " " + right[1]; + var exp = BuildLinqExpressionPredicate(rawEx, _catalogRt); + var results = _catalogs.Where(exp.Compile()); + results.Count(); + } + } + + + public class Product2 + { + [Key] + public int Id { get; set; } + public string Name { get; set; } + } + + public class User2 + { + [Key] + public int Id { get; set; } + public string Name { get; set; } + public string Email { get; set; } + } + + public class Catalog2 + { + [Key] + public int Id { get; set; } + public string Name { get; set; } + public IList Products { get; set; } + public User2 Owner { get; set; } + public bool IsPublished { get; set; } + public int PropInt32 { get; set; } + public long PropInt64 { get; set; } + public decimal PropDec { get; set; } + public Single PropSingle { get; set; } + public double PropDouble { get; set; } + } + } +} diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AtomServiceDocSerializerTestCase.cs b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AtomServiceDocSerializerTestCase.cs index dbf751ae..40441719 100644 --- a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AtomServiceDocSerializerTestCase.cs +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/AtomServiceDocSerializerTestCase.cs @@ -1,4 +1,19 @@ -namespace Castle.MonoRail.Extension.OData.Tests +// Copyright 2004-2012 Castle Project - http://www.castleproject.org/ +// Hamilton Verissimo de Oliveira and individual contributors as indicated. +// See the committers.txt/contributors.txt in the distribution for a +// full listing of individual contributors. +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this software; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +// 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +namespace Castle.MonoRail.Extension.OData.Tests { using System; using System.Collections.Generic; @@ -9,6 +24,7 @@ using System.Linq; using System.Text; using NUnit.Framework; + using Castle.MonoRail.Extension.OData.Serialization; [TestFixture] public class AtomServiceDocSerializerTestCase diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/Castle.MonoRail.Extension.OData.Tests.csproj b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/Castle.MonoRail.Extension.OData.Tests.csproj index 5c829288..8b3035f0 100644 --- a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/Castle.MonoRail.Extension.OData.Tests.csproj +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/Castle.MonoRail.Extension.OData.Tests.csproj @@ -41,12 +41,17 @@ ..\..\..\..\tests\lib\FluentAssertions.dll + + ..\..\..\..\lib\Newtonsoft.Json.dll + False + ..\..\..\..\tests\lib\nunit.framework.dll + @@ -56,7 +61,12 @@ + + + + + @@ -69,6 +79,7 @@ + @@ -84,6 +95,20 @@ Castle.MonoRail.Extension.OData + + + + Designer + PreserveNewest + + + Designer + + + Designer + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Documentation element is used to provide documentation of comments on the contents of the XML file. It is valid under Schema, Type, Index and Relationship elements. + + + + + + + + + + + + + + + + This type allows pretty much any content + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/xsds/atom.xsd b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/xsds/atom.xsd new file mode 100644 index 00000000..bb465aba --- /dev/null +++ b/MR3/Extensions/OData/tests/Castle.MonoRail.Extension.OData.Tests/xsds/atom.xsd @@ -0,0 +1,240 @@ + + + + + This version of the Atom schema is based on version 1.0 of the format specifications, + found here http://www.atomenabled.org/developers/syndication/atom-format-spec.php. + + + + + + An Atom document may have two root elements, feed and entry, as defined in section 2. + + + + + + + + The Atom text construct is defined in section 3.1 of the format spec. + + + + + + + + + + + + + + + + + + + + The Atom person construct is defined in section 3.2 of the format spec. + + + + + + + + + + + + + + Schema definition for an email address. + + + + + + + + + + The Atom feed construct is defined in section 4.1.1 of the format spec. + + + + + + + + + + + + + + + + + + + + + + + + The Atom entry construct is defined in section 4.1.2 of the format spec. + + + + + + + + + + + + + + + + + + + + + + + The Atom content construct is defined in section 4.1.3 of the format spec. + + + + + + + + + + + + + The Atom cagegory construct is defined in section 4.2.2 of the format spec. + + + + + + + + + + + The Atom generator element is defined in section 4.2.4 of the format spec. + + + + + + + + + + + + + + The Atom icon construct is defined in section 4.2.5 of the format spec. + + + + + + + + + + + + The Atom id construct is defined in section 4.2.6 of the format spec. + + + + + + + + + + + + The Atom link construct is defined in section 3.4 of the format spec. + + + + + + + + + + + + + + The Atom logo construct is defined in section 4.2.8 of the format spec. + + + + + + + + + + + + The Atom source construct is defined in section 4.2.11 of the format spec. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MR3/WebApplication1Mod1/.gitignore b/MR3/Extensions/OData/tests/ODataTestWebSite/.gitignore similarity index 100% rename from MR3/WebApplication1Mod1/.gitignore rename to MR3/Extensions/OData/tests/ODataTestWebSite/.gitignore diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap-responsive.css b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap-responsive.css new file mode 100644 index 00000000..7f669d57 --- /dev/null +++ b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap-responsive.css @@ -0,0 +1,808 @@ +/*! + * Bootstrap Responsive v2.0.3 + * + * Copyright 2012 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. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +@media (max-width: 767px) { + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .modal { + position: absolute; + top: 10px; + right: 10px; + left: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + [class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: auto; + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.762430939%; + *margin-left: 2.709239449638298%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .span12 { + width: 99.999999993%; + *width: 99.9468085036383%; + } + .row-fluid .span11 { + width: 91.436464082%; + *width: 91.38327259263829%; + } + .row-fluid .span10 { + width: 82.87292817100001%; + *width: 82.8197366816383%; + } + .row-fluid .span9 { + width: 74.30939226%; + *width: 74.25620077063829%; + } + .row-fluid .span8 { + width: 65.74585634900001%; + *width: 65.6926648596383%; + } + .row-fluid .span7 { + width: 57.182320438000005%; + *width: 57.129128948638304%; + } + .row-fluid .span6 { + width: 48.618784527%; + *width: 48.5655930376383%; + } + .row-fluid .span5 { + width: 40.055248616%; + *width: 40.0020571266383%; + } + .row-fluid .span4 { + width: 31.491712705%; + *width: 31.4385212156383%; + } + .row-fluid .span3 { + width: 22.928176794%; + *width: 22.874985304638297%; + } + .row-fluid .span2 { + width: 14.364640883%; + *width: 14.311449393638298%; + } + .row-fluid .span1 { + width: 5.801104972%; + *width: 5.747913482638298%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 714px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 652px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 590px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 528px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 466px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 404px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 342px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 280px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 218px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 156px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 94px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 32px; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.564102564%; + *margin-left: 2.510911074638298%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145300001%; + *width: 91.3997999636383%; + } + .row-fluid .span10 { + width: 82.905982906%; + *width: 82.8527914166383%; + } + .row-fluid .span9 { + width: 74.358974359%; + *width: 74.30578286963829%; + } + .row-fluid .span8 { + width: 65.81196581200001%; + *width: 65.7587743226383%; + } + .row-fluid .span7 { + width: 57.264957265%; + *width: 57.2117657756383%; + } + .row-fluid .span6 { + width: 48.717948718%; + *width: 48.6647572286383%; + } + .row-fluid .span5 { + width: 40.170940171000005%; + *width: 40.117748681638304%; + } + .row-fluid .span4 { + width: 31.623931624%; + *width: 31.5707401346383%; + } + .row-fluid .span3 { + width: 23.076923077%; + *width: 23.0237315876383%; + } + .row-fluid .span2 { + width: 14.529914530000001%; + *width: 14.4767230406383%; + } + .row-fluid .span1 { + width: 5.982905983%; + *width: 5.929714493638298%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1160px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1060px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 960px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 860px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 760px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 660px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 560px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 460px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 360px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 260px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 160px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 60px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 9px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #999999; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .dropdown-menu a:hover { + background-color: #222222; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: block; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-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); + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap-responsive.min.css b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap-responsive.min.css new file mode 100644 index 00000000..dd134a1b --- /dev/null +++ b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.0.3 + * + * Copyright 2012 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. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}@media(max-width:767px){.visible-phone{display:inherit!important}.hidden-phone{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(min-width:768px) and (max-width:979px){.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:18px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{position:absolute;top:10px;right:10px;left:10px;width:auto;margin:0}.modal.fade.in{top:auto}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.762430939%;*margin-left:2.709239449638298%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:99.999999993%;*width:99.9468085036383%}.row-fluid .span11{width:91.436464082%;*width:91.38327259263829%}.row-fluid .span10{width:82.87292817100001%;*width:82.8197366816383%}.row-fluid .span9{width:74.30939226%;*width:74.25620077063829%}.row-fluid .span8{width:65.74585634900001%;*width:65.6926648596383%}.row-fluid .span7{width:57.182320438000005%;*width:57.129128948638304%}.row-fluid .span6{width:48.618784527%;*width:48.5655930376383%}.row-fluid .span5{width:40.055248616%;*width:40.0020571266383%}.row-fluid .span4{width:31.491712705%;*width:31.4385212156383%}.row-fluid .span3{width:22.928176794%;*width:22.874985304638297%}.row-fluid .span2{width:14.364640883%;*width:14.311449393638298%}.row-fluid .span1{width:5.801104972%;*width:5.747913482638298%}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:714px}input.span11,textarea.span11,.uneditable-input.span11{width:652px}input.span10,textarea.span10,.uneditable-input.span10{width:590px}input.span9,textarea.span9,.uneditable-input.span9{width:528px}input.span8,textarea.span8,.uneditable-input.span8{width:466px}input.span7,textarea.span7,.uneditable-input.span7{width:404px}input.span6,textarea.span6,.uneditable-input.span6{width:342px}input.span5,textarea.span5,.uneditable-input.span5{width:280px}input.span4,textarea.span4,.uneditable-input.span4{width:218px}input.span3,textarea.span3,.uneditable-input.span3{width:156px}input.span2,textarea.span2,.uneditable-input.span2{width:94px}input.span1,textarea.span1,.uneditable-input.span1{width:32px}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.564102564%;*margin-left:2.510911074638298%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145300001%;*width:91.3997999636383%}.row-fluid .span10{width:82.905982906%;*width:82.8527914166383%}.row-fluid .span9{width:74.358974359%;*width:74.30578286963829%}.row-fluid .span8{width:65.81196581200001%;*width:65.7587743226383%}.row-fluid .span7{width:57.264957265%;*width:57.2117657756383%}.row-fluid .span6{width:48.717948718%;*width:48.6647572286383%}.row-fluid .span5{width:40.170940171000005%;*width:40.117748681638304%}.row-fluid .span4{width:31.623931624%;*width:31.5707401346383%}.row-fluid .span3{width:23.076923077%;*width:23.0237315876383%}.row-fluid .span2{width:14.529914530000001%;*width:14.4767230406383%}.row-fluid .span1{width:5.982905983%;*width:5.929714493638298%}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:1160px}input.span11,textarea.span11,.uneditable-input.span11{width:1060px}input.span10,textarea.span10,.uneditable-input.span10{width:960px}input.span9,textarea.span9,.uneditable-input.span9{width:860px}input.span8,textarea.span8,.uneditable-input.span8{width:760px}input.span7,textarea.span7,.uneditable-input.span7{width:660px}input.span6,textarea.span6,.uneditable-input.span6{width:560px}input.span5,textarea.span5,.uneditable-input.span5{width:460px}input.span4,textarea.span4,.uneditable-input.span4{width:360px}input.span3,textarea.span3,.uneditable-input.span3{width:260px}input.span2,textarea.span2,.uneditable-input.span2{width:160px}input.span1,textarea.span1,.uneditable-input.span1{width:60px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top{position:static;margin-bottom:18px}.navbar-fixed-top .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 9px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#999;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#222}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222;border-bottom:1px solid #222;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-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)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap.css b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap.css new file mode 100644 index 00000000..09e2833d --- /dev/null +++ b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap.css @@ -0,0 +1,4960 @@ +/*! + * Bootstrap v2.0.3 + * + * Copyright 2012 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. + */ + +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; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover { + color: #005580; + text-decoration: underline; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + margin-left: 20px; +} + +.container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.127659574%; + *margin-left: 2.0744680846382977%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .span12 { + width: 99.99999998999999%; + *width: 99.94680850063828%; +} + +.row-fluid .span11 { + width: 91.489361693%; + *width: 91.4361702036383%; +} + +.row-fluid .span10 { + width: 82.97872339599999%; + *width: 82.92553190663828%; +} + +.row-fluid .span9 { + width: 74.468085099%; + *width: 74.4148936096383%; +} + +.row-fluid .span8 { + width: 65.95744680199999%; + *width: 65.90425531263828%; +} + +.row-fluid .span7 { + width: 57.446808505%; + *width: 57.3936170156383%; +} + +.row-fluid .span6 { + width: 48.93617020799999%; + *width: 48.88297871863829%; +} + +.row-fluid .span5 { + width: 40.425531911%; + *width: 40.3723404216383%; +} + +.row-fluid .span4 { + width: 31.914893614%; + *width: 31.8617021246383%; +} + +.row-fluid .span3 { + width: 23.404255317%; + *width: 23.3510638276383%; +} + +.row-fluid .span2 { + width: 14.89361702%; + *width: 14.8404255306383%; +} + +.row-fluid .span1 { + width: 6.382978723%; + *width: 6.329787233638298%; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} + +p small { + font-size: 11px; + color: #999999; +} + +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-family: inherit; + font-weight: bold; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} + +h1 { + font-size: 30px; + line-height: 36px; +} + +h1 small { + font-size: 18px; +} + +h2 { + font-size: 24px; + line-height: 36px; +} + +h2 small { + font-size: 18px; +} + +h3 { + font-size: 18px; + line-height: 27px; +} + +h3 small { + font-size: 14px; +} + +h4, +h5, +h6 { + line-height: 18px; +} + +h4 { + font-size: 14px; +} + +h4 small { + font-size: 12px; +} + +h5 { + font-size: 12px; +} + +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} + +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} + +.page-header h1 { + line-height: 1; +} + +ul, +ol { + padding: 0; + margin: 0 0 9px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li { + line-height: 18px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +dl { + margin-bottom: 18px; +} + +dt, +dd { + line-height: 18px; +} + +dt { + font-weight: bold; + line-height: 17px; +} + +dd { + margin-left: 9px; +} + +.dl-horizontal dt { + float: left; + width: 120px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 130px; +} + +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +.muted { + color: #999999; +} + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #ddd; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} + +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 18px; + font-style: normal; + line-height: 18px; +} + +small { + font-size: 100%; +} + +cite { + font-style: normal; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.025px; + line-height: 18px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 18px; +} + +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 18px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} + +legend small { + font-size: 13.5px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; + color: #333333; +} + +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +label input, +label textarea, +label select { + display: block; +} + +input[type="image"], +input[type="checkbox"], +input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + background-color: transparent; + border: 0 \9; + /* IE9 and down */ + + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +input[type="image"] { + border: 0; +} + +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + background-color: #ffffff; + background-color: initial; + border: 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: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} + +input[type="file"] { + line-height: 18px \9; +} + +select { + width: 220px; + background-color: #ffffff; +} + +select[multiple], +select[size] { + height: auto; +} + +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +textarea { + height: auto; +} + +input[type="hidden"] { + display: none; +} + +.radio, +.checkbox { + min-height: 18px; + padding-left: 18px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +input, +textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-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 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; +} + +input:focus, +textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 930px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 850px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 770px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 690px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 610px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 530px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 450px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 370px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 290px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 210px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 130px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 50px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; + border-color: #ddd; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning > label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error > label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success > label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; + border-color: #468847; +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +input:focus:required:invalid, +textarea:focus:required:invalid, +select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:required:invalid:focus, +textarea:focus:required:invalid:focus, +select:focus:required:invalid: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-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; + cursor: not-allowed; + background-color: #ffffff; + 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); +} + +:-moz-placeholder { + color: #999999; +} + +::-webkit-input-placeholder { + color: #999999; +} + +.help-block, +.help-inline { + color: #555555; +} + +.help-block { + display: block; + margin-bottom: 9px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-prepend, +.input-append { + margin-bottom: 5px; +} + +.input-prepend input, +.input-append input, +.input-prepend select, +.input-append select, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: middle; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend input:focus, +.input-append input:focus, +.input-prepend select:focus, +.input-append select:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + z-index: 2; +} + +.input-prepend .uneditable-input, +.input-append .uneditable-input { + border-left-color: #ccc; +} + +.input-prepend .add-on, +.input-append .add-on { + display: inline-block; + width: auto; + height: 18px; + min-width: 16px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-prepend .add-on, +.input-append .add-on, +.input-prepend .btn, +.input-append .btn { + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend .active, +.input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append .uneditable-input { + border-right-color: #ccc; + border-left-color: #eee; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 9px; +} + +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 160px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 160px; +} + +.form-horizontal .help-block { + margin-top: 9px; + margin-bottom: 0; +} + +.form-horizontal .form-actions { + padding-left: 160px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 18px; +} + +.table th, +.table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapsed; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child th:first-child, +.table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child th:last-child, +.table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child th:first-child, +.table-bordered tbody:last-child 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; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child th:last-child, +.table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-striped tbody tr:nth-child(odd) td, +.table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #f5f5f5; +} + +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} + +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} + +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} + +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} + +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} + +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} + +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} + +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} + +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} + +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} + +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} + +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} + +table .span13 { + float: none; + width: 1004px; + margin-left: 0; +} + +table .span14 { + float: none; + width: 1084px; + margin-left: 0; +} + +table .span15 { + float: none; + width: 1164px; + margin-left: 0; +} + +table .span16 { + float: none; + width: 1244px; + margin-left: 0; +} + +table .span17 { + float: none; + width: 1324px; + margin-left: 0; +} + +table .span18 { + float: none; + width: 1404px; + margin-left: 0; +} + +table .span19 { + float: none; + width: 1484px; + margin-left: 0; +} + +table .span20 { + float: none; + width: 1564px; + margin-left: 0; +} + +table .span21 { + float: none; + width: 1644px; + margin-left: 0; +} + +table .span22 { + float: none; + width: 1724px; + margin-left: 0; +} + +table .span23 { + float: none; + width: 1804px; + margin-left: 0; +} + +table .span24 { + float: none; + width: 1884px; + margin-left: 0; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +[class^="icon-"]:last-child, +[class*=" icon-"]:last-child { + *margin-left: 0; +} + +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + background-position: -384px -120px; +} + +.icon-folder-open { + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; + opacity: 0.3; + filter: alpha(opacity=30); +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown:hover .caret, +.open .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 4px 0; + margin: 1px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu li > a:hover, +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} + +.open { + *z-index: 1000; +} + +.open .dropdown-menu { + display: block; +} + +.pull-right .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: "\2191"; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + 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); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + filter: alpha(opacity=0); + -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; +} + +.fade.in { + opacity: 1; + filter: alpha(opacity=100); +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 10px 4px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 13px; + line-height: 18px; + *line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + *zoom: 1; + -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); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + *background-color: #d9d9d9; + /* Buttons in IE7 don't get borders, so darken on hover */ + + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-color: #e6e6e6; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.btn-large [class^="icon-"] { + margin-top: 1px; +} + +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} + +.btn-small [class^="icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} + +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn { + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn-primary { + background-color: #0074cc; + *background-color: #0055cc; + background-image: -ms-linear-gradient(top, #0088cc, #0055cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); + background-image: -o-linear-gradient(top, #0088cc, #0055cc); + background-image: -moz-linear-gradient(top, #0088cc, #0055cc); + background-image: linear-gradient(top, #0088cc, #0055cc); + background-repeat: repeat-x; + border-color: #0055cc #0055cc #003580; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0055cc; + *background-color: #004ab3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #004099 \9; +} + +.btn-warning { + background-color: #faa732; + *background-color: #f89406; + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + background-color: #da4f49; + *background-color: #bd362f; + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + background-color: #5bb75b; + *background-color: #51a351; + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + background-color: #414141; + *background-color: #222222; + background-image: -ms-linear-gradient(top, #555555, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); + background-image: -webkit-linear-gradient(top, #555555, #222222); + background-image: -o-linear-gradient(top, #555555, #222222); + background-image: -moz-linear-gradient(top, #555555, #222222); + background-image: linear-gradient(top, #555555, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-group { + position: relative; + *margin-left: .3em; + *zoom: 1; +} + +.btn-group:before, +.btn-group:after { + display: table; + content: ""; +} + +.btn-group:after { + clear: both; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} + +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group > .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .dropdown-toggle { + *padding-top: 4px; + padding-right: 8px; + *padding-bottom: 4px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini.dropdown-toggle { + padding-right: 5px; + padding-left: 5px; +} + +.btn-group > .btn-small.dropdown-toggle { + *padding-top: 4px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large.dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0055cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 7px; + margin-left: 0; +} + +.btn:hover .caret, +.open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.btn-mini .caret { + margin-top: 5px; +} + +.btn-small .caret { + margin-top: 6px; +} + +.btn-large .caret { + margin-top: 6px; + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.dropup .btn-large .caret { + border-top: 0; + border-bottom: 5px solid #000000; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + color: #c09853; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert-heading { + color: inherit; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 18px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > .pull-right { + float: right; +} + +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 18px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.nav-tabs.nav-stacked > li > a:hover { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.nav-tabs .dropdown-toggle .caret, +.nav-pills .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav-tabs .dropdown-toggle:hover .caret, +.nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +.nav-tabs .active .dropdown-toggle .caret, +.nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 18px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + 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); +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; +} + +.navbar { + color: #999999; +} + +.navbar .brand:hover { + text-decoration: none; +} + +.navbar .brand { + display: block; + float: left; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #999999; +} + +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; +} + +.navbar .navbar-link { + color: #999999; +} + +.navbar .navbar-link:hover { + color: #ffffff; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn { + margin: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + background-color: #626262; + border: 1px solid #151515; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-search .search-query:focus, +.navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -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); +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; +} + +.navbar .nav > li { + display: block; + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 9px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar .btn { + display: inline-block; + padding: 4px 10px 4px; + margin: 5px 5px 6px; + line-height: 18px; +} + +.navbar .btn-group { + padding: 5px 5px 6px; + margin: 0; +} + +.navbar .nav > li > a:hover { + color: #ffffff; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav .active > a, +.navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} + +.navbar .divider-vertical { + width: 1px; + height: 40px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} + +.navbar .nav.pull-right { + margin-right: 0; + margin-left: 10px; +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + background-color: #2c2c2c; + *background-color: #222222; + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-image: -moz-linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + background-color: #222222; + *background-color: #151515; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #080808 \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown .dropdown-toggle .caret, +.navbar .nav li.dropdown.open .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar .nav li.dropdown.active .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + background-color: transparent; +} + +.navbar .nav li.dropdown.active > .dropdown-toggle:hover { + color: #ffffff; +} + +.navbar .pull-right .dropdown-menu, +.navbar .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right .dropdown-menu:before, +.navbar .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right .dropdown-menu:after, +.navbar .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + list-style: none; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.breadcrumb li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} + +.breadcrumb .active a { + color: #333333; +} + +.pagination { + height: 36px; + margin: 18px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + *zoom: 1; + -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; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} + +.pagination a:hover, +.pagination .active a { + background-color: #f5f5f5; +} + +.pagination .active a { + color: #999999; + cursor: default; +} + +.pagination .disabled span, +.pagination .disabled a, +.pagination .disabled a:hover { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pager { + margin-bottom: 18px; + margin-left: 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next a { + float: right; +} + +.pager .previous a { + float: left; +} + +.pager .disabled a, +.pager .disabled a:hover { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-open .dropdown-menu { + z-index: 2050; +} + +.modal-open .dropdown.open { + *z-index: 2050; +} + +.modal-open .popover { + z-index: 2060; +} + +.modal-open .tooltip { + z-index: 2070; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + width: 560px; + margin: -250px 0 0 -280px; + overflow: auto; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -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.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -ms-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-body { + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + 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; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.tooltip { + position: absolute; + z-index: 1020; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + margin-top: -2px; +} + +.tooltip.right { + margin-left: 2px; +} + +.tooltip.bottom { + margin-top: 2px; +} + +.tooltip.left { + margin-left: -2px; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} + +.popover.top { + margin-top: -5px; +} + +.popover.right { + margin-left: 5px; +} + +.popover.bottom { + margin-top: 5px; +} + +.popover.left { + margin-left: -5px; +} + +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover-inner { + width: 280px; + padding: 3px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -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 { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} + +.popover-content { + padding: 14px; + background-color: #ffffff; + -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; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 18px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + 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); +} + +a.thumbnail:hover { + border-color: #0088cc; + -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); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; +} + +.label, +.badge { + font-size: 10.998px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + padding: 1px 4px 2px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding: 1px 9px 2px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +a.label:hover, +a.badge:hover { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +@-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; + } +} + +@-ms-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 { + height: 18px; + margin-bottom: 18px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-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 { + width: 0; + height: 18px; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-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-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -o-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: -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: -ms-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: -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: 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); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + 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: -ms-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: -o-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-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} + +.progress-success.progress-striped .bar { + background-color: #62c462; + 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: -ms-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: -o-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-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar { + background-color: #5bc0de; + 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: -ms-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: -o-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-warning .bar { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); +} + +.progress-warning.progress-striped .bar { + background-color: #fbb450; + 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: -ms-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: -o-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); +} + +.accordion { + margin-bottom: 18px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel .item > img { + display: block; + line-height: 1; +} + +.carousel .active, +.carousel .next, +.carousel .prev { + display: block; +} + +.carousel .active { + left: 0; +} + +.carousel .next, +.carousel .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel .next { + left: 100%; +} + +.carousel .prev { + left: -100%; +} + +.carousel .next.left, +.carousel .prev.right { + left: 0; +} + +.carousel .active.left { + left: -100%; +} + +.carousel .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + color: #ffffff; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #eeeeee; + -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; + color: inherit; +} + +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; + color: inherit; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap.min.css b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap.min.css new file mode 100644 index 00000000..1c75d0c0 --- /dev/null +++ b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.0.3 + * + * Copyright 2012 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. + */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}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.127659574%;*margin-left:2.0744680846382977%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%}.row-fluid .span11{width:91.489361693%;*width:91.4361702036383%}.row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%}.row-fluid .span9{width:74.468085099%;*width:74.4148936096383%}.row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%}.row-fluid .span7{width:57.446808505%;*width:57.3936170156383%}.row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%}.row-fluid .span5{width:40.425531911%;*width:40.3723404216383%}.row-fluid .span4{width:31.914893614%;*width:31.8617021246383%}.row-fluid .span3{width:23.404255317%;*width:23.3510638276383%}.row-fluid .span2{width:14.89361702%;*width:14.8404255306383%}.row-fluid .span1{width:6.382978723%;*width:6.329787233638298%}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:""}.container-fluid:after{clear:both}p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px}p small{font-size:11px;color:#999}.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px}h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{font-size:18px;line-height:27px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eee}.page-header h1{line-height:1}ul,ol{padding:0;margin:0 0 9px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}ul{list-style:disc}ol{list-style:decimal}li{line-height:18px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}dl{margin-bottom:18px}dt,dd{line-height:18px}dt{font-weight:bold;line-height:17px}dd{margin-left:9px}.dl-horizontal dt{float:left;width:120px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:130px}hr{margin:18px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}strong{font-weight:bold}em{font-style:italic}.muted{color:#999}abbr[title]{cursor:help;border-bottom:1px dotted #ddd}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px}blockquote small{display:block;line-height:18px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:18px;font-style:normal;line-height:18px}small{font-size:100%}cite{font-style:normal}code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:18px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 18px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333;border:0;border-bottom:1px solid #eee}legend small{font-size:13.5px;color:#999}label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px;color:#333}input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555;background-color:#fff;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.uneditable-textarea{width:auto;height:auto}label input,label textarea,label select{display:block}input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;background-color:transparent;border:0 \9;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}input[type="image"]{border:0}input[type="file"]{width:auto;padding:initial;line-height:initial;background-color:#fff;background-color:initial;border: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:28px;*margin-top:4px;line-height:28px}input[type="file"]{line-height:18px \9}select{width:220px;background-color:#fff}select[multiple],select[size]{height:auto}input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}textarea{height:auto}input[type="hidden"]{display:none}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-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 linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-ms-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}input:focus,textarea:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:930px}input.span11,textarea.span11,.uneditable-input.span11{width:850px}input.span10,textarea.span10,.uneditable-input.span10{width:770px}input.span9,textarea.span9,.uneditable-input.span9{width:690px}input.span8,textarea.span8,.uneditable-input.span8{width:610px}input.span7,textarea.span7,.uneditable-input.span7{width:530px}input.span6,textarea.span6,.uneditable-input.span6{width:450px}input.span5,textarea.span5,.uneditable-input.span5{width:370px}input.span4,textarea.span4,.uneditable-input.span4{width:290px}input.span3,textarea.span3,.uneditable-input.span3{width:210px}input.span2,textarea.span2,.uneditable-input.span2{width:130px}input.span1,textarea.span1,.uneditable-input.span1{width:50px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee;border-color:#ddd}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid: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-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:""}.form-actions:after{clear:both}.uneditable-input{overflow:hidden;white-space:nowrap;cursor:not-allowed;background-color:#fff;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)}:-moz-placeholder{color:#999}::-webkit-input-placeholder{color:#999}.help-block,.help-inline{color:#555}.help-block{display:block;margin-bottom:9px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-prepend,.input-append{margin-bottom:5px}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:middle;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{z-index:2}.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc}.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;height:18px;min-width:16px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #fff;vertical-align:middle;background-color:#eee;border:1px solid #ccc}.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .uneditable-input{border-right-color:#ccc;border-left-color:#eee}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:9px}legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:18px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:160px}.form-horizontal .help-block{margin-top:9px;margin-bottom:0}.form-horizontal .form-actions{padding-left:160px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:18px}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child 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;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5}table .span1{float:none;width:44px;margin-left:0}table .span2{float:none;width:124px;margin-left:0}table .span3{float:none;width:204px;margin-left:0}table .span4{float:none;width:284px;margin-left:0}table .span5{float:none;width:364px;margin-left:0}table .span6{float:none;width:444px;margin-left:0}table .span7{float:none;width:524px;margin-left:0}table .span8{float:none;width:604px;margin-left:0}table .span9{float:none;width:684px;margin-left:0}table .span10{float:none;width:764px;margin-left:0}table .span11{float:none;width:844px;margin-left:0}table .span12{float:none;width:924px;margin-left:0}table .span13{float:none;width:1004px;margin-left:0}table .span14{float:none;width:1084px;margin-left:0}table .span15{float:none;width:1164px;margin-left:0}table .span16{float:none;width:1244px;margin-left:0}table .span17{float:none;width:1324px;margin-left:0}table .span18{float:none;width:1404px;margin-left:0}table .span19{float:none;width:1484px;margin-left:0}table .span20{float:none;width:1564px;margin-left:0}table .span21{float:none;width:1644px;margin-left:0}table .span22{float:none;width:1724px;margin-left:0}table .span23{float:none;width:1804px;margin-left:0}table .span24{float:none;width:1884px;margin-left:0}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0}.icon-white{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";opacity:.3;filter:alpha(opacity=30)}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown:hover .caret,.open .caret{opacity:1;filter:alpha(opacity=100)}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:4px 0;margin:1px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c}.open{*z-index:1000}.open .dropdown-menu{display:block}.pull-right .dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:"\2191"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;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)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;filter:alpha(opacity=0);-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-ms-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1;filter:alpha(opacity=100)}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-ms-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 10px 4px;margin-bottom:0;*margin-left:.3em;font-size:13px;line-height:18px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(top,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff',endColorstr='#e6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-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)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-ms-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:1px}.btn-small{padding:5px 9px;font-size:11px;line-height:16px}.btn-small [class^="icon-"]{margin-top:-1px}.btn-mini{padding:2px 6px;font-size:11px;line-height:14px}.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#ccc;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.btn-primary{background-color:#0074cc;*background-color:#05c;background-image:-ms-linear-gradient(top,#08c,#05c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#05c));background-image:-webkit-linear-gradient(top,#08c,#05c);background-image:-o-linear-gradient(top,#08c,#05c);background-image:-moz-linear-gradient(top,#08c,#05c);background-image:linear-gradient(top,#08c,#05c);background-repeat:repeat-x;border-color:#05c #05c #003580;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc',endColorstr='#0055cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#05c;*background-color:#004ab3}.btn-primary:active,.btn-primary.active{background-color:#004099 \9}.btn-warning{background-color:#faa732;*background-color:#f89406;background-image:-ms-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{background-color:#da4f49;*background-color:#bd362f;background-image:-ms-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#bd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{background-color:#5bb75b;*background-color:#51a351;background-image:-ms-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462',endColorstr='#51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{background-color:#49afcd;*background-color:#2f96b4;background-image:-ms-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de',endColorstr='#2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{background-color:#414141;*background-color:#222;background-image:-ms-linear-gradient(top,#555,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#555),to(#222));background-image:-webkit-linear-gradient(top,#555,#222);background-image:-o-linear-gradient(top,#555,#222);background-image:-moz-linear-gradient(top,#555,#222);background-image:linear-gradient(top,#555,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#555555',endColorstr='#222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-group{position:relative;*margin-left:.3em;*zoom:1}.btn-group:before,.btn-group:after{display:table;content:""}.btn-group:after{clear:both}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:9px;margin-bottom:9px}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-group>.btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.dropdown-toggle{*padding-top:4px;padding-right:8px;*padding-bottom:4px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini.dropdown-toggle{padding-right:5px;padding-left:5px}.btn-group>.btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px}.btn-group>.btn-large.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#05c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:7px;margin-left:0}.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100)}.btn-mini .caret{margin-top:5px}.btn-small .caret{margin-top:6px}.btn-large .caret{margin-top:6px;border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:.75;filter:alpha(opacity=75)}.alert{padding:8px 35px 8px 14px;margin-bottom:18px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert-heading{color:inherit}.alert .close{position:relative;top:-2px;right:-21px;line-height:18px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:18px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px}.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333;border-bottom-color:#333}.nav>.dropdown.active>a:hover{color:#000;cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.navbar{*position:relative;*z-index:2;margin-bottom:18px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top,#333,#222);background-image:-ms-linear-gradient(top,#333,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#333),to(#222));background-image:-webkit-linear-gradient(top,#333,#222);background-image:-o-linear-gradient(top,#333,#222);background-image:linear-gradient(top,#333,#222);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;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)}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar{color:#999}.navbar .brand:hover{text-decoration:none}.navbar .brand{display:block;float:left;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#999}.navbar .navbar-text{margin-bottom:0;line-height:40px}.navbar .navbar-link{color:#999}.navbar .navbar-link:hover{color:#fff}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn{margin:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#fff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}.navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-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)}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right}.navbar .nav>li{display:block;float:left}.navbar .nav>li>a{float:none;padding:9px 10px 11px;line-height:19px;color:#999;text-decoration:none;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar .btn{display:inline-block;padding:4px 10px 4px;margin:5px 5px 6px;line-height:18px}.navbar .btn-group{padding:5px 5px 6px;margin:0}.navbar .nav>li>a:hover{color:#fff;text-decoration:none;background-color:transparent}.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#fff;text-decoration:none;background-color:#222}.navbar .divider-vertical{width:1px;height:40px;margin:0 9px;overflow:hidden;background-color:#222;border-right:1px solid #333}.navbar .nav.pull-right{margin-right:0;margin-left:10px}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;background-color:#2c2c2c;*background-color:#222;background-image:-ms-linear-gradient(top,#333,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#333),to(#222));background-image:-webkit-linear-gradient(top,#333,#222);background-image:-o-linear-gradient(top,#333,#222);background-image:linear-gradient(top,#333,#222);background-image:-moz-linear-gradient(top,#333,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{background-color:#222;*background-color:#151515}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#080808 \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown .dropdown-toggle .caret,.navbar .nav li.dropdown.open .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar .nav li.dropdown.active .caret{opacity:1;filter:alpha(opacity=100)}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:transparent}.navbar .nav li.dropdown.active>.dropdown-toggle:hover{color:#fff}.navbar .pull-right .dropdown-menu,.navbar .dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right .dropdown-menu:before,.navbar .dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right .dropdown-menu:after,.navbar .dropdown-menu.pull-right:after{right:13px;left:auto}.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top,#fff,#f5f5f5);background-image:-ms-linear-gradient(top,#fff,#f5f5f5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#fff,#f5f5f5);background-image:-o-linear-gradient(top,#fff,#f5f5f5);background-image:linear-gradient(top,#fff,#f5f5f5);background-repeat:repeat-x;border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff',endColorstr='#f5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#999}.breadcrumb .active a{color:#333}.pagination{height:36px;margin:18px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-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;text-decoration:none;border:1px solid #ddd;border-left-width:0}.pagination a:hover,.pagination .active a{background-color:#f5f5f5}.pagination .active a{color:#999;cursor:default}.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999;cursor:default;background-color:transparent}.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin-bottom:18px;margin-left:0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover{color:#999;cursor:default;background-color:#fff}.modal-open .dropdown-menu{z-index:2050}.modal-open .dropdown.open{*z-index:2050}.modal-open .popover{z-index:2060}.modal-open .tooltip{z-index:2070}.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,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-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.fade{top:-25%;-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}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;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;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1020;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-2px}.tooltip.right{margin-left:2px}.tooltip.bottom{margin-top:2px}.tooltip.left{margin-left:-2px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px}.popover.top{margin-top:-5px}.popover.right{margin-left:5px}.popover.bottom{margin-top:5px}.popover.left{margin-left:-5px}.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent}.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000}.popover .arrow{position:absolute;width:0;height:0}.popover-inner{width:280px;padding:3px;overflow:hidden;background:#000;background:rgba(0,0,0,0.8);-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{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.popover-content{padding:14px;background-color:#fff;-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}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:18px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:1;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)}a.thumbnail:hover{border-color:#08c;-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)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px}.label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}@-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}}@-ms-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{height:18px;margin-bottom:18px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-ms-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(top,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5',endColorstr='#f9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-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{width:0;height:18px;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(top,#149bdf,#0480be);background-image:-ms-linear-gradient(top,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf',endColorstr='#0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-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-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-ms-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .bar{background-color:#149bdf;background-image:-o-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:-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:-ms-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:-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: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);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-ms-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(top,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35',GradientType=0)}.progress-danger.progress-striped .bar{background-color:#ee5f5b;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:-ms-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:-o-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-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-ms-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(top,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462',endColorstr='#57a957',GradientType=0)}.progress-success.progress-striped .bar{background-color:#62c462;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:-ms-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:-o-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-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-ms-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(top,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de',endColorstr='#339bb9',GradientType=0)}.progress-info.progress-striped .bar{background-color:#5bc0de;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:-ms-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:-o-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-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-ms-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0)}.progress-warning.progress-striped .bar{background-color:#fbb450;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:-ms-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:-o-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)}.accordion{margin-bottom:18px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:18px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-ms-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:10px 15px 5px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{color:#fff}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-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;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden} diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/img/glyphicons-halflings-white.png b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/img/glyphicons-halflings-white.png new file mode 100644 index 00000000..3bf6484a Binary files /dev/null and b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/img/glyphicons-halflings-white.png differ diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/img/glyphicons-halflings.png b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/img/glyphicons-halflings.png new file mode 100644 index 00000000..79bc568c Binary files /dev/null and b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/img/glyphicons-halflings.png differ diff --git a/MR3/Extensions/OData/tests/ODataTestWebSite/Content/js/bootstrap.js b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/js/bootstrap.js new file mode 100644 index 00000000..6944ade9 --- /dev/null +++ b/MR3/Extensions/OData/tests/ODataTestWebSite/Content/js/bootstrap.js @@ -0,0 +1,1824 @@ +/* =================================================== + * bootstrap-transition.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + $(function () { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd' + , 'msTransition' : 'MSTransitionEnd' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = options + this.options.slide && this.slide(this.options.slide) + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e = $.Event('slide') + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if ($next.hasClass('active')) return + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else if (options.interval) data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , selector + , isActive + + if ($this.is('.disabled, :disabled')) return + + selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body') + .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}(window.jQuery);/* ========================================================= + * bootstrap-modal.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (content, options) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + , e = $.Event('show') + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + $('body').addClass('modal-open') + + this.isShown = true + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function (e) { + e && e.preventDefault() + + var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element.removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal(that) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop(callback) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('