Showing preview only (791K chars total). Download the full file or copy to clipboard to get everything.
Repository: tpierrain/CQRS
Branch: master
Commit: 30953047c4dc
Files: 125
Total size: 745.6 KB
Directory structure:
gitextract_cow58ptr/
├── .gitattributes
├── .gitignore
├── BookARoom.sln
├── LabInstructions.md
├── MiscNotes.md
├── README.md
├── documentation/
│ ├── 0- InstallationsSteps.txt
│ └── FollowTheWhiteRabbit.md
├── global.json
├── src/
│ ├── BookARoom.Domain/
│ │ ├── BookARoom.Domain.xproj
│ │ ├── ICommand.cs
│ │ ├── IEvent.cs
│ │ ├── IMessage.cs
│ │ ├── IPublishEvents.cs
│ │ ├── ISendCommands.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── Query.cs
│ │ ├── ReadModel/
│ │ │ ├── BookingOption.cs
│ │ │ ├── Hotel.cs
│ │ │ ├── IProvideHotel.cs
│ │ │ ├── IProvideReservations.cs
│ │ │ ├── IProvideRooms.cs
│ │ │ ├── IQueryBookingOptions.cs
│ │ │ ├── IStoreAndProvideHotelsAndRooms.cs
│ │ │ ├── ISubscribeToEvents.cs
│ │ │ ├── Price.cs
│ │ │ ├── ReadModelFacade.cs
│ │ │ ├── Reservation.cs
│ │ │ ├── RoomWithPrices.cs
│ │ │ └── SearchBookingOptions.cs
│ │ ├── WriteModel/
│ │ │ ├── Booking.cs
│ │ │ ├── BookingCommand.cs
│ │ │ ├── BookingStore.cs
│ │ │ ├── IBookRooms.cs
│ │ │ ├── IHandleClients.cs
│ │ │ ├── ISaveBooking.cs
│ │ │ ├── RoomBooked.cs
│ │ │ └── WriteModelFacade.cs
│ │ └── project.json
│ ├── BookARoom.Infra/
│ │ ├── BookARoom.Infra.xproj
│ │ ├── CompositionRootHelper.cs
│ │ ├── MessageBus/
│ │ │ ├── AsynchronousThreadPoolPublicationStrategy.cs
│ │ │ ├── FakeBus.cs
│ │ │ ├── IPublishToHandlers.cs
│ │ │ └── SynchronousPublicationStrategy.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── ReadModel/
│ │ │ ├── Adapters/
│ │ │ │ ├── HotelsAndRoomsAdapter.cs
│ │ │ │ └── ReservationAdapter.cs
│ │ │ └── HotelsAndRoomsRepository.cs
│ │ ├── WriteModel/
│ │ │ └── BookingAndClientsRepository.cs
│ │ └── project.json
│ ├── BookARoom.Infra.Web/
│ │ ├── .bowerrc
│ │ ├── BookARoom.Infra.Web.xproj
│ │ ├── Controllers/
│ │ │ ├── BookingConfirmationController.cs
│ │ │ ├── BookingOptionsController.cs
│ │ │ ├── BookingRequestController.cs
│ │ │ ├── HomeController.cs
│ │ │ ├── QueryReservations.cs
│ │ │ └── ReservationsController.cs
│ │ ├── Program.cs
│ │ ├── Project_Readme.html
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── Startup.cs
│ │ ├── ViewModels/
│ │ │ ├── BookingOptionsViewModel.cs
│ │ │ ├── BookingRequestViewModel.cs
│ │ │ ├── QueryReservationsViewModel.cs
│ │ │ ├── ReservationsViewModel.cs
│ │ │ └── SearchRoomQueryViewModel.cs
│ │ ├── Views/
│ │ │ ├── BookingConfirmation/
│ │ │ │ └── index.cshtml
│ │ │ ├── BookingOptions/
│ │ │ │ └── index.cshtml
│ │ │ ├── BookingRequest/
│ │ │ │ └── index.cshtml
│ │ │ ├── Home/
│ │ │ │ ├── About.cshtml
│ │ │ │ ├── Caroussel-old-index.cshtml
│ │ │ │ ├── Contact.cshtml
│ │ │ │ └── Index.cshtml
│ │ │ ├── QueryReservations/
│ │ │ │ └── index.cshtml
│ │ │ ├── Reservations/
│ │ │ │ └── index.cshtml
│ │ │ ├── Shared/
│ │ │ │ ├── Error.cshtml
│ │ │ │ └── _Layout.cshtml
│ │ │ ├── _ViewImports.cshtml
│ │ │ └── _ViewStart.cshtml
│ │ ├── appsettings.json
│ │ ├── bower.json
│ │ ├── bundleconfig.json
│ │ ├── cssSandBox.html
│ │ ├── project.json
│ │ ├── web.config
│ │ └── wwwroot/
│ │ ├── _references.js
│ │ ├── css/
│ │ │ └── site.css
│ │ ├── hotels/
│ │ │ ├── BudaFull-the-always-unavailable-hotel-availabilities.json
│ │ │ ├── Danubius Health Spa Resort Helia-availabilities.json
│ │ │ ├── New York Sofitel-availabilities.json
│ │ │ └── THE GRAND BUDAPEST HOTEL-availabilities.json
│ │ ├── js/
│ │ │ └── site.js
│ │ └── lib/
│ │ ├── bootstrap/
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE
│ │ │ └── dist/
│ │ │ ├── css/
│ │ │ │ ├── bootstrap-theme.css
│ │ │ │ └── bootstrap.css
│ │ │ └── js/
│ │ │ ├── bootstrap.js
│ │ │ └── npm.js
│ │ ├── jquery/
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE.txt
│ │ │ └── dist/
│ │ │ └── jquery.js
│ │ ├── jquery-validation/
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE.md
│ │ │ └── dist/
│ │ │ ├── additional-methods.js
│ │ │ └── jquery.validate.js
│ │ └── jquery-validation-unobtrusive/
│ │ ├── .bower.json
│ │ └── jquery.validate.unobtrusive.js
│ └── BookARoom.IntegrationModel/
│ ├── BookARoom.IntegrationModel.xproj
│ ├── HotelDetailsWithRoomsAvailabilities.cs
│ ├── IntegrationFilesGenerator.cs
│ ├── Price.cs
│ ├── Program.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── RoomStatusAndPrices.cs
│ └── project.json
└── test/
└── BookARoom.Tests/
├── Acceptance/
│ ├── BookingTests.cs
│ ├── ReservationsTests.cs
│ └── SearchRoomsTests.cs
├── BookARoom.Tests.xproj
├── Constants.cs
├── HotelsAndRoomsAdapterTests.cs
├── Properties/
│ └── AssemblyInfo.cs
└── project.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
*ncrunchsolution
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
================================================
FILE: BookARoom.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2C91A5FB-FD1A-4059-8633-9E8DAFADF865}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
.gitignore = .gitignore
global.json = global.json
LabInstructions.md = LabInstructions.md
MiscNotes.md = MiscNotes.md
README.md = README.md
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BookARoom.Domain", "src\BookARoom.Domain\BookARoom.Domain.xproj", "{B50A9368-9FF0-4619-8B50-76D2ACD1A1F3}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BookARoom.Tests", "test\BookARoom.Tests\BookARoom.Tests.xproj", "{0197FC69-EAA2-4D9E-86AE-58064B296F7A}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BookARoom.IntegrationModel", "src\BookARoom.IntegrationModel\BookARoom.IntegrationModel.xproj", "{3C54CC13-C90F-4296-BD22-F9A1CE131C21}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BookARoom.Infra.Web", "src\BookARoom.Infra.Web\BookARoom.Infra.Web.xproj", "{A6C40114-AB7F-4567-94D3-7371109F9EB2}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BookARoom.Infra", "src\BookARoom.Infra\BookARoom.Infra.xproj", "{9A121180-73F0-42D8-97DF-16F7B6A9AB43}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B50A9368-9FF0-4619-8B50-76D2ACD1A1F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B50A9368-9FF0-4619-8B50-76D2ACD1A1F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B50A9368-9FF0-4619-8B50-76D2ACD1A1F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B50A9368-9FF0-4619-8B50-76D2ACD1A1F3}.Release|Any CPU.Build.0 = Release|Any CPU
{0197FC69-EAA2-4D9E-86AE-58064B296F7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0197FC69-EAA2-4D9E-86AE-58064B296F7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0197FC69-EAA2-4D9E-86AE-58064B296F7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0197FC69-EAA2-4D9E-86AE-58064B296F7A}.Release|Any CPU.Build.0 = Release|Any CPU
{3C54CC13-C90F-4296-BD22-F9A1CE131C21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C54CC13-C90F-4296-BD22-F9A1CE131C21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C54CC13-C90F-4296-BD22-F9A1CE131C21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C54CC13-C90F-4296-BD22-F9A1CE131C21}.Release|Any CPU.Build.0 = Release|Any CPU
{A6C40114-AB7F-4567-94D3-7371109F9EB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6C40114-AB7F-4567-94D3-7371109F9EB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6C40114-AB7F-4567-94D3-7371109F9EB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6C40114-AB7F-4567-94D3-7371109F9EB2}.Release|Any CPU.Build.0 = Release|Any CPU
{9A121180-73F0-42D8-97DF-16F7B6A9AB43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A121180-73F0-42D8-97DF-16F7B6A9AB43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A121180-73F0-42D8-97DF-16F7B6A9AB43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A121180-73F0-42D8-97DF-16F7B6A9AB43}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
================================================
FILE: LabInstructions.md
================================================
# CQRS lab instructions
The objective of this lab is to add the cancel a reservation feature __following an Outside-in TDD approach__.
## Outside-In TDD?
Also called the double-loop (or London school of TDD), the Outside-In TDD starts the flow from the outside of your system to be built, considering the system as a black box and makes us write one failing acceptance test first, then many underlying unit tests (Red-Green_Refactor) to make this acceptance test Green, before we Refactor it and continue with another black box acceptance test (ad lib).

