Merge branch 'master' into xamarin
This commit is contained in:
commit
76f95c0662
5
.gitignore
vendored
5
.gitignore
vendored
@ -25,7 +25,7 @@ bld/
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
**/wwwroot/lib/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
@ -256,4 +256,5 @@ pub/
|
||||
/src/Services/Identity/eShopOnContainers.Identity/Properties/launchSettings.json
|
||||
|
||||
#Ignore marker-file used to know which docker files we have.
|
||||
.eshopdocker_*
|
||||
.eshopdocker_*
|
||||
/src/Web/WebMVC/wwwroot/lib
|
||||
|
21
README.md
21
README.md
@ -14,11 +14,15 @@ Sample .NET Core reference application, powered by Microsoft, based on a simplif
|
||||
**Architecture overview**: This reference application is cross-platform either at the server and client side, thanks to .NET Core services capable of running on Linux or Windows containers depending on your Docker host, and to Xamarin for mobile apps running on Android, iOS or Windows/UWP plus any browser for the client web apps.
|
||||
The architecture proposes a simplified microservice oriented architecture implementation with multiple autonomous microservices (each one owning its own data/db) and implementing different approaches within each microservice (simple CRUD vs. DDD/CQRS patterns) using Http as the current communication protocol.
|
||||
<p>
|
||||
The plan is to add asynchronous communication for data updates propagation across multiple services based on integration events and an event bus plus other features defined at the <a href='https://github.com/dotnet/eShopOnContainers/wiki/01.-Roadmap-and-Milestones-for-future-releases'>roadmap</a>.
|
||||
It also supports asynchronous communication for data updates propagation across multiple services based on Integration Events and an Event Bus plus other features defined at the <a href='https://github.com/dotnet/eShopOnContainers/wiki/01.-Roadmap-and-Milestones-for-future-releases'>roadmap</a>.
|
||||
<p>
|
||||
<img src="img/eshop_logo.png">
|
||||
<img src="img/eShopOnContainers_Architecture_Diagram.png">
|
||||
<p>
|
||||
The microservices are different in type, meaning different internal architecture patterns approaches depending on it purpose, as shown in the image below.
|
||||
<p>
|
||||
<img src="img/eShopOnContainers_Types_Of_Microservices.png">
|
||||
<p>
|
||||
<p>
|
||||
Additional miroservice styles with other frameworks and No-SQL databases will be added, eventually. This is a great opportunity for pull requests from the community, like a new microservice using Nancy, or even other languages like Node, Go, Python or data containers with MongoDB with Azure DocDB compatibility, PostgreSQL, RavenDB, Event Store, MySql, etc. You name it! :)
|
||||
|
||||
@ -30,15 +34,14 @@ Additional miroservice styles with other frameworks and No-SQL databases will be
|
||||
## Related documentation and guidance
|
||||
While developing this reference application, we are creating a reference Guide/eBook named <b>"Architecting and Developing Containerized and Microservice based .NET Applications"</b> which explains in detail how to develop this kind of architectural style (microservices, Docker containers, Domain-Driven Design for certain microservices) plus other simpler architectural styles, like monolithic apps that can also live as Docker containers.
|
||||
<p>
|
||||
There's also an additional eBook focusing on Containers/Docker lifecycle (DevOps, CI/CD, etc.) with Microsoft Tools, already published.
|
||||
You can start reviewing these Guides/eBooks here:
|
||||
There are also additional eBooks focusing on Containers/Docker lifecycle (DevOps, CI/CD, etc.) with Microsoft Tools, already published plus an additional eBook focusing on Enterprise Apps Patterns with Xamarin.Forms.
|
||||
You can download them and start reviewing these Guides/eBooks here:
|
||||
<p>
|
||||
You can download both eBooks from here:
|
||||
|
||||
| Architecting & Developing | Containers Lifecycle & CI/CD |
|
||||
| ------------ | ------------|
|
||||
| <a href='docs/architecting-and-developing-containerized-and-microservice-based-net-applications-ebook-early-draft.pdf'><img src="img/ebook_arch_dev_microservices_containers_cover.png"> </a> | <a href='https://aka.ms/dockerlifecycleebook'> <img src="img/ebook_containers_lifecycle.png"> </a> |
|
||||
| <a href='docs/architecting-and-developing-containerized-and-microservice-based-net-applications-ebook-early-draft.pdf'>**Download** (Early DRAFT, still work in progress)</a> | <a href='https://aka.ms/dockerlifecycleebook'>**Download** - First Edition from late 2016</a> |
|
||||
| Architecting & Developing | Containers Lifecycle & CI/CD | App patterns with Xamarin.Forms |
|
||||
| ------------ | ------------| ------------|
|
||||
| <a href='https://aka.ms/microservicesebook'><img src="img/ebook_arch_dev_microservices_containers_cover.png"> </a> | <a href='https://aka.ms/dockerlifecycleebook'> <img src="img/ebook_containers_lifecycle.png"> </a> | <a href='https://aka.ms/xamarinpatternsebook'> <img src="img/xamarin-enterprise-patterns-ebook-cover-small.png"> </a> |
|
||||
| <sup> <a href='https://aka.ms/microservicesebook'>**Download** (Early DRAFT, still work in progress)</a> </sup> | <sup> <a href='https://aka.ms/dockerlifecycleebook'>**Download** (First Edition from late 2016) </a> </sup> | <sup> <a href='https://aka.ms/xamarinpatternsebook'>**Download** (Early DRAFT, still work in progress) </a> </sup> |
|
||||
|
||||
Send feedback to [cesardl@microsoft.com](cesardl@microsoft.com)
|
||||
<p>
|
||||
@ -89,7 +92,7 @@ The app was also partially tested on "Docker for Mac" using a development MacOS
|
||||
|
||||
## Sending feedback and pull requests
|
||||
As mentioned, we'd appreciate to your feedback, improvements and ideas.
|
||||
You can create new issues at the issues section, do pull requests and/or send emails to eshop_feedback@service.microsoft.com
|
||||
You can create new issues at the issues section, do pull requests and/or send emails to **eshop_feedback@service.microsoft.com**
|
||||
|
||||
## Questions
|
||||
[QUESTION] Answer +1 if the solution is working for you (Through VS2017 or CLI environment):
|
||||
|
@ -6,6 +6,7 @@ projectList=(
|
||||
"/src/Services/Identity/Identity.API"
|
||||
"/src/Web/WebMVC"
|
||||
"/src/Web/WebSPA"
|
||||
"/src/Web/WebStatus
|
||||
)
|
||||
|
||||
# Build SPA app
|
||||
@ -36,4 +37,4 @@ done
|
||||
#fi
|
||||
|
||||
# No need to build the images, docker build or docker compose will
|
||||
# do that using the images and containers defined in the docker-compose.yml file.
|
||||
# do that using the images and containers defined in the docker-compose.yml file.
|
||||
|
@ -7,6 +7,7 @@ projectList=(
|
||||
"../src/Services/Identity/Identity.API"
|
||||
"../src/Web/WebMVC"
|
||||
"../src/Web/WebSPA"
|
||||
"../src/Web/WebStatus"
|
||||
)
|
||||
|
||||
for project in "${projectList[@]}"
|
||||
|
@ -1,160 +0,0 @@
|
||||
|
||||
#########################################################################################################
|
||||
# This "expanded Script" can be used when debugging issues when building the .NET Core bits
|
||||
# as it is easier to follow and debug than when using a loop (like in the optimized build-bits.ps1)
|
||||
#########################################################################################################
|
||||
|
||||
Param([string] $rootPath)
|
||||
$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
|
||||
Write-Host "Current script directory is $scriptPath" -ForegroundColor Yellow
|
||||
|
||||
if ([string]::IsNullOrEmpty($rootPath)) {
|
||||
$rootPath = "$scriptPath\.."
|
||||
}
|
||||
Write-Host "Root path used is $rootPath" -ForegroundColor Yellow
|
||||
|
||||
# *** WebMVC paths ***
|
||||
$webMVCPath = $rootPath + "\src\Web\WebMVC"
|
||||
$webMVCPathToProject = $webMVCPath + "\WebMVC.csproj"
|
||||
Write-Host "webMVCPathToProject is $webMVCPathToProject" -ForegroundColor Yellow
|
||||
$webMVCPathToPub = $webMVCPath + "\obj\Docker\publish"
|
||||
Write-Host "webMVCPathToPub is $webMVCPathToPub" -ForegroundColor Yellow
|
||||
|
||||
|
||||
# *** WebSPA paths ***
|
||||
$webSPAPath = $rootPath + "\src\Web\WebSPA"
|
||||
$webSPAPathToProject = $webSPAPath + "\WebSPA.csproj"
|
||||
Write-Host "webSPAPathToProject is $webSPAPathToProject" -ForegroundColor Yellow
|
||||
$webSPAPathToPub = $webSPAPath + "\obj\Docker\publish"
|
||||
Write-Host "webSPAPathToPub is $webSPAPathToPub" -ForegroundColor Yellow
|
||||
|
||||
|
||||
# *** IdentitySvc paths ***
|
||||
$identitySvcPath = $rootPath + "\src\Services\Identity\Identity.API"
|
||||
$identitySvcToProject = $identitySvcPath + "\Identity.API.csproj"
|
||||
Write-Host "identitySvcToProject is $identitySvcToProject" -ForegroundColor Yellow
|
||||
$identitySvcPathToPub = $identitySvcPath + "\obj\Docker\publish"
|
||||
Write-Host "identitySvcPathToPub is $identitySvcPathToPub" -ForegroundColor Yellow
|
||||
|
||||
|
||||
# *** Catalog paths ***
|
||||
$catalogPath = $rootPath + "\src\Services\Catalog\Catalog.API"
|
||||
$catalogPathToProject = $catalogPath + "\Catalog.API.csproj"
|
||||
Write-Host "catalogPathToProject is $catalogPathToProject" -ForegroundColor Yellow
|
||||
$catalogPathToPub = $catalogPath + "\obj\Docker\publish"
|
||||
Write-Host "catalogPathToPub is $catalogPathToPub" -ForegroundColor Yellow
|
||||
|
||||
|
||||
# *** Ordering paths ***
|
||||
$orderingPath = $rootPath + "\src\Services\Ordering\Ordering.API"
|
||||
$orderingPathToProject = $orderingPath + "\Ordering.API.csproj"
|
||||
Write-Host "orderingPathToProject is $orderingPathToProject" -ForegroundColor Yellow
|
||||
$orderingPathToPub = $orderingPath + "\obj\Docker\publish"
|
||||
Write-Host "orderingPathToPub is $orderingPathToPub" -ForegroundColor Yellow
|
||||
|
||||
# *** Basket paths ***
|
||||
$basketPath = $rootPath + "\src\Services\Basket\Basket.API"
|
||||
$basketPathToProject = $basketPath + "\Basket.API.csproj"
|
||||
Write-Host "basketPathToProject is $basketPathToProject" -ForegroundColor Yellow
|
||||
$basketPathToPub = $basketPath + "\obj\Docker\publish"
|
||||
Write-Host "basketPathToPub is $basketPathToPub" -ForegroundColor Yellow
|
||||
|
||||
|
||||
########################################################################################
|
||||
# Delete old eShop dotnet publish bits
|
||||
########################################################################################
|
||||
# Write-Host "Deleting previous dotnet publish bits from all projects" -ForegroundColor Blue
|
||||
|
||||
remove-item -path $WebMVCPathToPub -Force -Recurse -ErrorAction SilentlyContinue
|
||||
remove-item -path $webSPAPathToPub -Force -Recurse -ErrorAction SilentlyContinue
|
||||
remove-item -path $identitySvcPathToPub -Force -Recurse -ErrorAction SilentlyContinue
|
||||
remove-item -path $catalogPathToPub -Force -Recurse -ErrorAction SilentlyContinue
|
||||
remove-item -path $orderingPathToPub -Force -Recurse -ErrorAction SilentlyContinue
|
||||
remove-item -path $basketPathToPub -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
|
||||
|
||||
########################################################################################
|
||||
# Building DotNet bits
|
||||
########################################################################################
|
||||
|
||||
# WebMVC: Build dotnet bits
|
||||
Write-Host "WebMVC: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $WebMVCPathToProject
|
||||
dotnet build $WebMVCPathToProject
|
||||
dotnet publish $WebMVCPathToProject -o $WebMVCPathToPub
|
||||
|
||||
|
||||
# WebSPA: Build dotnet bits
|
||||
Write-Host "WebSPA: Installing npm dependencies"
|
||||
#TEMP COMMENT--- Start-Process -WorkingDirectory $webSPAPath -NoNewWindow -Wait npm i
|
||||
|
||||
Write-Host "WebSPA: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $webSPAPathToProject
|
||||
dotnet build $webSPAPathToProject
|
||||
dotnet publish $webSPAPathToProject -o $webSPAPathToPub
|
||||
|
||||
|
||||
# Identity Service: Build dotnet bits
|
||||
Write-Host "Identity Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $identitySvcToProject
|
||||
dotnet build $identitySvcToProject
|
||||
dotnet publish $identitySvcToProject -o $identitySvcPathToPub
|
||||
|
||||
|
||||
# Catalog Service: Build dotnet bits
|
||||
Write-Host "Catalog Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $catalogPathToProject
|
||||
dotnet build $catalogPathToProject
|
||||
dotnet publish $catalogPathToProject -o $catalogPathToPub
|
||||
|
||||
|
||||
# Ordering Service: Build dotnet bits
|
||||
Write-Host "Ordering Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $orderingPathToProject
|
||||
dotnet build $orderingPathToProject
|
||||
dotnet publish $orderingPathToProject -o $orderingPathToPub
|
||||
|
||||
|
||||
# Basket Service: Build dotnet bits
|
||||
Write-Host "Basket Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $basketPathToProject
|
||||
dotnet build $basketPathToProject
|
||||
dotnet publish $basketPathToProject -o $basketPathToPub
|
||||
|
||||
|
||||
|
||||
########################################################################################
|
||||
# Delete old eShop Docker images
|
||||
########################################################################################
|
||||
|
||||
$imagesToDelete = docker images --filter=reference="eshop/*" -q
|
||||
|
||||
If (-Not $imagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."}
|
||||
Else
|
||||
{
|
||||
# Delete all containers
|
||||
Write-Host "Deleting all containers in local Docker Host"
|
||||
docker rm $(docker ps -a -q) -f
|
||||
|
||||
# Delete all eshop images
|
||||
Write-Host "Deleting eShop images in local Docker repo"
|
||||
Write-Host $imagesToDelete
|
||||
docker rmi $(docker images --filter=reference="eshop/*" -q) -f
|
||||
}
|
||||
|
||||
|
||||
########################################################################################
|
||||
# Build new eShop images
|
||||
########################################################################################
|
||||
|
||||
# WE DON'T NEED DOCKER BUILD AS WE CAN RUN "DOCKER-COMPOSE BUILD" OR "DOCKER-COMPOSE UP" AND IT WILL BUILD ALL THE IMAGES IN THE .YML FOR US
|
||||
|
||||
#*** build docker images ***
|
||||
# docker build -t eshop/web $webPathToPub
|
||||
# docker build -t eshop/catalog.api $catalogPathToPub
|
||||
# docker build -t eshop/ordering.api $orderingApiPathToPub
|
||||
# docker build -t eshop/basket.api $basketPathToPub
|
||||
# docker build -t eshop/webspa $webSPAPathToPub
|
||||
# docker build -t eshop/identity $identitySvcPathToPub
|
@ -15,13 +15,14 @@ $projectPaths =
|
||||
@{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"},
|
||||
@{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"},
|
||||
@{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}
|
||||
@{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"}
|
||||
|
||||
$projectPaths | foreach {
|
||||
$projectPath = $_.Path
|
||||
$projectFile = $_.Prj
|
||||
$outPath = $_.Path + "\obj\Docker\publish"
|
||||
$projectPathAndFile = "$projectPath\$projectFile"
|
||||
Write-Host "Deleting $outPath" -ForegroundColor Yellow
|
||||
Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow
|
||||
remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue
|
||||
Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow
|
||||
dotnet restore $projectPathAndFile
|
||||
|
@ -33,6 +33,7 @@ services:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5105
|
||||
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104
|
||||
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always
|
||||
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
|
||||
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5105.
|
||||
ports:
|
||||
@ -44,6 +45,7 @@ services:
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5102
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
||||
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||
- BasketUrl=http://basket.api:5103
|
||||
- EventBusConnection=rabbitmq
|
||||
ports:
|
||||
- "5102:5102"
|
||||
@ -85,7 +87,7 @@ services:
|
||||
- CatalogUrl=http://catalog.api:5101/hc
|
||||
- OrderingUrl=http://ordering.api:5102/hc
|
||||
- BasketUrl=http://basket.api:5103/hc
|
||||
- IdentityUrl=http://10.0.75.1:5105/hc
|
||||
- IdentityUrl=http://identity.api:5105/hc
|
||||
- mvc=http://webmvc:5100/hc
|
||||
- spa=http://webspa:5104/hc
|
||||
ports:
|
||||
|
@ -19,6 +19,7 @@ services:
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5103
|
||||
- ConnectionString=basket.data
|
||||
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||
- EventBusConnection=rabbitmq
|
||||
ports:
|
||||
- "5103:5103"
|
||||
|
||||
@ -28,6 +29,7 @@ services:
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5101
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
|
||||
- ExternalCatalogBaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||
- EventBusConnection=rabbitmq
|
||||
ports:
|
||||
- "5101:5101"
|
||||
|
||||
@ -38,6 +40,7 @@ services:
|
||||
- SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104
|
||||
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
|
||||
- MvcClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your host's firewall at range 5100-5105.
|
||||
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback
|
||||
ports:
|
||||
- "5105:5105"
|
||||
|
||||
@ -47,6 +50,8 @@ services:
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5102
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
||||
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||
- BasketUrl=http://basket.api:5103
|
||||
- EventBusConnection=rabbitmq
|
||||
ports:
|
||||
- "5102:5102"
|
||||
|
||||
@ -81,10 +86,13 @@ services:
|
||||
|
||||
webstatus:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5107
|
||||
- CatalogUrl=http://catalog.api:5101/hc
|
||||
- OrderingUrl=http://ordering.api:5102/hc
|
||||
- BasketUrl=http://basket.api:5103/hc
|
||||
- IdentityUrl=http://10.0.75.1:5105/hc
|
||||
- mvc=http://webmvc:5100/hc
|
||||
- spa=http://webspa:5104/hc
|
||||
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
|
||||
ports:
|
||||
- "5107:5107"
|
||||
- "5107:5107"
|
Binary file not shown.
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.0
|
||||
VisualStudioVersion = 15.0.26228.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
|
||||
EndProject
|
||||
@ -39,24 +39,10 @@ EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Infrastructure", "src\Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.csproj", "{95F1F07C-4D92-4742-BD07-E5B805AAB651}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\Services\UnitTest\UnitTest.csproj", "{7796F5D8-31FC-45A4-B673-19DE5BA194CF}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A579E108-5445-403D-A407-339AC4D1611B} = {A579E108-5445-403D-A407-339AC4D1611B}
|
||||
{F16E3C6A-1C94-4EAB-BE91-099618060B68} = {F16E3C6A-1C94-4EAB-BE91-099618060B68}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}"
|
||||
EndProject
|
||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A579E108-5445-403D-A407-339AC4D1611B} = {A579E108-5445-403D-A407-339AC4D1611B}
|
||||
{5B810E3D-112E-4857-B197-F09D2FD41E27} = {5B810E3D-112E-4857-B197-F09D2FD41E27}
|
||||
{F16E3C6A-1C94-4EAB-BE91-099618060B68} = {F16E3C6A-1C94-4EAB-BE91-099618060B68}
|
||||
{F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {F0333D8E-0B27-42B7-B2C6-78F3657624E2}
|
||||
{42681D9D-750A-4DF7-BD9F-9292CFD5C253} = {42681D9D-750A-4DF7-BD9F-9292CFD5C253}
|
||||
{2110CBB0-3B38-4EE4-A743-DF6968D80D90} = {2110CBB0-3B38-4EE4-A743-DF6968D80D90}
|
||||
{CFE2FACB-4538-4B99-8A10-306F3882952D} = {CFE2FACB-4538-4B99-8A10-306F3882952D}
|
||||
{231226CE-690B-4979-8870-9A79D80928E2} = {231226CE-690B-4979-8870-9A79D80928E2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}"
|
||||
EndProject
|
||||
@ -84,6 +70,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Health
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{FBF43D93-F2E7-4FF8-B4AB-186895949B88}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@ -914,6 +904,54 @@ Global
|
||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -947,5 +985,7 @@ Global
|
||||
{942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||
{7804FC60-23E6-490C-8E08-F9FEF829F184} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||
{FBF43D93-F2E7-4FF8-B4AB-186895949B88} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.9
|
||||
VisualStudioVersion = 15.0.26228.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
|
||||
EndProject
|
||||
@ -71,10 +71,12 @@ Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-co
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A579E108-5445-403D-A407-339AC4D1611B} = {A579E108-5445-403D-A407-339AC4D1611B}
|
||||
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2} = {9842DB3A-1391-48C7-A49C-2FABD0A18AC2}
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41} = {23FB706A-2701-41E9-8BF9-28936001CA41}
|
||||
{F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {F0333D8E-0B27-42B7-B2C6-78F3657624E2}
|
||||
{42681D9D-750A-4DF7-BD9F-9292CFD5C253} = {42681D9D-750A-4DF7-BD9F-9292CFD5C253}
|
||||
{2110CBB0-3B38-4EE4-A743-DF6968D80D90} = {2110CBB0-3B38-4EE4-A743-DF6968D80D90}
|
||||
{231226CE-690B-4979-8870-9A79D80928E2} = {231226CE-690B-4979-8870-9A79D80928E2}
|
||||
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357} = {2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}"
|
||||
@ -89,6 +91,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "sr
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "test\Services\FunctionalTests\FunctionalTests.csproj", "{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj", "{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.Data", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj", "{0E7AEB45-80F2-42B9-96BB-3414669E58AA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{D13768ED-5AF1-4E09-96DD-FF6E7A2E5E06}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D92EB452-7A72-4B26-A8ED-0204CD376BC4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{23FB706A-2701-41E9-8BF9-28936001CA41}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@ -1210,6 +1226,246 @@ Global
|
||||
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x64.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -1251,5 +1507,12 @@ Global
|
||||
{52AF222A-258C-4032-ACDD-857D7251BC1E} = {B473B70F-0796-4862-B1AD-BB742D93B868}
|
||||
{438B774F-5569-4DE2-AA62-3F8BAEB31C55} = {B473B70F-0796-4862-B1AD-BB742D93B868}
|
||||
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
||||
{96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B} = {1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
{D13768ED-5AF1-4E09-96DD-FF6E7A2E5E06} = {1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4} = {D13768ED-5AF1-4E09-96DD-FF6E7A2E5E06}
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 427 KiB After Width: | Height: | Size: 405 KiB |
BIN
img/eShopOnContainers_Architecture_Diagram_old.png
Normal file
BIN
img/eShopOnContainers_Architecture_Diagram_old.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 KiB |
BIN
img/eShopOnContainers_Types_Of_Microservices.png
Normal file
BIN
img/eShopOnContainers_Types_Of_Microservices.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
BIN
img/xamarin-enterprise-patterns-ebook-cover-small.png
Normal file
BIN
img/xamarin-enterprise-patterns-ebook-cover-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -0,0 +1,37 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities
|
||||
{
|
||||
public class ResilientTransaction
|
||||
{
|
||||
private DbContext _context;
|
||||
private ResilientTransaction(DbContext context) =>
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
|
||||
public static ResilientTransaction New (DbContext context) =>
|
||||
new ResilientTransaction(context);
|
||||
|
||||
public async Task ExecuteAsync(Func<Task> action)
|
||||
{
|
||||
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
||||
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||
var strategy = _context.Database.CreateExecutionStrategy();
|
||||
await strategy.ExecuteAsync(async () =>
|
||||
{
|
||||
using (var transaction = _context.Database.BeginTransaction())
|
||||
{
|
||||
await action();
|
||||
transaction.Commit();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebMVC.Services.Utilities
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
{
|
||||
public interface IHttpClient
|
||||
{
|
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Polly" Version="5.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
{
|
||||
public class ResiliencePolicy
|
||||
{
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Polly;
|
||||
using Polly.Wrap;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebMVC.Services.Utilities
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpClient wrapper that integrates Retry and Circuit
|
||||
@ -21,55 +21,15 @@ namespace WebMVC.Services.Utilities
|
||||
private PolicyWrap _policyWrapper;
|
||||
private ILogger<ResilientHttpClient> _logger;
|
||||
public HttpClient Inst => _client;
|
||||
public ResilientHttpClient(ILogger<ResilientHttpClient> logger)
|
||||
|
||||
public ResilientHttpClient(Policy[] policies, ILogger<ResilientHttpClient> logger)
|
||||
{
|
||||
_client = new HttpClient();
|
||||
_logger = logger;
|
||||
|
||||
// Add Policies to be applied
|
||||
_policyWrapper = Policy.WrapAsync(
|
||||
CreateRetryPolicy(),
|
||||
CreateCircuitBreakerPolicy()
|
||||
);
|
||||
}
|
||||
|
||||
private Policy CreateRetryPolicy() =>
|
||||
Policy.Handle<HttpRequestException>()
|
||||
.WaitAndRetryAsync(
|
||||
// number of retries
|
||||
6,
|
||||
// exponential backofff
|
||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||
// on retry
|
||||
(exception, timeSpan, retryCount, context) =>
|
||||
{
|
||||
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
|
||||
$"of {context.PolicyKey} " +
|
||||
$"at {context.ExecutionKey}, " +
|
||||
$"due to: {exception}.";
|
||||
_logger.LogWarning(msg);
|
||||
_logger.LogDebug(msg);
|
||||
}
|
||||
);
|
||||
|
||||
private Policy CreateCircuitBreakerPolicy() =>
|
||||
Policy.Handle<HttpRequestException>()
|
||||
.CircuitBreakerAsync(
|
||||
// number of exceptions before breaking circuit
|
||||
5,
|
||||
// time circuit opened before retry
|
||||
TimeSpan.FromMinutes(1),
|
||||
(exception, duration) =>
|
||||
{
|
||||
// on circuit opened
|
||||
_logger.LogTrace("Circuit breaker opened");
|
||||
},
|
||||
() =>
|
||||
{
|
||||
// on circuit closed
|
||||
_logger.LogTrace("Circuit breaker reset");
|
||||
}
|
||||
);
|
||||
_policyWrapper = Policy.WrapAsync(policies);
|
||||
}
|
||||
|
||||
public Task<string> GetStringAsync(string uri) =>
|
||||
HttpInvoker(() =>
|
@ -4,7 +4,7 @@ using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebMVC.Services.Utilities
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
{
|
||||
public class StandardHttpClient : IHttpClient
|
||||
{
|
@ -108,8 +108,9 @@
|
||||
<converters:InverseBoolConverter x:Key="InverseBoolConverter" />
|
||||
<converters:ItemsToHeightConverter x:Key="ItemsToHeightConverter" />
|
||||
<converters:ToUpperConverter x:Key="ToUpperConverter" />
|
||||
<converters:WebNavigatingEventArgsConverter x:Key="WebNavigatingEventArgsConverter" />
|
||||
|
||||
<converters:WebNavigatingEventArgsConverter x:Key="WebNavigatingEventArgsConverter" />
|
||||
<converters:WebNavigatedEventArgsConverter x:Key="WebNavigatedEventArgsConverter" />
|
||||
|
||||
<!-- STYLES -->
|
||||
<Style x:Key="ValidationErrorLabelStyle"
|
||||
TargetType="{x:Type Label}">
|
||||
|
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace eShopOnContainers.Core.Converters
|
||||
{
|
||||
public class WebNavigatedEventArgsConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var eventArgs = value as WebNavigatedEventArgs;
|
||||
if (eventArgs == null)
|
||||
throw new ArgumentException("Expected WebNavigatedEventArgs as value", "value");
|
||||
|
||||
return eventArgs.Url;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -60,7 +60,7 @@
|
||||
IdentityEndpoint = string.Format("{0}:5105/connect/authorize", baseEndpoint);
|
||||
UserInfoEndpoint = string.Format("{0}:5105/connect/userinfo", baseEndpoint);
|
||||
LogoutEndpoint = string.Format("{0}:5105/connect/endsession", baseEndpoint);
|
||||
IdentityCallback = "http://eshopxamarin/callback.html";
|
||||
IdentityCallback = string.Format("{0}:5105/xamarincallback", baseEndpoint);
|
||||
LogoutCallback = string.Format("{0}:5105/Account/Redirecting", baseEndpoint);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,16 @@ namespace eShopOnContainers.Core.Models.Basket
|
||||
|
||||
public decimal UnitPrice { get; set; }
|
||||
|
||||
public decimal OldUnitPrice { get; set; }
|
||||
|
||||
public bool HasNewPrice
|
||||
{
|
||||
get
|
||||
{
|
||||
return OldUnitPrice != 0.0m;
|
||||
}
|
||||
}
|
||||
|
||||
public int Quantity
|
||||
{
|
||||
get { return _quantity; }
|
||||
|
@ -34,6 +34,9 @@ namespace eShopOnContainers.Core.Models.Orders
|
||||
[JsonProperty("country")]
|
||||
public string ShippingCountry { get; set; }
|
||||
|
||||
[JsonProperty("zipCode")]
|
||||
public string ShippingZipCode { get; set; }
|
||||
|
||||
public int CardTypeId { get; set; }
|
||||
|
||||
public string CardNumber { get; set; }
|
||||
|
@ -76,7 +76,9 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
|
||||
if (basket != null && basket.Items != null && basket.Items.Any())
|
||||
{
|
||||
BadgeCount = 0;
|
||||
BasketItems.Clear();
|
||||
|
||||
foreach (var basketItem in basket.Items)
|
||||
{
|
||||
BadgeCount += basketItem.Quantity;
|
||||
|
@ -90,7 +90,7 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
ZipCode = userInfo?.ZipCode,
|
||||
State = userInfo?.State,
|
||||
Country = userInfo?.Country,
|
||||
City = string.Empty
|
||||
City = userInfo?.Address
|
||||
};
|
||||
|
||||
// Create Payment Info
|
||||
@ -117,7 +117,8 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
ShippingState = _shippingAddress.State,
|
||||
ShippingCountry = _shippingAddress.Country,
|
||||
ShippingStreet = _shippingAddress.Street,
|
||||
ShippingCity = _shippingAddress.City,
|
||||
ShippingCity = _shippingAddress.City,
|
||||
ShippingZipCode = _shippingAddress.ZipCode,
|
||||
Total = CalculateTotal(CreateOrderItems(orderItems))
|
||||
};
|
||||
|
||||
|
@ -221,14 +221,16 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
|
||||
private async Task NavigateAsync(string url)
|
||||
{
|
||||
if (url.Equals(GlobalSetting.Instance.LogoutCallback))
|
||||
var unescapedUrl = System.Net.WebUtility.UrlDecode(url);
|
||||
|
||||
if (unescapedUrl.Equals(GlobalSetting.Instance.LogoutCallback))
|
||||
{
|
||||
Settings.AuthAccessToken = string.Empty;
|
||||
Settings.AuthIdToken = string.Empty;
|
||||
IsLogin = false;
|
||||
LoginUrl = _identityService.CreateAuthorizationRequest();
|
||||
}
|
||||
else if (url.Contains(GlobalSetting.Instance.IdentityCallback))
|
||||
else if (unescapedUrl.Contains(GlobalSetting.Instance.IdentityCallback))
|
||||
{
|
||||
var authResponse = new AuthorizeResponse(url);
|
||||
|
||||
|
@ -345,10 +345,26 @@
|
||||
AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
|
||||
AbsoluteLayout.LayoutFlags="All">
|
||||
<WebView.Behaviors>
|
||||
<behaviors:EventToCommandBehavior
|
||||
EventName="Navigating"
|
||||
EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}"
|
||||
Command="{Binding NavigateCommand}" />
|
||||
<OnPlatform x:TypeArguments="Behavior">
|
||||
<OnPlatform.Android>
|
||||
<behaviors:EventToCommandBehavior
|
||||
EventName="Navigating"
|
||||
EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}"
|
||||
Command="{Binding NavigateCommand}" />
|
||||
</OnPlatform.Android>
|
||||
<OnPlatform.iOS>
|
||||
<behaviors:EventToCommandBehavior
|
||||
EventName="Navigating"
|
||||
EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}"
|
||||
Command="{Binding NavigateCommand}" />
|
||||
</OnPlatform.iOS>
|
||||
<OnPlatform.WinPhone>
|
||||
<behaviors:EventToCommandBehavior
|
||||
EventName="Navigated"
|
||||
EventArgsConverter="{StaticResource WebNavigatedEventArgsConverter}"
|
||||
Command="{Binding NavigateCommand}" />
|
||||
</OnPlatform.WinPhone>
|
||||
</OnPlatform>
|
||||
</WebView.Behaviors>
|
||||
</WebView>
|
||||
</AbsoluteLayout>
|
||||
|
@ -35,5 +35,16 @@ namespace eShopOnContainers.Core.Views
|
||||
await ((BasketViewModel)BasketView.BindingContext).InitializeAsync(null);
|
||||
await ((ProfileViewModel)ProfileView.BindingContext).InitializeAsync(null);
|
||||
}
|
||||
|
||||
protected override async void OnCurrentPageChanged()
|
||||
{
|
||||
base.OnCurrentPageChanged();
|
||||
|
||||
if (CurrentPage is BasketView)
|
||||
{
|
||||
// Force basket view refresh every time we access it
|
||||
await (BasketView.BindingContext as ViewModelBase).InitializeAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- IMAGE -->
|
||||
@ -131,10 +132,24 @@
|
||||
Text="{Binding Total, StringFormat='${0:N}'}"
|
||||
Style="{StaticResource OrderTotalStyle}"/>
|
||||
</Grid>
|
||||
<Grid
|
||||
<Grid
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="1"
|
||||
IsVisible="{Binding HasNewPrice}"
|
||||
BackgroundColor="#F0AD4E">
|
||||
<Label
|
||||
HorizontalOptions="Fill"
|
||||
VerticalOptions="Fill"
|
||||
HorizontalTextAlignment="Center"
|
||||
VerticalTextAlignment="Center"
|
||||
HeightRequest="60"
|
||||
Text="{Binding OldUnitPrice, StringFormat='Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ {0:N2}'}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="2"
|
||||
BackgroundColor="Gray"/>
|
||||
</Grid>
|
||||
</ContentView.Content>
|
||||
|
@ -58,6 +58,7 @@
|
||||
<Compile Include="Converters\ItemsToHeightConverter.cs" />
|
||||
<Compile Include="Converters\ItemTappedEventArgsConverter.cs" />
|
||||
<Compile Include="Converters\ToUpperConverter.cs" />
|
||||
<Compile Include="Converters\WebNavigatedEventArgsConverter.cs" />
|
||||
<Compile Include="Exceptions\ServiceAuthenticationException.cs" />
|
||||
<Compile Include="Extensions\ObservableExtension.cs" />
|
||||
<Compile Include="GlobalSettings.cs" />
|
||||
|
@ -24,5 +24,6 @@
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<Capability Name="privateNetworkClientServer" />
|
||||
</Capabilities>
|
||||
</Package>
|
@ -0,0 +1,27 @@
|
||||
using Basket.API.IntegrationEvents.Events;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.IntegrationEvents.EventHandling
|
||||
{
|
||||
public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler<OrderStartedIntegrationEvent>
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
public OrderStartedIntegrationEventHandler(IBasketRepository repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task Handle(OrderStartedIntegrationEvent @event)
|
||||
{
|
||||
await _repository.DeleteBasketAsync(@event.UserId.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.IntegrationEvents.Events
|
||||
{
|
||||
// Integration Events notes:
|
||||
// An Event is “something that has happened in the past”, therefore its name has to be
|
||||
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
|
||||
public class OrderStartedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public string UserId { get; }
|
||||
|
||||
public OrderStartedIntegrationEvent(string userId) =>
|
||||
UserId = userId;
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ using System;
|
||||
using Microsoft.Extensions.HealthChecks;
|
||||
using System.Threading.Tasks;
|
||||
using Basket.API.Infrastructure.Filters;
|
||||
using Basket.API.IntegrationEvents.Events;
|
||||
using Basket.API.IntegrationEvents.EventHandling;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
@ -40,7 +42,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
|
||||
services.AddHealthChecks(checks =>
|
||||
{
|
||||
checks.AddValueTaskCheck("Always OK", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
|
||||
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
|
||||
});
|
||||
|
||||
// Add framework services.
|
||||
@ -91,6 +93,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
|
||||
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
||||
services.AddTransient<IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>, ProductPriceChangedIntegrationEventHandler>();
|
||||
services.AddTransient<IIntegrationEventHandler<OrderStartedIntegrationEvent>, OrderStartedIntegrationEventHandler>();
|
||||
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var configuration = serviceProvider.GetRequiredService<IOptionsSnapshot<BasketSettings>>().Value;
|
||||
@ -117,8 +120,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
.UseSwaggerUi();
|
||||
|
||||
var catalogPriceHandler = app.ApplicationServices.GetService<IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>>();
|
||||
var orderStartedHandler = app.ApplicationServices.GetService<IIntegrationEventHandler<OrderStartedIntegrationEvent>>();
|
||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||
eventBus.Subscribe<ProductPriceChangedIntegrationEvent>(catalogPriceHandler);
|
||||
eventBus.Subscribe<OrderStartedIntegrationEvent>(orderStartedHandler);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@ using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
||||
using Catalog.API.IntegrationEvents;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
{
|
||||
@ -23,15 +25,13 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
{
|
||||
private readonly CatalogContext _catalogContext;
|
||||
private readonly IOptionsSnapshot<Settings> _settings;
|
||||
private readonly IEventBus _eventBus;
|
||||
private readonly Func<DbConnection, IIntegrationEventLogService> _integrationEventLogServiceFactory;
|
||||
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService;
|
||||
|
||||
public CatalogController(CatalogContext Context, IOptionsSnapshot<Settings> settings, IEventBus eventBus, Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
||||
public CatalogController(CatalogContext Context, IOptionsSnapshot<Settings> settings, ICatalogIntegrationEventService catalogIntegrationEventService)
|
||||
{
|
||||
_catalogContext = Context;
|
||||
_catalogIntegrationEventService = catalogIntegrationEventService;
|
||||
_settings = settings;
|
||||
_eventBus = eventBus;
|
||||
_integrationEventLogServiceFactory = integrationEventLogServiceFactory;
|
||||
|
||||
((DbContext)Context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
}
|
||||
@ -145,51 +145,28 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
{
|
||||
var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);
|
||||
if (catalogItem == null) return NotFound();
|
||||
|
||||
bool raiseProductPriceChangedEvent = false;
|
||||
IntegrationEvent priceChangedEvent = null;
|
||||
|
||||
if (catalogItem.Price != productToUpdate.Price) raiseProductPriceChangedEvent = true;
|
||||
|
||||
if (raiseProductPriceChangedEvent) // Create event if price has changed
|
||||
{
|
||||
var oldPrice = catalogItem.Price;
|
||||
priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
|
||||
}
|
||||
|
||||
//Update current product
|
||||
var raiseProductPriceChangedEvent = catalogItem.Price != productToUpdate.Price;
|
||||
var oldPrice = catalogItem.Price;
|
||||
|
||||
// Update current product
|
||||
catalogItem = productToUpdate;
|
||||
_catalogContext.CatalogItems.Update(catalogItem);
|
||||
|
||||
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
||||
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||
var strategy = _catalogContext.Database.CreateExecutionStrategy();
|
||||
var eventLogService = _integrationEventLogServiceFactory(_catalogContext.Database.GetDbConnection());
|
||||
await strategy.ExecuteAsync(async () =>
|
||||
if (raiseProductPriceChangedEvent) // Save and publish integration event if price has changed
|
||||
{
|
||||
//Create Integration Event to be published through the Event Bus
|
||||
var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
|
||||
|
||||
// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
|
||||
using (var transaction = _catalogContext.Database.BeginTransaction())
|
||||
{
|
||||
_catalogContext.CatalogItems.Update(catalogItem);
|
||||
await _catalogContext.SaveChangesAsync();
|
||||
|
||||
//Save to EventLog only if product price changed
|
||||
if (raiseProductPriceChangedEvent)
|
||||
{
|
||||
|
||||
await eventLogService.SaveEventAsync(priceChangedEvent, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//Publish to Event Bus only if product price changed
|
||||
if (raiseProductPriceChangedEvent)
|
||||
{
|
||||
_eventBus.Publish(priceChangedEvent);
|
||||
await eventLogService.MarkEventAsPublishedAsync(priceChangedEvent);
|
||||
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent);
|
||||
|
||||
// Publish through the Event Bus and mark the saved event as published
|
||||
await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
|
||||
}
|
||||
else // Save updated product
|
||||
{
|
||||
await _catalogContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
@ -13,14 +13,12 @@
|
||||
public DbSet<CatalogItem> CatalogItems { get; set; }
|
||||
public DbSet<CatalogBrand> CatalogBrands { get; set; }
|
||||
public DbSet<CatalogType> CatalogTypes { get; set; }
|
||||
//public DbSet<IntegrationEventLogEntry> IntegrationEventLog { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.Entity<CatalogBrand>(ConfigureCatalogBrand);
|
||||
builder.Entity<CatalogType>(ConfigureCatalogType);
|
||||
builder.Entity<CatalogItem>(ConfigureCatalogItem);
|
||||
//builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
|
||||
}
|
||||
|
||||
void ConfigureCatalogItem(EntityTypeBuilder<CatalogItem> builder)
|
||||
@ -79,31 +77,5 @@
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
}
|
||||
|
||||
//void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
|
||||
//{
|
||||
// builder.ToTable("IntegrationEventLog");
|
||||
|
||||
// builder.HasKey(e => e.EventId);
|
||||
|
||||
// builder.Property(e => e.EventId)
|
||||
// .IsRequired();
|
||||
|
||||
// builder.Property(e => e.Content)
|
||||
// .IsRequired();
|
||||
|
||||
// builder.Property(e => e.CreationTime)
|
||||
// .IsRequired();
|
||||
|
||||
// builder.Property(e => e.State)
|
||||
// .IsRequired();
|
||||
|
||||
// builder.Property(e => e.TimesSent)
|
||||
// .IsRequired();
|
||||
|
||||
// builder.Property(e => e.EventTypeName)
|
||||
// .IsRequired();
|
||||
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Catalog.API.IntegrationEvents
|
||||
{
|
||||
public class CatalogIntegrationEventService : ICatalogIntegrationEventService
|
||||
{
|
||||
private readonly Func<DbConnection, IIntegrationEventLogService> _integrationEventLogServiceFactory;
|
||||
private readonly IEventBus _eventBus;
|
||||
private readonly CatalogContext _catalogContext;
|
||||
private readonly IIntegrationEventLogService _eventLogService;
|
||||
|
||||
public CatalogIntegrationEventService(IEventBus eventBus, CatalogContext catalogContext,
|
||||
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
||||
{
|
||||
_catalogContext = catalogContext ?? throw new ArgumentNullException(nameof(catalogContext));
|
||||
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
|
||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||
_eventLogService = _integrationEventLogServiceFactory(_catalogContext.Database.GetDbConnection());
|
||||
}
|
||||
|
||||
public async Task PublishThroughEventBusAsync(IntegrationEvent evt)
|
||||
{
|
||||
_eventBus.Publish(evt);
|
||||
await _eventLogService.MarkEventAsPublishedAsync(evt);
|
||||
}
|
||||
|
||||
public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt)
|
||||
{
|
||||
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
||||
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||
await ResilientTransaction.New(_catalogContext)
|
||||
.ExecuteAsync(async () => {
|
||||
// Achieving atomicity between original catalog database operation and the IntegrationEventLog thanks to a local transaction
|
||||
await _catalogContext.SaveChangesAsync();
|
||||
await _eventLogService.SaveEventAsync(evt, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Catalog.API.IntegrationEvents
|
||||
{
|
||||
public interface ICatalogIntegrationEventService
|
||||
{
|
||||
Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt);
|
||||
Task PublishThroughEventBusAsync(IntegrationEvent evt);
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@
|
||||
using System.IO;
|
||||
using System.Data.Common;
|
||||
using System.Reflection;
|
||||
using global::Catalog.API.IntegrationEvents;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
@ -48,7 +50,7 @@
|
||||
|
||||
services.AddHealthChecks(checks =>
|
||||
{
|
||||
checks.AddUrlCheck(Configuration["ExternalCatalogBaseUrl"]);
|
||||
checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"]);
|
||||
});
|
||||
|
||||
services.AddMvc(options =>
|
||||
@ -97,10 +99,10 @@
|
||||
});
|
||||
|
||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||
|
||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var configuration = serviceProvider.GetRequiredService<IOptionsSnapshot<Settings>>().Value;
|
||||
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
|
||||
services.AddSingleton<IEventBus>(new EventBusRabbitMQ(configuration.EventBusConnection));
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,30 @@
|
||||
using IdentityServer4.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Collections.Generic;
|
||||
using IdentityServer4;
|
||||
|
||||
namespace Identity.API.Configuration
|
||||
{
|
||||
public class Config
|
||||
{
|
||||
// scopes define the resources in your system
|
||||
public static IEnumerable<Scope> GetScopes()
|
||||
// ApiResources define the apis in your system
|
||||
public static IEnumerable<ApiResource> GetApis()
|
||||
{
|
||||
return new List<Scope>
|
||||
return new List<ApiResource>
|
||||
{
|
||||
//Authentication OpenId uses this scopes;
|
||||
StandardScopes.OpenId,
|
||||
StandardScopes.Profile,
|
||||
new ApiResource("orders", "Orders Service"),
|
||||
new ApiResource("basket", "Basket Service")
|
||||
};
|
||||
}
|
||||
|
||||
//Each api we want to securice;
|
||||
new Scope
|
||||
{
|
||||
Name = "orders",
|
||||
Description = "Orders Service"
|
||||
},
|
||||
new Scope
|
||||
{
|
||||
Name = "basket",
|
||||
Description = "Basket Service"
|
||||
}
|
||||
// Identity resources are data like user ID, name, or email address of a user
|
||||
// see: http://docs.identityserver.io/en/release/configuration/resources.html
|
||||
public static IEnumerable<IdentityResource> GetResources()
|
||||
{
|
||||
return new List<IdentityResource>
|
||||
{
|
||||
new IdentityResources.OpenId(),
|
||||
new IdentityResources.Profile()
|
||||
};
|
||||
}
|
||||
|
||||
@ -47,8 +46,8 @@ namespace Identity.API.Configuration
|
||||
AllowedCorsOrigins = { $"{clientsUrl["Spa"]}" },
|
||||
AllowedScopes =
|
||||
{
|
||||
StandardScopes.OpenId.Name,
|
||||
StandardScopes.Profile.Name,
|
||||
IdentityServerConstants.StandardScopes.OpenId,
|
||||
IdentityServerConstants.StandardScopes.Profile,
|
||||
"orders",
|
||||
"basket"
|
||||
}
|
||||
@ -59,14 +58,14 @@ namespace Identity.API.Configuration
|
||||
ClientName = "eShop Xamarin OpenId Client",
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
RedirectUris = { "http://eshopxamarin/callback.html" },
|
||||
RedirectUris = { clientsUrl["Xamarin"] },
|
||||
RequireConsent = false,
|
||||
PostLogoutRedirectUris = { "http://13.88.8.119:5105/Account/Redirecting", "http://10.6.1.234:5105/Account/Redirecting" },
|
||||
AllowedCorsOrigins = { "http://eshopxamarin" },
|
||||
AllowedScopes =
|
||||
{
|
||||
StandardScopes.OpenId.Name,
|
||||
StandardScopes.Profile.Name,
|
||||
IdentityServerConstants.StandardScopes.OpenId,
|
||||
IdentityServerConstants.StandardScopes.Profile,
|
||||
"orders",
|
||||
"basket"
|
||||
}
|
||||
@ -82,6 +81,7 @@ namespace Identity.API.Configuration
|
||||
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||
RequireConsent = false,
|
||||
AllowOfflineAccess = true,
|
||||
RedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["Mvc"]}/signin-oidc",
|
||||
@ -96,9 +96,9 @@ namespace Identity.API.Configuration
|
||||
},
|
||||
AllowedScopes = new List<string>
|
||||
{
|
||||
StandardScopes.OpenId.Name,
|
||||
StandardScopes.Profile.Name,
|
||||
StandardScopes.OfflineAccess.Name,
|
||||
IdentityServerConstants.StandardScopes.OpenId,
|
||||
IdentityServerConstants.StandardScopes.Profile,
|
||||
IdentityServerConstants.StandardScopes.OfflineAccess,
|
||||
"orders",
|
||||
"basket",
|
||||
},
|
||||
|
@ -5,7 +5,6 @@
|
||||
using IdentityModel;
|
||||
using IdentityServer4.Quickstart.UI.Models;
|
||||
using IdentityServer4.Services;
|
||||
using IdentityServer4.Services.InMemory;
|
||||
using Microsoft.AspNetCore.Http.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
|
@ -22,7 +22,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
{
|
||||
private readonly ILogger<ConsentController> _logger;
|
||||
private readonly IClientStore _clientStore;
|
||||
private readonly IScopeStore _scopeStore;
|
||||
private readonly IResourceStore _resourceStore;
|
||||
private readonly IIdentityServerInteractionService _interaction;
|
||||
|
||||
|
||||
@ -30,12 +30,12 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
ILogger<ConsentController> logger,
|
||||
IIdentityServerInteractionService interaction,
|
||||
IClientStore clientStore,
|
||||
IScopeStore scopeStore)
|
||||
IResourceStore resourceStore)
|
||||
{
|
||||
_logger = logger;
|
||||
_interaction = interaction;
|
||||
_clientStore = clientStore;
|
||||
_scopeStore = scopeStore;
|
||||
_resourceStore = resourceStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -120,10 +120,10 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
|
||||
if (client != null)
|
||||
{
|
||||
var scopes = await _scopeStore.FindEnabledScopesAsync(request.ScopesRequested);
|
||||
if (scopes != null && scopes.Any())
|
||||
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
|
||||
if (resources != null && (resources.IdentityResources.Any() || resources.ApiResources.Any()))
|
||||
{
|
||||
return new ConsentViewModel(model, returnUrl, request, client, scopes);
|
||||
return new ConsentViewModel(model, returnUrl, request, client, resources);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -41,8 +41,8 @@
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0-msbuild3-final">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.0-rc3" />
|
||||
<PackageReference Include="IdentityServer4.EntityFramework" Version="1.0.0-rc3" />
|
||||
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.0" />
|
||||
<PackageReference Include="IdentityServer4.EntityFramework" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
|
||||
|
@ -10,7 +10,7 @@ namespace Identity.API.Models.AccountViewModels
|
||||
{
|
||||
public class ConsentViewModel : ConsentInputModel
|
||||
{
|
||||
public ConsentViewModel(ConsentInputModel model, string returnUrl, AuthorizationRequest request, Client client, IEnumerable<Scope> scopes)
|
||||
public ConsentViewModel(ConsentInputModel model, string returnUrl, AuthorizationRequest request, Client client, Resources resources)
|
||||
{
|
||||
RememberConsent = model?.RememberConsent ?? true;
|
||||
ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>();
|
||||
@ -22,8 +22,8 @@ namespace Identity.API.Models.AccountViewModels
|
||||
ClientLogoUrl = client.LogoUri;
|
||||
AllowRememberConsent = client.AllowRememberConsent;
|
||||
|
||||
IdentityScopes = scopes.Where(x => x.Type == ScopeType.Identity).Select(x => new ScopeViewModel(x, ScopesConsented.Contains(x.Name) || model == null)).ToArray();
|
||||
ResourceScopes = scopes.Where(x => x.Type == ScopeType.Resource).Select(x => new ScopeViewModel(x, ScopesConsented.Contains(x.Name) || model == null)).ToArray();
|
||||
IdentityScopes = resources.IdentityResources.Select(x => new ScopeViewModel(x, ScopesConsented.Contains(x.Name) || model == null)).ToArray();
|
||||
ResourceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => new ScopeViewModel(x, ScopesConsented.Contains(x.Name) || model == null)).ToArray();
|
||||
}
|
||||
|
||||
public string ClientName { get; set; }
|
||||
@ -47,6 +47,16 @@ namespace Identity.API.Models.AccountViewModels
|
||||
Checked = check || scope.Required;
|
||||
}
|
||||
|
||||
public ScopeViewModel(IdentityResource identity, bool check)
|
||||
{
|
||||
Name = identity.Name;
|
||||
DisplayName = identity.DisplayName;
|
||||
Description = identity.Description;
|
||||
Emphasize = identity.Emphasize;
|
||||
Required = identity.Required;
|
||||
Checked = check || identity.Required;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
@ -73,11 +73,13 @@ namespace eShopOnContainers.Identity
|
||||
Dictionary<string, string> clientUrls = new Dictionary<string, string>();
|
||||
clientUrls.Add("Mvc", Configuration.GetValue<string>("MvcClient"));
|
||||
clientUrls.Add("Spa", Configuration.GetValue<string>("SpaClient"));
|
||||
clientUrls.Add("Xamarin", Configuration.GetValue<string>("XamarinCallback"));
|
||||
|
||||
// Adds IdentityServer
|
||||
services.AddIdentityServer(x => x.IssuerUri = "null")
|
||||
.AddSigningCredential(Certificate.Get())
|
||||
.AddInMemoryScopes(Config.GetScopes())
|
||||
.AddInMemoryApiResources(Config.GetApis())
|
||||
.AddInMemoryIdentityResources(Config.GetResources())
|
||||
.AddInMemoryClients(Config.GetClients(clientUrls))
|
||||
.AddAspNetIdentity<ApplicationUser>()
|
||||
.Services.AddTransient<IProfileService, ProfileService>();
|
||||
|
@ -4,6 +4,7 @@
|
||||
},
|
||||
"MvcClient": "http://localhost:5100",
|
||||
"SpaClient": "http://localhost:5104",
|
||||
"XamarinCallback": "http://localhost:5105/xamarincallback",
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
|
@ -1,6 +1,8 @@
|
||||
using MediatR;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ordering.API.IntegrationEvents;
|
||||
using Ordering.API.IntegrationEvents.Events;
|
||||
using Ordering.Domain.Events;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
@ -11,10 +13,15 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri
|
||||
: IAsyncNotificationHandler<BuyerAndPaymentMethodVerifiedDomainEvent>
|
||||
{
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly ILoggerFactory _logger;
|
||||
public UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler(IOrderRepository orderRepository, ILoggerFactory logger)
|
||||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||
private readonly ILoggerFactory _logger;
|
||||
|
||||
public UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler(
|
||||
IOrderRepository orderRepository, ILoggerFactory logger,
|
||||
IOrderingIntegrationEventService orderingIntegrationEventService)
|
||||
{
|
||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@ -26,12 +33,20 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri
|
||||
var orderToUpdate = await _orderRepository.GetAsync(buyerPaymentMethodVerifiedEvent.OrderId);
|
||||
orderToUpdate.SetBuyerId(buyerPaymentMethodVerifiedEvent.Buyer.Id);
|
||||
orderToUpdate.SetPaymentId(buyerPaymentMethodVerifiedEvent.Payment.Id);
|
||||
|
||||
await _orderRepository.UnitOfWork
|
||||
.SaveEntitiesAsync();
|
||||
|
||||
|
||||
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(buyerPaymentMethodVerifiedEvent.Buyer.IdentityGuid);
|
||||
|
||||
// Using a local transaction to achieve atomicity between original Ordering database operation and
|
||||
// the IntegrationEventLog. Only saving event if order has been successfully persisted to db
|
||||
await _orderingIntegrationEventService
|
||||
.SaveEventAndOrderingContextChangesAsync(orderStartedIntegrationEvent);
|
||||
|
||||
// Publish ordering integration event and mark it as published
|
||||
await _orderingIntegrationEventService
|
||||
.PublishThroughEventBusAsync(orderStartedIntegrationEvent);
|
||||
|
||||
_logger.CreateLogger(nameof(UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler))
|
||||
.LogTrace($"Order with Id: {buyerPaymentMethodVerifiedEvent.OrderId} has been successfully updated with a payment method id: { buyerPaymentMethodVerifiedEvent.Payment.Id }");
|
||||
.LogTrace($"Order with Id: {buyerPaymentMethodVerifiedEvent.OrderId} has been successfully updated with a payment method id: { buyerPaymentMethodVerifiedEvent.Payment.Id }");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
|
||||
builder.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly)
|
||||
.As(o => o.GetInterfaces()
|
||||
.Where(i => i.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
|
||||
.Select(i => new KeyedService("IAsyncNotificationHandler", i)));
|
||||
.Select(i => new KeyedService("IAsyncNotificationHandler", i)))
|
||||
.AsImplementedInterfaces();
|
||||
|
||||
|
||||
builder
|
||||
.RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly)
|
||||
|
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||
|
||||
namespace Ordering.API.Infrastructure.IntegrationEventMigrations
|
||||
{
|
||||
[DbContext(typeof(IntegrationEventLogContext))]
|
||||
[Migration("20170330131634_IntegrationEventInitial")]
|
||||
partial class IntegrationEventInitial
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.1")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.IntegrationEventLogEntry", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<DateTime>("CreationTime");
|
||||
|
||||
b.Property<string>("EventTypeName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<int>("State");
|
||||
|
||||
b.Property<int>("TimesSent");
|
||||
|
||||
b.HasKey("EventId");
|
||||
|
||||
b.ToTable("IntegrationEventLog");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ordering.API.Infrastructure.IntegrationEventMigrations
|
||||
{
|
||||
public partial class IntegrationEventInitial : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "IntegrationEventLog",
|
||||
columns: table => new
|
||||
{
|
||||
EventId = table.Column<Guid>(nullable: false),
|
||||
Content = table.Column<string>(nullable: false),
|
||||
CreationTime = table.Column<DateTime>(nullable: false),
|
||||
EventTypeName = table.Column<string>(nullable: false),
|
||||
State = table.Column<int>(nullable: false),
|
||||
TimesSent = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_IntegrationEventLog", x => x.EventId);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "IntegrationEventLog");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||
|
||||
namespace Ordering.API.Infrastructure.IntegrationEventMigrations
|
||||
{
|
||||
[DbContext(typeof(IntegrationEventLogContext))]
|
||||
partial class IntegrationEventLogContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.1")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.IntegrationEventLogEntry", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<DateTime>("CreationTime");
|
||||
|
||||
b.Property<string>("EventTypeName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<int>("State");
|
||||
|
||||
b.Property<int>("TimesSent");
|
||||
|
||||
b.HasKey("EventId");
|
||||
|
||||
b.ToTable("IntegrationEventLog");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||
|
||||
namespace Ordering.API.Migrations
|
||||
{
|
||||
[DbContext(typeof(OrderingContext))]
|
||||
[Migration("20170403082405_NoBuyerPropertyInOrder")]
|
||||
partial class NoBuyerPropertyInOrder
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752")
|
||||
.HasAnnotation("SqlServer:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq")
|
||||
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<string>("IdentityGuid")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IdentityGuid")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("buyers","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("cardtypes","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq")
|
||||
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<string>("Alias")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<int>("BuyerId");
|
||||
|
||||
b.Property<string>("CardHolderName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<string>("CardNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.Property<int>("CardTypeId");
|
||||
|
||||
b.Property<DateTime>("Expiration");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BuyerId");
|
||||
|
||||
b.HasIndex("CardTypeId");
|
||||
|
||||
b.ToTable("paymentmethods","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("City");
|
||||
|
||||
b.Property<string>("Country");
|
||||
|
||||
b.Property<string>("State");
|
||||
|
||||
b.Property<string>("Street");
|
||||
|
||||
b.Property<string>("ZipCode");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("address","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "orderseq")
|
||||
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<int?>("AddressId");
|
||||
|
||||
b.Property<int?>("BuyerId");
|
||||
|
||||
b.Property<DateTime>("OrderDate");
|
||||
|
||||
b.Property<int>("OrderStatusId");
|
||||
|
||||
b.Property<int?>("PaymentMethodId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AddressId");
|
||||
|
||||
b.HasIndex("BuyerId");
|
||||
|
||||
b.HasIndex("OrderStatusId");
|
||||
|
||||
b.HasIndex("PaymentMethodId");
|
||||
|
||||
b.ToTable("orders","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<decimal>("Discount");
|
||||
|
||||
b.Property<int>("OrderId");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<int>("ProductId");
|
||||
|
||||
b.Property<string>("ProductName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<decimal>("UnitPrice");
|
||||
|
||||
b.Property<int>("Units");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.ToTable("orderItems","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("orderstatus","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.ClientRequest", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<DateTime>("Time");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("requests","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||
.WithMany("PaymentMethods")
|
||||
.HasForeignKey("BuyerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType")
|
||||
.WithMany()
|
||||
.HasForeignKey("CardTypeId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address")
|
||||
.WithMany()
|
||||
.HasForeignKey("AddressId");
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||
.WithMany()
|
||||
.HasForeignKey("BuyerId");
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderStatusId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", "PaymentMethod")
|
||||
.WithMany()
|
||||
.HasForeignKey("PaymentMethodId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
|
||||
.WithMany("OrderItems")
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ordering.API.Migrations
|
||||
{
|
||||
public partial class NoBuyerPropertyInOrder : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||
|
||||
namespace Ordering.API.Migrations
|
||||
{
|
||||
[DbContext(typeof(OrderingContext))]
|
||||
[Migration("20170405110939_NoPaymentMethodPropertyInOrder")]
|
||||
partial class NoPaymentMethodPropertyInOrder
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.1")
|
||||
.HasAnnotation("SqlServer:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq")
|
||||
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<string>("IdentityGuid")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IdentityGuid")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("buyers","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("cardtypes","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq")
|
||||
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<string>("Alias")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<int>("BuyerId");
|
||||
|
||||
b.Property<string>("CardHolderName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<string>("CardNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.Property<int>("CardTypeId");
|
||||
|
||||
b.Property<DateTime>("Expiration");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BuyerId");
|
||||
|
||||
b.HasIndex("CardTypeId");
|
||||
|
||||
b.ToTable("paymentmethods","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("City");
|
||||
|
||||
b.Property<string>("Country");
|
||||
|
||||
b.Property<string>("State");
|
||||
|
||||
b.Property<string>("Street");
|
||||
|
||||
b.Property<string>("ZipCode");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("address","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "orderseq")
|
||||
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<int?>("AddressId");
|
||||
|
||||
b.Property<int?>("BuyerId");
|
||||
|
||||
b.Property<DateTime>("OrderDate");
|
||||
|
||||
b.Property<int>("OrderStatusId");
|
||||
|
||||
b.Property<int?>("PaymentMethodId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AddressId");
|
||||
|
||||
b.HasIndex("BuyerId");
|
||||
|
||||
b.HasIndex("OrderStatusId");
|
||||
|
||||
b.HasIndex("PaymentMethodId");
|
||||
|
||||
b.ToTable("orders","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||
|
||||
b.Property<decimal>("Discount");
|
||||
|
||||
b.Property<int>("OrderId");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<int>("ProductId");
|
||||
|
||||
b.Property<string>("ProductName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<decimal>("UnitPrice");
|
||||
|
||||
b.Property<int>("Units");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.ToTable("orderItems","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("orderstatus","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.ClientRequest", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<DateTime>("Time");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("requests","ordering");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||
.WithMany("PaymentMethods")
|
||||
.HasForeignKey("BuyerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType")
|
||||
.WithMany()
|
||||
.HasForeignKey("CardTypeId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address")
|
||||
.WithMany()
|
||||
.HasForeignKey("AddressId");
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||
.WithMany()
|
||||
.HasForeignKey("BuyerId");
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderStatusId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod")
|
||||
.WithMany()
|
||||
.HasForeignKey("PaymentMethodId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
|
||||
.WithMany("OrderItems")
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ordering.API.Migrations
|
||||
{
|
||||
public partial class NoPaymentMethodPropertyInOrder : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ namespace Ordering.API.Migrations
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752")
|
||||
.HasAnnotation("ProductVersion", "1.1.1")
|
||||
.HasAnnotation("SqlServer:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
.HasAnnotation("SqlServer:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||
@ -217,7 +217,7 @@ namespace Ordering.API.Migrations
|
||||
.WithMany()
|
||||
.HasForeignKey("AddressId");
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", "Buyer")
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||
.WithMany()
|
||||
.HasForeignKey("BuyerId");
|
||||
|
||||
@ -226,7 +226,7 @@ namespace Ordering.API.Migrations
|
||||
.HasForeignKey("OrderStatusId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", "PaymentMethod")
|
||||
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod")
|
||||
.WithMany()
|
||||
.HasForeignKey("PaymentMethodId");
|
||||
});
|
||||
|
@ -0,0 +1,19 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ordering.API.IntegrationEvents.Events
|
||||
{
|
||||
// Integration Events notes:
|
||||
// An Event is “something that has happened in the past”, therefore its name has to be
|
||||
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
|
||||
public class OrderStartedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public string UserId { get; }
|
||||
|
||||
public OrderStartedIntegrationEvent(string userId) =>
|
||||
UserId = userId;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ordering.API.IntegrationEvents
|
||||
{
|
||||
public interface IOrderingIntegrationEventService
|
||||
{
|
||||
Task SaveEventAndOrderingContextChangesAsync(IntegrationEvent evt);
|
||||
Task PublishThroughEventBusAsync(IntegrationEvent evt);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ordering.API.IntegrationEvents
|
||||
{
|
||||
public class OrderingIntegrationEventService : IOrderingIntegrationEventService
|
||||
{
|
||||
private readonly Func<DbConnection, IIntegrationEventLogService> _integrationEventLogServiceFactory;
|
||||
private readonly IEventBus _eventBus;
|
||||
private readonly OrderingContext _orderingContext;
|
||||
private readonly IIntegrationEventLogService _eventLogService;
|
||||
|
||||
public OrderingIntegrationEventService (IEventBus eventBus, OrderingContext orderingContext,
|
||||
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
||||
{
|
||||
_orderingContext = orderingContext ?? throw new ArgumentNullException(nameof(orderingContext));
|
||||
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
|
||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||
_eventLogService = _integrationEventLogServiceFactory(_orderingContext.Database.GetDbConnection());
|
||||
}
|
||||
|
||||
public async Task PublishThroughEventBusAsync(IntegrationEvent evt)
|
||||
{
|
||||
_eventBus.Publish(evt);
|
||||
await _eventLogService.MarkEventAsPublishedAsync(evt);
|
||||
}
|
||||
|
||||
public async Task SaveEventAndOrderingContextChangesAsync(IntegrationEvent evt)
|
||||
{
|
||||
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
||||
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||
await ResilientTransaction.New(_orderingContext)
|
||||
.ExecuteAsync(async () => {
|
||||
// Achieving atomicity between original ordering database operation and the IntegrationEventLog thanks to a local transaction
|
||||
await _orderingContext.SaveChangesAsync();
|
||||
await _eventLogService.SaveEventAsync(evt, _orderingContext.Database.CurrentTransaction.GetDbTransaction());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj" />
|
||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||
@ -38,16 +41,18 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.0" />
|
||||
@ -73,4 +78,9 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Infrastructure\IntegrationEventMigrations\" />
|
||||
<Folder Include="IntegrationEvents\EventHandling\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -4,6 +4,7 @@
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using global::Ordering.API.Infrastructure.Middlewares;
|
||||
using global::Ordering.API.IntegrationEvents;
|
||||
using Infrastructure;
|
||||
using Infrastructure.Auth;
|
||||
using Infrastructure.AutofacModules;
|
||||
@ -12,12 +13,17 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.HealthChecks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ordering.Infrastructure;
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Reflection;
|
||||
|
||||
public class Startup
|
||||
@ -53,9 +59,9 @@
|
||||
|
||||
services.AddHealthChecks(checks =>
|
||||
{
|
||||
checks.AddSqlCheck("Ordering_Db", Configuration["ConnectionString"]);
|
||||
checks.AddSqlCheck("OrderingDb", Configuration["ConnectionString"]);
|
||||
});
|
||||
|
||||
|
||||
services.AddEntityFrameworkSqlServer()
|
||||
.AddDbContext<OrderingContext>(options =>
|
||||
{
|
||||
@ -95,7 +101,11 @@
|
||||
// Add application services.
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddTransient<IIdentityService, IdentityService>();
|
||||
|
||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
||||
services.AddSingleton<IEventBus>(new EventBusRabbitMQ(Configuration["EventBusConnection"]));
|
||||
services.AddOptions();
|
||||
|
||||
//configure autofac
|
||||
@ -126,6 +136,12 @@
|
||||
.UseSwaggerUi();
|
||||
|
||||
OrderingContextSeed.SeedAsync(app).Wait();
|
||||
|
||||
var integrationEventLogContext = new IntegrationEventLogContext(
|
||||
new DbContextOptionsBuilder<IntegrationEventLogContext>()
|
||||
.UseSqlServer(Configuration["ConnectionString"], b => b.MigrationsAssembly("Ordering.API"))
|
||||
.Options);
|
||||
integrationEventLogContext.Database.Migrate();
|
||||
}
|
||||
|
||||
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||
|
@ -7,7 +7,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
|
||||
public class PaymentMethod
|
||||
: Entity
|
||||
{
|
||||
private int _buyerId;
|
||||
private string _alias;
|
||||
private string _cardNumber;
|
||||
private string _securityNumber;
|
||||
|
@ -18,7 +18,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
||||
|
||||
public Address Address { get; private set; }
|
||||
|
||||
public Buyer Buyer { get; private set; }
|
||||
private int? _buyerId;
|
||||
|
||||
public OrderStatus OrderStatus { get; private set; }
|
||||
@ -37,7 +36,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
||||
// It's much cheaper than .ToList() because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance)
|
||||
//https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx
|
||||
|
||||
public PaymentMethod PaymentMethod { get; private set; }
|
||||
private int? _paymentMethodId;
|
||||
|
||||
protected Order() { }
|
||||
|
@ -12,7 +12,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
||||
// aligned with DDD Aggregates and Domain Entities (Instead of properties and property collections)
|
||||
private string _productName;
|
||||
private string _pictureUrl;
|
||||
private int _orderId;
|
||||
private decimal _unitPrice;
|
||||
private decimal _discount;
|
||||
private int _units;
|
||||
|
@ -16,8 +16,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -62,6 +62,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
||||
{
|
||||
addressConfiguration.ToTable("address", DEFAULT_SCHEMA);
|
||||
|
||||
// DDD Pattern comment: Implementing the Address Id as "Shadow property"
|
||||
// becuase the Address is a Value-Object (VO) and an Id (Identity) is not desired for a VO
|
||||
// EF Core just needs the Id so it is capable to store it in a database table
|
||||
// See: https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties
|
||||
addressConfiguration.Property<int>("Id")
|
||||
.IsRequired();
|
||||
|
||||
@ -154,13 +158,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
||||
//Set as Field (New since EF 1.1) to access the OrderItem collection property through its field
|
||||
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
|
||||
|
||||
orderConfiguration.HasOne(o => o.PaymentMethod)
|
||||
orderConfiguration.HasOne<PaymentMethod>()
|
||||
.WithMany()
|
||||
.HasForeignKey("PaymentMethodId")
|
||||
.IsRequired(false)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
orderConfiguration.HasOne(o => o.Buyer)
|
||||
orderConfiguration.HasOne<Buyer>()
|
||||
.WithMany()
|
||||
.IsRequired(false)
|
||||
.HasForeignKey("BuyerId");
|
||||
|
@ -45,14 +45,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
var user = _appUserParser.Parse(HttpContext.User);
|
||||
await _orderSvc.CreateOrder(model);
|
||||
|
||||
//Empty basket for current user.
|
||||
await _basketSvc.CleanBasket(user);
|
||||
|
||||
//Redirect to historic list.
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
catch(BrokenCircuitException ex)
|
||||
catch(BrokenCircuitException)
|
||||
{
|
||||
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on");
|
||||
}
|
||||
|
10
src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs
Normal file
10
src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
||||
{
|
||||
public interface IResilientHttpClientFactory
|
||||
{
|
||||
ResilientHttpClient CreateResilientHttpClient();
|
||||
}
|
||||
}
|
59
src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs
Normal file
59
src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Polly;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
||||
{
|
||||
public class ResilientHttpClientFactory : IResilientHttpClientFactory
|
||||
{
|
||||
private readonly ILogger<ResilientHttpClient> _logger;
|
||||
|
||||
public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger)
|
||||
=>_logger = logger;
|
||||
|
||||
public ResilientHttpClient CreateResilientHttpClient()
|
||||
=> new ResilientHttpClient(CreatePolicies(), _logger);
|
||||
|
||||
|
||||
private Policy[] CreatePolicies()
|
||||
=> new Policy[]
|
||||
{
|
||||
Policy.Handle<HttpRequestException>()
|
||||
.WaitAndRetryAsync(
|
||||
// number of retries
|
||||
6,
|
||||
// exponential backofff
|
||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||
// on retry
|
||||
(exception, timeSpan, retryCount, context) =>
|
||||
{
|
||||
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
|
||||
$"of {context.PolicyKey} " +
|
||||
$"at {context.ExecutionKey}, " +
|
||||
$"due to: {exception}.";
|
||||
_logger.LogWarning(msg);
|
||||
_logger.LogDebug(msg);
|
||||
}),
|
||||
Policy.Handle<HttpRequestException>()
|
||||
.CircuitBreakerAsync(
|
||||
// number of exceptions before breaking circuit
|
||||
5,
|
||||
// time circuit opened before retry
|
||||
TimeSpan.FromMinutes(1),
|
||||
(exception, duration) =>
|
||||
{
|
||||
// on circuit opened
|
||||
_logger.LogTrace("Circuit breaker opened");
|
||||
},
|
||||
() =>
|
||||
{
|
||||
// on circuit closed
|
||||
_logger.LogTrace("Circuit breaker reset");
|
||||
})};
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
@ -7,7 +8,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using WebMVC.Services.Utilities;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@ -6,7 +7,6 @@ using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using WebMVC.Services.Utilities;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using Microsoft.Extensions.Options;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using WebMVC.Services.Utilities;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
|
@ -14,8 +14,9 @@ using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Options;
|
||||
using WebMVC.Services.Utilities;
|
||||
using Microsoft.Extensions.HealthChecks;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
||||
using Microsoft.eShopOnContainers.WebMVC.Infrastructure;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.WebMVC
|
||||
{
|
||||
@ -48,7 +49,10 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
||||
|
||||
services.AddHealthChecks(checks =>
|
||||
{
|
||||
checks.AddUrlCheck(Configuration["CallBackUrl"]);
|
||||
checks.AddUrlCheck(Configuration["CatalogUrl"]);
|
||||
checks.AddUrlCheck(Configuration["OrderingUrl"]);
|
||||
checks.AddUrlCheck(Configuration["BasketUrl"]);
|
||||
checks.AddUrlCheck(Configuration["IdentityUrl"]);
|
||||
});
|
||||
|
||||
// Add application services.
|
||||
@ -58,15 +62,16 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
||||
services.AddTransient<IBasketService, BasketService>();
|
||||
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
|
||||
|
||||
if(Configuration.GetValue<string>("ActivateCircuitBreaker") == bool.TrueString)
|
||||
if (Configuration.GetValue<string>("UseResilientHttp") == bool.TrueString)
|
||||
{
|
||||
services.AddTransient<IHttpClient, ResilientHttpClient>();
|
||||
services.AddTransient<IResilientHttpClientFactory, ResilientHttpClientFactory>();
|
||||
services.AddTransient<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient());
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddTransient<IHttpClient, StandardHttpClient>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
@ -109,15 +114,10 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
||||
ResponseType = "code id_token",
|
||||
SaveTokens = true,
|
||||
GetClaimsFromUserInfoEndpoint = true,
|
||||
RequireHttpsMetadata = false,
|
||||
RequireHttpsMetadata = false,
|
||||
Scope = { "openid", "profile", "orders", "basket" }
|
||||
};
|
||||
|
||||
oidcOptions.Scope.Clear();
|
||||
oidcOptions.Scope.Add("openid");
|
||||
oidcOptions.Scope.Add("profile");
|
||||
oidcOptions.Scope.Add("orders");
|
||||
oidcOptions.Scope.Add("basket");
|
||||
|
||||
//Wait untill identity service is ready on compose.
|
||||
app.UseOpenIdConnectAuthentication(oidcOptions);
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
<div class="esh-basket-items--border row">
|
||||
@if (item.OldUnitPrice != 0)
|
||||
{
|
||||
<div class="alert alert-warning esh-basket-margin12" role="alert"> Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was @item.OldUnitPrice $</div>
|
||||
<div class="alert alert-warning esh-basket-margin12" role="alert"> Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ @item.OldUnitPrice </div>
|
||||
}
|
||||
</div>
|
||||
<br/>
|
||||
|
@ -13,6 +13,13 @@
|
||||
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="wwwroot\lib\bootstrap\**" />
|
||||
<Content Remove="wwwroot\lib\bootstrap\**" />
|
||||
<EmbeddedResource Remove="wwwroot\lib\bootstrap\**" />
|
||||
<None Remove="wwwroot\lib\bootstrap\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.0" />
|
||||
@ -32,7 +39,6 @@
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Polly" Version="5.0.6" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.1.0" />
|
||||
@ -55,6 +61,7 @@
|
||||
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj" />
|
||||
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||
<ProjectReference Include="..\..\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -63,4 +70,8 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\lib\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -4,7 +4,7 @@
|
||||
"BasketUrl": "http://localhost:5103",
|
||||
"IdentityUrl": "http://localhost:5105",
|
||||
"CallBackUrl": "http://localhost:5100/",
|
||||
"ActivateCircuitBreaker": "True",
|
||||
"UseResilientHttp": "True",
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
|
@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "bootstrap",
|
||||
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
|
||||
"keywords": [
|
||||
"css",
|
||||
"js",
|
||||
"sass",
|
||||
"mobile-first",
|
||||
"responsive",
|
||||
"front-end",
|
||||
"framework",
|
||||
"web"
|
||||
],
|
||||
"homepage": "https://getbootstrap.com",
|
||||
"license": "MIT",
|
||||
"moduleType": "globals",
|
||||
"main": [
|
||||
"scss/bootstrap.scss",
|
||||
"dist/js/bootstrap.js"
|
||||
],
|
||||
"ignore": [
|
||||
"/.*",
|
||||
"_config.yml",
|
||||
"CNAME",
|
||||
"composer.json",
|
||||
"CONTRIBUTING.md",
|
||||
"docs",
|
||||
"js/tests",
|
||||
"test-infra"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "1.9.1 - 3",
|
||||
"tether": "^1.3.7"
|
||||
},
|
||||
"version": "4.0.0-alpha.5",
|
||||
"_release": "4.0.0-alpha.5",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v4.0.0-alpha.5",
|
||||
"commit": "b5890e0608ad2262cde4a38e90afa19f1cb5d852"
|
||||
},
|
||||
"_source": "https://github.com/twbs/bootstrap.git",
|
||||
"_target": "4.0.0-alpha.5",
|
||||
"_originalSource": "bootstrap"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
Bootstrap uses [GitHub's Releases feature](https://github.com/blog/1547-release-your-software) for its changelogs.
|
||||
|
||||
See [the Releases section of our GitHub project](https://github.com/twbs/bootstrap/releases) for changelogs for each release version of Bootstrap.
|
||||
|
||||
Release announcement posts on [the official Bootstrap blog](https://blog.getbootstrap.com) contain summaries of the most noteworthy changes made in each release.
|
@ -1,8 +0,0 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
group :development, :test do
|
||||
gem 'jekyll', '~> 3.3.0'
|
||||
gem 'jekyll-redirect-from', '~> 0.11.0'
|
||||
gem 'jekyll-sitemap', '~> 0.11.0'
|
||||
gem 'scss_lint', '~> 0.50.2'
|
||||
end
|
@ -1,56 +0,0 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.4.0)
|
||||
colorator (1.1.0)
|
||||
ffi (1.9.14)
|
||||
forwardable-extended (2.6.0)
|
||||
jekyll (3.3.0)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
jekyll-sass-converter (~> 1.0)
|
||||
jekyll-watch (~> 1.1)
|
||||
kramdown (~> 1.3)
|
||||
liquid (~> 3.0)
|
||||
mercenary (~> 0.3.3)
|
||||
pathutil (~> 0.9)
|
||||
rouge (~> 1.7)
|
||||
safe_yaml (~> 1.0)
|
||||
jekyll-redirect-from (0.11.0)
|
||||
jekyll (>= 2.0)
|
||||
jekyll-sass-converter (1.4.0)
|
||||
sass (~> 3.4)
|
||||
jekyll-sitemap (0.11.0)
|
||||
addressable (~> 2.4.0)
|
||||
jekyll-watch (1.5.0)
|
||||
listen (~> 3.0, < 3.1)
|
||||
kramdown (1.12.0)
|
||||
liquid (3.0.6)
|
||||
listen (3.0.8)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
mercenary (0.3.6)
|
||||
pathutil (0.14.0)
|
||||
forwardable-extended (~> 2.6)
|
||||
rake (11.3.0)
|
||||
rb-fsevent (0.9.7)
|
||||
rb-inotify (0.9.7)
|
||||
ffi (>= 0.5.0)
|
||||
rouge (1.11.1)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.4.22)
|
||||
scss_lint (0.50.2)
|
||||
rake (>= 0.9, < 12)
|
||||
sass (~> 3.4.20)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
jekyll (~> 3.3.0)
|
||||
jekyll-redirect-from (~> 0.11.0)
|
||||
jekyll-sitemap (~> 0.11.0)
|
||||
scss_lint (~> 0.50.2)
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.2
|
@ -1,405 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap's Gruntfile
|
||||
* https://getbootstrap.com
|
||||
* Copyright 2013-2016 The Bootstrap Authors
|
||||
* Copyright 2013-2016 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
module.exports = function (grunt) {
|
||||
'use strict';
|
||||
|
||||
// Force use of Unix newlines
|
||||
grunt.util.linefeed = '\n';
|
||||
|
||||
RegExp.quote = function (string) {
|
||||
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
};
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var isTravis = require('is-travis');
|
||||
|
||||
var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' });
|
||||
|
||||
Object.keys(configBridge.paths).forEach(function (key) {
|
||||
configBridge.paths[key].forEach(function (val, i, arr) {
|
||||
arr[i] = path.join('./docs', val);
|
||||
});
|
||||
});
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
|
||||
// Metadata.
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
banner: '/*!\n' +
|
||||
' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
|
||||
' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
|
||||
' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' +
|
||||
' */\n',
|
||||
jqueryCheck: 'if (typeof jQuery === \'undefined\') {\n' +
|
||||
' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\')\n' +
|
||||
'}\n',
|
||||
jqueryVersionCheck: '+function ($) {\n' +
|
||||
' var version = $.fn.jquery.split(\' \')[0].split(\'.\')\n' +
|
||||
' if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] >= 4)) {\n' +
|
||||
' throw new Error(\'Bootstrap\\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0\')\n' +
|
||||
' }\n' +
|
||||
'}(jQuery);\n\n',
|
||||
|
||||
// Task configuration.
|
||||
clean: {
|
||||
dist: 'dist',
|
||||
docs: 'docs/dist'
|
||||
},
|
||||
|
||||
// JS build configuration
|
||||
babel: {
|
||||
dev: {
|
||||
options: {
|
||||
sourceMap: true
|
||||
},
|
||||
files: {
|
||||
'js/dist/util.js' : 'js/src/util.js',
|
||||
'js/dist/alert.js' : 'js/src/alert.js',
|
||||
'js/dist/button.js' : 'js/src/button.js',
|
||||
'js/dist/carousel.js' : 'js/src/carousel.js',
|
||||
'js/dist/collapse.js' : 'js/src/collapse.js',
|
||||
'js/dist/dropdown.js' : 'js/src/dropdown.js',
|
||||
'js/dist/modal.js' : 'js/src/modal.js',
|
||||
'js/dist/scrollspy.js' : 'js/src/scrollspy.js',
|
||||
'js/dist/tab.js' : 'js/src/tab.js',
|
||||
'js/dist/tooltip.js' : 'js/src/tooltip.js',
|
||||
'js/dist/popover.js' : 'js/src/popover.js'
|
||||
}
|
||||
},
|
||||
dist: {
|
||||
options: {
|
||||
extends: '../../js/.babelrc'
|
||||
},
|
||||
files: {
|
||||
'<%= concat.bootstrap.dest %>' : '<%= concat.bootstrap.dest %>'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stamp: {
|
||||
options: {
|
||||
banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>\n+function () {\n',
|
||||
footer: '\n}();'
|
||||
},
|
||||
bootstrap: {
|
||||
files: {
|
||||
src: '<%= concat.bootstrap.dest %>'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
concat: {
|
||||
options: {
|
||||
// Custom function to remove all export and import statements
|
||||
process: function (src) {
|
||||
return src.replace(/^(export|import).*/gm, '');
|
||||
}
|
||||
},
|
||||
bootstrap: {
|
||||
src: [
|
||||
'js/src/util.js',
|
||||
'js/src/alert.js',
|
||||
'js/src/button.js',
|
||||
'js/src/carousel.js',
|
||||
'js/src/collapse.js',
|
||||
'js/src/dropdown.js',
|
||||
'js/src/modal.js',
|
||||
'js/src/scrollspy.js',
|
||||
'js/src/tab.js',
|
||||
'js/src/tooltip.js',
|
||||
'js/src/popover.js'
|
||||
],
|
||||
dest: 'dist/js/<%= pkg.name %>.js'
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
compress: {
|
||||
warnings: false
|
||||
},
|
||||
mangle: true,
|
||||
preserveComments: /^!|@preserve|@license|@cc_on/i
|
||||
},
|
||||
core: {
|
||||
src: '<%= concat.bootstrap.dest %>',
|
||||
dest: 'dist/js/<%= pkg.name %>.min.js'
|
||||
},
|
||||
docsJs: {
|
||||
src: configBridge.paths.docsJs,
|
||||
dest: 'docs/assets/js/docs.min.js'
|
||||
}
|
||||
},
|
||||
|
||||
qunit: {
|
||||
options: {
|
||||
inject: 'js/tests/unit/phantom.js'
|
||||
},
|
||||
files: 'js/tests/index.html'
|
||||
},
|
||||
|
||||
// CSS build configuration
|
||||
scsslint: {
|
||||
options: {
|
||||
bundleExec: true,
|
||||
config: 'scss/.scss-lint.yml',
|
||||
reporterOutput: null
|
||||
},
|
||||
core: {
|
||||
src: ['scss/*.scss', '!scss/_normalize.scss']
|
||||
},
|
||||
docs: {
|
||||
src: ['docs/assets/scss/*.scss', '!docs/assets/scss/docs.scss']
|
||||
}
|
||||
},
|
||||
|
||||
cssmin: {
|
||||
options: {
|
||||
compatibility: 'ie9,-properties.zeroUnits',
|
||||
sourceMap: true,
|
||||
// sourceMapInlineSources: true,
|
||||
advanced: false
|
||||
},
|
||||
core: {
|
||||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: 'dist/css',
|
||||
src: ['*.css', '!*.min.css'],
|
||||
dest: 'dist/css',
|
||||
ext: '.min.css'
|
||||
}
|
||||
]
|
||||
},
|
||||
docs: {
|
||||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: 'docs/assets/css',
|
||||
src: ['*.css', '!*.min.css'],
|
||||
dest: 'docs/assets/css',
|
||||
ext: '.min.css'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
copy: {
|
||||
docs: {
|
||||
expand: true,
|
||||
cwd: 'dist/',
|
||||
src: [
|
||||
'**/*'
|
||||
],
|
||||
dest: 'docs/dist/'
|
||||
}
|
||||
},
|
||||
|
||||
connect: {
|
||||
server: {
|
||||
options: {
|
||||
port: 3000,
|
||||
base: '.'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
jekyll: {
|
||||
options: {
|
||||
bundleExec: true,
|
||||
config: '_config.yml',
|
||||
incremental: false
|
||||
},
|
||||
docs: {},
|
||||
github: {
|
||||
options: {
|
||||
raw: 'github: true'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
htmllint: {
|
||||
options: {
|
||||
ignore: [
|
||||
'Attribute “autocomplete” is only allowed when the input type is “color”, “date”, “datetime”, “datetime-local”, “email”, “hidden”, “month”, “number”, “password”, “range”, “search”, “tel”, “text”, “time”, “url”, or “week”.',
|
||||
'Attribute “autocomplete” not allowed on element “button” at this point.',
|
||||
'Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).',
|
||||
'Element “div” not allowed as child of element “progress” in this context. (Suppressing further errors from this subtree.)',
|
||||
'Element “img” is missing required attribute “src”.',
|
||||
'The “color” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
|
||||
'The “date” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
|
||||
'The “datetime” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
|
||||
'The “datetime-local” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
|
||||
'The “month” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
|
||||
'The “time” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
|
||||
'The “week” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.'
|
||||
]
|
||||
},
|
||||
src: ['_gh_pages/**/*.html', 'js/tests/visual/*.html']
|
||||
},
|
||||
|
||||
watch: {
|
||||
src: {
|
||||
files: '<%= concat.bootstrap.src %>',
|
||||
tasks: ['babel:dev']
|
||||
},
|
||||
sass: {
|
||||
files: 'scss/**/*.scss',
|
||||
tasks: ['dist-css', 'docs']
|
||||
},
|
||||
docs: {
|
||||
files: 'docs/assets/scss/**/*.scss',
|
||||
tasks: ['dist-css', 'docs']
|
||||
}
|
||||
},
|
||||
|
||||
'saucelabs-qunit': {
|
||||
all: {
|
||||
options: {
|
||||
build: process.env.TRAVIS_JOB_ID,
|
||||
concurrency: 10,
|
||||
maxRetries: 3,
|
||||
maxPollRetries: 4,
|
||||
urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'],
|
||||
browsers: grunt.file.readYAML('grunt/sauce_browsers.yml')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
exec: {
|
||||
postcss: {
|
||||
command: 'npm run postcss'
|
||||
},
|
||||
'postcss-docs': {
|
||||
command: 'npm run postcss-docs'
|
||||
},
|
||||
htmlhint: {
|
||||
command: 'npm run htmlhint'
|
||||
},
|
||||
'upload-preview': {
|
||||
command: './grunt/upload-preview.sh'
|
||||
}
|
||||
},
|
||||
|
||||
buildcontrol: {
|
||||
options: {
|
||||
dir: '_gh_pages',
|
||||
commit: true,
|
||||
push: true,
|
||||
message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
|
||||
},
|
||||
pages: {
|
||||
options: {
|
||||
remote: 'git@github.com:twbs/derpstrap.git',
|
||||
branch: 'gh-pages'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
compress: {
|
||||
main: {
|
||||
options: {
|
||||
archive: 'bootstrap-<%= pkg.version %>-dist.zip',
|
||||
mode: 'zip',
|
||||
level: 9,
|
||||
pretty: true
|
||||
},
|
||||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: 'dist/',
|
||||
src: ['**'],
|
||||
dest: 'bootstrap-<%= pkg.version %>-dist'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
// These plugins provide necessary tasks.
|
||||
require('load-grunt-tasks')(grunt, { scope: 'devDependencies',
|
||||
// Exclude Sass compilers. We choose the one to load later on.
|
||||
pattern: ['grunt-*', '!grunt-sass', '!grunt-contrib-sass'] });
|
||||
require('time-grunt')(grunt);
|
||||
|
||||
// Docs HTML validation task
|
||||
grunt.registerTask('validate-html', ['jekyll:docs', 'htmllint', 'exec:htmlhint']);
|
||||
|
||||
var runSubset = function (subset) {
|
||||
return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset;
|
||||
};
|
||||
var isUndefOrNonZero = function (val) {
|
||||
return val === undefined || val !== '0';
|
||||
};
|
||||
|
||||
// Test task.
|
||||
var testSubtasks = [];
|
||||
// Skip core tests if running a different subset of the test suite
|
||||
if (runSubset('core') &&
|
||||
// Skip core tests if this is a Savage build
|
||||
process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') {
|
||||
testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'test-scss', 'qunit', 'docs']);
|
||||
}
|
||||
// Skip HTML validation if running a different subset of the test suite
|
||||
if (runSubset('validate-html') &&
|
||||
isTravis &&
|
||||
// Skip HTML5 validator when [skip validator] is in the commit message
|
||||
isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) {
|
||||
testSubtasks.push('validate-html');
|
||||
}
|
||||
// Only run Sauce Labs tests if there's a Sauce access key
|
||||
if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
|
||||
// Skip Sauce if running a different subset of the test suite
|
||||
runSubset('sauce-js-unit')) {
|
||||
testSubtasks = testSubtasks.concat(['dist', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs', 'exec:upload-preview']);
|
||||
// Skip Sauce on Travis when [skip sauce] is in the commit message
|
||||
if (isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) {
|
||||
testSubtasks.push('connect');
|
||||
testSubtasks.push('saucelabs-qunit');
|
||||
}
|
||||
}
|
||||
grunt.registerTask('test', testSubtasks);
|
||||
|
||||
// JS distribution task.
|
||||
grunt.registerTask('dist-js', ['babel:dev', 'concat', 'babel:dist', 'stamp', 'uglify:core']);
|
||||
|
||||
grunt.registerTask('test-scss', ['scsslint:core']);
|
||||
|
||||
// CSS distribution task.
|
||||
// Supported Compilers: sass (Ruby) and libsass.
|
||||
(function (sassCompilerName) {
|
||||
require('./grunt/bs-sass-compile/' + sassCompilerName + '.js')(grunt);
|
||||
})(process.env.TWBS_SASS || 'libsass');
|
||||
// grunt.registerTask('sass-compile', ['sass:core', 'sass:extras', 'sass:docs']);
|
||||
grunt.registerTask('sass-compile', ['sass:core', 'sass:extras', 'sass:docs']);
|
||||
|
||||
grunt.registerTask('dist-css', ['sass-compile', 'exec:postcss', 'cssmin:core', 'cssmin:docs']);
|
||||
|
||||
// Full distribution task.
|
||||
grunt.registerTask('dist', ['clean:dist', 'dist-css', 'dist-js']);
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('default', ['clean:dist', 'test']);
|
||||
|
||||
// Docs task.
|
||||
grunt.registerTask('docs-css', ['cssmin:docs', 'exec:postcss-docs']);
|
||||
grunt.registerTask('lint-docs-css', ['scsslint:docs']);
|
||||
grunt.registerTask('docs-js', ['uglify:docsJs']);
|
||||
grunt.registerTask('docs', ['lint-docs-css', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs']);
|
||||
grunt.registerTask('docs-github', ['jekyll:github']);
|
||||
|
||||
grunt.registerTask('prep-release', ['dist', 'docs', 'docs-github', 'compress']);
|
||||
|
||||
// Publish to GitHub
|
||||
grunt.registerTask('publish', ['buildcontrol:pages']);
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
Before opening an issue:
|
||||
|
||||
- [Search for duplicate or closed issues](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue)
|
||||
- [Validate](https://validator.w3.org/nu/) and [lint](https://github.com/twbs/bootlint#in-the-browser) any HTML to avoid common problems
|
||||
- Prepare a [reduced test case](https://css-tricks.com/reduced-test-cases/) for any bugs
|
||||
- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md)
|
||||
|
||||
When asking general "how to" questions:
|
||||
|
||||
- Please do not open an issue here
|
||||
- Instead, ask for help on [StackOverflow, IRC, or Slack](https://github.com/twbs/bootstrap/blob/master/README.md#community)
|
||||
|
||||
When reporting a bug, include:
|
||||
|
||||
- Operating system and version (Windows, Mac OS X, Android, iOS, Win10 Mobile)
|
||||
- Browser and version (Chrome, Firefox, Safari, IE, MS Edge, Opera 15+, Android Browser)
|
||||
- Reduced test cases and potential fixes using [JS Bin](https://jsbin.com)
|
||||
|
||||
When suggesting a feature, include:
|
||||
|
||||
- As much detail as possible for what we should add and why it's important to Bootstrap
|
||||
- Relevant links to prior art, screenshots, or live demos whenever possible
|
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2016 Twitter, Inc.
|
||||
Copyright (c) 2011-2016 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@ -1,135 +0,0 @@
|
||||
# [Bootstrap](https://getbootstrap.com)
|
||||
|
||||
[](https://bootstrap-slack.herokuapp.com)
|
||||

|
||||
[](https://www.npmjs.com/package/bootstrap)
|
||||
[](https://rubygems.org/gems/bootstrap)
|
||||
[](https://travis-ci.org/twbs/bootstrap)
|
||||
[](https://david-dm.org/twbs/bootstrap?type=dev)
|
||||
[](https://atmospherejs.com/twbs/bootstrap)
|
||||
[](https://packagist.org/packages/twbs/bootstrap)
|
||||
[](https://www.nuget.org/packages/bootstrap/4.0.0-alpha5)
|
||||
|
||||
[](https://saucelabs.com/u/bootstrap)
|
||||
|
||||
Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development, created by [Mark Otto](https://twitter.com/mdo) and [Jacob Thornton](https://twitter.com/fat), and maintained by the [core team](https://github.com/orgs/twbs/people) with the massive support and involvement of the community.
|
||||
|
||||
To get started, check out <https://getbootstrap.com>!
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Quick start](#quick-start)
|
||||
- [Bugs and feature requests](#bugs-and-feature-requests)
|
||||
- [Documentation](#documentation)
|
||||
- [Contributing](#contributing)
|
||||
- [Community](#community)
|
||||
- [Versioning](#versioning)
|
||||
- [Creators](#creators)
|
||||
- [Copyright and license](#copyright-and-license)
|
||||
|
||||
## Quick start
|
||||
|
||||
Several quick start options are available:
|
||||
|
||||
- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.0.0-alpha.5.zip)
|
||||
- Clone the repo: `git clone https://github.com/twbs/bootstrap.git`
|
||||
- Install with [npm](https://www.npmjs.com): `npm install bootstrap@4.0.0-alpha.5`
|
||||
- Install with [Meteor](https://www.meteor.com): `meteor add twbs:bootstrap@=4.0.0-alpha.5`
|
||||
- Install with [Composer](https://getcomposer.org): `composer require twbs/bootstrap`
|
||||
- Install with [Bower](https://bower.io): `bower install bootstrap#v4.0.0-alpha.5`
|
||||
- Install with [NuGet](https://www.nuget.org): CSS: `Install-Package bootstrap -Pre` Sass: `Install-Package bootstrap.sass -Pre` (`-Pre` is only required until Bootstrap v4 has a stable release).
|
||||
|
||||
Read the [Getting started page](https://getbootstrap.com/getting-started/) for information on the framework contents, templates and examples, and more.
|
||||
|
||||
### What's included
|
||||
|
||||
Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this:
|
||||
|
||||
```
|
||||
bootstrap/
|
||||
├── css/
|
||||
│ ├── bootstrap.css
|
||||
│ ├── bootstrap.css.map
|
||||
│ ├── bootstrap.min.css
|
||||
│ └── bootstrap.min.css.map
|
||||
└── js/
|
||||
├── bootstrap.js
|
||||
└── bootstrap.min.js
|
||||
```
|
||||
|
||||
We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). CSS [source maps](https://developer.chrome.com/devtools/docs/css-preprocessors) (`bootstrap.*.map`) are available for use with certain browsers' developer tools.
|
||||
|
||||
|
||||
## Bugs and feature requests
|
||||
|
||||
Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new).
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Bootstrap's documentation, included in this repo in the root directory, is built with [Jekyll](https://jekyllrb.com) and publicly hosted on GitHub Pages at <https://getbootstrap.com>. The docs may also be run locally.
|
||||
|
||||
### Running documentation locally
|
||||
|
||||
1. Run through the [tooling setup](https://github.com/twbs/bootstrap/blob/v4-dev/docs/getting-started/build-tools.md#tooling-setup) to install Jekyll (the site builder) and other Ruby dependencies with `bundle install`.
|
||||
2. Run `grunt` (or a specific set of Grunt tasks) to rebuild distributed CSS and JavaScript files, as well as our docs assets.
|
||||
3. From the root `/bootstrap` directory, run `bundle exec jekyll serve` in the command line.
|
||||
4. Open <http://localhost:9001> in your browser, and voilà.
|
||||
|
||||
Learn more about using Jekyll by reading its [documentation](https://jekyllrb.com/docs/home/).
|
||||
|
||||
### Documentation for previous releases
|
||||
|
||||
Documentation for v2.3.2 has been made available for the time being at <https://getbootstrap.com/2.3.2/> while folks transition to Bootstrap 3.
|
||||
|
||||
[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download.
|
||||
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development.
|
||||
|
||||
Moreover, if your pull request contains JavaScript patches or features, you must include [relevant unit tests](https://github.com/twbs/bootstrap/tree/master/js/tests). All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo).
|
||||
|
||||
Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at <http://editorconfig.org>.
|
||||
|
||||
|
||||
|
||||
## Community
|
||||
|
||||
Get updates on Bootstrap's development and chat with the project maintainers and community members.
|
||||
|
||||
- Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap).
|
||||
- Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com).
|
||||
- Join [the official Slack room](https://bootstrap-slack.herokuapp.com).
|
||||
- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##bootstrap` channel.
|
||||
- Implementation help may be found at Stack Overflow (tagged [`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4)).
|
||||
- Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability.
|
||||
|
||||
|
||||
|
||||
## Versioning
|
||||
|
||||
For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under [the Semantic Versioning guidelines](http://semver.org/). Sometimes we screw up, but we'll adhere to those rules whenever possible.
|
||||
|
||||
See [the Releases section of our GitHub project](https://github.com/twbs/bootstrap/releases) for changelogs for each release version of Bootstrap. Release announcement posts on [the official Bootstrap blog](https://blog.getbootstrap.com) contain summaries of the most noteworthy changes made in each release.
|
||||
|
||||
|
||||
## Creators
|
||||
|
||||
**Mark Otto**
|
||||
|
||||
- <https://twitter.com/mdo>
|
||||
- <https://github.com/mdo>
|
||||
|
||||
**Jacob Thornton**
|
||||
|
||||
- <https://twitter.com/fat>
|
||||
- <https://github.com/fat>
|
||||
|
||||
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Code and documentation copyright 2011-2016 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/master/LICENSE). Docs released under [Creative Commons](https://github.com/twbs/bootstrap/blob/master/docs/LICENSE).
|
@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "bootstrap",
|
||||
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
|
||||
"keywords": [
|
||||
"css",
|
||||
"js",
|
||||
"sass",
|
||||
"mobile-first",
|
||||
"responsive",
|
||||
"front-end",
|
||||
"framework",
|
||||
"web"
|
||||
],
|
||||
"homepage": "https://getbootstrap.com",
|
||||
"license": "MIT",
|
||||
"moduleType": "globals",
|
||||
"main": [
|
||||
"scss/bootstrap.scss",
|
||||
"dist/js/bootstrap.js"
|
||||
],
|
||||
"ignore": [
|
||||
"/.*",
|
||||
"_config.yml",
|
||||
"CNAME",
|
||||
"composer.json",
|
||||
"CONTRIBUTING.md",
|
||||
"docs",
|
||||
"js/tests",
|
||||
"test-infra"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "1.9.1 - 3",
|
||||
"tether": "^1.3.7"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,996 +0,0 @@
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.container::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.container {
|
||||
width: 540px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
width: 720px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
width: 960px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
width: 1140px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.container-fluid::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
.row::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.row {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.row {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.row {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.row {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
.col-xs, .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-sm, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-md, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-lg, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-xl, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 {
|
||||
position: relative;
|
||||
min-height: 1px;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.col-xs, .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-sm, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-md, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-lg, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-xl, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.col-xs, .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-sm, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-md, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-lg, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-xl, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.col-xs, .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-sm, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-md, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-lg, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-xl, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.col-xs, .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-sm, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-md, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-lg, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-xl, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.col-xs-1 {
|
||||
float: left;
|
||||
width: 8.333333%;
|
||||
}
|
||||
|
||||
.col-xs-2 {
|
||||
float: left;
|
||||
width: 16.666667%;
|
||||
}
|
||||
|
||||
.col-xs-3 {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.col-xs-4 {
|
||||
float: left;
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.col-xs-5 {
|
||||
float: left;
|
||||
width: 41.666667%;
|
||||
}
|
||||
|
||||
.col-xs-6 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.col-xs-7 {
|
||||
float: left;
|
||||
width: 58.333333%;
|
||||
}
|
||||
|
||||
.col-xs-8 {
|
||||
float: left;
|
||||
width: 66.666667%;
|
||||
}
|
||||
|
||||
.col-xs-9 {
|
||||
float: left;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.col-xs-10 {
|
||||
float: left;
|
||||
width: 83.333333%;
|
||||
}
|
||||
|
||||
.col-xs-11 {
|
||||
float: left;
|
||||
width: 91.666667%;
|
||||
}
|
||||
|
||||
.col-xs-12 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pull-xs-0 {
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.pull-xs-1 {
|
||||
right: 8.333333%;
|
||||
}
|
||||
|
||||
.pull-xs-2 {
|
||||
right: 16.666667%;
|
||||
}
|
||||
|
||||
.pull-xs-3 {
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
.pull-xs-4 {
|
||||
right: 33.333333%;
|
||||
}
|
||||
|
||||
.pull-xs-5 {
|
||||
right: 41.666667%;
|
||||
}
|
||||
|
||||
.pull-xs-6 {
|
||||
right: 50%;
|
||||
}
|
||||
|
||||
.pull-xs-7 {
|
||||
right: 58.333333%;
|
||||
}
|
||||
|
||||
.pull-xs-8 {
|
||||
right: 66.666667%;
|
||||
}
|
||||
|
||||
.pull-xs-9 {
|
||||
right: 75%;
|
||||
}
|
||||
|
||||
.pull-xs-10 {
|
||||
right: 83.333333%;
|
||||
}
|
||||
|
||||
.pull-xs-11 {
|
||||
right: 91.666667%;
|
||||
}
|
||||
|
||||
.pull-xs-12 {
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.push-xs-0 {
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.push-xs-1 {
|
||||
left: 8.333333%;
|
||||
}
|
||||
|
||||
.push-xs-2 {
|
||||
left: 16.666667%;
|
||||
}
|
||||
|
||||
.push-xs-3 {
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
.push-xs-4 {
|
||||
left: 33.333333%;
|
||||
}
|
||||
|
||||
.push-xs-5 {
|
||||
left: 41.666667%;
|
||||
}
|
||||
|
||||
.push-xs-6 {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.push-xs-7 {
|
||||
left: 58.333333%;
|
||||
}
|
||||
|
||||
.push-xs-8 {
|
||||
left: 66.666667%;
|
||||
}
|
||||
|
||||
.push-xs-9 {
|
||||
left: 75%;
|
||||
}
|
||||
|
||||
.push-xs-10 {
|
||||
left: 83.333333%;
|
||||
}
|
||||
|
||||
.push-xs-11 {
|
||||
left: 91.666667%;
|
||||
}
|
||||
|
||||
.push-xs-12 {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.offset-xs-1 {
|
||||
margin-left: 8.333333%;
|
||||
}
|
||||
|
||||
.offset-xs-2 {
|
||||
margin-left: 16.666667%;
|
||||
}
|
||||
|
||||
.offset-xs-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
.offset-xs-4 {
|
||||
margin-left: 33.333333%;
|
||||
}
|
||||
|
||||
.offset-xs-5 {
|
||||
margin-left: 41.666667%;
|
||||
}
|
||||
|
||||
.offset-xs-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.offset-xs-7 {
|
||||
margin-left: 58.333333%;
|
||||
}
|
||||
|
||||
.offset-xs-8 {
|
||||
margin-left: 66.666667%;
|
||||
}
|
||||
|
||||
.offset-xs-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
|
||||
.offset-xs-10 {
|
||||
margin-left: 83.333333%;
|
||||
}
|
||||
|
||||
.offset-xs-11 {
|
||||
margin-left: 91.666667%;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.col-sm-1 {
|
||||
float: left;
|
||||
width: 8.333333%;
|
||||
}
|
||||
.col-sm-2 {
|
||||
float: left;
|
||||
width: 16.666667%;
|
||||
}
|
||||
.col-sm-3 {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
.col-sm-4 {
|
||||
float: left;
|
||||
width: 33.333333%;
|
||||
}
|
||||
.col-sm-5 {
|
||||
float: left;
|
||||
width: 41.666667%;
|
||||
}
|
||||
.col-sm-6 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
.col-sm-7 {
|
||||
float: left;
|
||||
width: 58.333333%;
|
||||
}
|
||||
.col-sm-8 {
|
||||
float: left;
|
||||
width: 66.666667%;
|
||||
}
|
||||
.col-sm-9 {
|
||||
float: left;
|
||||
width: 75%;
|
||||
}
|
||||
.col-sm-10 {
|
||||
float: left;
|
||||
width: 83.333333%;
|
||||
}
|
||||
.col-sm-11 {
|
||||
float: left;
|
||||
width: 91.666667%;
|
||||
}
|
||||
.col-sm-12 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
.pull-sm-0 {
|
||||
right: auto;
|
||||
}
|
||||
.pull-sm-1 {
|
||||
right: 8.333333%;
|
||||
}
|
||||
.pull-sm-2 {
|
||||
right: 16.666667%;
|
||||
}
|
||||
.pull-sm-3 {
|
||||
right: 25%;
|
||||
}
|
||||
.pull-sm-4 {
|
||||
right: 33.333333%;
|
||||
}
|
||||
.pull-sm-5 {
|
||||
right: 41.666667%;
|
||||
}
|
||||
.pull-sm-6 {
|
||||
right: 50%;
|
||||
}
|
||||
.pull-sm-7 {
|
||||
right: 58.333333%;
|
||||
}
|
||||
.pull-sm-8 {
|
||||
right: 66.666667%;
|
||||
}
|
||||
.pull-sm-9 {
|
||||
right: 75%;
|
||||
}
|
||||
.pull-sm-10 {
|
||||
right: 83.333333%;
|
||||
}
|
||||
.pull-sm-11 {
|
||||
right: 91.666667%;
|
||||
}
|
||||
.pull-sm-12 {
|
||||
right: 100%;
|
||||
}
|
||||
.push-sm-0 {
|
||||
left: auto;
|
||||
}
|
||||
.push-sm-1 {
|
||||
left: 8.333333%;
|
||||
}
|
||||
.push-sm-2 {
|
||||
left: 16.666667%;
|
||||
}
|
||||
.push-sm-3 {
|
||||
left: 25%;
|
||||
}
|
||||
.push-sm-4 {
|
||||
left: 33.333333%;
|
||||
}
|
||||
.push-sm-5 {
|
||||
left: 41.666667%;
|
||||
}
|
||||
.push-sm-6 {
|
||||
left: 50%;
|
||||
}
|
||||
.push-sm-7 {
|
||||
left: 58.333333%;
|
||||
}
|
||||
.push-sm-8 {
|
||||
left: 66.666667%;
|
||||
}
|
||||
.push-sm-9 {
|
||||
left: 75%;
|
||||
}
|
||||
.push-sm-10 {
|
||||
left: 83.333333%;
|
||||
}
|
||||
.push-sm-11 {
|
||||
left: 91.666667%;
|
||||
}
|
||||
.push-sm-12 {
|
||||
left: 100%;
|
||||
}
|
||||
.offset-sm-0 {
|
||||
margin-left: 0%;
|
||||
}
|
||||
.offset-sm-1 {
|
||||
margin-left: 8.333333%;
|
||||
}
|
||||
.offset-sm-2 {
|
||||
margin-left: 16.666667%;
|
||||
}
|
||||
.offset-sm-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-sm-4 {
|
||||
margin-left: 33.333333%;
|
||||
}
|
||||
.offset-sm-5 {
|
||||
margin-left: 41.666667%;
|
||||
}
|
||||
.offset-sm-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-sm-7 {
|
||||
margin-left: 58.333333%;
|
||||
}
|
||||
.offset-sm-8 {
|
||||
margin-left: 66.666667%;
|
||||
}
|
||||
.offset-sm-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-sm-10 {
|
||||
margin-left: 83.333333%;
|
||||
}
|
||||
.offset-sm-11 {
|
||||
margin-left: 91.666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.col-md-1 {
|
||||
float: left;
|
||||
width: 8.333333%;
|
||||
}
|
||||
.col-md-2 {
|
||||
float: left;
|
||||
width: 16.666667%;
|
||||
}
|
||||
.col-md-3 {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
.col-md-4 {
|
||||
float: left;
|
||||
width: 33.333333%;
|
||||
}
|
||||
.col-md-5 {
|
||||
float: left;
|
||||
width: 41.666667%;
|
||||
}
|
||||
.col-md-6 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
.col-md-7 {
|
||||
float: left;
|
||||
width: 58.333333%;
|
||||
}
|
||||
.col-md-8 {
|
||||
float: left;
|
||||
width: 66.666667%;
|
||||
}
|
||||
.col-md-9 {
|
||||
float: left;
|
||||
width: 75%;
|
||||
}
|
||||
.col-md-10 {
|
||||
float: left;
|
||||
width: 83.333333%;
|
||||
}
|
||||
.col-md-11 {
|
||||
float: left;
|
||||
width: 91.666667%;
|
||||
}
|
||||
.col-md-12 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
.pull-md-0 {
|
||||
right: auto;
|
||||
}
|
||||
.pull-md-1 {
|
||||
right: 8.333333%;
|
||||
}
|
||||
.pull-md-2 {
|
||||
right: 16.666667%;
|
||||
}
|
||||
.pull-md-3 {
|
||||
right: 25%;
|
||||
}
|
||||
.pull-md-4 {
|
||||
right: 33.333333%;
|
||||
}
|
||||
.pull-md-5 {
|
||||
right: 41.666667%;
|
||||
}
|
||||
.pull-md-6 {
|
||||
right: 50%;
|
||||
}
|
||||
.pull-md-7 {
|
||||
right: 58.333333%;
|
||||
}
|
||||
.pull-md-8 {
|
||||
right: 66.666667%;
|
||||
}
|
||||
.pull-md-9 {
|
||||
right: 75%;
|
||||
}
|
||||
.pull-md-10 {
|
||||
right: 83.333333%;
|
||||
}
|
||||
.pull-md-11 {
|
||||
right: 91.666667%;
|
||||
}
|
||||
.pull-md-12 {
|
||||
right: 100%;
|
||||
}
|
||||
.push-md-0 {
|
||||
left: auto;
|
||||
}
|
||||
.push-md-1 {
|
||||
left: 8.333333%;
|
||||
}
|
||||
.push-md-2 {
|
||||
left: 16.666667%;
|
||||
}
|
||||
.push-md-3 {
|
||||
left: 25%;
|
||||
}
|
||||
.push-md-4 {
|
||||
left: 33.333333%;
|
||||
}
|
||||
.push-md-5 {
|
||||
left: 41.666667%;
|
||||
}
|
||||
.push-md-6 {
|
||||
left: 50%;
|
||||
}
|
||||
.push-md-7 {
|
||||
left: 58.333333%;
|
||||
}
|
||||
.push-md-8 {
|
||||
left: 66.666667%;
|
||||
}
|
||||
.push-md-9 {
|
||||
left: 75%;
|
||||
}
|
||||
.push-md-10 {
|
||||
left: 83.333333%;
|
||||
}
|
||||
.push-md-11 {
|
||||
left: 91.666667%;
|
||||
}
|
||||
.push-md-12 {
|
||||
left: 100%;
|
||||
}
|
||||
.offset-md-0 {
|
||||
margin-left: 0%;
|
||||
}
|
||||
.offset-md-1 {
|
||||
margin-left: 8.333333%;
|
||||
}
|
||||
.offset-md-2 {
|
||||
margin-left: 16.666667%;
|
||||
}
|
||||
.offset-md-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-md-4 {
|
||||
margin-left: 33.333333%;
|
||||
}
|
||||
.offset-md-5 {
|
||||
margin-left: 41.666667%;
|
||||
}
|
||||
.offset-md-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-md-7 {
|
||||
margin-left: 58.333333%;
|
||||
}
|
||||
.offset-md-8 {
|
||||
margin-left: 66.666667%;
|
||||
}
|
||||
.offset-md-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-md-10 {
|
||||
margin-left: 83.333333%;
|
||||
}
|
||||
.offset-md-11 {
|
||||
margin-left: 91.666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.col-lg-1 {
|
||||
float: left;
|
||||
width: 8.333333%;
|
||||
}
|
||||
.col-lg-2 {
|
||||
float: left;
|
||||
width: 16.666667%;
|
||||
}
|
||||
.col-lg-3 {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
.col-lg-4 {
|
||||
float: left;
|
||||
width: 33.333333%;
|
||||
}
|
||||
.col-lg-5 {
|
||||
float: left;
|
||||
width: 41.666667%;
|
||||
}
|
||||
.col-lg-6 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
.col-lg-7 {
|
||||
float: left;
|
||||
width: 58.333333%;
|
||||
}
|
||||
.col-lg-8 {
|
||||
float: left;
|
||||
width: 66.666667%;
|
||||
}
|
||||
.col-lg-9 {
|
||||
float: left;
|
||||
width: 75%;
|
||||
}
|
||||
.col-lg-10 {
|
||||
float: left;
|
||||
width: 83.333333%;
|
||||
}
|
||||
.col-lg-11 {
|
||||
float: left;
|
||||
width: 91.666667%;
|
||||
}
|
||||
.col-lg-12 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
.pull-lg-0 {
|
||||
right: auto;
|
||||
}
|
||||
.pull-lg-1 {
|
||||
right: 8.333333%;
|
||||
}
|
||||
.pull-lg-2 {
|
||||
right: 16.666667%;
|
||||
}
|
||||
.pull-lg-3 {
|
||||
right: 25%;
|
||||
}
|
||||
.pull-lg-4 {
|
||||
right: 33.333333%;
|
||||
}
|
||||
.pull-lg-5 {
|
||||
right: 41.666667%;
|
||||
}
|
||||
.pull-lg-6 {
|
||||
right: 50%;
|
||||
}
|
||||
.pull-lg-7 {
|
||||
right: 58.333333%;
|
||||
}
|
||||
.pull-lg-8 {
|
||||
right: 66.666667%;
|
||||
}
|
||||
.pull-lg-9 {
|
||||
right: 75%;
|
||||
}
|
||||
.pull-lg-10 {
|
||||
right: 83.333333%;
|
||||
}
|
||||
.pull-lg-11 {
|
||||
right: 91.666667%;
|
||||
}
|
||||
.pull-lg-12 {
|
||||
right: 100%;
|
||||
}
|
||||
.push-lg-0 {
|
||||
left: auto;
|
||||
}
|
||||
.push-lg-1 {
|
||||
left: 8.333333%;
|
||||
}
|
||||
.push-lg-2 {
|
||||
left: 16.666667%;
|
||||
}
|
||||
.push-lg-3 {
|
||||
left: 25%;
|
||||
}
|
||||
.push-lg-4 {
|
||||
left: 33.333333%;
|
||||
}
|
||||
.push-lg-5 {
|
||||
left: 41.666667%;
|
||||
}
|
||||
.push-lg-6 {
|
||||
left: 50%;
|
||||
}
|
||||
.push-lg-7 {
|
||||
left: 58.333333%;
|
||||
}
|
||||
.push-lg-8 {
|
||||
left: 66.666667%;
|
||||
}
|
||||
.push-lg-9 {
|
||||
left: 75%;
|
||||
}
|
||||
.push-lg-10 {
|
||||
left: 83.333333%;
|
||||
}
|
||||
.push-lg-11 {
|
||||
left: 91.666667%;
|
||||
}
|
||||
.push-lg-12 {
|
||||
left: 100%;
|
||||
}
|
||||
.offset-lg-0 {
|
||||
margin-left: 0%;
|
||||
}
|
||||
.offset-lg-1 {
|
||||
margin-left: 8.333333%;
|
||||
}
|
||||
.offset-lg-2 {
|
||||
margin-left: 16.666667%;
|
||||
}
|
||||
.offset-lg-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-lg-4 {
|
||||
margin-left: 33.333333%;
|
||||
}
|
||||
.offset-lg-5 {
|
||||
margin-left: 41.666667%;
|
||||
}
|
||||
.offset-lg-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-lg-7 {
|
||||
margin-left: 58.333333%;
|
||||
}
|
||||
.offset-lg-8 {
|
||||
margin-left: 66.666667%;
|
||||
}
|
||||
.offset-lg-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-lg-10 {
|
||||
margin-left: 83.333333%;
|
||||
}
|
||||
.offset-lg-11 {
|
||||
margin-left: 91.666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.col-xl-1 {
|
||||
float: left;
|
||||
width: 8.333333%;
|
||||
}
|
||||
.col-xl-2 {
|
||||
float: left;
|
||||
width: 16.666667%;
|
||||
}
|
||||
.col-xl-3 {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
.col-xl-4 {
|
||||
float: left;
|
||||
width: 33.333333%;
|
||||
}
|
||||
.col-xl-5 {
|
||||
float: left;
|
||||
width: 41.666667%;
|
||||
}
|
||||
.col-xl-6 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
.col-xl-7 {
|
||||
float: left;
|
||||
width: 58.333333%;
|
||||
}
|
||||
.col-xl-8 {
|
||||
float: left;
|
||||
width: 66.666667%;
|
||||
}
|
||||
.col-xl-9 {
|
||||
float: left;
|
||||
width: 75%;
|
||||
}
|
||||
.col-xl-10 {
|
||||
float: left;
|
||||
width: 83.333333%;
|
||||
}
|
||||
.col-xl-11 {
|
||||
float: left;
|
||||
width: 91.666667%;
|
||||
}
|
||||
.col-xl-12 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
.pull-xl-0 {
|
||||
right: auto;
|
||||
}
|
||||
.pull-xl-1 {
|
||||
right: 8.333333%;
|
||||
}
|
||||
.pull-xl-2 {
|
||||
right: 16.666667%;
|
||||
}
|
||||
.pull-xl-3 {
|
||||
right: 25%;
|
||||
}
|
||||
.pull-xl-4 {
|
||||
right: 33.333333%;
|
||||
}
|
||||
.pull-xl-5 {
|
||||
right: 41.666667%;
|
||||
}
|
||||
.pull-xl-6 {
|
||||
right: 50%;
|
||||
}
|
||||
.pull-xl-7 {
|
||||
right: 58.333333%;
|
||||
}
|
||||
.pull-xl-8 {
|
||||
right: 66.666667%;
|
||||
}
|
||||
.pull-xl-9 {
|
||||
right: 75%;
|
||||
}
|
||||
.pull-xl-10 {
|
||||
right: 83.333333%;
|
||||
}
|
||||
.pull-xl-11 {
|
||||
right: 91.666667%;
|
||||
}
|
||||
.pull-xl-12 {
|
||||
right: 100%;
|
||||
}
|
||||
.push-xl-0 {
|
||||
left: auto;
|
||||
}
|
||||
.push-xl-1 {
|
||||
left: 8.333333%;
|
||||
}
|
||||
.push-xl-2 {
|
||||
left: 16.666667%;
|
||||
}
|
||||
.push-xl-3 {
|
||||
left: 25%;
|
||||
}
|
||||
.push-xl-4 {
|
||||
left: 33.333333%;
|
||||
}
|
||||
.push-xl-5 {
|
||||
left: 41.666667%;
|
||||
}
|
||||
.push-xl-6 {
|
||||
left: 50%;
|
||||
}
|
||||
.push-xl-7 {
|
||||
left: 58.333333%;
|
||||
}
|
||||
.push-xl-8 {
|
||||
left: 66.666667%;
|
||||
}
|
||||
.push-xl-9 {
|
||||
left: 75%;
|
||||
}
|
||||
.push-xl-10 {
|
||||
left: 83.333333%;
|
||||
}
|
||||
.push-xl-11 {
|
||||
left: 91.666667%;
|
||||
}
|
||||
.push-xl-12 {
|
||||
left: 100%;
|
||||
}
|
||||
.offset-xl-0 {
|
||||
margin-left: 0%;
|
||||
}
|
||||
.offset-xl-1 {
|
||||
margin-left: 8.333333%;
|
||||
}
|
||||
.offset-xl-2 {
|
||||
margin-left: 16.666667%;
|
||||
}
|
||||
.offset-xl-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-xl-4 {
|
||||
margin-left: 33.333333%;
|
||||
}
|
||||
.offset-xl-5 {
|
||||
margin-left: 41.666667%;
|
||||
}
|
||||
.offset-xl-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-xl-7 {
|
||||
margin-left: 58.333333%;
|
||||
}
|
||||
.offset-xl-8 {
|
||||
margin-left: 66.666667%;
|
||||
}
|
||||
.offset-xl-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-xl-10 {
|
||||
margin-left: 83.333333%;
|
||||
}
|
||||
.offset-xl-11 {
|
||||
margin-left: 91.666667%;
|
||||
}
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-grid.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,453 +0,0 @@
|
||||
/*! normalize.css v4.2.0 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
main,
|
||||
menu,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
template,
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects;
|
||||
}
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none;
|
||||
text-decoration: underline;
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
hr {
|
||||
-webkit-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
button,
|
||||
html [type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
legend {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
display: table;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder {
|
||||
color: inherit;
|
||||
opacity: 0.54;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
html {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
-webkit-box-sizing: inherit;
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
@-ms-viewport {
|
||||
width: device-width;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
-ms-overflow-style: scrollbar;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
color: #373a3c;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
cursor: help;
|
||||
border-bottom: 1px dotted #818a91;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0275d8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:focus, a:hover {
|
||||
color: #014c8c;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:focus {
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a,
|
||||
area,
|
||||
button,
|
||||
[role="button"],
|
||||
input,
|
||||
label,
|
||||
select,
|
||||
summary,
|
||||
textarea {
|
||||
-ms-touch-action: manipulation;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #818a91;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
textarea {
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
input[type="radio"]:disabled,
|
||||
input[type="checkbox"]:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"] {
|
||||
-webkit-appearance: listbox;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user