__The huge advantage of this Outside-In TDD is that__ we will end with the exact expected result at the end for our (black box- system (since we wrote acceptance tests to define its behaviours). Thus, we follow a strict and minimal (and YAGNI) approach to deliver our app/service/... We avoid any digression or not objective-driven task. __A straight to the point approach!__
Note: since the BookARoom system is already existing (built thanks to this workflow), the lab instructions below focus more on the new acceptance tests than on underlying unit tests that whether already exist (and are impacted here) or aren't needed.
####Tips:
In any case, your tests (including the unit ones) must __ALWAYS TEST BEHAVIOURS; NOT IMPLEMENTATIONS!__ (otherwise your tests will be fragile and painfull).
---
## Step1: Add a failing acceptance test (Make it fail)
1. Create a new __CancelBookingTests__ test fixture within the BookARoom.Tests projects (within the 'Acceptance' directory)
2. Add a first failing test (__Should_Update_booking_engine_when_CancelBookingCommand_is_sent()__):
````C#
using System;
using BookARoom.Domain;
using BookARoom.Domain.WriteModel;
using BookARoom.Infra;
using BookARoom.Infra.MessageBus;
using BookARoom.Infra.WriteModel;
using NFluent;
using NUnit.Framework;
namespace BookARoom.Tests.Acceptance
{
[TestFixture]
public class CancelBookingTests
{
[Test]
public void Should_Update_booking_engine_when_CancelBookingCommand_is_sent()
{
var bookingEngine = new BookingAndClientsRepository();
var bus = new FakeBus();
CompositionRootHelper.BuildTheWriteModelHexagon(bookingEngine, bookingEngine, bus, bus);
var hotelId = 2;
var roomNumber = "101";
var clientId = "thomas@pierrain.net";
var bookingCommand = new BookingCommand(clientId: clientId, hotelName: "New York Sofitel", hotelId: hotelId, roomNumber: roomNumber, checkInDate: Constants.MyFavoriteSaturdayIn2017, checkOutDate: Constants.MyFavoriteSaturdayIn2017.AddDays(1));
bus.Send(bookingCommand);
Check.That(bookingEngine.GetBookingsFrom(clientId)).HasSize(1);
var bookingGuid = bookingEngine.GetBookingsFrom(clientId).First().BookingId;
var cancelBookingCommand = new CancelBookingCommand(bookingGuid);
bus.Send(cancelBookingCommand);
// Booking is still there, but canceled
Check.That(bookingEngine.GetBookingsFrom(clientId)).HasSize(1);
Check.That(bookingEngine.GetBookingsFrom(clientId).First().IsCanceled).IsTrue();
}
}
// Note: since we 'TDD as if you meant it', the newly created command sits aside the test (we'll move it in a second step).
public class CancelBookingCommand: ICommand
{
public Guid BookingId { get; }
public CancelBookingCommand(Guid bookingId)
{
this.BookingId = bookingId;
}
}
}
````
To make our solution build again, we must create (Alt-Enter) a new *IsCancelled* property for the *Booking* type :
````C#
public class Booking
{
// existing code
public bool IsCanceled { get; private set; } // a new property to identify booking cancelation
// existing code
}
````
## Step2: Make it work
1. We __move the CancelBookingCommand__ type to the proper project (__BookARoom.Domain\WriteModel__) in order for it to be referenced from within the domain logic.
2. We __register a handler for this new command__. It means:
1. To make the *WriteModelFacade* type implements: *IHandleCommand<CancelBookingCommand>
* (with an implementation throwing a *System.NotImplementedException*)
2. To make the CompositionRootHelper subscribes the proper handler for this CancelBookingCommand
Here is the impact on the code:
````C#
namespace BookARoom.Domain.WriteModel
{
public class WriteModelFacade : IHandleCommand<BookingCommand>, IHandleCommand<CancelBookingCommand>
{
// existing code
public void Handle(CancelBookingCommand command)
{
throw new System.NotImplementedException();
}
}
}
````
and
````C#
/// <summary>
/// Ease the integration of the various hexagons (one for the read model, the other for the write model).
/// </summary>
public class CompositionRootHelper
{
// existing code
/// <summary>
/// Subscribe the "command handler" to per-type command publication on the eventPublisher.
/// </summary>
/// <param name="writeModelFacade">The callback/handler provider.</param>
/// <param name="bus">The eventPublisher to subscribe on.</param>
private static void SubscribeCommands(WriteModelFacade writeModelFacade, ISubscribeToEvents bus)
{
bus.RegisterHandler<BookingCommand>(writeModelFacade.Handle);
bus.RegisterHandler<CancelBookingCommand>(writeModelFacade.Handle); // the line to be added
}
// existing code
}
````
3. We replace the System.NotImplementedException of the (WriteModelFacade) handler by a code calling a method we create on-the-fly on the IBookRooms interface:
````C#
// (...) somewhere within the WriteModelFacade type
public void Handle(CancelBookingCommand command)
{
this.BookingStore.CancelBooking(command); // better than a NotImplementedException right?
}
````
````C#
namespace BookARoom.Domain.WriteModel
{
public interface IBookRooms
{
void BookARoom(BookingCommand bookingCommand);
void CancelBooking(CancelBookingCommand cancelBookingCommand); // the new operation
}
}
````
We then implement this method on the __BookingStore__ concrete type:
````C#
using System;
namespace BookARoom.Domain.WriteModel
{
public class BookingStore : IBookRooms
{
// existing code
public void CancelBooking(CancelBookingCommand cancelBookingCommand)
{
var booking = this.bookingRepository.GetBooking(cancelBookingCommand.ClientId, cancelBookingCommand.BookingId);
if (booking.IsForClient(cancelBookingCommand.ClientId))
{
// We cancel the booking
booking.Cancel();
// And save its updated version
this.bookingRepository.Update(booking);
}
else
{
throw new InvalidOperationException("Can't cancel a booking for another client.");
}
}
// existing code
}
}
````
Since this newly implemented *CancelBooking* method refers to undefined methods and type, __we need to catch-up the implementation__ in order to make it build again. It means:
1. __To Add a new *ClientId* property__ on the existing *CancelBookingCommand* type (needed to prevent someone from cancelling someone else's booking) and to fix the acceptance test that uses it (*Should_Update_booking_engine_when_CancelBookingCommand_is_sent()*)
2. __To Add 2 methods on the IBookingRepository interface__: *Booking GetBooking(string clientId, Guid bookingId)* and *void Update(Booking booking)*
3. __To implement new methods on the *Booking* type__ (*Cancel()* and *IsForClient(string clientId)*)
4. To catch-up *IBookingRepository* implementation of the *BookingAndClientsRepository* concrete type __by adding the 2 missing methods__: GetBooking(...) and Update(...)
Let's see what it takes with code:
````C#
public class CancelBookingCommand: ICommand
{
public Guid BookingId { get; }
public string ClientId { get; } // new property
public CancelBookingCommand(Guid bookingId, string clientId)
{
this.BookingId = bookingId;
this.ClientId = clientId; // new property assignment
}
}
````
with the acceptance test
````C#
[Test]
public void Should_Update_booking_engine_when_CancelBookingCommand_is_sent()
{
// existing code
var cancelBookingCommand = new CancelBookingCommand(bookingGuid, clientId);
// existing code
}
````
then
````C#
namespace BookARoom.Domain.WriteModel
{
public interface IBookingRepository
{
void Save(Booking booking);
Booking GetBooking(string clientId, Guid bookingId);
void Update(Booking booking);
}
}
````
and
````C#
namespace BookARoom.Domain.WriteModel
{
public class Booking
{
// existing code
public bool IsForClient(string clientId)
{
throw new NotImplementedException();
}
public void Cancel()
{
throw new NotImplementedException();
}
// existing code
}
}
````
and
````C#
namespace BookARoom.Infra.WriteModel
{
public class BookingAndClientsRepository : IBookingRepository, IClientRepository
{
// existing code
public Booking GetBooking(string clientId, Guid bookingId)
{
throw new NotImplementedException();
}
public void Update(Booking booking)
{
throw new NotImplementedException();
}
}
}
````
__From now, it should compile again ;-)__ and the *Should_Update_booking_engine_when_CancelBookingCommand_is_sent()* test should now fail due to one of the many NotImplementedException we left on the field.
- - -
Time to implement all these behaviours by replacing every NotImplementedException by some code. Follow the white rabbit here...
We start with the implementation of the *GetBooking(string clientId, Guid bookingId)* method on the BookingAndClientsRepository type:
````C#
namespace BookARoom.Infra.WriteModel
{
public class BookingAndClientsRepository : IBookingRepository, IClientRepository
{
private readonly Dictionary<string, List<ICommand>> perClientCommands;
// existing code
public Booking GetBooking(string clientId, Guid bookingId)
{
var allCommandsForThisClient = this.perClientCommands[clientId];
foreach (var command in allCommandsForThisClient)
{
var bookingCommand = command as BookingCommand;
if (bookingCommand != null && bookingCommand.Guid == bookingId)
{
return new Booking(bookingCommand.ClientId, bookingCommand.HotelId, bookingCommand.RoomNumber, bookingCommand.CheckInDate, bookingCommand.CheckOutDate);
}
}
return Booking.Null;
}
// existing code
}
}
````
which by the way, force us to add a __Null (object pattern)__ property on the new *Booking* type that we need to implement to get rid of its previous NotImplementedExceptions:
````C#
using System;
namespace BookARoom.Domain.WriteModel
{
public class Booking
{
public static Booking Null { get; } = new NullBooking();
// We provide getters only so that the state of this domain object is only changed via one of its operations (methods)
public Guid BookingId { get; }
public string ClientId { get; }
public int HotelId { get; }
public string RoomNumber { get; }
public DateTime CheckInDate { get; }
public DateTime CheckOutDate { get; }
public bool IsCanceled { get; private set; }
public Booking(Guid bookingId , string clientId, int hotelId, string roomNumber, DateTime checkInDate, DateTime checkOutDate)
{
this.BookingId = bookingId;
this.ClientId = clientId;
this.HotelId = hotelId;
this.RoomNumber = roomNumber;
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
}
public virtual bool IsForClient(string clientId)
{
if (this.ClientId == clientId)
{
return true;
}
return false;
}
public virtual void Cancel()
{
this.IsCanceled = true;
}
private class NullBooking : Booking
{
public NullBooking() : base(Guid.Empty, string.Empty, 0, string.Empty, DateTime.Now, DateTime.Now)
{
}
public override bool IsForClient(string clientId)
{
return false;
}
public override void Cancel()
{
}
}
}
}
````
we continue to replace all our NotImplementedException by some code. Next-one pointed out by our acceptance test is the *Update()* method of the *BookingAndClientsRepository* type:
````C#
public void Update(Booking booking)
{
if (!this.perClientBookings.ContainsKey(booking.ClientId))
{
this.perClientBookings[booking.ClientId] = new List<Booking>();
}
var bookingsForThisClient = this.perClientBookings[booking.ClientId];
int? index = null;
for (int i = 0; i < bookingsForThisClient.Count; i++)
{
if (bookingsForThisClient[i].BookingId == booking.BookingId)
{
index = i;
break;
}
}
if (index.HasValue)
{
bookingsForThisClient[index.Value] = booking;
}
}
````
We run our tests again, and TADA! it's all green.
- - -
## Step 3: Make it better (Refactor)
I let you do homework ;-)
## Step 4: Write a failing acceptance test showing that a 'CancelBooking' task updates the "My Reservations" read model (Make it fail)
Here it is:
````C#
[Test]
public void Should_Update_readmodel_user_reservations_when_CancelBookingCommand_is_sent()
{
var bookingEngine = new BookingAndClientsRepository();
var bus = new FakeBus(synchronousPublication:true);
CompositionRootHelper.BuildTheWriteModelHexagon(bookingEngine, bookingEngine, bus, bus);
var hotelsAndRoomsAdapter = new HotelsAndRoomsAdapter(Constants.RelativePathForHotelIntegrationFiles, bus);
hotelsAndRoomsAdapter.LoadAllHotelsFiles();
var reservationAdapter = new ReservationAdapter(bus);
CompositionRootHelper.BuildTheReadModelHexagon(hotelsAndRoomsAdapter, hotelsAndRoomsAdapter, reservationAdapter, bus);
var clientId = "thomas@pierrain.net";
Check.That(reservationAdapter.GetReservationsFor(clientId)).IsEmpty();
var hotelId = 2;
var roomNumber = "101";
var bookingCommand = new BookingCommand(clientId: clientId, hotelName: "New York Sofitel", hotelId: hotelId, roomNumber: roomNumber, checkInDate: Constants.MyFavoriteSaturdayIn2017, checkOutDate: Constants.MyFavoriteSaturdayIn2017.AddDays(1));
bus.Send(bookingCommand);
var bookingGuid = bookingEngine.GetBookingsFrom(clientId).First().BookingId;
Check.That(reservationAdapter.GetReservationsFor(clientId)).HasSize(1);
var reservation = reservationAdapter.GetReservationsFor(clientId).First();
Check.That(reservation.RoomNumber).IsEqualTo(roomNumber);
Check.That(reservation.HotelId).IsEqualTo(hotelId.ToString());
var cancelCommand = new CancelBookingCommand(bookingGuid, clientId);
bus.Send(cancelCommand);
Check.That(reservationAdapter.GetReservationsFor(clientId)).HasSize(0);
}
````
So far, we've added the concept of cancelation for the *Booking* (on the write-side). Now, it's time to add the same notion on the read-side (*Reservation*) to make this test compile.
````C#
namespace BookARoom.Domain.ReadModel
{
public class Reservation
{
// existing code
public bool IsCanceled { get; private set; } // NEW PROP
// existing code
}
}
````
## Step 5: Make it work
For that, __the write-side domain logic will have to triggering a *BookingCanceled* event that will impact the read-side model__ (reservations to begin, rooms availabilities in a second time).
To know where to raise event, we follow the white rabbit from the main CommandHandler (i.e. the WriteModelFacade) to the *BookingStore.CancelBooking(cmd)* method: bingo! this is it.
````C#
using System;
namespace BookARoom.Domain.WriteModel
{
public class BookingStore : IBookRooms
{
// existing code
public void CancelBooking(CancelBookingCommand command)
{
var booking = this.bookingRepository.GetBooking(command.BookingGuid, command.ClientId);
if (booking.IsForClient(command.ClientId))
{
booking.Cancel();
this.bookingRepository.Update(booking);
// HERE, WE INSTANTIATE AND PUBLISH A BRAND NEW EVENT --------------
var bookingCanceled = new BookingCanceled(booking.ClientId, booking.BookingId);
this.publishEvents.PublishTo(bookingCanceled);
// THE EVENT HAS BEEN PUBLISHED ------------------------------------
}
else
{
throw new InvalidOperationException("Can't cancel someone else booking.");
}
}
// existing code
}
}
````
Alt-Enter on the red BookingCanceled type and we create it on-the-fly:
````C#
using System;
namespace BookARoom.Domain.WriteModel
{
public class BookingCanceled : IEvent
{
public string ClientId { get; } // immutable
public Guid BookingId { get; }
public BookingCanceled(string clientId, Guid bookingId)
{
this.ClientId = clientId;
this.BookingId = bookingId;
}
}
}
````
Now, we just have to make the *ReservationAdapter* to subscribe this new event. This is achieved within its constructor where we declare a new callback handler to be used. Like this:
````C#
namespace BookARoom.Infra.ReadModel.Adapters
{
public class ReservationAdapter : IProvideReservations
{
private readonly ISubscribeToEvents eventsSubscriber;
private readonly Dictionary<string, List<Reservation>> perClientReservations = new Dictionary<string, List<Reservation>>();
public ReservationAdapter(ISubscribeToEvents eventsSubscriber)
{
this.eventsSubscriber = eventsSubscriber;
// subscribes to the events
this.eventsSubscriber.RegisterHandler<RoomBooked>(Handle);
this.eventsSubscriber.RegisterHandler<BookingCanceled>(Handle); // NEW EVENT SUBSCRIPTION
}
private void Handle(BookingCanceled @event) // NEW CALLBACK
{
// Find the reservation made by this client and declares it Canceled
var reservationsForThisClient = this.perClientReservations[@event.ClientId];
foreach (var reservation in reservationsForThisClient)
{
if (reservation.Guid == @event.BookingId)
{
reservation.Cancel();
}
}
}
// existing code
}
}
````
Time for us to Implement the Cancel() method on the *Reservation* type and Voila! The acceptance test is GREEN ;)
````C#
namespace BookARoom.Domain.ReadModel
{
public class Reservation
{
// existing code
public void Cancel() // NEW METHOD
{
this.IsCanceled = true;
}
// existing code
}
}
````
## Step 6: Make it better (Refactor)
I let you do homework ;-)
## Step 7: Write a failing acceptance test showing that a 'CancelBooking' task impacts the "rooms search engine" on the read-side
Provided here, in a non-refactored form to ease Copy-and-Paste (but will deserve some extract methods in your IDE):
````C#
[Test]
public void Should_impact_room_search_results_when_CancelBookingCommand_is_sent()
{
// Initialize Read-model side
var bus = new FakeBus(synchronousPublication: true);
var hotelsAdapter = new HotelsAndRoomsAdapter(Constants.RelativePathForHotelIntegrationFiles, bus);
var reservationsAdapter = new ReservationAdapter(bus);
hotelsAdapter.LoadHotelFile("New York Sofitel-availabilities.json");
// Initialize Write-model side
var bookingRepository = new BookingAndClientsRepository();
CompositionRootHelper.BuildTheWriteModelHexagon(bookingRepository, bookingRepository, bus, bus);
var readFacade = CompositionRootHelper.BuildTheReadModelHexagon(hotelsAdapter, hotelsAdapter, reservationsAdapter, bus);
// Search Rooms availabilities
var checkInDate = Constants.MyFavoriteSaturdayIn2017;
var checkOutDate = checkInDate.AddDays(1);
var searchQuery = new SearchBookingOptions(checkInDate, checkOutDate, location: "New York", numberOfAdults: 2);
var bookingOptions = readFacade.SearchBookingOptions(searchQuery);
// We should get 1 booking option with 13 available rooms in it.
Check.That(bookingOptions).HasSize(1);
var bookingOption = bookingOptions.First();
var initialRoomsNumbers = 13;
Check.That(bookingOption.AvailableRoomsWithPrices).HasSize(initialRoomsNumbers);
// Now, let's book that room!
var firstRoomOfThisBookingOption = bookingOption.AvailableRoomsWithPrices.First();
var clientId = "thomas@pierrain.net";
var bookingCommand = new BookingCommand(clientId: clientId, hotelName: "New York Sofitel", hotelId: bookingOption.Hotel.Identifier, roomNumber: firstRoomOfThisBookingOption.RoomIdentifier, checkInDate: checkInDate, checkOutDate: checkOutDate);
// We send the BookARoom command
bus.Send(bookingCommand);
// We check that both the BookingRepository (Write model) and the available rooms (Read model) have been updated.
Check.That(bookingRepository.GetBookingsFrom(clientId).Count()).IsEqualTo(1);
var bookingId = bookingRepository.GetBookingsFrom(clientId).First().BookingId;
// Fetch rooms availabilities now. One room should have disappeared from the search result
bookingOptions = readFacade.SearchBookingOptions(searchQuery);
Check.That(bookingOptions).HasSize(1);
Check.That(bookingOption.AvailableRoomsWithPrices).As("available matching rooms").HasSize(initialRoomsNumbers - 1);
// We cancel our booking
var cancelBookingCommand = new CancelBookingCommand(bookingId, clientId);
bus.Send(cancelBookingCommand);
// Search again and the missing room should be back on the search result again
bookingOptions = readFacade.SearchBookingOptions(searchQuery);
Check.That(bookingOptions).HasSize(1);
Check.That(bookingOption.AvailableRoomsWithPrices).As("available matching rooms").HasSize(initialRoomsNumbers - 1 + 1);
}
````
## Step 8: Make it work
As we previously did for the *ReservationAdapter*, let's make the *HotelsAndRoomsAdapter* (implementing *IProvideRooms*) subscribes to the *BookingCanceled* event.
````C#
public class HotelsAndRoomsAdapter : IProvideRooms, IProvideHotel
{
private readonly ISubscribeToEvents eventsSubscriber;
private readonly IStoreAndProvideHotelsAndRooms repository;
public HotelsAndRoomsAdapter(string integrationFilesDirectoryPath, ISubscribeToEvents eventsSubscriber)
{
this.IntegrationFilesDirectoryPath = integrationFilesDirectoryPath;
this.repository = new HotelsAndRoomsRepository();
this.eventsSubscriber = eventsSubscriber;
this.eventsSubscriber.RegisterHandler<RoomBooked>(this.Handle);
this.eventsSubscriber.RegisterHandler<BookingCanceled>(this.Handle); // NEW EVENT REGISTRATION
}
// NEW CALLBACK FOR BOOKING CANCELED EVENT
private void Handle(BookingCanceled bookingCanceled)
{
throw new NotImplementedException();
}
// existing code
}
````
For once, I'll let you implement it alone to make the last acceptance test turn to green.
As you will see, there is something more to do since the read-model will need some extra information in order to be able to make the corresponding room appeard again.
Will you need to add extra information from the source event?
Instead, will you need to request those informations on the read-model side (near to the need)?
As you have probably already understand, __there is no one size fits all CQRS architecture__. Only trade-offs and options to adjust to your domain needs and constraints.
- - -
## Step 9: Make it better (Refactor)
I let you do homework ;-)
---
## Step 10: Integrate our work to the (Web site) UI
TODO with a DELETE VERB.
- - -
================================================
FILE: MiscNotes.md
================================================
# Misc notes related to the BookARoom project
#### Hotel APIs:
[http://www.programmableweb.com/category/hotels/apis?category=20057]()
Even if the objective is to illustrate the CQRS pattern, the Domain part of the current is somehow anemic as of today... To be improved.
================================================
FILE: README.md
================================================

BookARoom is a simple project __to explain CQRS__ during a live coding session at MS experiences'16 (__slides are available here: [https://github.com/tpierrain/CQRS-slides](https://github.com/tpierrain/CQRS-slides)__) or __[here on slideshare](http://www.slideshare.net/ThomasPierrain/cqrs-without-event-sourcing)__
The project is a __dotnet core__ ASP.NET web site (in order to be containerized in the next session), allowing users:
1. To consult and search for available rooms (READ model)
2. To book a room (WRITE model)
Of course, booking a room (write model) will impact the read model accordingly.
---

This project is not a real one nor a prod-ready code. The intent here is __to illustrate the CQRS pattern during a 40 minutes session__. Thus, some __trade-offs have been taken__ in that direction (e.g. the usage of *Command* and *Queries* terminology instead of domain specific names that I would have used otherwise).
##### CQRS without Event Sourcing?!?
Yes, since the timing will be short for __[this *MS experiences'16* session in Paris](https://experiences.microsoft.fr/Event/speaker/thomas-pierrain/e11c8e2e-f572-e611-80c3-000d3a2229a6)__ (no more than 30 minutes of live-coding), I've decided to focus only on CQRS pattern, WITHOUT Event Sourcing (ES). Indeed, ES is often a mental dam for people's understanding.
I also find important that people understand that __CQRS  Event sourcing__, but __CQRS != Event sourcing__.
---
### Highlights of the talk
1. __CQRS (WITHOUT Event Sourcing)__:
- Why CQRS?
- Pattern origin
- How read and write models articulate
- Eventual consistency challenges and options
- Short clarification between __CQRS & Event sourcing__
1. How __Outside-in TDD__ works
1. How __Hexagonal Architecture__ can help us to focus on __Domain first__, before tackling the infra code (ASP.NET) in a second time
1. What is __dotnet core__ and how it articulates with the new version of ASP.NET
---
### Projects & Dependencies
-  __BookARoom.Domain__: containing all the domain logic of the solution (for both read and write models). __(has no dependency)__
-  __BookARoom.Infra__: containing the reusable infrastructure code (i.e. non-domain one like adapters, command handler, repositories) for both read and write models. __(depends on both Domain and IntegrationModel projects)__
-  __BookARoom.Infra.Web__: ASP.NET core project hosting the web infrastructure code (like ViewModels, Views and Controllers) which relies on the BookARoom.Infra code. __(depends on both Domain, Infra and IntegrationModel projects)__
-  __BookARoom.Tests__: containing tests for all projects. __(depends on all the other BookARoom projects)__
-  __BookARoom.IntegrationModel__: command-line project to generate integration json files for hotel (from code). __(has no dependency)__
---
### Tips and tricks
##### How to run the tests
Note: resharper and ncrunch don't support yet dotnet core; you can only run them via Visual Studio test runner (e.g. Ctrl-R, A) or by executing:
dotnet test
within the BookARoom.Tests project directory.
---
### CQRS in a nutshell
There are many forms of CQRS implementation. The implementation of the BookARoom project follows this version:

from original source: [https://msdn.microsoft.com/en-us/library/jj591573.aspx](https://msdn.microsoft.com/en-us/library/jj591573.aspx)
---

The objective of this lab is to __add the "cancel a reservation" feature__.
__[Step by step Instructions (following outside-in TDD technique) are presented here](LabInstructions.md)__.
---
### Tracks of improvement
1. Fight against the current anemic model (mainly because I never worked on that topic and that I don't have any expert available to help me ;-( and embrace more the ubiquitous language of this domain.
...
================================================
FILE: documentation/0- InstallationsSteps.txt
================================================
1. WebEssentials VS addin + other related plugins http://vswebessentials.com/changelog
6. Webextension pack: https://visualstudiogallery.msdn.microsoft.com/f3b504c6-0095-42f1-a989-51d5fc2a8459
================================================
FILE: documentation/FollowTheWhiteRabbit.md
================================================
# RoomsBooking project (steps to follow)
## Setup your dev environment
### 1. Install all the plugins and dependencies for ASP.NET dotnet core project
### 2. Configure your project.json to allow unit test execution in a dotnet core environment
(note: review what I've found after my own explorations: https://github.com/dotnet/core-docs/blob/master/docs/core/testing/unit-testing-with-dotnet-test.md )
1. Within the *project.json* file, comment:
````C#
"frameworks": {
//"netstandard1.6": {
// "imports": "dnxcore50"
//}
````
2. Set (instead) the values specified below (source: [https://github.com/nunit/dotnet-test-nunit/tree/release/3.4.0#projectjson](https://github.com/nunit/dotnet-test-nunit/tree/release/3.4.0#projectjson) )
````C#
{
"version": "1.0.0-*",
"dependencies": {
"NUnit": "3.4.1",
"dotnet-test-nunit": "3.4.0-beta-1"
},
"testRunner": "nunit",
"frameworks": {
"netcoreapp1.0": {
"imports": "portable-net45+win8",
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0-*",
"type": "platform"
}
}
}
}
}
````
3. Open a cmd window at the directory root of your project and execute:
````C#
# Restore the NuGet packages
dotnet restore
# Run the unit tests in the current directory
dotnet test
````
## Coding
================================================
FILE: global.json
================================================
{
"projects": [ "src", "test" ],
"sdk": {
"version": "1.0.0-preview2-003131"
}
}
================================================
FILE: src/BookARoom.Domain/BookARoom.Domain.xproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>b50a9368-9ff0-4619-8b50-76d2acd1a1f3</ProjectGuid>
<RootNamespace>BookARoom.Domain</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
================================================
FILE: src/BookARoom.Domain/ICommand.cs
================================================
namespace BookARoom.Domain
{
public interface ICommand : IMessage
{
}
}
================================================
FILE: src/BookARoom.Domain/IEvent.cs
================================================
namespace BookARoom.Domain
{
public interface IEvent : IMessage
{
// public int Version; // no time for Event Sourcing here.
}
}
================================================
FILE: src/BookARoom.Domain/IMessage.cs
================================================
namespace BookARoom.Domain
{
public interface IMessage
{
}
}
================================================
FILE: src/BookARoom.Domain/IPublishEvents.cs
================================================
namespace BookARoom.Domain
{
public interface IPublishEvents
{
void PublishTo<T>(T @event) where T : IEvent;
}
}
================================================
FILE: src/BookARoom.Domain/ISendCommands.cs
================================================
namespace BookARoom.Domain
{
public interface ISendCommands
{
void Send<T>(T command) where T : ICommand;
}
}
================================================
FILE: src/BookARoom.Domain/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BookARoom")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b50a9368-9ff0-4619-8b50-76d2acd1a1f3")]
================================================
FILE: src/BookARoom.Domain/Query.cs
================================================
namespace BookARoom.Domain
{
public class Query : IMessage
{
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/BookingOption.cs
================================================
using System.Collections.Generic;
using System.Linq;
namespace BookARoom.Domain.ReadModel
{
public class BookingOption
{
public Hotel Hotel { get; }
public IEnumerable<RoomWithPrices> AvailableRoomsWithPrices { get; }
public BookingOption(Hotel hotel, IEnumerable<RoomWithPrices> availableRoomsWithPrices)
{
this.Hotel = hotel;
this.AvailableRoomsWithPrices = availableRoomsWithPrices;
}
public override string ToString()
{
return $"Booking option for hotel: '{this.Hotel}' - {this.AvailableRoomsWithPrices.Count()} possible room(s)";
}
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/Hotel.cs
================================================
namespace BookARoom.Domain.ReadModel
{
public class Hotel
{
public Hotel(int hotelId, string name, string location, int numberOfRooms)
{
this.Identifier = hotelId;
this.Name = name;
this.Location = location;
this.NumberOfRooms = numberOfRooms;
}
public string Location { get; }
public string Name { get; }
public int Identifier { get; }
public int NumberOfRooms { get; }
public override string ToString()
{
return this.Name;
}
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/IProvideHotel.cs
================================================
using System.Collections.Generic;
namespace BookARoom.Domain.ReadModel
{
/// <summary>
/// Provides Hotels to stay.
/// <remarks>Repository of Hotels.</remarks>
/// </summary>
public interface IProvideHotel
{
IEnumerable<Hotel> SearchFromLocation(string location);
Hotel GetHotel(int hotelId);
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/IProvideReservations.cs
================================================
using System.Collections.Generic;
namespace BookARoom.Domain.ReadModel
{
public interface IProvideReservations
{
IEnumerable<Reservation> GetReservationsFor(string clientId);
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/IProvideRooms.cs
================================================
using System;
using System.Collections.Generic;
namespace BookARoom.Domain.ReadModel
{
/// <summary>
/// Find rooms.
/// <remarks>Repository of AvailableRoomsWithPrices.</remarks>
/// </summary>
public interface IProvideRooms
{
// TODO: return IEnumerable<AvailableRoomsWithPrices> instead
IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensitiveWay(string location, DateTime checkInDate, DateTime checkOutDate);
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/IQueryBookingOptions.cs
================================================
using System.Collections.Generic;
namespace BookARoom.Domain.ReadModel
{
/// <summary>
/// Interface to interact with our system in order to query booking options.
/// </summary>
public interface IQueryBookingOptions
{
IEnumerable<BookingOption> SearchBookingOptions(SearchBookingOptions query);
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/IStoreAndProvideHotelsAndRooms.cs
================================================
using System;
using System.Collections.Generic;
namespace BookARoom.Domain.ReadModel
{
public interface IStoreAndProvideHotelsAndRooms : IProvideHotel
{
IEnumerable<Hotel> Hotels { get; }
IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensitiveWay(string location, DateTime checkInDate, DateTime checkOutDate);
void StoreHotel(int hotelId, Hotel hotel);
void StoreHotelAvailabilities(Hotel hotel, Dictionary<DateTime, List<RoomWithPrices>> perDateRoomsAvailabilities);
void DeclareRoomBooked(int hotelId, string roomNumber, DateTime checkInDate, DateTime checkOutDate);
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/ISubscribeToEvents.cs
================================================
using System;
namespace BookARoom.Domain.ReadModel
{
public interface ISubscribeToEvents
{
void RegisterHandler<T>(Action<T> handler) where T : IMessage;
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/Price.cs
================================================
namespace BookARoom.Domain.ReadModel
{
public class Price
{
public string Currency;
public double Value;
public Price(string currency, double value)
{
Currency = currency;
Value = value;
}
public override string ToString()
{
return $"{Value} {Currency}";
}
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/ReadModelFacade.cs
================================================
using System;
using System.Collections.Generic;
namespace BookARoom.Domain.ReadModel
{
/// <summary>
/// Allow to search BookingOptions or to get details about Hotels.
/// </summary>
public class ReadModelFacade : IQueryBookingOptions, IProvideHotel, IProvideReservations
{
// TODO: question: find a domain name instead or keep focus on the CQRS pattern to ease understanding of the MS experiences'16 audience?
private readonly IProvideRooms roomsProvider;
private readonly IProvideHotel hotelProvider;
private readonly IProvideReservations reservationsProvider;
/// <summary>
/// Instantiates a <see cref="ReadModelFacade"/>.
/// </summary>
/// <param name="roomsProvider"></param>
/// <param name="hotelProvider"></param>
/// <param name="reservationsProvider"></param>
/// <param name="bus"></param>
public ReadModelFacade(IProvideRooms roomsProvider, IProvideHotel hotelProvider, IProvideReservations reservationsProvider, ISubscribeToEvents bus)
{
this.roomsProvider = roomsProvider;
this.hotelProvider = hotelProvider;
this.reservationsProvider = reservationsProvider;
}
#region IQueryBookingOptions members
public IEnumerable<BookingOption> SearchBookingOptions(SearchBookingOptions query)
{
return this.SearchBookingOptions(query.CheckInDate, query.CheckOutDate, query.Location, query.NumberOfAdults, query.NumberOfRoomsNeeded, query.ChildrenCount);
}
private IEnumerable<BookingOption> SearchBookingOptions(DateTime checkInDate, DateTime checkOutDate, string location, int adultsCount, int numberOfRoomsNeeded = 1, int childrenCount = 0)
{
if (checkInDate > checkOutDate)
{
throw new InvalidOperationException($"Check out date ({checkOutDate}) must be after Check in date ({checkInDate}).");
}
return this.roomsProvider.SearchAvailableHotelsInACaseInsensitiveWay(location, checkInDate, checkOutDate);
}
#endregion
#region IProvideHotel members
public IEnumerable<Hotel> SearchFromLocation(string location)
{
throw new NotImplementedException();
}
public Hotel GetHotel(int hotelId)
{
return this.hotelProvider.GetHotel(hotelId);
}
#endregion
public IEnumerable<Reservation> GetReservationsFor(string clientId)
{
return this.reservationsProvider.GetReservationsFor(clientId);
}
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/Reservation.cs
================================================
using System;
namespace BookARoom.Domain.ReadModel
{
public class Reservation
{
public Guid Guid { get; private set; }
public string ClientId { get; }
public string HotelName { get; set; }
public string HotelId { get; }
public string RoomNumber { get; }
public DateTime CheckInDate { get; }
public DateTime CheckOutDate { get; }
public Reservation(Guid guid, string clientId, string hotelName, string hotelId, string roomNumber, DateTime checkInDate, DateTime checkOutDate)
{
this.Guid = guid;
this.ClientId = clientId;
this.HotelName = hotelName;
this.HotelId = hotelId;
this.RoomNumber = roomNumber;
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
}
public override string ToString()
{
return $"Reservation for:{ClientId} at Hotel:{HotelName} (id:{HotelId}), RoomNumber:{RoomNumber} for check-in date:{CheckInDate.ToString("d")} and check-out date:{CheckOutDate.ToString("d")}";
}
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/RoomWithPrices.cs
================================================
namespace BookARoom.Domain.ReadModel
{
public class RoomWithPrices
{
public string RoomIdentifier;
public Price OneAdultOccupancyPrice;
public Price TwoAdultsOccupancyPrice;
public RoomWithPrices(string roomIdentifier, Price oneAdultOccupancyPrice, Price twoAdultsOccupancyPrice)
{
RoomIdentifier = roomIdentifier;
OneAdultOccupancyPrice = oneAdultOccupancyPrice;
TwoAdultsOccupancyPrice = twoAdultsOccupancyPrice;
}
}
}
================================================
FILE: src/BookARoom.Domain/ReadModel/SearchBookingOptions.cs
================================================
using System;
namespace BookARoom.Domain.ReadModel
{
public class SearchBookingOptions : Query
{
public DateTime CheckInDate { get; }
public DateTime CheckOutDate { get; }
public string Location { get; }
public int NumberOfAdults { get; }
public int NumberOfRoomsNeeded { get; }
public int ChildrenCount { get; }
public SearchBookingOptions(DateTime checkInDate, DateTime checkOutDate, string location, int numberOfAdults, int numberOfRoomsNeeded = 1, int childrenCount = 0)
{
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
this.Location = location;
this.NumberOfAdults = numberOfAdults;
this.NumberOfRoomsNeeded = numberOfRoomsNeeded;
this.ChildrenCount = childrenCount;
}
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/Booking.cs
================================================
using System;
namespace BookARoom.Domain.WriteModel
{
public class Booking
{
// We provide getters only so that the state of this domain object is only changed via one of its operations (methods)
public Guid BookingId { get; }
public string ClientId { get; }
public int HotelId { get; }
public string RoomNumber { get; }
public DateTime CheckInDate { get; }
public DateTime CheckOutDate { get; }
public Booking(Guid bookingId , string clientId, int hotelId, string roomNumber, DateTime checkInDate, DateTime checkOutDate)
{
this.BookingId = bookingId;
this.ClientId = clientId;
this.HotelId = hotelId;
this.RoomNumber = roomNumber;
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
}
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/BookingCommand.cs
================================================
using System;
namespace BookARoom.Domain.WriteModel
{
public class BookingCommand : ICommand
{
public string ClientId { get; }
public string HotelName { get; }
public int HotelId { get; }
public string RoomNumber { get; }
public DateTime CheckInDate { get; }
public DateTime CheckOutDate { get; }
public BookingCommand(string clientId, string hotelName, int hotelId, string roomNumber, DateTime checkInDate, DateTime checkOutDate)
{
this.ClientId = clientId;
this.HotelName = hotelName;
this.HotelId = hotelId;
this.RoomNumber = roomNumber;
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
}
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/BookingStore.cs
================================================
using System;
namespace BookARoom.Domain.WriteModel
{
public class BookingStore : IBookRooms
{
private readonly ISaveBooking saveBooking;
private readonly IHandleClients handleClients;
private readonly IPublishEvents publishEvents;
public BookingStore(ISaveBooking saveBooking, IHandleClients handleClients, IPublishEvents publishEvents)
{
this.saveBooking = saveBooking;
this.handleClients = handleClients;
this.publishEvents = publishEvents;
}
public void BookARoom(BookingCommand command)
{
if (!this.handleClients.IsClientAlready(command.ClientId))
{
this.handleClients.CreateClient(command.ClientId);
}
Guid guid = Guid.NewGuid();
var booking = new Booking(guid, command.ClientId, command.HotelId, command.RoomNumber, command.CheckInDate, command.CheckOutDate);
this.saveBooking.Save(booking);
// we could enrich the event from here (eg. finding the HotelName from the HotelId)
var roomBooked = new RoomBooked(guid, command.HotelName, command.HotelId, command.ClientId, command.RoomNumber, command.CheckInDate, command.CheckOutDate);
this.publishEvents.PublishTo(roomBooked);
}
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/IBookRooms.cs
================================================
namespace BookARoom.Domain.WriteModel
{
public interface IBookRooms
{
void BookARoom(BookingCommand command);
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/IHandleClients.cs
================================================
namespace BookARoom.Domain.WriteModel
{
// TODO: find a better name following Vaughn VERNON's reco (I do something...) or keep the reference to repository to help people understanding?
public interface IHandleClients
{
bool IsClientAlready(string clientIdentifier);
void CreateClient(string clientIdentifier);
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/ISaveBooking.cs
================================================
using System;
namespace BookARoom.Domain.WriteModel
{
public interface ISaveBooking
{
void Save(Booking booking);
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/RoomBooked.cs
================================================
using System;
namespace BookARoom.Domain.WriteModel
{
public class RoomBooked : IEvent
{
public Guid Guid { get; }
public string HotelName { get; }
public int HotelId { get; }
public string ClientId { get; }
public string RoomNumber { get; }
public DateTime CheckInDate { get; }
public DateTime CheckOutDate { get; }
public RoomBooked(Guid guid, string hotelName, int hotelId, string clientId, string roomNumber, DateTime checkInDate, DateTime checkOutDate)
{
this.Guid = guid;
this.HotelName = hotelName;
this.HotelId = hotelId;
this.ClientId = clientId;
this.RoomNumber = roomNumber;
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
}
}
}
================================================
FILE: src/BookARoom.Domain/WriteModel/WriteModelFacade.cs
================================================
namespace BookARoom.Domain.WriteModel
{
public class WriteModelFacade : IHandleCommand<BookingCommand>
{
public IBookRooms BookingStore { get; }
public WriteModelFacade(IBookRooms bookingStore)
{
this.BookingStore = bookingStore;
}
public void Handle(BookingCommand command)
{
this.BookingStore.BookARoom(command);
}
}
public interface IHandleCommand<T>
{
void Handle(T command);
}
}
================================================
FILE: src/BookARoom.Domain/project.json
================================================
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"netstandard1.6": {
"imports": "dnxcore50"
}
}
}
================================================
FILE: src/BookARoom.Infra/BookARoom.Infra.xproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>9a121180-73f0-42d8-97df-16f7b6a9ab43</ProjectGuid>
<RootNamespace>BookARoom.Infra</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
================================================
FILE: src/BookARoom.Infra/CompositionRootHelper.cs
================================================
using BookARoom.Domain;
using BookARoom.Domain.ReadModel;
using BookARoom.Domain.WriteModel;
using BookARoom.Infra.MessageBus;
using BookARoom.Infra.ReadModel.Adapters;
namespace BookARoom.Infra
{
/// <summary>
/// Ease the integration of the various hexagons (one for the read model, the other for the write model).
/// </summary>
public class CompositionRootHelper
{
public static ReadModelFacade BuildTheReadModelHexagon(IProvideRooms roomsAdapter, IProvideHotel hotelAdapter, IProvideReservations reservationAdapter = null, ISubscribeToEvents bus = null)
{
if (bus == null)
{
bus = new FakeBus();
}
if (reservationAdapter == null)
{
reservationAdapter = new ReservationAdapter(bus);
}
return new ReadModelFacade(roomsAdapter, hotelAdapter, reservationAdapter, bus);
}
public static WriteModelFacade BuildTheWriteModelHexagon(ISaveBooking saveBooking, IHandleClients handleClients, IPublishEvents eventPublisher, ISubscribeToEvents eventSubscriber)
{
var writeModelCommandHandler = new WriteModelFacade(new BookingStore(saveBooking, handleClients, eventPublisher));
CompositionRootHelper.SubscribeCommands(writeModelCommandHandler, eventSubscriber);
return writeModelCommandHandler;
}
/// <summary>
/// Subscribe the "command handler" to per-type command publication on the eventPublisher.
/// </summary>
/// <param name="writeModelFacade">The callback/handler provider.</param>
/// <param name="bus">The eventPublisher to subscribe on.</param>
private static void SubscribeCommands(WriteModelFacade writeModelFacade, ISubscribeToEvents bus)
{
bus.RegisterHandler<BookingCommand>(writeModelFacade.Handle);
}
}
}
================================================
FILE: src/BookARoom.Infra/MessageBus/AsynchronousThreadPoolPublicationStrategy.cs
================================================
using System;
using System.Threading;
using BookARoom.Domain;
namespace BookARoom.Infra.MessageBus
{
public class AsynchronousThreadPoolPublicationStrategy : IPublishToHandlers
{
public void PublishTo<T>(Action<IMessage> handler, T @event) where T : IEvent
{
//dispatch on thread pool for added awesomeness
ThreadPool.QueueUserWorkItem(x => handler(@event));
}
}
}
================================================
FILE: src/BookARoom.Infra/MessageBus/FakeBus.cs
================================================
using System;
using System.Collections.Generic;
using BookARoom.Domain;
using BookARoom.Domain.ReadModel;
namespace BookARoom.Infra.MessageBus
{
/// <summary>
/// Class coming from Greg YOUNG's https://github.com/gregoryyoung/m-r repo (thanks Greg!).
/// (I just added the <see cref="ISubscribeToEvents"/> interface for my own needs and
/// slightly changed the Publish method to introduce a synchronous/asynchronous strategy).
/// </summary>
public class FakeBus : ISendCommands, IPublishEvents, ISubscribeToEvents
{
private readonly Dictionary<Type, List<Action<IMessage>>> _routes = new Dictionary<Type, List<Action<IMessage>>>();
private readonly IPublishToHandlers publicationStrategy;
public FakeBus(bool synchronousPublication = true)
{
if (synchronousPublication)
{
this.publicationStrategy = new SynchronousPublicationStrategy();
}
else
{
this.publicationStrategy = new AsynchronousThreadPoolPublicationStrategy();
}
}
public void RegisterHandler<T>(Action<T> handler) where T : IMessage
{
List<Action<IMessage>> handlers;
if(!_routes.TryGetValue(typeof(T), out handlers))
{
handlers = new List<Action<IMessage>>();
_routes.Add(typeof(T), handlers);
}
handlers.Add((x => handler((T)x)));
}
public void Send<T>(T command) where T : ICommand
{
List<Action<IMessage>> handlers;
if (_routes.TryGetValue(typeof(T), out handlers))
{
if (handlers.Count != 1) throw new InvalidOperationException("cannot send to more than one handler");
handlers[0](command);
}
else
{
throw new InvalidOperationException("no handler registered");
}
}
public void PublishTo<T>(T @event) where T : IEvent
{
List<Action<IMessage>> handlers;
if (!_routes.TryGetValue(@event.GetType(), out handlers)) return;
foreach(var handler in handlers)
{
this.publicationStrategy.PublishTo(handler, @event);
}
}
}
}
================================================
FILE: src/BookARoom.Infra/MessageBus/IPublishToHandlers.cs
================================================
using System;
using BookARoom.Domain;
namespace BookARoom.Infra.MessageBus
{
public interface IPublishToHandlers
{
void PublishTo<T>(Action<IMessage> handler, T @event) where T : IEvent;
}
}
================================================
FILE: src/BookARoom.Infra/MessageBus/SynchronousPublicationStrategy.cs
================================================
using System;
using BookARoom.Domain;
namespace BookARoom.Infra.MessageBus
{
public class SynchronousPublicationStrategy : IPublishToHandlers
{
public void PublishTo<T>(Action<IMessage> handler, T @event) where T : IEvent
{
handler(@event); // synchronous publication to simplify the test of this first step
}
}
}
================================================
FILE: src/BookARoom.Infra/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BookARoom.Infra")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9a121180-73f0-42d8-97df-16f7b6a9ab43")]
================================================
FILE: src/BookARoom.Infra/ReadModel/Adapters/HotelsAndRoomsAdapter.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BookARoom.Domain.ReadModel;
using BookARoom.Domain.WriteModel;
using BookARoom.IntegrationModel;
using Newtonsoft.Json;
using Price = BookARoom.Domain.ReadModel.Price;
namespace BookARoom.Infra.ReadModel.Adapters
{
/// <summary>
/// Adapter between the Integration model (json external files) and the domain one.
/// <remarks>Implementation of the Ports and Adapters patterns (a.k.a. hexagonal architecture).</remarks>
/// </summary>
public class HotelsAndRoomsAdapter : IProvideRooms, IProvideHotel
{
// TODO: extract behaviours from this adapter to put it on the domain-side
private readonly ISubscribeToEvents eventsSubscriber;
private readonly IStoreAndProvideHotelsAndRooms repository;
public HotelsAndRoomsAdapter(string integrationFilesDirectoryPath, ISubscribeToEvents eventsSubscriber)
{
this.IntegrationFilesDirectoryPath = integrationFilesDirectoryPath;
this.repository = new HotelsAndRoomsRepository();
this.eventsSubscriber = eventsSubscriber;
this.eventsSubscriber.RegisterHandler<RoomBooked>(this.Handle);
// TODO: question: should we 'functionally subscribe' within the domain code instead?
// TODO: handle the unsubscription
}
private void Handle(RoomBooked roomBooked)
{
this.repository.DeclareRoomBooked(roomBooked.HotelId, roomBooked.RoomNumber, roomBooked.CheckInDate, roomBooked.CheckOutDate);
}
public string IntegrationFilesDirectoryPath { get; }
public IEnumerable<Hotel> Hotels => this.repository.Hotels;
public void LoadHotelFile(string hotelFileNameOrFilePath)
{
if (!File.Exists(hotelFileNameOrFilePath))
{
hotelFileNameOrFilePath = Path.Combine(this.IntegrationFilesDirectoryPath, hotelFileNameOrFilePath);
}
var integrationModelForThisHotel = GetIntegrationModelForThisHotel(hotelFileNameOrFilePath);
this.AdaptAndStoreData(integrationModelForThisHotel);
}
public void LoadAllHotelsFiles()
{
var filesNames = Directory.GetFiles(this.IntegrationFilesDirectoryPath);
foreach (var fileName in filesNames)
{
LoadHotelFile(fileName);
}
}
private static HotelDetailsWithRoomsAvailabilities GetIntegrationModelForThisHotel(string hotelFileNameOrFilePath)
{
IntegrationModel.HotelDetailsWithRoomsAvailabilities integrationFileAvailabilitieses = null;
using (var streamReader = File.OpenText(hotelFileNameOrFilePath))
{
var jsonContent = streamReader.ReadToEnd();
integrationFileAvailabilitieses = JsonConvert.DeserializeObject<HotelDetailsWithRoomsAvailabilities>(jsonContent);
}
return integrationFileAvailabilitieses;
}
// TODO: get rid of regions by extracting more cohesive types
#region IProvideRooms methods
public IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensitiveWay(string location, DateTime checkInDate, DateTime checkOutDate)
{
return repository.SearchAvailableHotelsInACaseInsensitiveWay(location, checkInDate, checkOutDate);
}
#endregion
#region IProvideHotel
public IEnumerable<Hotel> SearchFromLocation(string location)
{
return repository.SearchFromLocation(location);
}
public Hotel GetHotel(int hotelId)
{
return repository.GetHotel(hotelId);
}
#endregion
#region adapter from integration model to domain model
private void AdaptAndStoreData(HotelDetailsWithRoomsAvailabilities dataForThisHotel)
{
var hotel = AdaptHotel(dataForThisHotel.HotelId, dataForThisHotel.HotelName, dataForThisHotel.Location, dataForThisHotel.NumberOfRooms);
this.AdaptAndStoreIntegrationFileContentForAnHotel(hotel, dataForThisHotel);
this.repository.StoreHotel(dataForThisHotel.HotelId, hotel);
}
private void AdaptAndStoreIntegrationFileContentForAnHotel(Hotel hotel, HotelDetailsWithRoomsAvailabilities integrationFileAvailabilitieses)
{
var roomsPerDateAvailabilities = AdaptHotelAvailabilities(integrationFileAvailabilitieses.AvailabilitiesAt);
this.repository.StoreHotelAvailabilities(hotel, roomsPerDateAvailabilities);
}
private Dictionary<DateTime, List<RoomWithPrices>> AdaptHotelAvailabilities(Dictionary<DateTime, RoomStatusAndPrices[]> receivedAvailabilities)
{
var result = new Dictionary<DateTime, List<RoomWithPrices>>();
foreach (var receivedAvailability in receivedAvailabilities)
{
result[receivedAvailability.Key] = AdaptAllRoomsStatusOfThisHotelForThisDate(receivedAvailabilities);
}
return result;
}
private static List<RoomWithPrices> AdaptAllRoomsStatusOfThisHotelForThisDate(Dictionary<DateTime, RoomStatusAndPrices[]> receivedAvailabilities)
{
return (from receivedRoomStatus in receivedAvailabilities.Values
from roomStatusAndPrices in receivedRoomStatus
select AdaptRoomStatus(roomStatusAndPrices)).ToList();
}
private static RoomWithPrices AdaptRoomStatus(RoomStatusAndPrices roomStatusAndPrices)
{
return new RoomWithPrices(roomStatusAndPrices.RoomIdentifier, AdaptPrice(roomStatusAndPrices.OneAdultOccupancyPrice), AdaptPrice(roomStatusAndPrices.TwoAdultsOccupancyPrice));
}
private static Price AdaptPrice(IntegrationModel.Price price)
{
return new Price(price.Currency, price.Value);
}
private static Hotel AdaptHotel(int hotelId, string hotelName, string location, int numberOfRooms)
{
return new Hotel(hotelId, hotelName, location, numberOfRooms);
}
#endregion
}
}
================================================
FILE: src/BookARoom.Infra/ReadModel/Adapters/ReservationAdapter.cs
================================================
using System.Collections.Generic;
using BookARoom.Domain.ReadModel;
using BookARoom.Domain.WriteModel;
using ISubscribeToEvents = BookARoom.Domain.ReadModel.ISubscribeToEvents;
namespace BookARoom.Infra.ReadModel.Adapters
{
public class ReservationAdapter : IProvideReservations
{
private readonly ISubscribeToEvents eventsSubscriber;
private readonly Dictionary<string, List<Reservation>> perClientReservations = new Dictionary<string, List<Reservation>>();
public ReservationAdapter(ISubscribeToEvents eventsSubscriber)
{
this.eventsSubscriber = eventsSubscriber;
this.eventsSubscriber.RegisterHandler<RoomBooked>(Handle);
}
private void Handle(RoomBooked @event)
{
if (!this.perClientReservations.ContainsKey(@event.ClientId))
{
this.perClientReservations[@event.ClientId] = new List<Reservation>();
}
var reservation = new Reservation(@event.Guid, @event.ClientId, @event.HotelName, @event.HotelId.ToString(), @event.RoomNumber, @event.CheckInDate, @event.CheckOutDate);
this.perClientReservations[@event.ClientId].Add(reservation);
}
public IEnumerable<Reservation> GetReservationsFor(string clientId)
{
List<Reservation> result;
this.perClientReservations.TryGetValue(clientId, out result);
if (result == null)
{
result = new List<Reservation>();
}
return result;
}
}
}
================================================
FILE: src/BookARoom.Infra/ReadModel/HotelsAndRoomsRepository.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using BookARoom.Domain.ReadModel;
namespace BookARoom.Infra.ReadModel
{
public class HotelsAndRoomsRepository : IStoreAndProvideHotelsAndRooms
{
public readonly Dictionary<Hotel, Dictionary<DateTime, List<RoomWithPrices>>> hotelsWithPerDateRoomsStatus;
private readonly Dictionary<int, Hotel> hotelsPerId = new Dictionary<int, Hotel>();
public HotelsAndRoomsRepository()
{
this.hotelsWithPerDateRoomsStatus = new Dictionary<Hotel, Dictionary<DateTime, List<RoomWithPrices>>>();
}
public IEnumerable<Hotel> Hotels => this.hotelsWithPerDateRoomsStatus.Keys;
public IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensitiveWay(string location, DateTime checkInDate, DateTime checkOutDate)
{
var result = (from hotelWithAvailabilities in this.hotelsWithPerDateRoomsStatus
from dateAndRooms in this.hotelsWithPerDateRoomsStatus.Values
from date in dateAndRooms.Keys
from availableRooms in dateAndRooms.Values
where string.Equals(hotelWithAvailabilities.Key.Location, location, StringComparison.CurrentCultureIgnoreCase)
&& (date >= checkInDate && date <= checkOutDate)
&& availableRooms.Count > 0
&& dateAndRooms.Values.Contains(availableRooms)
&& hotelWithAvailabilities.Value == dateAndRooms
select new BookingOption(hotelWithAvailabilities.Key, availableRooms) ).ToList().Distinct();
return result;
}
public void DeclareRoomBooked(int hotelId, string roomNumber, DateTime checkInDate, DateTime checkOutDate)
{
var hotel = this.hotelsPerId[hotelId];
var availabilitiesPerDate = this.hotelsWithPerDateRoomsStatus[hotel];
var availabilities = availabilitiesPerDate[checkInDate];
RoomWithPrices roomAvailabilityToRemove = availabilities.FirstOrDefault(roomWithPrices => roomWithPrices.RoomIdentifier == roomNumber);
availabilities.Remove(roomAvailabilityToRemove);
}
public void StoreHotelAvailabilities(Hotel hotel, Dictionary<DateTime, List<RoomWithPrices>> perDateRoomsAvailabilities)
{
this.hotelsWithPerDateRoomsStatus[hotel] = perDateRoomsAvailabilities;
}
public IEnumerable<Hotel> SearchFromLocation(string location)
{
return from hotel in this.hotelsWithPerDateRoomsStatus.Keys
where hotel.Location == location
select hotel;
}
public Hotel GetHotel(int hotelId)
{
return this.hotelsPerId[hotelId];
}
public void StoreHotel(int hotelId, Hotel hotel)
{
this.hotelsPerId[hotelId] = hotel;
}
}
}
================================================
FILE: src/BookARoom.Infra/WriteModel/BookingAndClientsRepository.cs
================================================
using System.Collections.Generic;
using BookARoom.Domain.WriteModel;
namespace BookARoom.Infra.WriteModel
{
public class BookingAndClientsRepository : ISaveBooking, IHandleClients
{
private readonly Dictionary<string, List<Booking>> perClientBookings;
public BookingAndClientsRepository()
{
perClientBookings = new Dictionary<string, List<Booking>>();
}
public void Save(Booking booking)
{
perClientBookings[booking.ClientId].Add(booking);
}
public bool IsClientAlready(string clientIdentifier)
{
return perClientBookings.ContainsKey(clientIdentifier);
}
public void CreateClient(string clientIdentifier)
{
if (!perClientBookings.ContainsKey(clientIdentifier))
{
perClientBookings[clientIdentifier] = new List<Booking>();
}
}
public IEnumerable<Booking> GetBookingsFrom(string clientIdentifier)
{
if (perClientBookings.ContainsKey(clientIdentifier))
{
return perClientBookings[clientIdentifier];
}
return new List<Booking>();
}
}
}
================================================
FILE: src/BookARoom.Infra/project.json
================================================
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.0",
"BookARoom.Domain": {
"target": "project"
},
"BookARoom.IntegrationModel": {
"target": "project"
}
},
//"frameworks": {
// "netstandard1.6": {
// "imports": "dnxcore50"
// }
//}
"frameworks": {
"netcoreapp1.0": {
"imports": "portable-net45+win8",
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0-*",
"type": "platform"
}
}
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/.bowerrc
================================================
{
"directory": "wwwroot/lib"
}
================================================
FILE: src/BookARoom.Infra.Web/BookARoom.Infra.Web.xproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>a6c40114-ab7f-4567-94d3-7371109f9eb2</ProjectGuid>
<RootNamespace>BookARoom.Infra.Web</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<DnxInvisibleContent Include="bower.json" />
<DnxInvisibleContent Include=".bowerrc" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
================================================
FILE: src/BookARoom.Infra.Web/Controllers/BookingConfirmationController.cs
================================================
using BookARoom.Domain;
using BookARoom.Domain.WriteModel;
using BookARoom.Infra.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace BookARoom.Infra.Web.Controllers
{
public class BookingConfirmationController : Controller
{
private readonly ISendCommands bus;
public BookingConfirmationController(ISendCommands bus)
{
this.bus = bus;
}
// GET: /<controller>/
[HttpPost]
public IActionResult Index(BookingRequestViewModel viewModel)
{
if (!string.IsNullOrWhiteSpace(viewModel.ClientMail))
{
// Create the task and send it to the bus
var bookingCommand = new BookingCommand(clientId: viewModel.ClientMail, hotelName: viewModel.HotelName, hotelId: int.Parse(viewModel.HotelId), roomNumber: viewModel.RoomId, checkInDate: viewModel.CheckInDate, checkOutDate: viewModel.CheckOutDate);
this.bus.Send(bookingCommand);
viewModel.BookingSucceeded = true;
}
else
{
viewModel.BookingSucceeded = false;
}
return View(viewModel);
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Controllers/BookingOptionsController.cs
================================================
using BookARoom.Domain;
using BookARoom.Domain.ReadModel;
using BookARoom.Infra.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace BookARoom.Infra.Web.Controllers
{
public class BookingOptionsController : Controller
{
private readonly IQueryBookingOptions searchService;
public BookingOptionsController(IQueryBookingOptions searchService)
{
this.searchService = searchService;
}
// GET: /<controller>/
public IActionResult Index(BookingOptionsViewModel bookingOptionsViewModel)
{
return View(bookingOptionsViewModel);
}
[HttpPost]
public IActionResult Index(SearchRoomQueryViewModel queryViewModel)
{
var searchQuery = new SearchBookingOptions(queryViewModel.CheckInDate, queryViewModel.CheckOutDate, queryViewModel.Destination, queryViewModel.NumberOfAdults);
var searchResult = this.searchService.SearchBookingOptions(searchQuery);
var bookingOptionsViewModel = new BookingOptionsViewModel(queryViewModel, queryViewModel.Destination, searchResult);
bookingOptionsViewModel.Location = searchQuery.Location;
return View(bookingOptionsViewModel);
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Controllers/BookingRequestController.cs
================================================
using BookARoom.Infra.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace BookARoom.Infra.Web.Controllers
{
public class BookingRequestController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(BookingRequestViewModel bookingRequestViewModel)
{
return View(bookingRequestViewModel);
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Controllers/HomeController.cs
================================================
using System;
using BookARoom.Domain;
using BookARoom.Domain.ReadModel;
using BookARoom.Infra.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BookARoom.Infra.Web.Controllers
{
public class HomeController : Controller
{
private readonly IQueryBookingOptions searchService;
public HomeController(ISendCommands bus, IQueryBookingOptions searchService)
{
this.searchService = searchService;
}
public IActionResult Index()
{
ViewData["Message"] = "Search a room";
var defaultCheckInDate = new DateTime(2017, 09, 16);
var defaultSearchQuery = new SearchRoomQueryViewModel("Budapest", defaultCheckInDate, defaultCheckInDate.AddDays(1), numberOfAdults:2);
return View(defaultSearchQuery);
}
public IActionResult About()
{
ViewData["Message"] = "What is BookARoom?";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Wanna know more?";
return View();
}
public IActionResult Error()
{
return View();
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Controllers/QueryReservations.cs
================================================
using BookARoom.Infra.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace BookARoom.Infra.Web.Controllers
{
public class QueryReservations : Controller
{
public IActionResult Index(string email)
{
ViewData["Message"] = "Consult your reservations";
return View(new QueryReservationsViewModel(email));
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Controllers/ReservationsController.cs
================================================
using BookARoom.Domain.ReadModel;
using BookARoom.Infra.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace BookARoom.Infra.Web.Controllers
{
public class ReservationsController : Controller
{
private readonly IProvideReservations reservationsProvider;
public ReservationsController(IProvideReservations reservationsProvider)
{
this.reservationsProvider = reservationsProvider;
}
[HttpGet]
public IActionResult Index(string email)
{
var reservations = this.reservationsProvider.GetReservationsFor(email);
var reservationsViewModel = new ReservationsViewModel(email, reservations);
return View(reservationsViewModel);
}
[HttpPost]
public IActionResult Index(QueryReservationsViewModel queryReservationsViewModel)
{
var reservations = this.reservationsProvider.GetReservationsFor(queryReservationsViewModel.ClientMail);
var reservationsViewModel = new ReservationsViewModel(queryReservationsViewModel.ClientMail, reservations);
return View(reservationsViewModel);
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Program.cs
================================================
using System.IO;
using Microsoft.AspNetCore.Hosting;
namespace BookARoom.Infra.Web
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Project_Readme.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Welcome to ASP.NET Core</title>
<style>
html {
background: #f1f1f1;
height: 100%;
}
body {
background: #fff;
color: #505050;
font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;
margin: 1%;
min-height: 95.5%;
border: 1px solid silver;
position: relative;
}
#header {
padding: 0;
}
#header h1 {
font-size: 44px;
font-weight: normal;
margin: 0;
padding: 10px 30px 10px 30px;
}
#header span {
margin: 0;
padding: 0 30px;
display: block;
}
#header p {
font-size: 20px;
color: #fff;
background: #007acc;
padding: 0 30px;
line-height: 50px;
margin-top: 25px;
}
#header p a {
color: #fff;
text-decoration: underline;
font-weight: bold;
padding-right: 35px;
background: no-repeat right bottom url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAMAAAAcqPc3AAAANlBMVEUAAAAAeswfitI9mthXp91us+KCvuaTx+mjz+2x1u+83PLH4vTR5/ba7Pjj8Pns9fv1+v3////wy3dWAAAAAXRSTlMAQObYZgAAAHxJREFUeNp9kVcSwCAIRMHUYoH7XzaxOxJ9P8oyQ1uIqNPwh3s2aLmIM2YtqrLcQIeQEylhuCeUOlhgve5yoBCfWmlnlgkN4H8ykbpaE7gR03AbUHiwoOxUH9Xp+ubd41p1HF3mBPrfC87BHeTdaB3ceeKL9HGpcvX9zu6+DdMWT9KQPvYAAAAASUVORK5CYII=);
}
#main {
padding: 5px 30px;
clear: both;
}
.section {
width: 21.7%;
float: left;
margin: 0 0 0 4%;
}
.section h2 {
font-size: 13px;
text-transform: uppercase;
margin: 0;
border-bottom: 1px solid silver;
padding-bottom: 12px;
margin-bottom: 8px;
}
.section.first {
margin-left: 0;
}
.section.first h2 {
font-size: 24px;
text-transform: none;
margin-bottom: 25px;
border: none;
}
.section.first li {
border-top: 1px solid silver;
padding: 8px 0;
}
.section.last {
margin-right: 0;
}
ul {
list-style: none;
padding: 0;
margin: 0;
line-height: 20px;
}
li {
padding: 4px 0;
}
a {
color: #267cb2;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
#footer {
clear: both;
padding-top: 50px;
}
#footer p {
position: absolute;
bottom: 10px;
}
</style>
</head>
<body>
<div id="header">
<h1>Welcome to ASP.NET Core</h1>
<span>
We've made some big updates in this release, so it’s <b>important</b> that you spend
a few minutes to learn what’s new.
</span>
<p>You've created a new ASP.NET Core project. <a href="http://go.microsoft.com/fwlink/?LinkId=518016">Learn what's new</a></p>
</div>
<div id="main">
<div class="section first">
<h2>This application consists of:</h2>
<ul>
<li>Sample pages using ASP.NET Core MVC</li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side libraries</li>
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
</ul>
</div>
<div class="section">
<h2>How to</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699562">Add an appsetting in config and access it in app.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699318">Add client packages using Bower.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
</ul>
</div>
<div class="section">
<h2>Overview</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
</ul>
</div>
<div class="section last">
<h2>Run & Deploy</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
</ul>
</div>
<div id="footer">
<p>We would love to hear your <a href="http://go.microsoft.com/fwlink/?LinkId=518015">feedback</a></p>
</div>
</div>
</body>
</html>
================================================
FILE: src/BookARoom.Infra.Web/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:65280/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"BookARoom.Infra.Web": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Startup.cs
================================================
using BookARoom.Domain;
using BookARoom.Domain.ReadModel;
using BookARoom.Infra.MessageBus;
using BookARoom.Infra.ReadModel.Adapters;
using BookARoom.Infra.WriteModel;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace BookARoom.Infra.Web
{
public class Startup
{
private IHostingEnvironment env;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
this.env = env;
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Build the WRITE side (we use a bus for it) ----------
var bus = new FakeBus();
var bookingRepository = new BookingAndClientsRepository();
var bookingHandler = CompositionRootHelper.BuildTheWriteModelHexagon(bookingRepository, bookingRepository, bus, bus);
// TODO: register handlers for the query part coming from the bus?
// Build the READ side ---------------------------------
var hotelsAdapter = new HotelsAndRoomsAdapter($"{env.WebRootPath}/hotels/", bus);
hotelsAdapter.LoadAllHotelsFiles();
var readFacade = CompositionRootHelper.BuildTheReadModelHexagon(hotelsAdapter, hotelsAdapter, null, bus);
// Registers all services to the MVC IoC framework
services.AddSingleton<ISendCommands>(bus);
services.AddSingleton<IQueryBookingOptions>(readFacade);
services.AddSingleton<IProvideHotel>(readFacade);
services.AddSingleton<IProvideReservations>(readFacade);
// Add framework services.
services.AddMvc();
}
// 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)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/ViewModels/BookingOptionsViewModel.cs
================================================
using System.Collections.Generic;
using BookARoom.Domain.ReadModel;
namespace BookARoom.Infra.Web.ViewModels
{
public class BookingOptionsViewModel
{
public SearchRoomQueryViewModel SearchCriterias { get; set; }
public BookingRequestViewModel BookingRequest { get; set; }
public string Location { get; set; }
public IEnumerable<BookingOption> Options { get; set; }
public BookingOptionsViewModel()
{
}
public BookingOptionsViewModel(SearchRoomQueryViewModel searchCriterias, string location, IEnumerable<BookingOption> Options)
{
this.SearchCriterias = searchCriterias;
this.Location = location;
this.Options = Options;
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/ViewModels/BookingRequestViewModel.cs
================================================
using System;
namespace BookARoom.Infra.Web.ViewModels
{
public class BookingRequestViewModel
{
public string ClientMail { get; set; }
public string HotelName { get; set; }
public string HotelId { get; set; }
public string RoomId { get; set; }
public DateTime CheckInDate { get; set; }
public DateTime CheckOutDate { get; set; }
public bool BookingSucceeded { get; set; }
}
}
================================================
FILE: src/BookARoom.Infra.Web/ViewModels/QueryReservationsViewModel.cs
================================================
namespace BookARoom.Infra.Web.ViewModels
{
public class QueryReservationsViewModel
{
public string ClientMail { get; set; }
public QueryReservationsViewModel()
{
}
public QueryReservationsViewModel(string clientMail)
{
ClientMail = clientMail;
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/ViewModels/ReservationsViewModel.cs
================================================
using System.Collections.Generic;
using BookARoom.Domain.ReadModel;
namespace BookARoom.Infra.Web.ViewModels
{
public class ReservationsViewModel
{
public string ClientEMail { get; set; }
public IEnumerable<Reservation> Reservations { get; set; }
public ReservationsViewModel()
{
}
public ReservationsViewModel(string clientEMail, IEnumerable<Reservation> reservations)
{
ClientEMail = clientEMail;
Reservations = reservations;
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/ViewModels/SearchRoomQueryViewModel.cs
================================================
using System;
namespace BookARoom.Infra.Web.ViewModels
{
public class SearchRoomQueryViewModel
{
public string Destination { get; set; }
public DateTime CheckInDate { get; set; }
public DateTime CheckOutDate { get; set; }
public int NumberOfAdults { get; set; }
public SearchRoomQueryViewModel()
{
}
public SearchRoomQueryViewModel(string destination, DateTime checkInDate, DateTime checkOutDate, int numberOfAdults)
{
this.Destination = destination;
this.CheckInDate = checkInDate;
this.CheckOutDate = checkOutDate;
this.NumberOfAdults = numberOfAdults;
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/Views/BookingConfirmation/index.cshtml
================================================
@using System.Text.Encodings.Web
@model BookARoom.Infra.Web.ViewModels.BookingRequestViewModel
@{
ViewData["Title"] = "Room booked";
}
<br />
<br />
@if (Model.BookingSucceeded)
{
<h2>Your reservation has been taken into account.</h2>
<div>You will received a confirmation e-mail in few seconds.</div>
<br/>
<br/>
<div>You can consult all your booking reservations in the <a href="~/Reservations?email=@Model.ClientMail">"My reservations"</a> section of the site.
</div>
<br/>
<br/>
<div><strong>BookARoom</strong> wish you an happy journey at the <strong>@Model.HotelName</strong>.
</div>
}
else
{
<img src="~/images/HomerError.png" />
<h2>Your booking reservation has failed due to a missing or wrong e-mail.</h2>
<br/>
<div><a href="" class="button" onclick="history.back(); return false;">Click here to retry.</a></div>
<br />
}
================================================
FILE: src/BookARoom.Infra.Web/Views/BookingOptions/index.cshtml
================================================
@model BookARoom.Infra.Web.ViewModels.BookingOptionsViewModel
@{
ViewData["Title"] = "Pick your best booking option";
}
<br/>
<h2>You would like to go to: "<b>@Model.SearchCriterias.Destination</b>"</h2>
and to book a room <b>for @Model.SearchCriterias.NumberOfAdults adult(s)</b> with check-in date: <b>@Model.SearchCriterias.CheckInDate.ToString("d")</b> and check-out date: <b>@Model.SearchCriterias.CheckOutDate.ToString("d")</b> <br />
@if (!Model.Options.Any())
{
<br />
<br />
<strong>Sorry, we couldn't find any available room for your criteria.</strong>
<br />
<br />
<a href="" class="button" onclick="history.back(); return false;">Ok, let me change my criteria</a>
<br />
<br />
<br />
}
else
{
<br />
<a href="" class="button" onclick="history.back(); return false;">Oups, let me change something.</a>
<br />
<br />
<br />
<div>Here is the list of all available booking options for you. Just click the button to book-a-room!</div>
<br />
<script>
function postFormFor(hotelIdentifier, hotelName, roomIdentifier) {
document.forms["bookingForm"].HotelId.value = hotelIdentifier;
document.forms["bookingForm"].HotelName.value = hotelName;
document.forms["bookingForm"].RoomId.value = roomIdentifier;
document.forms["bookingForm"].submit();
}
</script>
<form id="bookingForm" method="post" action="BookingRequest">
<input asp-for="@Model.BookingRequest.CheckInDate" type="hidden" name="CheckInDate" value="@Model.SearchCriterias.CheckInDate"/>
<input asp-for="@Model.BookingRequest.CheckOutDate" type="hidden" name="CheckOutDate" value="@Model.SearchCriterias.CheckOutDate"/>
<input asp-for="@Model.BookingRequest.HotelId" type="hidden" name="HotelId" value=""/>
<input asp-for="@Model.BookingRequest.HotelName" type="hidden" name="HotelName" value=""/>
<input asp-for="@Model.BookingRequest.RoomId" type="hidden" name="RoomId" value=""/>
<table>
<tr>
<th>Hotel name</th>
<th>Room code</th>
<th>One adult<br/>occupancy price</th>
<th>Two adults<br/>occupancy price</th>
<th>Book</th>
</tr>
@foreach (var bookingOption in Model.Options)
{
@foreach (var availableRoomsWithPrice in bookingOption.AvailableRoomsWithPrices)
{
<tr>
<td><strong>@bookingOption.Hotel</strong></td>
<td>@availableRoomsWithPrice.RoomIdentifier</td>
<td>@availableRoomsWithPrice.OneAdultOccupancyPrice</td>
<td>@availableRoomsWithPrice.TwoAdultsOccupancyPrice</td>
<td>
<a href="" class="button" onclick="postFormFor('@bookingOption.Hotel.Identifier', '@bookingOption.Hotel.Name', '@availableRoomsWithPrice.RoomIdentifier'); return false;">Book that room!</a>
</td>
</tr>
}
}
</table>
</form>
}
================================================
FILE: src/BookARoom.Infra.Web/Views/BookingRequest/index.cshtml
================================================
@model BookARoom.Infra.Web.ViewModels.BookingRequestViewModel
@{
ViewData["Title"] = "Book your room";
}
<br /><br />
<h2>Please, fill your e-mail in order to be able to book the following reservation:</h2>
<form method="post" action="BookingConfirmation">
<br />
<br />
Email: <input asp-for="ClientMail" type="email" name="ClientMail" /><br />
<br />
<br />
<h2>Booking request sum-up:</h2>
Hotel: <strong> @Model.HotelName</strong>
<input asp-for="HotelName" type="hidden" name="HotelName" value="@Model.HotelName" />
<input asp-for="HotelId" type="hidden" name="HotelId" value="@Model.HotelId" />
<br />
Room code: <strong>@Model.RoomId</strong>
<input asp-for="RoomId" type="hidden" name="RoomId" value="@Model.RoomId" />
<br />
<br />
Check-in date: <strong>@Model.CheckInDate.ToString("d")</strong>
<input asp-for="CheckInDate" type="hidden" name="CheckInDate" value="@Model.CheckInDate" />
<br />
Check-out date: <strong>@Model.CheckOutDate.ToString("d")</strong>
<input asp-for="CheckOutDate" type="hidden" name="CheckOutDate" value="@Model.CheckOutDate" />
<br />
<br />
<input type="submit" value="Confirm booking" />
</form>
================================================
FILE: src/BookARoom.Infra.Web/Views/Home/About.cshtml
================================================
@{
ViewData["Title"] = "About";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<p>BookARoom is a <strong>fake application to illustrate CQRS</strong> (without Event Sourcing) during a MS experiences conference.</p>
================================================
FILE: src/BookARoom.Infra.Web/Views/Home/Caroussel-old-index.cshtml
================================================
@{
ViewData["Title"] = "Home Page";
}
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
<li data-target="#myCarousel" data-slide-to="3"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
Learn how to build ASP.NET apps that can run anywhere.
<a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525028&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
<div class="item">
<img src="~/images/banner2.svg" alt="Visual Studio" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
There are powerful new features in Visual Studio for building modern web apps.
<a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525030&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
<div class="item">
<img src="~/images/banner3.svg" alt="Package Management" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
Bring in libraries from NuGet, Bower, and npm, and automate tasks using Grunt or Gulp.
<a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525029&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
<div class="item">
<img src="~/images/banner4.svg" alt="Microsoft Azure" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
<a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525027&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<div class="row">
<div class="col-md-3">
<h2>Application uses</h2>
<ul>
<li>Sample pages using ASP.NET Core MVC</li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side libraries</li>
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>How to</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699562">Add an appsetting in config and access it in app.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699318">Add client packages using Bower.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>Overview</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>Run & Deploy</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
</ul>
</div>
</div>
================================================
FILE: src/BookARoom.Infra.Web/Views/Home/Contact.cshtml
================================================
@{
ViewData["Title"] = "Contact";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<address>
<strong>Support:</strong>Thomas PIERRAIN (<strong><a href="https://twitter.com/tpierrain">use case driven</a></strong> on twitter)<br />
<strong>Code source:</strong> <a href="https://github.com/tpierrain/CQRS">https://github.com/tpierrain/CQRS</a><br />
</address>
================================================
FILE: src/BookARoom.Infra.Web/Views/Home/Index.cshtml
================================================
@model BookARoom.Infra.Web.ViewModels.SearchRoomQueryViewModel
@{
ViewData["Title"] = "Let’s find you an hotel to stay!";
}
<img src="~/images/bookARoom.gif" alt="Book a Room"/>
<h2>Let’s find you an hotel to stay!</h2>
<form method="post" action="BookingOptions">
<div><label>Destination: </label><input asp-for="Destination" type="text" size="220"/></div>
<div>
<span><label asp-for="CheckInDate">Check-in: </label><input asp-for="CheckInDate" name="checkInDate" type="date" /></span>
<span><label asp-for="CheckOutDate">Check-out: </label><input asp-for="CheckOutDate" name="checkOutDate" type="date" /></span>
</div>
<div><label>Number of adults: </label><input asp-for="NumberOfAdults" name="numberOfAdults" type="text" size="2" /></div>
<div><input type="submit" value="Search" /></div>
</form>
================================================
FILE: src/BookARoom.Infra.Web/Views/QueryReservations/index.cshtml
================================================
@model BookARoom.Infra.Web.ViewModels.QueryReservationsViewModel
@{
ViewData["Title"] = "Fill you e-mail";
}
<br /><br />
<h2>Please, fill your e-mail in order to be able to list all your reservations:</h2>
<form method="post" action="~/Reservations">
<br />
<br />
Email: <input asp-for="ClientMail" type="email" name="ClientMail" /><br />
<br />
<br />
<input type="submit" value="View my reservations" />
</form>
================================================
FILE: src/BookARoom.Infra.Web/Views/Reservations/index.cshtml
================================================
@model BookARoom.Infra.Web.ViewModels.ReservationsViewModel
@{
ViewData["Title"] = "Pick your best booking option";
}
<br />
<h2>Reservations made with "<strong>@Model.ClientEMail</strong>"</h2>
@if (!Model.Reservations.Any())
{
<br />
<br />
<strong>No reservation has been made with that e-mail so far.</strong>
<br />
<br />
<a href="~/QueryReservations/" class="button">Let me try with another mail</a>
<br />
<br />
<br />
}
else
{
<br />
<a href="~/QueryReservations/" class="button">Let me try with another mail</a>
<br />
<br />
<br />
<script>
//function postFormFor(hotelIdentifier, hotelName, roomIdentifier) {
// document.forms["bookingForm"].HotelId.value = hotelIdentifier;
// document.forms["bookingForm"].HotelName.value = hotelName;
// document.forms["bookingForm"].RoomId.value = roomIdentifier;
// document.forms["bookingForm"].submit();
//}
function cancelBooking(guid) {
alert("cancel booking for '" + guid + "'");
}
</script>
<form id="reservationsForm" method="post" action="ModifyReservation">
<input asp-for="@Model.ClientEMail" type="hidden" name="ClientEMail" value="@Model.ClientEMail" />
<table>
<tr>
<th>Hotel name</th>
<th>Hotel Id</th>
<th>Room code</th>
<th>check-in date</th>
<th>check-out date</th>
<th></th>
</tr>
@foreach (var reservation in Model.Reservations)
{
<tr>
<td><strong>@reservation.HotelName</strong></td>
<td>@reservation.HotelId</td>
<td>@reservation.RoomNumber</td>
<td>@reservation.CheckInDate.ToString("d")</td>
<td>@reservation.CheckOutDate.ToString("d")</td>
<td>
@*<a href="" class="button" onclick="cancelBooking('@reservation.Guid'); return false;">Cancel</a>*@
</td>
</tr>
}
</table>
</form>
}
================================================
FILE: src/BookARoom.Infra.Web/Views/Shared/Error.cshtml
================================================
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>
================================================
FILE: src/BookARoom.Infra.Web/Views/Shared/_Layout.cshtml
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - BookARoom</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<img src="~/images/icon.png" class="navbar-brand navbar-right" />
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">BookARoom.Infra.Web</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="QueryReservations" asp-action="Index">My reservations</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2016 - BookARoom</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
</body>
</html>
================================================
FILE: src/BookARoom.Infra.Web/Views/_ViewImports.cshtml
================================================
@using BookARoom.Infra.Web
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
================================================
FILE: src/BookARoom.Infra.Web/Views/_ViewStart.cshtml
================================================
@{
Layout = "_Layout";
}
================================================
FILE: src/BookARoom.Infra.Web/appsettings.json
================================================
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
================================================
FILE: src/BookARoom.Infra.Web/bower.json
================================================
{
"name": "asp.net",
"private": true,
"dependencies": {
"bootstrap": "3.3.6",
"jquery": "2.2.0",
"jquery-validation": "1.14.0",
"jquery-validation-unobtrusive": "3.2.6"
}
}
================================================
FILE: src/BookARoom.Infra.Web/bundleconfig.json
================================================
// Configure bundling and minification for the project.
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
{
"outputFileName": "wwwroot/css/site.min.css",
// An array of relative input file paths. Globbing patterns supported
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
// Optionally specify minification options
"minify": {
"enabled": true,
"renameLocals": true
},
// Optinally generate .map file
"sourceMap": false
}
]
================================================
FILE: src/BookARoom.Infra.Web/cssSandBox.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="./wwwroot/css/site.css" />
</head>
<body>
<h1>H1 title</h1>
<h2>H2 title</h2>
Table:<br/>
<table>
<tr>
<th>one</th>
<th>two</th>
<th>three</th>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
</table>
<hr/>
<form>
<label>Truc: </label>
<input type="text" />
<br/>
<input type="submit" value="allez go!">
</form>
<hr/>
<br/>
<button name="">Try new criteria</button>
</body>
</html>
================================================
FILE: src/BookARoom.Infra.Web/project.json
================================================
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
"BookARoom.Domain": {
"target": "project"
},
"BookARoom.Infra": {
"target": "project"
},
"BookARoom.IntegrationModel": {
"target": "project"
}
},
"tools": {
"BundlerMinifier.Core": "2.0.238",
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"include": [
"wwwroot",
"Views",
"Areas/**/Views",
"appsettings.json",
"web.config"
]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}
================================================
FILE: src/BookARoom.Infra.Web/web.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/_references.js
================================================
/// <autosync enabled="true" />
/// <reference path="js/site.js" />
/// <reference path="lib/bootstrap/dist/js/bootstrap.js" />
/// <reference path="lib/jquery/dist/jquery.js" />
/// <reference path="lib/jquery-validation/dist/jquery.validate.js" />
/// <reference path="lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js" />
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/css/site.css
================================================
body {
background-color: #f0ecec;
padding-top: 50px;
padding-bottom: 20px;
font-family: sans-serif;
}
/* Wrapping element */
/* Set some basic padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
padding-right: 15px;
}
/* Set widths on the form inputs since otherwise they're 100% wide */
input,
select,
textarea {
border: thin solid #2f4f4f;
background-color: #ffffff;
max-width: 380px;
margin-left:5px;
margin-right:5px;
margin-bottom: 5px;
margin-top: 5px;
padding: 4px;
}
a.button, button, input[type="submit"]{
cursor:pointer;
padding: 8px;
background-color: #ec1414;
border-style: solid;
border-color: #c21212;
color: #ffffff;
}
/* Carousel */
.carousel-caption p {
font-size: 20px;
line-height: 1.4;
}
/* Make .svg files in the carousel display properly in older browsers */
.carousel-inner .item img[src$=".svg"]
{
width: 100%;
}
/* Hide/rearrange for smaller screens */
@media screen and (max-width: 767px) {
/* Hide captions */
.carousel-caption {
display: none
}
}
table {
border: medium solid #c21212;
border-collapse: collapse;
}
td {
border: thin solid #c21212;
padding: 20px;
text-align: center;
background-color: #ffffff;
}
th {
border: thin solid #c21212;
background-color: #ec1414;
padding: 10px;
text-align: center;
color: #ffffff;
}
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/hotels/BudaFull-the-always-unavailable-hotel-availabilities.json
================================================
{
"HotelId": 4,
"HotelName": "BudaFull-the-always-unavailable-hotel",
"Location": "Budapest",
"NumberOfRooms": 5,
"AvailabilitiesAt": {
"2017-09-16T00:00:00": []
}
}
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/hotels/Danubius Health Spa Resort Helia-availabilities.json
================================================
{
"HotelId": 3,
"HotelName": "Danubius Health Spa Resort Helia",
"Location": "Budapest",
"NumberOfRooms": 125,
"AvailabilitiesAt": {
"2017-09-16T00:00:00": [
{
"RoomIdentifier": "101",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
}
]
}
}
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/hotels/New York Sofitel-availabilities.json
================================================
{
"HotelId": 1,
"HotelName": "New York Sofitel",
"Location": "New York",
"NumberOfRooms": 405,
"AvailabilitiesAt": {
"2017-09-16T00:00:00": [
{
"RoomIdentifier": "101",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "102",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "201",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 209.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 240.0
}
},
{
"RoomIdentifier": "301",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "302",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "303",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "304",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "305",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "306",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "307",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "308",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "405",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 145.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 170.0
}
},
{
"RoomIdentifier": "501",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 12000.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 12000.0
}
}
]
}
}
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/hotels/THE GRAND BUDAPEST HOTEL-availabilities.json
================================================
{
"HotelId": 2,
"HotelName": "THE GRAND BUDAPEST HOTEL",
"Location": "Budapest",
"NumberOfRooms": 240,
"AvailabilitiesAt": {
"2017-09-16T00:00:00": [
{
"RoomIdentifier": "101",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "102",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 109.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 140.0
}
},
{
"RoomIdentifier": "201",
"OneAdultOccupancyPrice": {
"Currency": "EUR",
"Value": 209.0
},
"TwoAdultsOccupancyPrice": {
"Currency": "EUR",
"Value": 240.0
}
}
]
}
}
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/js/site.js
================================================
// Write your Javascript code.
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/.bower.json
================================================
{
"name": "bootstrap",
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
"keywords": [
"css",
"js",
"less",
"mobile-first",
"responsive",
"front-end",
"framework",
"web"
],
"homepage": "http://getbootstrap.com",
"license": "MIT",
"moduleType": "globals",
"main": [
"less/bootstrap.less",
"dist/js/bootstrap.js"
],
"ignore": [
"/.*",
"_config.yml",
"CNAME",
"composer.json",
"CONTRIBUTING.md",
"docs",
"js/tests",
"test-infra"
],
"dependencies": {
"jquery": "1.9.1 - 2"
},
"version": "3.3.6",
"_release": "3.3.6",
"_resolution": {
"type": "version",
"tag": "v3.3.6",
"commit": "81df608a40bf0629a1dc08e584849bb1e43e0b7a"
},
"_source": "git://github.com/twbs/bootstrap.git",
"_target": "3.3.6",
"_originalSource": "bootstrap"
}
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2011-2015 Twitter, Inc
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.
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css
================================================
/*!
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn-default.disabled,
.btn-primary.disabled,
.btn-success.disabled,
.btn-info.disabled,
.btn-warning.disabled,
.btn-danger.disabled,
.btn-default[disabled],
.btn-primary[disabled],
.btn-success[disabled],
.btn-info[disabled],
.btn-warning[disabled],
.btn-danger[disabled],
fieldset[disabled] .btn-default,
fieldset[disabled] .btn-primary,
fieldset[disabled] .btn-success,
fieldset[disabled] .btn-info,
fieldset[disabled] .btn-warning,
fieldset[disabled] .btn-danger {
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-default .badge,
.btn-primary .badge,
.btn-success .badge,
.btn-info .badge,
.btn-warning .badge,
.btn-danger .badge {
text-shadow: none;
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
background-color: #e0e0e0;
background-image: none;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #245580;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #265a88;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #265a88;
border-color: #245580;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
background-color: #265a88;
background-image: none;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-success.disabled,
.btn-success[disabled],
fieldset[disabled] .btn-success,
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled.focus,
.btn-success[disabled].focus,
fieldset[disabled] .btn-success.focus,
.btn-success.disabled:active,
.btn-success[disabled]:active,
fieldset[disabled] .btn-success:active,
.btn-success.disabled.active,
.btn-success[disabled].active,
fieldset[disabled] .btn-success.active {
background-color: #419641;
background-image: none;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-info.disabled,
.btn-info[disabled],
fieldset[disabled] .btn-info,
.btn-info.disabled:hover,
.btn-info[disabled]:hover,
fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
.btn-info.disabled.focus,
.btn-info[disabled].focus,
fieldset[disabled] .btn-info.focus,
.btn-info.disabled:active,
.btn-info[disabled]:active,
fieldset[disabled] .btn-info:active,
.btn-info.disabled.active,
.btn-info[disabled].active,
fieldset[disabled] .btn-info.active {
background-color: #2aabd2;
background-image: none;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-warning.disabled,
.btn-warning[disabled],
fieldset[disabled] .btn-warning,
.btn-warning.disabled:hover,
.btn-warning[disabled]:hover,
fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
.btn-warning.disabled.focus,
.btn-warning[disabled].focus,
fieldset[disabled] .btn-warning.focus,
.btn-warning.disabled:active,
.btn-warning[disabled]:active,
fieldset[disabled] .btn-warning:active,
.btn-warning.disabled.active,
.btn-warning[disabled].active,
fieldset[disabled] .btn-warning.active {
background-color: #eb9316;
background-image: none;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.btn-danger.disabled,
.btn-danger[disabled],
fieldset[disabled] .btn-danger,
.btn-danger.disabled:hover,
.btn-danger[disabled]:hover,
fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
.btn-danger.disabled.focus,
.btn-danger[disabled].focus,
fieldset[disabled] .btn-danger.focus,
.btn-danger.disabled:active,
.btn-danger[disabled]:active,
fieldset[disabled] .btn-danger:active,
.btn-danger.disabled.active,
.btn-danger[disabled].active,
fieldset[disabled] .btn-danger.active {
background-color: #c12e2a;
background-image: none;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #2e6da4;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
}
.navbar-inverse .navbar-nav > .open > a,
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
@media (max-width: 767px) {
.navbar .navbar-nav .open .dropdown-menu > .active > a,
.navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #fff;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #286090;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
background-repeat: repeat-x;
border-color: #2b669a;
}
.list-group-item.active .badge,
.list-group-item.active:hover .badge,
.list-group-item.active:focus .badge {
text-shadow: none;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */
================================================
FILE: src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/css/bootstrap.css
================================================
/*!
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
html {
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
body {
margin: 0;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
audio,
canvas,
progress,
video {
display: inline-block;
vertical-align: baseline;
}
audio:not([controls]) {
display: none;
height: 0;
}
[hidden],
template {
display: none;
}
a {
background-color: transparent;
}
a:active,
a:hover {
outline: 0;
}
abbr[title] {
border-bottom: 1px dotted;
}
b,
strong {
font-weight: bold;
}
dfn {
font-style: italic;
}
h1 {
margin: .67em 0;
font-size: 2em;
}
mark {
color: #000;
background: #ff0;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sup {
top: -.5em;
}
sub {
bottom: -.25em;
}
img {
border: 0;
}
svg:not(:root) {
overflow: hidden;
}
figure {
margin: 1em 40px;
}
hr {
height: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
pre {
overflow: auto;
}
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
button,
input,
optgroup,
select,
textarea {
margin: 0;
font: inherit;
color: inherit;
}
button {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button;
cursor: pointer;
}
button[disabled],
html input[disabled] {
cursor: default;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}
input {
line-height: normal;
}
input[type="checkbox"],
input[type="radio"] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
input[type="search"] {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
-webkit-appearance: textfield;
}
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
fieldset {
padding: .35em .625em .75em;
margin: 0 2px;
border: 1px solid #c0c0c0;
}
legend {
padding: 0;
border: 0;
}
textarea {
overflow: auto;
}
optgroup {
font-weight: bold;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
td,
th {
padding: 0;
}
/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
@media print {
*,
*:before,
*:after {
color: #000 !important;
text-shadow: none !important;
background: transparent !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
}
a,
a:visited {
text-decoration: underline;
}
a[href]:after {
content: " (" attr(href) ")";
}
abbr[title]:after {
content: " (" attr(title) ")";
}
a[href^="#"]:after,
a[href^="javascript:"]:after {
content: "";
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
tr,
img {
page-break-inside: avoid;
}
img {
max-width: 100% !important;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
.navbar {
display: none;
}
.btn > .caret,
.dropup > .btn > .caret {
border-top-color: #000 !important;
}
.label {
border: 1px solid #000;
}
.table {
border-collapse: collapse !important;
}
.table td,
.table th {
background-color: #fff !important;
}
.table-bordered th,
.table-bordered td {
border: 1px solid #ddd !important;
}
}
@font-face {
font-family: 'Glyphicons Halflings';
src: url('../fonts/glyphicons-halflings-regular.eot');
src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
.glyphicon {
position: relative;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.glyphicon-asterisk:before {
content: "\002a";
}
.glyphicon-plus:before {
content: "\002b";
}
.glyphicon-euro:before,
.glyphicon-eur:before {
content: "\20ac";
}
.glyphicon-minus:before {
content: "\2212";
}
.glyphicon-cloud:before {
content: "\2601";
}
.glyphicon-envelope:before {
content: "\2709";
}
.glyphicon-pencil:before {
content: "\270f";
}
.glyphicon-glass:before {
content: "\e001";
}
.glyphicon-music:before {
content: "\e002";
}
.glyphicon-search:before {
content: "\e003";
}
.glyphicon-heart:before {
content: "\e005";
}
.glyphicon-star:before {
content: "\e006";
}
.glyphicon-star-empty:before {
content: "\e007";
}
.glyphicon-user:before {
content: "\e008";
}
.glyphicon-film:before {
content: "\e009";
}
.glyphicon-th-large:before {
content: "\e010";
}
.glyphicon-th:before {
content: "\e011";
}
.glyphicon-th-list:before {
content: "\e012";
}
.glyphicon-ok:before {
content: "\e013";
}
.glyphicon-remove:before {
content: "\e014";
}
.glyphicon-zoom-in:before {
content: "\e015";
}
.glyphicon-zoom-out:before {
content: "\e016";
}
.glyphicon-off:before {
content: "\e017";
}
.glyphicon-signal:before {
content: "\e018";
}
.glyphicon-cog:before {
content: "\e019";
}
.glyphicon-trash:before {
content: "\e020";
}
.glyphicon-home:before {
content: "\e021";
}
.glyphicon-file:before {
content: "\e022";
}
.glyphicon-time:before {
content: "\e023";
}
.glyphicon-road:before {
content: "\e024";
}
.glyphicon-download-alt:before {
content: "\e025";
}
.glyphicon-download:before {
content: "\e026";
}
.glyphicon-upload:before {
content: "\e027";
}
.glyphicon-inbox:before {
content: "\e028";
}
.glyphicon-play-circle:before {
content: "\e029";
}
.glyphicon-repeat:before {
content: "\e030";
}
.glyphicon-refresh:before {
content: "\e031";
}
.glyphicon-list-alt:before {
content: "\e032";
}
.glyphicon-lock:before {
content: "\e033";
}
.glyphicon-flag:before {
content: "\e034";
}
.glyphicon-headphones:before {
content: "\e035";
}
.glyphicon-volume-off:before {
content: "\e036";
}
.glyphicon-volume-down:before {
content: "\e037";
}
.glyphicon-volume-up:before {
content: "\e038";
}
.glyphicon-qrcode:before {
content: "\e039";
}
.glyphicon-barcode:before {
content: "\e040";
}
.glyphicon-tag:before {
content: "\e041";
}
.glyphicon-tags:before {
content: "\e042";
}
.glyphicon-book:before {
content: "\e043";
}
.glyphicon-bookmark:before {
content: "\e044";
}
.glyphicon-print:before {
content: "\e045";
}
.glyphicon-camera:before {
content: "\e046";
}
.glyphicon-font:before {
content: "\e047";
}
.glyphicon-bold:before {
content: "\e048";
}
.glyphicon-italic:before {
content: "\e049";
}
.glyphicon-text-height:before {
content: "\e050";
}
.glyphicon-text-width:before {
content: "\e051";
}
.glyphicon-align-left:before {
content: "\e052";
}
.glyphicon-align-center:before {
content: "\e053";
}
.glyphicon-align-right:before {
content: "\e054";
}
.glyphicon-align-justify:before {
content: "\e055";
}
.glyphicon-list:before {
content: "\e056";
}
.glyphicon-indent-left:before {
content: "\e057";
}
.glyphicon-indent-right:before {
content: "\e058";
}
.glyphicon-facetime-video:before {
content: "\e059";
}
.glyphicon-picture:before {
content: "\e060";
}
.glyphicon-map-marker:before {
content: "\e062";
}
.glyphicon-adjust:before {
content: "\e063";
}
.glyphicon-tint:before {
content: "\e064";
}
.glyphicon-edit:before {
content: "\e065";
}
.glyphicon-share:before {
content: "\e066";
}
.glyphicon-check:before {
content: "\e067";
}
.glyphicon-move:before {
content: "\e068";
}
.glyphicon-step-backward:before {
content: "\e069";
}
.glyphicon-fast-backward:before {
content: "\e070";
}
.glyphicon-backward:before {
content: "\e071";
}
.glyphicon-play:before {
content: "\e072";
}
.glyphicon-pause:before {
content: "\e073";
}
.glyphicon-stop:before {
content: "\e074";
}
.glyphicon-forward:before {
content: "\e075";
}
.glyphicon-fast-forward:before {
content: "\e076";
}
.glyphicon-step-forward:before {
content: "\e077";
}
.glyphicon-eject:before {
content: "\e078";
}
.glyphicon-chevron-left:before {
content: "\e079";
}
.glyphicon-chevron-right:before {
content: "\e080";
}
.glyphicon-plus-sign:before {
content: "\e081";
}
.glyphicon-minus-sign:before {
content: "\e082";
}
.glyphicon-remove-sign:before {
content: "\e083";
}
.glyphicon-ok-sign:before {
content: "\e084";
}
.glyphicon-question-sign:before {
content: "\e085";
}
.glyphicon-info-sign:before {
content: "\e086";
}
.glyphicon-screenshot:before {
content: "\e087";
}
.glyphicon-remove-circle:before {
content: "\e088";
}
.glyphicon-ok-circle:before {
content: "\e089";
}
.glyphicon-ban-circle:before {
content: "\e090";
}
.glyphicon-arrow-left:before {
content: "\e091";
}
.glyphicon-arrow-right:before {
content: "\e092";
}
.glyphicon-arrow-up:before {
content: "\e093";
}
.glyphicon-arrow-down:before {
content: "\e094";
}
.glyphicon-share-alt:before {
content: "\e095";
}
.glyphicon-resize-full:before {
content: "\e096";
}
.glyphicon-resize-small:before {
content: "\e097";
}
.glyphicon-exclamation-sign:before {
content: "\e101";
}
.glyphicon-gift:before {
content: "\e102";
}
.glyphicon-leaf:before {
content: "\e103";
}
.glyphicon-fire:before {
content: "\e104";
}
.glyphicon-eye-open:before {
content: "\e105";
}
.glyphicon-eye-close:before {
content: "\e106";
}
.glyphicon-warning-sign:before {
content: "\e107";
}
.glyphicon-plane:before {
content: "\e108";
}
.glyphicon-calendar:before {
content: "\e109";
}
.glyphicon-random:before {
content: "\e110";
}
.glyphicon-comment:before {
content: "\e111";
}
.glyphicon-magnet:before {
content: "\e112";
}
.glyphicon-chevron-up:before {
content: "\e113";
}
.glyphicon-chevron-down:before {
content: "\e114";
}
.glyphicon-retweet:before {
content: "\e115";
}
.glyphicon-shopping-cart:before {
content: "\e116";
}
.glyphicon-folder-close:before {
content: "\e117";
}
.glyphicon-folder-open:before {
content: "\e118";
}
.glyphicon-resize-vertical:before {
content: "\e119";
}
.glyphicon-resize-horizontal:before {
content: "\e120";
}
.glyphicon-hdd:before {
content: "\e121";
}
.glyphicon-bullhorn:before {
content: "\e122";
}
.glyphicon-bell:before {
content: "\e123";
}
.glyphicon-certificate:before {
content: "\e124";
}
.glyphicon-thumbs-up:before {
content: "\e125";
}
.glyphicon-thumbs-down:before {
content: "\e126";
}
.glyphicon-hand-right:before {
content: "\e127";
}
.glyphicon-hand-left:before {
content: "\e128";
}
.glyphicon-hand-up:before {
content: "\e129";
}
.glyphicon-hand-down:before {
content: "\e130";
}
.glyphicon-circle-arrow-right:before {
content: "\e131";
}
.glyphicon-circle-arrow-left:before {
content: "\e132";
}
.glyphicon-circle-arrow-up:before {
content: "\e133";
}
.glyphicon-circle-arrow-down:before {
content: "\e134";
}
.glyphicon-globe:before {
content: "\e135";
}
.glyphicon-wrench:before {
content: "\e136";
}
.glyphicon-tasks:before {
content: "\e137";
}
.glyphicon-filter:before {
content: "\e138";
}
.glyphicon-briefcase:before {
content: "\e139";
}
.glyphicon-fullscreen:before {
content: "\e140";
}
.glyphicon-dashboard:before {
content: "\e141";
}
.glyphicon-paperclip:before {
content: "\e142";
}
.glyphicon-heart-empty:before {
content: "\e143";
}
.glyphicon-link:before {
content: "\e144";
}
.glyphicon-phone:before {
content: "\e145";
}
.glyphicon-pushpin:before {
content: "\e146";
}
.glyphicon-usd:before {
content: "\e148";
}
.glyphicon-gbp:before {
content: "\e149";
}
.glyphicon-sort:before {
content: "\e150";
}
.glyphicon-sort-by-alphabet:before {
content: "\e151";
}
.glyphicon-sort-by-alphabet-alt:before {
content: "\e152";
}
.glyphicon-sort-by-order:before {
content: "\e153";
}
.glyphicon-sort-by-order-alt:before {
content: "\e154";
}
.glyphicon-sort-by-attributes:before {
content: "\e155";
}
.glyphicon-sort-by-attributes-alt:before {
content: "\e156";
}
.glyphicon-unchecked:before {
content: "\e157";
}
.glyphicon-expand:before {
content: "\e158";
}
.glyphicon-collapse-down:before {
content: "\e159";
}
.glyphicon-collapse-up:before {
content: "\e160";
}
.glyphicon-log-in:before {
content: "\e161";
}
.glyphicon-flash:before {
content: "\e162";
}
.glyphicon-log-out:before {
content: "\e163";
}
.glyphicon-new-window:before {
content: "\e164";
}
.glyphicon-record:before {
content: "\e165";
}
.glyphicon-save:before {
content: "\e166";
}
.glyphicon-open:before {
content: "\e167";
}
.glyphicon-saved:before {
content: "\e168";
}
.glyphicon-import:before {
content: "\e169";
}
.glyphicon-export:before {
content: "\e170";
}
.glyphicon-send:before {
content: "\e171";
}
.glyphicon-floppy-disk:before {
content: "\e172";
}
.glyphicon-floppy-saved:before {
content: "\e173";
}
.glyphicon-floppy-remove:before {
content: "\e174";
}
.glyphicon-floppy-save:before {
content: "\e175";
}
.glyphicon-floppy-open:before {
content: "\e176";
}
.glyphicon-credit-card:before {
content: "\e177";
}
.glyphicon-transfer:before {
content: "\e178";
}
.glyphicon-cutlery:before {
content: "\e179";
}
.glyphicon-header:before {
content: "\e180";
}
.glyphicon-compressed:before {
content: "\e181";
}
.glyphicon-earphone:before {
content: "\e182";
}
.glyphicon-phone-alt:before {
content: "\e183";
}
.glyphicon-tower:before {
content: "\e184";
}
.glyphicon-stats:before {
content: "\e185";
}
.glyphicon-sd-video:before {
content: "\e186";
}
.glyphicon-hd-video:before {
content: "\e187";
}
.glyphicon-subtitles:before {
content: "\e188";
}
.glyphicon-sound-stereo:before {
content: "\e189";
}
.glyphicon-sound-dolby:before {
content: "\e190";
}
.glyphicon-sound-5-1:before {
content: "\e191";
}
.glyphicon-sound-6-1:before {
content: "\e192";
}
.glyphicon-sound-7-1:before {
content: "\e193";
}
.glyphicon-copyright-mark:before {
content: "\e194";
}
.glyphicon-registration-mark:before {
content: "\e195";
}
.glyphicon-cloud-download:before {
content: "\e197";
}
.glyphicon-cloud-upload:before {
content: "\e198";
}
.glyphicon-tree-conifer:before {
content: "\e199";
}
.glyphicon-tree-deciduous:before {
content: "\e200";
}
.glyphicon-cd:before {
content: "\e201";
}
.glyphicon-save-file:before {
content: "\e202";
}
.glyphicon-open-file:before {
content: "\e203";
}
.glyphicon-level-up:before {
content: "\e204";
}
.glyphicon-copy:before {
content: "\e205";
}
.glyphicon-paste:before {
content: "\e206";
}
.glyphicon-alert:before {
content: "\e209";
}
.glyphicon-equalizer:before {
content: "\e210";
}
.glyphicon-king:before {
content: "\e211";
}
.glyphicon-queen:before {
content: "\e212";
}
.glyphicon-pawn:before {
content: "\e213";
}
.glyphicon-bishop:before {
content: "\e214";
}
.glyphicon-knight:before {
content: "\e215";
}
.glyphicon-baby-formula:before {
content: "\e216";
}
.glyphicon-tent:before {
content: "\26fa";
}
.glyphicon-blackboard:before {
content: "\e218";
}
.glyphicon-bed:before {
content: "\e219";
}
.glyphicon-apple:before {
content: "\f8ff";
}
.glyphicon-erase:before {
content: "\e221";
}
.glyphicon-hourglass:before {
content: "\231b";
}
.glyphicon-lamp:before {
content: "\e223";
}
.glyphicon-duplicate:before {
content: "\e224";
}
.glyphicon-piggy-bank:before {
content: "\e225";
}
.glyphicon-scissors:before {
content: "\e226";
}
.glyphicon-bitcoin:before {
content: "\e227";
}
.glyphicon-btc:before {
content: "\e227";
}
.glyphicon-xbt:before {
content: "\e227";
}
.glyphicon-yen:before {
content: "\00a5";
}
.glyphicon-jpy:before {
content: "\00a5";
}
.glyphicon-ruble:before {
content: "\20bd";
}
.glyphicon-rub:before {
content: "\20bd";
}
.glyphicon-scale:before {
content: "\e230";
}
.glyphicon-ice-lolly:before {
content: "\e231";
}
.glyphicon-ice-lolly-tasted:before {
content: "\e232";
}
.glyphicon-education:before {
content: "\e233";
}
.glyphicon-option-horizontal:before {
content: "\e234";
}
.glyphicon-option-vertical:before {
content: "\e235";
}
.glyphicon-menu-hamburger:before {
content: "\e236";
}
.glyphicon-modal-window:before {
content: "\e237";
}
.glyphicon-oil:before {
content: "\e238";
}
.glyphicon-grain:before {
content: "\e239";
}
.glyphicon-sunglasses:before {
content: "\e240";
}
.glyphicon-text-size:before {
content: "\e241";
}
.glyphicon-text-color:before {
content: "\e242";
}
.glyphicon-text-background:before {
content: "\e243";
}
.glyphicon-object-align-top:before {
content: "\e244";
}
.glyphicon-object-align-bottom:before {
content: "\e245";
}
.glyphicon-object-align-horizontal:before {
content: "\e246";
}
.glyphicon-object-align-left:before {
content: "\e247";
}
.glyphicon-object-align-vertical:before {
content: "\e248";
}
.glyphicon-object-align-right:before {
content: "\e249";
}
.glyphicon-triangle-right:before {
content: "\e250";
}
.glyphicon-triangle-left:before {
content: "\e251";
}
.glyphicon-triangle-bottom:before {
content: "\e252";
}
.glyphicon-triangle-top:before {
content: "\e253";
}
.glyphicon-console:before {
content: "\e254";
}
.glyphicon-superscript:before {
content: "\e255";
}
.glyphicon-subscript:before {
content: "\e256";
}
.glyphicon-menu-left:before {
content: "\e257";
}
.glyphicon-menu-right:before {
content: "\e258";
}
.glyphicon-menu-down:before {
content: "\e259";
}
.glyphicon-menu-up:before {
content: "\e260";
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
font-size: 10px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #333;
background-color: #fff;
}
input,
button,
select,
textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
a {
color: #337ab7;
text-decoration: none;
}
a:hover,
a:focus {
color: #23527c;
text-decoration: underline;
}
a:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
figure {
margin: 0;
}
img {
vertical-align: middle;
}
.img-responsive,
.thumbnail > img,
.thumbnail a > img,
.carousel-inner > .item > img,
.carousel-inner > .item > a > img {
display: block;
max-width: 100%;
height: auto;
}
.img-rounded {
border-radius: 6px;
}
.img-thumbnail {
display: inline-block;
max-width: 100%;
height: auto;
padding: 4px;
line-height: 1.42857143;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
-webkit-transition: all .2s ease-in-out;
-o-transition: all .2s ease-in-out;
transition: all .2s ease-in-out;
}
.img-circle {
border-radius: 50%;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.sr-only-focusable:active,
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
}
[role="button"] {
cursor: pointer;
}
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.1;
color: inherit;
}
h1 small,
h2 small,
h3 small,
h4 small,
h5 small,
h6 small,
.h1 small,
.h2 small,
.h3 small,
.h4 small,
.h5 small,
.h6 small,
h1 .small,
h2 .small,
h3 .small,
h4 .small,
h5 .small,
h6 .small,
.h1 .small,
.h2 .small,
.h3 .small,
.h4 .small,
.h5 .small,
.h6 .small {
font-weight: normal;
line-height: 1;
color: #777;
}
h1,
.h1,
h2,
.h2,
h3,
.h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h1 small,
.h1 small,
h2 small,
.h2 small,
h3 small,
.h3 small,
h1 .small,
.h1 .small,
h2 .small,
.h2 .small,
h3 .small,
.h3 .small {
font-size: 65%;
}
h4,
.h4,
h5,
.h5,
h6,
.h6 {
margin-top: 10px;
margin-bottom: 10px;
}
h4 small,
.h4 small,
h5 small,
.h5 small,
h6 small,
.h6 small,
h4 .small,
.h4 .small,
h5 .small,
.h5 .small,
h6 .small,
.h6 .small {
font-size: 75%;
}
h1,
.h1 {
font-size: 36px;
}
h2,
.h2 {
font-size: 30px;
}
h3,
.h3 {
font-size: 24px;
}
h4,
.h4 {
font-size: 18px;
}
h5,
.h5 {
font-size: 14px;
}
h6,
.h6 {
font-size: 12px;
}
p {
margin: 0 0 10px;
}
.lead {
margin-bottom: 20px;
font-size: 16px;
font-weight: 300;
line-height: 1.4;
}
@media (min-width: 768px) {
.lead {
font-size: 21px;
}
}
small,
.small {
font-size: 85%;
}
mark,
.mark {
padding: .2em;
background-color: #fcf8e3;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.text-center {
text-align: center;
}
.text-justify {
text-align: justify;
}
.text-nowrap {
white-space: nowrap;
}
.text-lowercase {
text-transform: lowercase;
}
.text-uppercase {
text-transform: uppercase;
}
.text-capitalize {
text-transform: capitalize;
}
.text-muted {
color: #777;
}
.text-primary {
color: #337ab7;
}
a.text-primary:hover,
a.text-primary:focus {
color: #286090;
}
.text-success {
color: #3c763d;
}
a.text-success:hover,
a.text-success:focus {
color: #2b542c;
}
.text-info {
color: #31708f;
}
a.text-info:hover,
a.text-info:focus {
color: #245269;
}
.text-warning {
color: #8a6d3b;
}
a.text-warning:hover,
a.text-warning:focus {
color: #66512c;
}
.text-danger {
color: #a94442;
}
a.text-danger:hover,
a.text-danger:focus {
color: #843534;
}
.bg-primary {
color: #fff;
background-color: #337ab7;
}
a.bg-primary:hover,
a.bg-primary:focus {
background-color: #286090;
}
.bg-success {
background-color: #dff0d8;
}
a.bg-success:hover,
a.bg-success:focus {
background-color: #c1e2b3;
}
.bg-info {
background-color: #d9edf7;
}
a.bg-info:hover,
a.bg-info:focus {
background-color: #afd9ee;
}
.bg-warning {
background-color: #fcf8e3;
}
a.bg-warning:hover,
a.bg-warning:focus {
background-color: #f7ecb5;
}
.bg-danger {
background-color: #f2dede;
}
a.bg-danger:hover,
a.bg-danger:focus {
background-color: #e4b9b9;
}
.page-header {
padding-bottom: 9px;
margin: 40px 0 20px;
border-bottom: 1px solid #eee;
}
ul,
ol {
margin-top: 0;
margin-bottom: 10px;
}
ul ul,
ol ul,
ul ol,
ol ol {
margin-bottom: 0;
}
.list-unstyled {
padding-left: 0;
list-style: none;
}
.list-inline {
padding-left: 0;
margin-left: -5px;
list-style: none;
}
.list-inline > li {
display: inline-block;
padding-right: 5px;
padding-left: 5px;
}
dl {
margin-top: 0;
margin-bottom: 20px;
}
dt,
dd {
line-height: 1.42857143;
}
dt {
font-weight: bold;
}
dd {
margin-left: 0;
}
@media (min-width: 768px) {
.dl-horizontal dt {
float: left;
width: 160px;
overflow: hidden;
clear: left;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
}
.dl-horizontal dd {
margin-left: 180px;
}
}
abbr[title],
abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted #777;
}
.initialism {
font-size: 90%;
text-transform: uppercase;
}
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
blockquote p:last-child,
blockquote ul:last-child,
blockquote ol:last-child {
margin-bottom: 0;
}
blockquote footer,
blockquote small,
blockquote .small {
display: block;
font-size: 80%;
line-height: 1.42857143;
color: #777;
}
blockquote footer:before,
blockquote small:before,
blockquote .small:before {
content: '\2014 \00A0';
}
.blockquote-reverse,
blockquote.pull-right {
padding-right: 15px;
padding-left: 0;
text-align: right;
border-right: 5px solid #eee;
border-left: 0;
}
.blockquote-reverse footer:before,
blockquote.pull-right footer:before,
.blockquote-reverse small:before,
blockquote.pull-right small:before,
.blockquote-reverse .small:before,
blockquote.pull-right .small:before {
content: '';
}
.blockquote-reverse footer:after,
blockquote.pull-right footer:after,
.blockquote-reverse small:after,
blockquote.pull-right small:after,
.blockquote-reverse .small:after,
blockquote.pull-right .small:after {
content: '\00A0 \2014';
}
address {
margin-bottom: 20px;
font-style: normal;
line-height: 1.42857143;
}
code,
kbd,
pre,
samp {
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
}
kbd {
padding: 2px 4px;
font-size: 90%;
color: #fff;
background-color: #333;
border-radius: 3px;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
}
kbd kbd {
padding: 0;
font-size: 100%;
font-weight: bold;
-webkit-box-shadow: none;
gitextract_cow58ptr/
├── .gitattributes
├── .gitignore
├── BookARoom.sln
├── LabInstructions.md
├── MiscNotes.md
├── README.md
├── documentation/
│ ├── 0- InstallationsSteps.txt
│ └── FollowTheWhiteRabbit.md
├── global.json
├── src/
│ ├── BookARoom.Domain/
│ │ ├── BookARoom.Domain.xproj
│ │ ├── ICommand.cs
│ │ ├── IEvent.cs
│ │ ├── IMessage.cs
│ │ ├── IPublishEvents.cs
│ │ ├── ISendCommands.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── Query.cs
│ │ ├── ReadModel/
│ │ │ ├── BookingOption.cs
│ │ │ ├── Hotel.cs
│ │ │ ├── IProvideHotel.cs
│ │ │ ├── IProvideReservations.cs
│ │ │ ├── IProvideRooms.cs
│ │ │ ├── IQueryBookingOptions.cs
│ │ │ ├── IStoreAndProvideHotelsAndRooms.cs
│ │ │ ├── ISubscribeToEvents.cs
│ │ │ ├── Price.cs
│ │ │ ├── ReadModelFacade.cs
│ │ │ ├── Reservation.cs
│ │ │ ├── RoomWithPrices.cs
│ │ │ └── SearchBookingOptions.cs
│ │ ├── WriteModel/
│ │ │ ├── Booking.cs
│ │ │ ├── BookingCommand.cs
│ │ │ ├── BookingStore.cs
│ │ │ ├── IBookRooms.cs
│ │ │ ├── IHandleClients.cs
│ │ │ ├── ISaveBooking.cs
│ │ │ ├── RoomBooked.cs
│ │ │ └── WriteModelFacade.cs
│ │ └── project.json
│ ├── BookARoom.Infra/
│ │ ├── BookARoom.Infra.xproj
│ │ ├── CompositionRootHelper.cs
│ │ ├── MessageBus/
│ │ │ ├── AsynchronousThreadPoolPublicationStrategy.cs
│ │ │ ├── FakeBus.cs
│ │ │ ├── IPublishToHandlers.cs
│ │ │ └── SynchronousPublicationStrategy.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── ReadModel/
│ │ │ ├── Adapters/
│ │ │ │ ├── HotelsAndRoomsAdapter.cs
│ │ │ │ └── ReservationAdapter.cs
│ │ │ └── HotelsAndRoomsRepository.cs
│ │ ├── WriteModel/
│ │ │ └── BookingAndClientsRepository.cs
│ │ └── project.json
│ ├── BookARoom.Infra.Web/
│ │ ├── .bowerrc
│ │ ├── BookARoom.Infra.Web.xproj
│ │ ├── Controllers/
│ │ │ ├── BookingConfirmationController.cs
│ │ │ ├── BookingOptionsController.cs
│ │ │ ├── BookingRequestController.cs
│ │ │ ├── HomeController.cs
│ │ │ ├── QueryReservations.cs
│ │ │ └── ReservationsController.cs
│ │ ├── Program.cs
│ │ ├── Project_Readme.html
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── Startup.cs
│ │ ├── ViewModels/
│ │ │ ├── BookingOptionsViewModel.cs
│ │ │ ├── BookingRequestViewModel.cs
│ │ │ ├── QueryReservationsViewModel.cs
│ │ │ ├── ReservationsViewModel.cs
│ │ │ └── SearchRoomQueryViewModel.cs
│ │ ├── Views/
│ │ │ ├── BookingConfirmation/
│ │ │ │ └── index.cshtml
│ │ │ ├── BookingOptions/
│ │ │ │ └── index.cshtml
│ │ │ ├── BookingRequest/
│ │ │ │ └── index.cshtml
│ │ │ ├── Home/
│ │ │ │ ├── About.cshtml
│ │ │ │ ├── Caroussel-old-index.cshtml
│ │ │ │ ├── Contact.cshtml
│ │ │ │ └── Index.cshtml
│ │ │ ├── QueryReservations/
│ │ │ │ └── index.cshtml
│ │ │ ├── Reservations/
│ │ │ │ └── index.cshtml
│ │ │ ├── Shared/
│ │ │ │ ├── Error.cshtml
│ │ │ │ └── _Layout.cshtml
│ │ │ ├── _ViewImports.cshtml
│ │ │ └── _ViewStart.cshtml
│ │ ├── appsettings.json
│ │ ├── bower.json
│ │ ├── bundleconfig.json
│ │ ├── cssSandBox.html
│ │ ├── project.json
│ │ ├── web.config
│ │ └── wwwroot/
│ │ ├── _references.js
│ │ ├── css/
│ │ │ └── site.css
│ │ ├── hotels/
│ │ │ ├── BudaFull-the-always-unavailable-hotel-availabilities.json
│ │ │ ├── Danubius Health Spa Resort Helia-availabilities.json
│ │ │ ├── New York Sofitel-availabilities.json
│ │ │ └── THE GRAND BUDAPEST HOTEL-availabilities.json
│ │ ├── js/
│ │ │ └── site.js
│ │ └── lib/
│ │ ├── bootstrap/
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE
│ │ │ └── dist/
│ │ │ ├── css/
│ │ │ │ ├── bootstrap-theme.css
│ │ │ │ └── bootstrap.css
│ │ │ └── js/
│ │ │ ├── bootstrap.js
│ │ │ └── npm.js
│ │ ├── jquery/
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE.txt
│ │ │ └── dist/
│ │ │ └── jquery.js
│ │ ├── jquery-validation/
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE.md
│ │ │ └── dist/
│ │ │ ├── additional-methods.js
│ │ │ └── jquery.validate.js
│ │ └── jquery-validation-unobtrusive/
│ │ ├── .bower.json
│ │ └── jquery.validate.unobtrusive.js
│ └── BookARoom.IntegrationModel/
│ ├── BookARoom.IntegrationModel.xproj
│ ├── HotelDetailsWithRoomsAvailabilities.cs
│ ├── IntegrationFilesGenerator.cs
│ ├── Price.cs
│ ├── Program.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── RoomStatusAndPrices.cs
│ └── project.json
└── test/
└── BookARoom.Tests/
├── Acceptance/
│ ├── BookingTests.cs
│ ├── ReservationsTests.cs
│ └── SearchRoomsTests.cs
├── BookARoom.Tests.xproj
├── Constants.cs
├── HotelsAndRoomsAdapterTests.cs
├── Properties/
│ └── AssemblyInfo.cs
└── project.json
SYMBOL INDEX (288 symbols across 64 files)
FILE: src/BookARoom.Domain/ICommand.cs
type ICommand (line 3) | public interface ICommand : IMessage
FILE: src/BookARoom.Domain/IEvent.cs
type IEvent (line 3) | public interface IEvent : IMessage
FILE: src/BookARoom.Domain/IMessage.cs
type IMessage (line 3) | public interface IMessage
FILE: src/BookARoom.Domain/IPublishEvents.cs
type IPublishEvents (line 3) | public interface IPublishEvents
method PublishTo (line 5) | void PublishTo<T>(T @event) where T : IEvent;
FILE: src/BookARoom.Domain/ISendCommands.cs
type ISendCommands (line 3) | public interface ISendCommands
method Send (line 5) | void Send<T>(T command) where T : ICommand;
FILE: src/BookARoom.Domain/Query.cs
class Query (line 3) | public class Query : IMessage
FILE: src/BookARoom.Domain/ReadModel/BookingOption.cs
class BookingOption (line 6) | public class BookingOption
method BookingOption (line 12) | public BookingOption(Hotel hotel, IEnumerable<RoomWithPrices> availabl...
method ToString (line 18) | public override string ToString()
FILE: src/BookARoom.Domain/ReadModel/Hotel.cs
class Hotel (line 3) | public class Hotel
method Hotel (line 5) | public Hotel(int hotelId, string name, string location, int numberOfRo...
method ToString (line 18) | public override string ToString()
FILE: src/BookARoom.Domain/ReadModel/IProvideHotel.cs
type IProvideHotel (line 9) | public interface IProvideHotel
method SearchFromLocation (line 11) | IEnumerable<Hotel> SearchFromLocation(string location);
method GetHotel (line 12) | Hotel GetHotel(int hotelId);
FILE: src/BookARoom.Domain/ReadModel/IProvideReservations.cs
type IProvideReservations (line 5) | public interface IProvideReservations
method GetReservationsFor (line 7) | IEnumerable<Reservation> GetReservationsFor(string clientId);
FILE: src/BookARoom.Domain/ReadModel/IProvideRooms.cs
type IProvideRooms (line 10) | public interface IProvideRooms
method SearchAvailableHotelsInACaseInsensitiveWay (line 13) | IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensitiveWay(...
FILE: src/BookARoom.Domain/ReadModel/IQueryBookingOptions.cs
type IQueryBookingOptions (line 8) | public interface IQueryBookingOptions
method SearchBookingOptions (line 10) | IEnumerable<BookingOption> SearchBookingOptions(SearchBookingOptions q...
FILE: src/BookARoom.Domain/ReadModel/IStoreAndProvideHotelsAndRooms.cs
type IStoreAndProvideHotelsAndRooms (line 6) | public interface IStoreAndProvideHotelsAndRooms : IProvideHotel
method SearchAvailableHotelsInACaseInsensitiveWay (line 10) | IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensitiveWay(...
method StoreHotel (line 12) | void StoreHotel(int hotelId, Hotel hotel);
method StoreHotelAvailabilities (line 13) | void StoreHotelAvailabilities(Hotel hotel, Dictionary<DateTime, List<R...
method DeclareRoomBooked (line 15) | void DeclareRoomBooked(int hotelId, string roomNumber, DateTime checkI...
FILE: src/BookARoom.Domain/ReadModel/ISubscribeToEvents.cs
type ISubscribeToEvents (line 5) | public interface ISubscribeToEvents
method RegisterHandler (line 7) | void RegisterHandler<T>(Action<T> handler) where T : IMessage;
FILE: src/BookARoom.Domain/ReadModel/Price.cs
class Price (line 3) | public class Price
method Price (line 8) | public Price(string currency, double value)
method ToString (line 14) | public override string ToString()
FILE: src/BookARoom.Domain/ReadModel/ReadModelFacade.cs
class ReadModelFacade (line 9) | public class ReadModelFacade : IQueryBookingOptions, IProvideHotel, IPro...
method ReadModelFacade (line 24) | public ReadModelFacade(IProvideRooms roomsProvider, IProvideHotel hote...
method SearchBookingOptions (line 33) | public IEnumerable<BookingOption> SearchBookingOptions(SearchBookingOp...
method SearchBookingOptions (line 38) | private IEnumerable<BookingOption> SearchBookingOptions(DateTime check...
method SearchFromLocation (line 52) | public IEnumerable<Hotel> SearchFromLocation(string location)
method GetHotel (line 57) | public Hotel GetHotel(int hotelId)
method GetReservationsFor (line 64) | public IEnumerable<Reservation> GetReservationsFor(string clientId)
FILE: src/BookARoom.Domain/ReadModel/Reservation.cs
class Reservation (line 5) | public class Reservation
method Reservation (line 16) | public Reservation(Guid guid, string clientId, string hotelName, strin...
method ToString (line 27) | public override string ToString()
FILE: src/BookARoom.Domain/ReadModel/RoomWithPrices.cs
class RoomWithPrices (line 3) | public class RoomWithPrices
method RoomWithPrices (line 9) | public RoomWithPrices(string roomIdentifier, Price oneAdultOccupancyPr...
FILE: src/BookARoom.Domain/ReadModel/SearchBookingOptions.cs
class SearchBookingOptions (line 5) | public class SearchBookingOptions : Query
method SearchBookingOptions (line 14) | public SearchBookingOptions(DateTime checkInDate, DateTime checkOutDat...
FILE: src/BookARoom.Domain/WriteModel/Booking.cs
class Booking (line 5) | public class Booking
method Booking (line 15) | public Booking(Guid bookingId , string clientId, int hotelId, string r...
FILE: src/BookARoom.Domain/WriteModel/BookingCommand.cs
class BookingCommand (line 5) | public class BookingCommand : ICommand
method BookingCommand (line 14) | public BookingCommand(string clientId, string hotelName, int hotelId, ...
FILE: src/BookARoom.Domain/WriteModel/BookingStore.cs
class BookingStore (line 5) | public class BookingStore : IBookRooms
method BookingStore (line 11) | public BookingStore(ISaveBooking saveBooking, IHandleClients handleCli...
method BookARoom (line 18) | public void BookARoom(BookingCommand command)
FILE: src/BookARoom.Domain/WriteModel/IBookRooms.cs
type IBookRooms (line 3) | public interface IBookRooms
method BookARoom (line 5) | void BookARoom(BookingCommand command);
FILE: src/BookARoom.Domain/WriteModel/IHandleClients.cs
type IHandleClients (line 4) | public interface IHandleClients
method IsClientAlready (line 6) | bool IsClientAlready(string clientIdentifier);
method CreateClient (line 7) | void CreateClient(string clientIdentifier);
FILE: src/BookARoom.Domain/WriteModel/ISaveBooking.cs
type ISaveBooking (line 5) | public interface ISaveBooking
method Save (line 7) | void Save(Booking booking);
FILE: src/BookARoom.Domain/WriteModel/RoomBooked.cs
class RoomBooked (line 5) | public class RoomBooked : IEvent
method RoomBooked (line 15) | public RoomBooked(Guid guid, string hotelName, int hotelId, string cli...
FILE: src/BookARoom.Domain/WriteModel/WriteModelFacade.cs
class WriteModelFacade (line 3) | public class WriteModelFacade : IHandleCommand<BookingCommand>
method WriteModelFacade (line 7) | public WriteModelFacade(IBookRooms bookingStore)
method Handle (line 12) | public void Handle(BookingCommand command)
type IHandleCommand (line 18) | public interface IHandleCommand<T>
method Handle (line 20) | void Handle(T command);
FILE: src/BookARoom.Infra.Web/Controllers/BookingConfirmationController.cs
class BookingConfirmationController (line 10) | public class BookingConfirmationController : Controller
method BookingConfirmationController (line 14) | public BookingConfirmationController(ISendCommands bus)
method Index (line 21) | [HttpPost]
FILE: src/BookARoom.Infra.Web/Controllers/BookingOptionsController.cs
class BookingOptionsController (line 10) | public class BookingOptionsController : Controller
method BookingOptionsController (line 14) | public BookingOptionsController(IQueryBookingOptions searchService)
method Index (line 20) | public IActionResult Index(BookingOptionsViewModel bookingOptionsViewM...
method Index (line 25) | [HttpPost]
FILE: src/BookARoom.Infra.Web/Controllers/BookingRequestController.cs
class BookingRequestController (line 8) | public class BookingRequestController : Controller
method Index (line 11) | public IActionResult Index()
method Index (line 16) | [HttpPost]
FILE: src/BookARoom.Infra.Web/Controllers/HomeController.cs
class HomeController (line 9) | public class HomeController : Controller
method HomeController (line 13) | public HomeController(ISendCommands bus, IQueryBookingOptions searchSe...
method Index (line 18) | public IActionResult Index()
method About (line 28) | public IActionResult About()
method Contact (line 35) | public IActionResult Contact()
method Error (line 42) | public IActionResult Error()
FILE: src/BookARoom.Infra.Web/Controllers/QueryReservations.cs
class QueryReservations (line 8) | public class QueryReservations : Controller
method Index (line 10) | public IActionResult Index(string email)
FILE: src/BookARoom.Infra.Web/Controllers/ReservationsController.cs
class ReservationsController (line 9) | public class ReservationsController : Controller
method ReservationsController (line 13) | public ReservationsController(IProvideReservations reservationsProvider)
method Index (line 18) | [HttpGet]
method Index (line 27) | [HttpPost]
FILE: src/BookARoom.Infra.Web/Program.cs
class Program (line 6) | public class Program
method Main (line 8) | public static void Main(string[] args)
FILE: src/BookARoom.Infra.Web/Startup.cs
class Startup (line 14) | public class Startup
method Startup (line 18) | public Startup(IHostingEnvironment env)
method ConfigureServices (line 33) | public void ConfigureServices(IServiceCollection services)
method Configure (line 60) | public void Configure(IApplicationBuilder app, IHostingEnvironment env...
FILE: src/BookARoom.Infra.Web/ViewModels/BookingOptionsViewModel.cs
class BookingOptionsViewModel (line 6) | public class BookingOptionsViewModel
method BookingOptionsViewModel (line 14) | public BookingOptionsViewModel()
method BookingOptionsViewModel (line 18) | public BookingOptionsViewModel(SearchRoomQueryViewModel searchCriteria...
FILE: src/BookARoom.Infra.Web/ViewModels/BookingRequestViewModel.cs
class BookingRequestViewModel (line 5) | public class BookingRequestViewModel
FILE: src/BookARoom.Infra.Web/ViewModels/QueryReservationsViewModel.cs
class QueryReservationsViewModel (line 3) | public class QueryReservationsViewModel
method QueryReservationsViewModel (line 7) | public QueryReservationsViewModel()
method QueryReservationsViewModel (line 11) | public QueryReservationsViewModel(string clientMail)
FILE: src/BookARoom.Infra.Web/ViewModels/ReservationsViewModel.cs
class ReservationsViewModel (line 6) | public class ReservationsViewModel
method ReservationsViewModel (line 11) | public ReservationsViewModel()
method ReservationsViewModel (line 15) | public ReservationsViewModel(string clientEMail, IEnumerable<Reservati...
FILE: src/BookARoom.Infra.Web/ViewModels/SearchRoomQueryViewModel.cs
class SearchRoomQueryViewModel (line 5) | public class SearchRoomQueryViewModel
method SearchRoomQueryViewModel (line 12) | public SearchRoomQueryViewModel()
method SearchRoomQueryViewModel (line 16) | public SearchRoomQueryViewModel(string destination, DateTime checkInDa...
FILE: src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.js
function transitionEnd (line 34) | function transitionEnd() {
function removeElement (line 126) | function removeElement() {
function Plugin (line 142) | function Plugin(option) {
function Plugin (line 251) | function Plugin(option) {
function Plugin (line 470) | function Plugin(option) {
function getTargetFromTrigger (line 689) | function getTargetFromTrigger($trigger) {
function Plugin (line 701) | function Plugin(option) {
function getParent (line 768) | function getParent($this) {
function clearMenus (line 781) | function clearMenus(e) {
function Plugin (line 874) | function Plugin(option) {
function Plugin (line 1200) | function Plugin(option, _relatedTarget) {
function complete (line 1566) | function complete() {
function Plugin (line 1736) | function Plugin(option) {
function Plugin (line 1845) | function Plugin(option) {
function ScrollSpy (line 1888) | function ScrollSpy(element, options) {
function Plugin (line 2008) | function Plugin(option) {
function next (line 2117) | function next() {
function Plugin (line 2163) | function Plugin(option) {
function Plugin (line 2320) | function Plugin(option) {
FILE: src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js
function setValidationValues (line 14) | function setValidationValues(options, ruleName, value) {
function splitAndTrim (line 21) | function splitAndTrim(value) {
function escapeAttributeValue (line 25) | function escapeAttributeValue(value) {
function getModelPrefix (line 30) | function getModelPrefix(fieldName) {
function appendModelPrefix (line 34) | function appendModelPrefix(value, prefix) {
function onError (line 41) | function onError(error, inputElement) { // 'this' is the form element
function onErrors (line 58) | function onErrors(event, validator) { // 'this' is the form element
function onSuccess (line 72) | function onSuccess(error) { // 'this' is the form element
function onReset (line 88) | function onReset(event) { // 'this' is the form element
function validationInfo (line 113) | function validationInfo(form) {
FILE: src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation/dist/additional-methods.js
function stripHtml (line 19) | function stripHtml(value) {
FILE: src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation/dist/jquery.validate.js
function handle (line 65) | function handle() {
function delegate (line 375) | function delegate( event ) {
FILE: src/BookARoom.Infra.Web/wwwroot/lib/jquery/dist/jquery.js
function isArrayLike (line 524) | function isArrayLike( obj ) {
function Sizzle (line 733) | function Sizzle( selector, context, results, seed ) {
function createCache (line 873) | function createCache() {
function markFunction (line 891) | function markFunction( fn ) {
function assert (line 900) | function assert( fn ) {
function addHandle (line 922) | function addHandle( attrs, handler ) {
function siblingCheck (line 937) | function siblingCheck( a, b ) {
function createInputPseudo (line 964) | function createInputPseudo( type ) {
function createButtonPseudo (line 975) | function createButtonPseudo( type ) {
function createPositionalPseudo (line 986) | function createPositionalPseudo( fn ) {
function testContext (line 1009) | function testContext( context ) {
function setFilters (line 2054) | function setFilters() {}
function toSelector (line 2125) | function toSelector( tokens ) {
function addCombinator (line 2135) | function addCombinator( matcher, combinator, base ) {
function elementMatcher (line 2193) | function elementMatcher( matchers ) {
function multipleContexts (line 2207) | function multipleContexts( selector, contexts, results ) {
function condense (line 2216) | function condense( unmatched, map, filter, context, xml ) {
function setMatcher (line 2237) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
function matcherFromTokens (line 2330) | function matcherFromTokens( tokens ) {
function matcherFromGroupMatchers (line 2388) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
function winnow (line 2726) | function winnow( elements, qualifier, not ) {
function sibling (line 3033) | function sibling( cur, dir ) {
function createOptions (line 3109) | function createOptions( options ) {
function completed (line 3544) | function completed() {
function Data (line 3655) | function Data() {
function dataAttr (line 3865) | function dataAttr( elem, key, data ) {
function adjustCSS (line 4182) | function adjustCSS( elem, prop, valueParts, tween ) {
function getAll (line 4271) | function getAll( context, tag ) {
function setGlobalEval (line 4288) | function setGlobalEval( elems, refElements ) {
function buildFragment (line 4304) | function buildFragment( elems, context, scripts, selection, ignored ) {
function returnTrue (line 4425) | function returnTrue() {
function returnFalse (line 4429) | function returnFalse() {
function safeActiveElement (line 4435) | function safeActiveElement() {
function on (line 4441) | function on( elem, types, selector, data, fn, one ) {
function manipulationTarget (line 5131) | function manipulationTarget( elem, content ) {
function disableScript (line 5142) | function disableScript( elem ) {
function restoreScript (line 5146) | function restoreScript( elem ) {
function cloneCopyEvent (line 5158) | function cloneCopyEvent( src, dest ) {
function fixInput (line 5193) | function fixInput( src, dest ) {
function domManip (line 5206) | function domManip( collection, args, callback, ignored ) {
function remove (line 5296) | function remove( elem, selector, keepData ) {
function actualDisplay (line 5587) | function actualDisplay( name, doc ) {
function defaultDisplay (line 5603) | function defaultDisplay( nodeName ) {
function computeStyleTests (line 5699) | function computeStyleTests() {
function curCSS (line 5789) | function curCSS( elem, name, computed ) {
function addGetHookIf (line 5836) | function addGetHookIf( conditionFn, hookFn ) {
function vendorPropName (line 5873) | function vendorPropName( name ) {
function setPositiveNumber (line 5892) | function setPositiveNumber( elem, value, subtract ) {
function augmentWidthOrHeight (line 5904) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
function getWidthOrHeight (line 5948) | function getWidthOrHeight( elem, name, extra ) {
function showHide (line 6006) | function showHide( elements, show ) {
function Tween (line 6345) | function Tween( elem, options, prop, end, easing ) {
function createFxNow (line 6469) | function createFxNow() {
function genFx (line 6477) | function genFx( type, includeWidth ) {
function createTween (line 6497) | function createTween( value, prop, animation ) {
function defaultPrefilter (line 6511) | function defaultPrefilter( elem, props, opts ) {
function propFilter (line 6647) | function propFilter( props, specialEasing ) {
function Animation (line 6684) | function Animation( elem, properties, options ) {
function getClass (line 7357) | function getClass( elem ) {
function addToPrefiltersOrTransports (line 8022) | function addToPrefiltersOrTransports( structure ) {
function inspectPrefiltersOrTransports (line 8056) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
function ajaxExtend (line 8085) | function ajaxExtend( target, src ) {
function ajaxHandleResponses (line 8105) | function ajaxHandleResponses( s, jqXHR, responses ) {
function ajaxConvert (line 8163) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
function done (line 8668) | function done( status, nativeStatusText, responses, headers ) {
function buildParams (line 8921) | function buildParams( prefix, obj, traditional, add ) {
function getWindow (line 9504) | function getWindow( elem ) {
FILE: src/BookARoom.Infra/CompositionRootHelper.cs
class CompositionRootHelper (line 12) | public class CompositionRootHelper
method BuildTheReadModelHexagon (line 14) | public static ReadModelFacade BuildTheReadModelHexagon(IProvideRooms r...
method BuildTheWriteModelHexagon (line 29) | public static WriteModelFacade BuildTheWriteModelHexagon(ISaveBooking ...
method SubscribeCommands (line 42) | private static void SubscribeCommands(WriteModelFacade writeModelFacad...
FILE: src/BookARoom.Infra/MessageBus/AsynchronousThreadPoolPublicationStrategy.cs
class AsynchronousThreadPoolPublicationStrategy (line 7) | public class AsynchronousThreadPoolPublicationStrategy : IPublishToHandlers
method PublishTo (line 9) | public void PublishTo<T>(Action<IMessage> handler, T @event) where T :...
FILE: src/BookARoom.Infra/MessageBus/FakeBus.cs
class FakeBus (line 13) | public class FakeBus : ISendCommands, IPublishEvents, ISubscribeToEvents
method FakeBus (line 18) | public FakeBus(bool synchronousPublication = true)
method RegisterHandler (line 30) | public void RegisterHandler<T>(Action<T> handler) where T : IMessage
method Send (line 43) | public void Send<T>(T command) where T : ICommand
method PublishTo (line 58) | public void PublishTo<T>(T @event) where T : IEvent
FILE: src/BookARoom.Infra/MessageBus/IPublishToHandlers.cs
type IPublishToHandlers (line 6) | public interface IPublishToHandlers
method PublishTo (line 8) | void PublishTo<T>(Action<IMessage> handler, T @event) where T : IEvent;
FILE: src/BookARoom.Infra/MessageBus/SynchronousPublicationStrategy.cs
class SynchronousPublicationStrategy (line 6) | public class SynchronousPublicationStrategy : IPublishToHandlers
method PublishTo (line 8) | public void PublishTo<T>(Action<IMessage> handler, T @event) where T :...
FILE: src/BookARoom.Infra/ReadModel/Adapters/HotelsAndRoomsAdapter.cs
class HotelsAndRoomsAdapter (line 17) | public class HotelsAndRoomsAdapter : IProvideRooms, IProvideHotel
method HotelsAndRoomsAdapter (line 23) | public HotelsAndRoomsAdapter(string integrationFilesDirectoryPath, ISu...
method Handle (line 34) | private void Handle(RoomBooked roomBooked)
method LoadHotelFile (line 43) | public void LoadHotelFile(string hotelFileNameOrFilePath)
method LoadAllHotelsFiles (line 55) | public void LoadAllHotelsFiles()
method GetIntegrationModelForThisHotel (line 64) | private static HotelDetailsWithRoomsAvailabilities GetIntegrationModel...
method SearchAvailableHotelsInACaseInsensitiveWay (line 79) | public IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensit...
method SearchFromLocation (line 88) | public IEnumerable<Hotel> SearchFromLocation(string location)
method GetHotel (line 93) | public Hotel GetHotel(int hotelId)
method AdaptAndStoreData (line 102) | private void AdaptAndStoreData(HotelDetailsWithRoomsAvailabilities dat...
method AdaptAndStoreIntegrationFileContentForAnHotel (line 110) | private void AdaptAndStoreIntegrationFileContentForAnHotel(Hotel hotel...
method AdaptHotelAvailabilities (line 117) | private Dictionary<DateTime, List<RoomWithPrices>> AdaptHotelAvailabil...
method AdaptAllRoomsStatusOfThisHotelForThisDate (line 129) | private static List<RoomWithPrices> AdaptAllRoomsStatusOfThisHotelForT...
method AdaptRoomStatus (line 136) | private static RoomWithPrices AdaptRoomStatus(RoomStatusAndPrices room...
method AdaptPrice (line 141) | private static Price AdaptPrice(IntegrationModel.Price price)
method AdaptHotel (line 146) | private static Hotel AdaptHotel(int hotelId, string hotelName, string ...
FILE: src/BookARoom.Infra/ReadModel/Adapters/ReservationAdapter.cs
class ReservationAdapter (line 8) | public class ReservationAdapter : IProvideReservations
method ReservationAdapter (line 13) | public ReservationAdapter(ISubscribeToEvents eventsSubscriber)
method Handle (line 19) | private void Handle(RoomBooked @event)
method GetReservationsFor (line 30) | public IEnumerable<Reservation> GetReservationsFor(string clientId)
FILE: src/BookARoom.Infra/ReadModel/HotelsAndRoomsRepository.cs
class HotelsAndRoomsRepository (line 8) | public class HotelsAndRoomsRepository : IStoreAndProvideHotelsAndRooms
method HotelsAndRoomsRepository (line 13) | public HotelsAndRoomsRepository()
method SearchAvailableHotelsInACaseInsensitiveWay (line 20) | public IEnumerable<BookingOption> SearchAvailableHotelsInACaseInsensit...
method DeclareRoomBooked (line 36) | public void DeclareRoomBooked(int hotelId, string roomNumber, DateTime...
method StoreHotelAvailabilities (line 48) | public void StoreHotelAvailabilities(Hotel hotel, Dictionary<DateTime,...
method SearchFromLocation (line 53) | public IEnumerable<Hotel> SearchFromLocation(string location)
method GetHotel (line 60) | public Hotel GetHotel(int hotelId)
method StoreHotel (line 65) | public void StoreHotel(int hotelId, Hotel hotel)
FILE: src/BookARoom.Infra/WriteModel/BookingAndClientsRepository.cs
class BookingAndClientsRepository (line 6) | public class BookingAndClientsRepository : ISaveBooking, IHandleClients
method BookingAndClientsRepository (line 10) | public BookingAndClientsRepository()
method Save (line 15) | public void Save(Booking booking)
method IsClientAlready (line 20) | public bool IsClientAlready(string clientIdentifier)
method CreateClient (line 25) | public void CreateClient(string clientIdentifier)
method GetBookingsFrom (line 33) | public IEnumerable<Booking> GetBookingsFrom(string clientIdentifier)
FILE: src/BookARoom.IntegrationModel/HotelDetailsWithRoomsAvailabilities.cs
class HotelDetailsWithRoomsAvailabilities (line 6) | public class HotelDetailsWithRoomsAvailabilities
method HotelDetailsWithRoomsAvailabilities (line 15) | public HotelDetailsWithRoomsAvailabilities(int hotelId, string hotelNa...
FILE: src/BookARoom.IntegrationModel/IntegrationFilesGenerator.cs
class IntegrationFilesGenerator (line 11) | public static class IntegrationFilesGenerator
method GenerateJsonFileForNewYorkSofitel (line 17) | public static void GenerateJsonFileForNewYorkSofitel()
method GenerateJsonFileForGrandBudapestHotel (line 46) | public static void GenerateJsonFileForGrandBudapestHotel()
method GenerateJsonFileForDanubiusHealthSpaResortHelia (line 60) | public static void GenerateJsonFileForDanubiusHealthSpaResortHelia()
method GenerateJsonFileForBudaFullAlwaysUnavailable (line 74) | public static void GenerateJsonFileForBudaFullAlwaysUnavailable()
method SerializeToJsonFile (line 88) | private static string SerializeToJsonFile(HotelDetailsWithRoomsAvailab...
FILE: src/BookARoom.IntegrationModel/Price.cs
class Price (line 3) | public class Price
method Price (line 8) | public Price(string currency, double value)
FILE: src/BookARoom.IntegrationModel/Program.cs
class Program (line 5) | public class Program
method Main (line 7) | public static void Main(string[] args)
FILE: src/BookARoom.IntegrationModel/RoomStatusAndPrices.cs
class RoomStatusAndPrices (line 3) | public class RoomStatusAndPrices
method RoomStatusAndPrices (line 9) | public RoomStatusAndPrices(string roomIdentifier, Price oneAdultOccupa...
FILE: test/BookARoom.Tests/Acceptance/BookingTests.cs
class BookingTests (line 15) | [TestFixture]
method Should_impact_booking_repository_when_sending_a_booking_command (line 18) | [Test]
method Should_impact_both_write_and_read_models_when_sending_a_booking_command (line 35) | [Test]
FILE: test/BookARoom.Tests/Acceptance/ReservationsTests.cs
class ReservationsTests (line 14) | [TestFixture]
method Should_retrieve_updated_list_of_reservations (line 17) | [Test]
FILE: test/BookARoom.Tests/Acceptance/SearchRoomsTests.cs
class SearchRoomsTests (line 12) | [TestFixture]
method Should_find_no_room_when_searching_an_empty_location_catalog (line 15) | [Test]
method Should_find_matching_and_available_hotels (line 26) | [Test]
method Should_find_only_hotels_that_match_location_and_availability_for_this_period (line 46) | [Test]
method Should_throw_exception_when_checkinDate_is_after_checkOutDate (line 61) | [Test]
method Should_find_hotels_despite_incorrect_case_for_location (line 75) | [Test]
method Should_find_one_more_matching_hotel_after_new_hotel_is_integrated (line 89) | [Test]
method Should_get_hotel_from_its_id (line 108) | [Test]
FILE: test/BookARoom.Tests/Constants.cs
class Constants (line 5) | public static class Constants
FILE: test/BookARoom.Tests/HotelsAndRoomsAdapterTests.cs
class HotelsAndRoomsAdapterTests (line 8) | [TestFixture]
method Should_load_a_file (line 11) | [Test]
method Should_load_all_files (line 23) | [Test]
Condensed preview — 125 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (835K chars).
[
{
"path": ".gitattributes",
"chars": 2518,
"preview": "###############################################################################\n# Set default behavior to automatically "
},
{
"path": ".gitignore",
"chars": 3850,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
},
{
"path": "BookARoom.sln",
"chars": 3411,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 14\nVisualStudioVersion = 14.0.25420.1\nMini"
},
{
"path": "LabInstructions.md",
"chars": 26658,
"preview": "# CQRS lab instructions\n\nThe objective of this lab is to add the cancel a reservation feature __following an Outside-in "
},
{
"path": "MiscNotes.md",
"chars": 274,
"preview": "# Misc notes related to the BookARoom project\n\n#### Hotel APIs:\n[http://www.programmableweb.com/category/hotels/apis?cat"
},
{
"path": "README.md",
"chars": 4693,
"preview": "\n\nBookARoom is a simple project"
},
{
"path": "documentation/0- InstallationsSteps.txt",
"chars": 194,
"preview": "1. WebEssentials VS addin + other related plugins http://vswebessentials.com/changelog\n\n6. Webextension pack: https://vi"
},
{
"path": "documentation/FollowTheWhiteRabbit.md",
"chars": 1559,
"preview": "# RoomsBooking project (steps to follow)\n\n## Setup your dev environment\n\n### 1. Install all the plugins and dependencies"
},
{
"path": "global.json",
"chars": 100,
"preview": "{\n \"projects\": [ \"src\", \"test\" ],\n \"sdk\": {\n \"version\": \"1.0.0-preview2-003131\"\n }\n}\n"
},
{
"path": "src/BookARoom.Domain/BookARoom.Domain.xproj",
"chars": 1137,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
},
{
"path": "src/BookARoom.Domain/ICommand.cs",
"chars": 84,
"preview": "namespace BookARoom.Domain\n{\n public interface ICommand : IMessage\n {\n }\n}"
},
{
"path": "src/BookARoom.Domain/IEvent.cs",
"chars": 149,
"preview": "namespace BookARoom.Domain\n{\n public interface IEvent : IMessage\n {\n // public int Version; // no time for"
},
{
"path": "src/BookARoom.Domain/IMessage.cs",
"chars": 73,
"preview": "namespace BookARoom.Domain\n{\n public interface IMessage\n {\n }\n}"
},
{
"path": "src/BookARoom.Domain/IPublishEvents.cs",
"chars": 132,
"preview": "namespace BookARoom.Domain\n{\n public interface IPublishEvents\n {\n void PublishTo<T>(T @event) where T : IEv"
},
{
"path": "src/BookARoom.Domain/ISendCommands.cs",
"chars": 129,
"preview": "namespace BookARoom.Domain\n{\n public interface ISendCommands\n {\n void Send<T>(T command) where T : ICommand"
},
{
"path": "src/BookARoom.Domain/Properties/AssemblyInfo.cs",
"chars": 819,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
},
{
"path": "src/BookARoom.Domain/Query.cs",
"chars": 78,
"preview": "namespace BookARoom.Domain\n{\n public class Query : IMessage\n {\n }\n}\n"
},
{
"path": "src/BookARoom.Domain/ReadModel/BookingOption.cs",
"chars": 658,
"preview": "using System.Collections.Generic;\nusing System.Linq;\n\nnamespace BookARoom.Domain.ReadModel\n{\n public class BookingOp"
},
{
"path": "src/BookARoom.Domain/ReadModel/Hotel.cs",
"chars": 584,
"preview": "namespace BookARoom.Domain.ReadModel\n{\n public class Hotel\n {\n public Hotel(int hotelId, string name, strin"
},
{
"path": "src/BookARoom.Domain/ReadModel/IProvideHotel.cs",
"chars": 343,
"preview": "using System.Collections.Generic;\n\nnamespace BookARoom.Domain.ReadModel\n{\n /// <summary>\n /// Provides Hotels to "
},
{
"path": "src/BookARoom.Domain/ReadModel/IProvideReservations.cs",
"chars": 200,
"preview": "using System.Collections.Generic;\n\nnamespace BookARoom.Domain.ReadModel\n{\n public interface IProvideReservations\n "
},
{
"path": "src/BookARoom.Domain/ReadModel/IProvideRooms.cs",
"chars": 471,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace BookARoom.Domain.ReadModel\n{\n /// <summary>\n /// Find r"
},
{
"path": "src/BookARoom.Domain/ReadModel/IQueryBookingOptions.cs",
"chars": 333,
"preview": "using System.Collections.Generic;\n\nnamespace BookARoom.Domain.ReadModel\n{\n /// <summary>\n /// Interface to intera"
},
{
"path": "src/BookARoom.Domain/ReadModel/IStoreAndProvideHotelsAndRooms.cs",
"chars": 641,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace BookARoom.Domain.ReadModel\n{\n public interface IStoreAndP"
},
{
"path": "src/BookARoom.Domain/ReadModel/ISubscribeToEvents.cs",
"chars": 178,
"preview": "using System;\n\nnamespace BookARoom.Domain.ReadModel\n{\n public interface ISubscribeToEvents\n {\n void Registe"
},
{
"path": "src/BookARoom.Domain/ReadModel/Price.cs",
"chars": 375,
"preview": "namespace BookARoom.Domain.ReadModel\n{\n public class Price\n {\n public string Currency;\n public doub"
},
{
"path": "src/BookARoom.Domain/ReadModel/ReadModelFacade.cs",
"chars": 2639,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace BookARoom.Domain.ReadModel\n{\n /// <summary>\n /// Allow"
},
{
"path": "src/BookARoom.Domain/ReadModel/Reservation.cs",
"chars": 1121,
"preview": "using System;\n\nnamespace BookARoom.Domain.ReadModel\n{\n public class Reservation\n {\n public Guid Guid { get"
},
{
"path": "src/BookARoom.Domain/ReadModel/RoomWithPrices.cs",
"chars": 518,
"preview": "namespace BookARoom.Domain.ReadModel\n{\n public class RoomWithPrices\n {\n public string RoomIdentifier;\n "
},
{
"path": "src/BookARoom.Domain/ReadModel/SearchBookingOptions.cs",
"chars": 855,
"preview": "using System;\n\nnamespace BookARoom.Domain.ReadModel\n{\n public class SearchBookingOptions : Query\n {\n publi"
},
{
"path": "src/BookARoom.Domain/WriteModel/Booking.cs",
"chars": 870,
"preview": "using System;\n\nnamespace BookARoom.Domain.WriteModel\n{\n public class Booking\n {\n // We provide getters onl"
},
{
"path": "src/BookARoom.Domain/WriteModel/BookingCommand.cs",
"chars": 771,
"preview": "using System;\n\nnamespace BookARoom.Domain.WriteModel\n{\n public class BookingCommand : ICommand\n {\n public "
},
{
"path": "src/BookARoom.Domain/WriteModel/BookingStore.cs",
"chars": 1342,
"preview": "using System;\n\nnamespace BookARoom.Domain.WriteModel\n{\n public class BookingStore : IBookRooms\n {\n private"
},
{
"path": "src/BookARoom.Domain/WriteModel/IBookRooms.cs",
"chars": 134,
"preview": "namespace BookARoom.Domain.WriteModel\n{\n public interface IBookRooms\n {\n void BookARoom(BookingCommand com"
},
{
"path": "src/BookARoom.Domain/WriteModel/IHandleClients.cs",
"chars": 346,
"preview": "namespace BookARoom.Domain.WriteModel\n{\n // TODO: find a better name following Vaughn VERNON's reco (I do something."
},
{
"path": "src/BookARoom.Domain/WriteModel/ISaveBooking.cs",
"chars": 139,
"preview": "using System;\n\nnamespace BookARoom.Domain.WriteModel\n{\n public interface ISaveBooking\n {\n void Save(Bookin"
},
{
"path": "src/BookARoom.Domain/WriteModel/RoomBooked.cs",
"chars": 836,
"preview": "using System;\n\nnamespace BookARoom.Domain.WriteModel\n{\n public class RoomBooked : IEvent\n {\n public Guid G"
},
{
"path": "src/BookARoom.Domain/WriteModel/WriteModelFacade.cs",
"chars": 499,
"preview": "namespace BookARoom.Domain.WriteModel\n{\n public class WriteModelFacade : IHandleCommand<BookingCommand>\n {\n "
},
{
"path": "src/BookARoom.Domain/project.json",
"chars": 172,
"preview": "{\n \"version\": \"1.0.0-*\",\n\n \"dependencies\": {\n \"NETStandard.Library\": \"1.6.0\"\n },\n\n \"frameworks\": {\n \"netstand"
},
{
"path": "src/BookARoom.Infra/BookARoom.Infra.xproj",
"chars": 1139,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
},
{
"path": "src/BookARoom.Infra/CompositionRootHelper.cs",
"chars": 1921,
"preview": "using BookARoom.Domain;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Domain.WriteModel;\nusing BookARoom.Infra.Mess"
},
{
"path": "src/BookARoom.Infra/MessageBus/AsynchronousThreadPoolPublicationStrategy.cs",
"chars": 425,
"preview": "using System;\nusing System.Threading;\nusing BookARoom.Domain;\n\nnamespace BookARoom.Infra.MessageBus\n{\n public class A"
},
{
"path": "src/BookARoom.Infra/MessageBus/FakeBus.cs",
"chars": 2344,
"preview": "using System;\nusing System.Collections.Generic;\nusing BookARoom.Domain;\nusing BookARoom.Domain.ReadModel;\n\nnamespace Bo"
},
{
"path": "src/BookARoom.Infra/MessageBus/IPublishToHandlers.cs",
"chars": 211,
"preview": "using System;\nusing BookARoom.Domain;\n\nnamespace BookARoom.Infra.MessageBus\n{\n public interface IPublishToHandlers\n "
},
{
"path": "src/BookARoom.Infra/MessageBus/SynchronousPublicationStrategy.cs",
"chars": 362,
"preview": "using System;\nusing BookARoom.Domain;\n\nnamespace BookARoom.Infra.MessageBus\n{\n public class SynchronousPublicationStr"
},
{
"path": "src/BookARoom.Infra/Properties/AssemblyInfo.cs",
"chars": 825,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
},
{
"path": "src/BookARoom.Infra/ReadModel/Adapters/HotelsAndRoomsAdapter.cs",
"chars": 6209,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing BookARoom.Domain.ReadModel;\nu"
},
{
"path": "src/BookARoom.Infra/ReadModel/Adapters/ReservationAdapter.cs",
"chars": 1575,
"preview": "using System.Collections.Generic;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Domain.WriteModel;\nusing ISubscribe"
},
{
"path": "src/BookARoom.Infra/ReadModel/HotelsAndRoomsRepository.cs",
"chars": 2932,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BookARoom.Domain.ReadModel;\n\nnamespace BookARo"
},
{
"path": "src/BookARoom.Infra/WriteModel/BookingAndClientsRepository.cs",
"chars": 1233,
"preview": "using System.Collections.Generic;\nusing BookARoom.Domain.WriteModel;\n\nnamespace BookARoom.Infra.WriteModel\n{\n public"
},
{
"path": "src/BookARoom.Infra/project.json",
"chars": 540,
"preview": "{\n \"version\": \"1.0.0-*\",\n\n \"dependencies\": {\n \"NETStandard.Library\": \"1.6.0\",\n \"BookARoom.Domain\": {\n \"tar"
},
{
"path": "src/BookARoom.Infra.Web/.bowerrc",
"chars": 33,
"preview": "{\n \"directory\": \"wwwroot/lib\"\n}\n"
},
{
"path": "src/BookARoom.Infra.Web/BookARoom.Infra.Web.xproj",
"chars": 1274,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
},
{
"path": "src/BookARoom.Infra.Web/Controllers/BookingConfirmationController.cs",
"chars": 1310,
"preview": "using BookARoom.Domain;\nusing BookARoom.Domain.WriteModel;\nusing BookARoom.Infra.Web.ViewModels;\nusing Microsoft.AspNet"
},
{
"path": "src/BookARoom.Infra.Web/Controllers/BookingOptionsController.cs",
"chars": 1385,
"preview": "using BookARoom.Domain;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Infra.Web.ViewModels;\nusing Microsoft.AspNetC"
},
{
"path": "src/BookARoom.Infra.Web/Controllers/BookingRequestController.cs",
"chars": 600,
"preview": "using BookARoom.Infra.Web.ViewModels;\nusing Microsoft.AspNetCore.Mvc;\n\n// For more information on enabling MVC for empt"
},
{
"path": "src/BookARoom.Infra.Web/Controllers/HomeController.cs",
"chars": 1208,
"preview": "using System;\nusing BookARoom.Domain;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Infra.Web.ViewModels;\nusing Mic"
},
{
"path": "src/BookARoom.Infra.Web/Controllers/QueryReservations.cs",
"chars": 487,
"preview": "using BookARoom.Infra.Web.ViewModels;\nusing Microsoft.AspNetCore.Mvc;\n\n// For more information on enabling MVC for empt"
},
{
"path": "src/BookARoom.Infra.Web/Controllers/ReservationsController.cs",
"chars": 1287,
"preview": "using BookARoom.Domain.ReadModel;\nusing BookARoom.Infra.Web.ViewModels;\nusing Microsoft.AspNetCore.Mvc;\n\n// For more in"
},
{
"path": "src/BookARoom.Infra.Web/Program.cs",
"chars": 459,
"preview": "using System.IO;\nusing Microsoft.AspNetCore.Hosting;\n\nnamespace BookARoom.Infra.Web\n{\n public class Program\n {\n "
},
{
"path": "src/BookARoom.Infra.Web/Project_Readme.html",
"chars": 6657,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>Welcome to ASP.NET Core</title>\n <st"
},
{
"path": "src/BookARoom.Infra.Web/Properties/launchSettings.json",
"chars": 624,
"preview": "{\n \"iisSettings\": {\n \"windowsAuthentication\": false,\n \"anonymousAuthentication\": true,\n \"iisExpress\": {\n "
},
{
"path": "src/BookARoom.Infra.Web/Startup.cs",
"chars": 3160,
"preview": "using BookARoom.Domain;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Infra.MessageBus;\nusing BookARoom.Infra.ReadM"
},
{
"path": "src/BookARoom.Infra.Web/ViewModels/BookingOptionsViewModel.cs",
"chars": 766,
"preview": "using System.Collections.Generic;\nusing BookARoom.Domain.ReadModel;\n\nnamespace BookARoom.Infra.Web.ViewModels\n{\n pub"
},
{
"path": "src/BookARoom.Infra.Web/ViewModels/BookingRequestViewModel.cs",
"chars": 447,
"preview": "using System;\n\nnamespace BookARoom.Infra.Web.ViewModels\n{\n public class BookingRequestViewModel\n {\n public"
},
{
"path": "src/BookARoom.Infra.Web/ViewModels/QueryReservationsViewModel.cs",
"chars": 333,
"preview": "namespace BookARoom.Infra.Web.ViewModels\n{\n public class QueryReservationsViewModel\n {\n public string Clie"
},
{
"path": "src/BookARoom.Infra.Web/ViewModels/ReservationsViewModel.cs",
"chars": 538,
"preview": "using System.Collections.Generic;\nusing BookARoom.Domain.ReadModel;\n\nnamespace BookARoom.Infra.Web.ViewModels\n{\n pub"
},
{
"path": "src/BookARoom.Infra.Web/ViewModels/SearchRoomQueryViewModel.cs",
"chars": 704,
"preview": "using System;\n\nnamespace BookARoom.Infra.Web.ViewModels\n{\n public class SearchRoomQueryViewModel\n {\n publi"
},
{
"path": "src/BookARoom.Infra.Web/Views/BookingConfirmation/index.cshtml",
"chars": 897,
"preview": "@using System.Text.Encodings.Web\n@model BookARoom.Infra.Web.ViewModels.BookingRequestViewModel\n@{\n ViewData[\"Title\"]"
},
{
"path": "src/BookARoom.Infra.Web/Views/BookingOptions/index.cshtml",
"chars": 3214,
"preview": "@model BookARoom.Infra.Web.ViewModels.BookingOptionsViewModel\n@{\n ViewData[\"Title\"] = \"Pick your best booking option"
},
{
"path": "src/BookARoom.Infra.Web/Views/BookingRequest/index.cshtml",
"chars": 1231,
"preview": "@model BookARoom.Infra.Web.ViewModels.BookingRequestViewModel\n@{\n ViewData[\"Title\"] = \"Book your room\";\n}\n\n<br /><br"
},
{
"path": "src/BookARoom.Infra.Web/Views/Home/About.cshtml",
"chars": 235,
"preview": "@{\n ViewData[\"Title\"] = \"About\";\n}\n<h2>@ViewData[\"Title\"].</h2>\n<h3>@ViewData[\"Message\"]</h3>\n\n<p>BookARoom is a <st"
},
{
"path": "src/BookARoom.Infra.Web/Views/Home/Caroussel-old-index.cshtml",
"chars": 5682,
"preview": "@{\n ViewData[\"Title\"] = \"Home Page\";\n}\n\n<div id=\"myCarousel\" class=\"carousel slide\" data-ride=\"carousel\" data-interv"
},
{
"path": "src/BookARoom.Infra.Web/Views/Home/Contact.cshtml",
"chars": 385,
"preview": "@{\n ViewData[\"Title\"] = \"Contact\";\n}\n<h2>@ViewData[\"Title\"].</h2>\n<h3>@ViewData[\"Message\"]</h3>\n\n<address>\n <stro"
},
{
"path": "src/BookARoom.Infra.Web/Views/Home/Index.cshtml",
"chars": 843,
"preview": "@model BookARoom.Infra.Web.ViewModels.SearchRoomQueryViewModel\n@{\n ViewData[\"Title\"] = \"Let’s find you an hotel to s"
},
{
"path": "src/BookARoom.Infra.Web/Views/QueryReservations/index.cshtml",
"chars": 446,
"preview": "@model BookARoom.Infra.Web.ViewModels.QueryReservationsViewModel\n@{\n ViewData[\"Title\"] = \"Fill you e-mail\";\n}\n\n<br /"
},
{
"path": "src/BookARoom.Infra.Web/Views/Reservations/index.cshtml",
"chars": 2209,
"preview": "@model BookARoom.Infra.Web.ViewModels.ReservationsViewModel\n@{\n ViewData[\"Title\"] = \"Pick your best booking option\";"
},
{
"path": "src/BookARoom.Infra.Web/Views/Shared/Error.cshtml",
"chars": 708,
"preview": "@{\n ViewData[\"Title\"] = \"Error\";\n}\n\n<h1 class=\"text-danger\">Error.</h1>\n<h2 class=\"text-danger\">An error occurred wh"
},
{
"path": "src/BookARoom.Infra.Web/Views/Shared/_Layout.cshtml",
"chars": 3250,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initi"
},
{
"path": "src/BookARoom.Infra.Web/Views/_ViewImports.cshtml",
"chars": 81,
"preview": "@using BookARoom.Infra.Web\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n"
},
{
"path": "src/BookARoom.Infra.Web/Views/_ViewStart.cshtml",
"chars": 30,
"preview": "@{\n Layout = \"_Layout\";\n}\n"
},
{
"path": "src/BookARoom.Infra.Web/appsettings.json",
"chars": 166,
"preview": "{\n \"Logging\": {\n \"IncludeScopes\": false,\n \"LogLevel\": {\n \"Default\": \"Debug\",\n \"System\": \"Information\","
},
{
"path": "src/BookARoom.Infra.Web/bower.json",
"chars": 197,
"preview": "{\n \"name\": \"asp.net\",\n \"private\": true,\n \"dependencies\": {\n \"bootstrap\": \"3.3.6\",\n \"jquery\": \"2.2.0\",\n \"jque"
},
{
"path": "src/BookARoom.Infra.Web/bundleconfig.json",
"chars": 601,
"preview": "// Configure bundling and minification for the project.\n// More info at https://go.microsoft.com/fwlink/?LinkId=808241\n"
},
{
"path": "src/BookARoom.Infra.Web/cssSandBox.html",
"chars": 676,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <title></title>\n <link rel=\"stylesheet\" href=\"./wwwro"
},
{
"path": "src/BookARoom.Infra.Web/project.json",
"chars": 1943,
"preview": "{\n \"dependencies\": {\n \"Microsoft.NETCore.App\": {\n \"version\": \"1.0.0\",\n \"type\": \"platform\"\n },\n \"Mic"
},
{
"path": "src/BookARoom.Infra.Web/web.config",
"chars": 549,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\n <!--\n Configure your application settings in appsettings.j"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/_references.js",
"chars": 341,
"preview": "/// <autosync enabled=\"true\" />\n/// <reference path=\"js/site.js\" />\n/// <reference path=\"lib/bootstrap/dist/js/bootstra"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/css/site.css",
"chars": 1393,
"preview": "body {\n background-color: #f0ecec;\n padding-top: 50px;\n padding-bottom: 20px;\n font-family: sans-serif;\n}\n\n"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/hotels/BudaFull-the-always-unavailable-hotel-availabilities.json",
"chars": 182,
"preview": "{\n \"HotelId\": 4,\n \"HotelName\": \"BudaFull-the-always-unavailable-hotel\",\n \"Location\": \"Budapest\",\n \"NumberOfRooms\": "
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/hotels/Danubius Health Spa Resort Helia-availabilities.json",
"chars": 435,
"preview": "{\n \"HotelId\": 3,\n \"HotelName\": \"Danubius Health Spa Resort Helia\",\n \"Location\": \"Budapest\",\n \"NumberOfRooms\": 125,\n"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/hotels/New York Sofitel-availabilities.json",
"chars": 3447,
"preview": "{\n \"HotelId\": 1,\n \"HotelName\": \"New York Sofitel\",\n \"Location\": \"New York\",\n \"NumberOfRooms\": 405,\n \"Availabilitie"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/hotels/THE GRAND BUDAPEST HOTEL-availabilities.json",
"chars": 931,
"preview": "{\n \"HotelId\": 2,\n \"HotelName\": \"THE GRAND BUDAPEST HOTEL\",\n \"Location\": \"Budapest\",\n \"NumberOfRooms\": 240,\n \"Avail"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/js/site.js",
"chars": 32,
"preview": "// Write your Javascript code.\n"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/.bower.json",
"chars": 918,
"preview": "{\n \"name\": \"bootstrap\",\n \"description\": \"The most popular front-end framework for developing responsive, mobile first "
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/LICENSE",
"chars": 1084,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2011-2015 Twitter, Inc\n\nPermission is hereby granted, free of charge, to any person"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css",
"chars": 26132,
"preview": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://gi"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/css/bootstrap.css",
"chars": 146082,
"preview": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://gi"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.js",
"chars": 68954,
"preview": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under the MIT license"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/bootstrap/dist/js/npm.js",
"chars": 484,
"preview": "// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\nrequ"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery/.bower.json",
"chars": 523,
"preview": "{\n \"name\": \"jquery\",\n \"main\": \"dist/jquery.js\",\n \"license\": \"MIT\",\n \"ignore\": [\n \"package.json\"\n ],\n \"keywords\""
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery/LICENSE.txt",
"chars": 1606,
"preview": "Copyright jQuery Foundation and other contributors, https://jquery.org/\n\nThis software consists of voluntary contributio"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery/dist/jquery.js",
"chars": 258388,
"preview": "/*!\n * jQuery JavaScript Library v2.2.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Cop"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation/.bower.json",
"chars": 885,
"preview": "{\n \"name\": \"jquery-validation\",\n \"homepage\": \"http://jqueryvalidation.org/\",\n \"repository\": {\n \"type\": \"git\",\n "
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation/LICENSE.md",
"chars": 1094,
"preview": "The MIT License (MIT)\n=====================\n\nCopyright Jörn Zaefferer\n\nPermission is hereby granted, free of charge, to "
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation/dist/additional-methods.js",
"chars": 36839,
"preview": "/*!\n * jQuery Validation Plugin v1.14.0\n *\n * http://jqueryvalidation.org/\n *\n * Copyright (c) 2015 Jörn Zaefferer\n * Re"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation/dist/jquery.validate.js",
"chars": 42629,
"preview": "/*!\n * jQuery Validation Plugin v1.14.0\n *\n * http://jqueryvalidation.org/\n *\n * Copyright (c) 2015 Jörn Zaefferer\n * Re"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation-unobtrusive/.bower.json",
"chars": 1100,
"preview": "{\n \"name\": \"jquery-validation-unobtrusive\",\n \"version\": \"3.2.6\",\n \"homepage\": \"https://github.com/aspnet/jquery-valid"
},
{
"path": "src/BookARoom.Infra.Web/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
"chars": 18618,
"preview": "/*!\n** Unobtrusive validation support library for jQuery and jQuery Validate\n** Copyright (C) Microsoft Corporation. All"
},
{
"path": "src/BookARoom.IntegrationModel/BookARoom.IntegrationModel.xproj",
"chars": 1147,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
},
{
"path": "src/BookARoom.IntegrationModel/HotelDetailsWithRoomsAvailabilities.cs",
"chars": 876,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace BookARoom.IntegrationModel\n{\n public class HotelDetailsWi"
},
{
"path": "src/BookARoom.IntegrationModel/IntegrationFilesGenerator.cs",
"chars": 5452,
"preview": "using System;\nusing System.IO;\nusing System.Text;\nusing Newtonsoft.Json;\n\nnamespace BookARoom.IntegrationModel\n{\n //"
},
{
"path": "src/BookARoom.IntegrationModel/Price.cs",
"chars": 270,
"preview": "namespace BookARoom.IntegrationModel\n{\n public class Price\n {\n public string Currency;\n public doub"
},
{
"path": "src/BookARoom.IntegrationModel/Program.cs",
"chars": 815,
"preview": "using System;\n\nnamespace BookARoom.IntegrationModel\n{\n public class Program\n {\n public static void Main(st"
},
{
"path": "src/BookARoom.IntegrationModel/Properties/AssemblyInfo.cs",
"chars": 831,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
},
{
"path": "src/BookARoom.IntegrationModel/RoomStatusAndPrices.cs",
"chars": 552,
"preview": "namespace BookARoom.IntegrationModel\n{\n public class RoomStatusAndPrices\n {\n public string RoomIdentifier "
},
{
"path": "src/BookARoom.IntegrationModel/project.json",
"chars": 308,
"preview": "{\n \"version\": \"1.0.0-*\",\n \"buildOptions\": {\n \"emitEntryPoint\": true\n },\n\n \"dependencies\": {\n \"Microsoft.NETCo"
},
{
"path": "test/BookARoom.Tests/Acceptance/BookingTests.cs",
"chars": 3927,
"preview": "using System;\nusing System.Linq;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Domain.WriteModel;\nusing BookARoom.I"
},
{
"path": "test/BookARoom.Tests/Acceptance/ReservationsTests.cs",
"chars": 2235,
"preview": "using System.Collections.Generic;\nusing System.Linq;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Domain.WriteMode"
},
{
"path": "test/BookARoom.Tests/Acceptance/SearchRoomsTests.cs",
"chars": 6690,
"preview": "using System;\nusing System.Linq;\nusing BookARoom.Domain.ReadModel;\nusing BookARoom.Infra;\nusing BookARoom.Infra.Message"
},
{
"path": "test/BookARoom.Tests/BookARoom.Tests.xproj",
"chars": 1230,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
},
{
"path": "test/BookARoom.Tests/Constants.cs",
"chars": 295,
"preview": "using System;\n\nnamespace BookARoom.Tests\n{\n public static class Constants\n {\n public static DateTime MyFav"
},
{
"path": "test/BookARoom.Tests/HotelsAndRoomsAdapterTests.cs",
"chars": 1011,
"preview": "using BookARoom.Infra.MessageBus;\nusing BookARoom.Infra.ReadModel.Adapters;\nusing NFluent;\nusing NUnit.Framework;\n\nname"
},
{
"path": "test/BookARoom.Tests/Properties/AssemblyInfo.cs",
"chars": 825,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
},
{
"path": "test/BookARoom.Tests/project.json",
"chars": 708,
"preview": "{\n \"version\": \"1.0.0-*\",\n\n \"dependencies\": {\n \"BookARoom.Domain\": {\n \"target\": \"project\"\n },\n \"BookARoom"
}
]
About this extraction
This page contains the full source code of the tpierrain/CQRS GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 125 files (745.6 KB), approximately 214.5k tokens, and a symbol index with 288 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.