How to automatic have your architecture validated by MsBuild

Visual Studio Ultimate edition has an architecture diagram that can be validated by right clicking the architecture. This is very interesting for project that become bigger and bigger to ensure that none of the developers by-pass layers or libraries in a way that is not intended.


The problem is that people tend not do validate the architecture for several reasons. The simplest one is that maybe not a lot of your developers has the Ultimate edition. Nevertheless, the good news is that Visual Studio Online lets you do what you can do locally with MsBuild. MsBuild with the argument /p:ValidateArchitecture=true will validate any architecture diagram you have.

msbuild /p:ValidateArchitecture=true

This can also be setup when building on the cloud. Open Visual Studio, go in the Builds tab from the Team Explorer. Edit any of your build definition, select Process and go under Build and Advanced. You can set from there MsBuild’s arguments. Use the same argument that you are using locally : /p:ValidateArchitecture=true.


When the architecture is not respected, the build server will thrown an error saying the problem within the architecture layer/code. This is the best way to ensure a strong architecture on the long term.

Unit Testing MVC Area Route Mapping to Controller and Url Creation

One of the key element of your website should be that every Url that you have should goes to the controller’s action that you expect. This is also true when you are using an Asp.Net Html Helper that generate an URL. To be sure that you can rely that an Url links to the right action and that every Url generated have the right string structure, you must unit test them. This is far more important when your project start to become bigger and bigger. Routing rules can override a previous route and create unreachable code from your web interface. To solve that issue, every routes should be unit tested.


Asp.Net MVC routing system is quite interesting and easy to unit tests. I read that it is hard to unit test but this is not my experience. In this article, I will show you how to unit test routing from a specific AreaRegistration file. This is exactly the same process if you have your route inside the RouteConfig.cs file. Instead of using the area class, you use the RouteConfig class. They both use the System.Web.Routing.RouteTable and this is what we need to setup tests.

So before going into the detail, here is an example to unit test and Url to a controller’s action.

public void GivenRouteForContest_WhenPortefolioId()
    // Arrange
    string url = Constants.Areas.CONTEST + "/1/Portefolio/2";

    // Act
    RouteData routeData = base.GetRouteDataForUrl(url).RouteData;

    // Assert
    Assert.AreEqual("Portefolio", routeData.Values[Constants.RoutePortionName.CONTROLLER]);
    Assert.AreEqual("IndexById", routeData.Values[Constants.RoutePortionName.ACTION]);
    Assert.AreEqual("1", routeData.Values[Constants.RoutePortionName.ACTIVE_CURRENT_CONTEST_ID]);
    Assert.AreEqual("2", routeData.Values[Constants.RoutePortionName.ACTIVE_CURRENT_PORTEFEOLIO_ID]);

As you can see by this unit test example, the url is defined in the arrange section. The act part is a one liner that call a method that act as a proxy to call the real GetRouteData. To have access to that method, all my routing tests inherit from a testing class that allows me to call. I named that class RouteTestBase. It has a method is running between code which clear all routes and configures the route. This is where I have setup the configuration of the area I wanted to test. This is where you may want to use the global route configuration. This class has two public methods. The first one is used for unit testing string url to route data and the second one is to test Html Url helper to generate the string url.

public class RouteTestBase
    public void BetweenTest()
        var areaRegistration = new ContestAreaRegistration();
        var areaRegistrationContext = new AreaRegistrationContext(areaRegistration.AreaName, RouteTable.Routes);

    /// <summary>
    /// From URL to Controller/Action, this method return the route and http context after passing the URL
    /// into the RouteTable.
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    protected RouteAndContext GetRouteDataForUrl(string url)
        var context = FakeHttpContext(requestUrl: "~/" + url);
        RouteData routeData = RouteTable.Routes.GetRouteData(context);
        return new RouteAndContext(context, routeData);

    /// <summary>
    /// Generate an UrlHelper to be used to generate URL string. 
    /// </summary>
    /// <param name="appPath">Define the application path. By default, if all routing start from the domain than this should not be set.</param>
    /// <returns>Html</returns>
    protected UrlHelper GetUrlHelper(string appPath = "~/")
        HttpContextBase httpContext = FakeHttpContext(appPath:"/",requestUrl: appPath);
        var routeData = RouteTable.Routes.GetRouteData(httpContext) ?? new RouteData();
        RequestContext requestContext = new RequestContext(httpContext, routeData);
        UrlHelper helper = new UrlHelper(requestContext, RouteTable.Routes);
        return helper;

    private HttpContextBase FakeHttpContext(string appPath="~/", string requestUrl = "/")
        // Mocks
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var user = new Mock<IPrincipal>();
        var identity = new Mock<IIdentity>();

        // Query String Parameters
        var routePart = requestUrl;
        var queryStringPart = requestUrl;

        if (routePart.Contains("?"))
            var indexQueryString = routePart.IndexOf("?", StringComparison.InvariantCulture);
            routePart = requestUrl.Substring(0, indexQueryString);
            queryStringPart = requestUrl.Substring(indexQueryString + 1, requestUrl.Length - indexQueryString-1);
            NameValueCollection parameters = new NameValueCollection();
            var parametersList = queryStringPart.Split('&');
            foreach (var paramter in parametersList)
                var keyAndvalue = paramter.Split('=');
                parameters.Add(keyAndvalue[0], keyAndvalue[1]);
            request.Setup(req => req.Params).Returns(parameters);

        // Setup all Http Context
        request.Setup(req => req.ApplicationPath).Returns(appPath);
        request.Setup(req => req.AppRelativeCurrentExecutionFilePath).Returns(routePart);
        request.Setup(req => req.PathInfo).Returns(string.Empty);
        request.Setup(req => req.ServerVariables).Returns(new NameValueCollection());
        response.Setup(res => res.ApplyAppPathModifier(It.IsAny<string>())).Returns((string virtualPath) => virtualPath);
        user.Setup(usr => usr.Identity).Returns(identity.Object);
        identity.Setup(ident => ident.IsAuthenticated).Returns(true);
        context.Setup(ctx => ctx.Request).Returns(request.Object);
        context.Setup(ctx => ctx.Response).Returns(response.Object);
        context.Setup(ctx => ctx.Session).Returns(session.Object);
        context.Setup(ctx => ctx.Server).Returns(server.Object);
        context.Setup(ctx => ctx.User).Returns(user.Object);

        return context.Object;

    /// <summary>
    /// Class used to return the RouteData and the HttpContextBase
    /// </summary>
    public class RouteAndContext
        public RouteAndContext(HttpContextBase httpContextBase, RouteData routeData)
            this.HttpContext = httpContextBase;
            this.RouteData = routeData;
        public HttpContextBase HttpContext { get; private set; }
        public RouteData RouteData { get; private set; }

Indeed this class has hard-coded area class in the TestInitialize method. But, my project contains only few areas and I want to keep everything simple. I will all every area one by one in this method. However, you could make it generic very easily by passing to the constructor of that method a list of AreaRegistrationContext.

The test concerning the Html’s helper is also pretty simple once you have this class to inherit from. In you arrange you get the UrlHelper. You could set this initialization inside the method that run between each test, but this one allow to pass the application path. This parameter allows to not use the domain only has the base application path. The acting section of this unit test is the same as what is using when you are using the Html helper to generate an Url.

public void ControllerUserContest_ActionEnter()
    // Arrange
    UrlHelper helper = base.GetUrlHelper();
    var routeParameters = new RouteValueDictionary(new Dictionary<string, object>()) {
                                        {Constants.AREA, Constants.Areas.CONTEST},

    // Act
    string url = helper.Action("Enter", "UserContest", routeParameters);

    // Assert
    Assert.AreEqual("/" + Constants.Areas.CONTEST + "/1/Enter", url);

The helper.Action calls the url helper Action method and this is why we are using this one to get the string Url to test.

public virtual TagBuilder GenerateActionLink(
            [NotNull] string linkText,
            string actionName,
            string controllerName,
            string protocol,
            string hostname,
            string fragment,
            object routeValues,
            object htmlAttributes)
            var url = _urlHelper.Action(actionName, controllerName, routeValues, protocol, hostname, fragment);
            return GenerateLink(linkText, url, htmlAttributes);

The code above is from Asp.Net MVC framework which shows what the GenerateActionLink is using the url helper Action method. So, as you can see, once you have the inherit base class, it is a matter of a single calls and some assertion to test all your routes. I strongly suggest that for each of your routes you have a single unit test to avoid any huge impact on your website.

1000 Unit Tests

I have this side project that I am burning a lot of time since about 1 year now. It reaches few days ago the milestone of 1000 automated unit tests.


The code coverage is not bad too. I stroked the test projects because they are not significant. The model is cover at 82% which contains the core business logics. The service layer contains some integration logic and should be more covered but well we still have a coverage that make me comfortable and this is what is important so far. I am also proud of the 69% of the data access. Some of these database tests mock the database and some not which is perfect to test if Entity Framework is not breaking. The main difference is that with those 1000 unit tests I feel that I’ll be able to continue to add features without disturbing parts that I wouldn’t expect to broke. This was one of the main reason of that project — to rebuild the old one that had less than 100 unit tests in PHP on a period of 10 years!


I am also using nDepend software to keep track of the unit tests. That tool is great for identifying some part to improve your software but it is also great to track your tests coverage during the life of your software.


As you can see, we can track in time the number of lines, number of comments and the coverage. We can see two spikes down which were caused from a batch of tests that was failing during major refactoring. The graph show that I am pretty constant in the amount of code that I wrote every months. I am also keeping the same trend with the coverage. The number of comments is slightly going down but this is something I knew and will fix soon.

The project should be mostly done by the end of the year. Their is a big chance to reach 1500 units tests. I also plan to integrate some function tests with Visual Studio Coded UI for main scenario. So far, having these tests are more of a blessing than anything. Not only they will be really important later but even when writing them these make me think twice about how easy to make them to test and also revise the code in a rapid way which remove a lot of errors to go into production.

Sql Update Column with Random Value

While seeding a database you may want to do a quick change at your value. The fastest way to have new value which are not all the same is to randomize update or insert value in your SQL table. You can use 3 SQL methods to achieve this insertion of random value. The first is the rand method. This method generate a float number between 0 an 1. If you are using this method you will have the same value when updating a bulk of values. The reason is the the seed remain the same for all updates. To have unique value generated on each updates you must provide a new seed to the cast method. This is where the second method is required, the checksum method which from unique string give you a unique number to seed. To have a unique number you use the third method called NewId. This one generate a unique Guid. Finally, you can use the cast method if you want to have an integer.

update YourTableName
set YourColumnName = cast(rand(CHECKSUM(NEWID())) * 500 as int)
where Id = '9308cbb9-f079-4456-9bb8-d1de88367aaa'

From there, you can play with the fact that you receive a value between 0 an 1. For example, if you want to have a range of 0 to 500 you just need to multiply by 500. If you want to have value between 100 and 500 than you need to multiply by 400 and add 100.


Leaving Canada to go Working in Washington for Microsoft

Since August 1st, 2014 my wife and I have moved to Redmond in the state of Washington (USA). We both lived since we were born near of Montreal, Canada. I got the opportunity to join the Cloud Division at Microsoft to work on MSDN, TechNet and Visual Studio, so we decided to do a the big jump. This journey was special since we come from the French part of Canada and we had to do a brain-switch into a total immersive English world. It was also a big change since we were getting married later in the year — we had to change our plan and to re-plan the wedding 4 months in advance. Furthermore, we have an house that we did just build so we did not wanted to sell it : we had to find someone reliable to rent it. After having selling our cars, found someone for the house, cancelled all ours subscriptions like for the cable, Internet, cellphone etc. We were ready to move from Canada to United States. For those who are wondering why we keep the house, it is because we plan, someday to come back. Why we had to rent it is because the government of Canada require you to not have any possible residence that you can live if you do not want to be considered a Canadian resident. Which we do not want, we want to be considered an American resident for tax purpose. In the same line of idea, I have a revenue building with 6 renters. This is fine because I have a firm that will handle the building during my absence. Before leaving I also add to reimburse all my Home Buyer Plan (HBP) or “Rap” in French. This is another condition to be a non-resident of Canada. All these information, and more, were giving to me by KPMG Canada and KPMG USA.
Leaving a country for another is not something easy. Microsoft make it easier. First of all, Microsoft is really well organized for anything about people moving from a country to another. The day I accepted the job offer, we had a relocation package. The relocation package can vary depending of your negotiation and the country you come from. It is also the case with the type of visa. My package had the service of consultation with KPMG to be sure that I do everything legal from the Canadian tax and from the US tax side. I got several calls from both KPMG which made my decision way easier to take. Also, Microsoft takes care of getting the visa for you and send you all the legal forms to have when you cross the border. This is a big relief because government’s papers ain’t easy to understand. Since my wife and I were married, Microsoft covers her for the visa (as a dependent) and paid for the airplane for her too. They also hire a company to move our personal belonging. Since we were living in a house, we could have brought every thing (except ours cars). We were conservative since we plan to come back, we brought the minimum like our clothes, a television, a sofa, a bed and few others kitchen tools.

When arrived in Tacoma Airport, we were happy to have the temporary car from Microsoft. Even if it was just for 30 days, this helped us a lot. We were able to get from the airport to the temporary house, that we had for 45 days. An important detail is that we brought from Canada a GPS and it is essential. Not only we did not know the state, we had to move across multiple towns. From Tacoma, we went to Bellevue to get the key of our temporary apartment which were in Kirkland. I am working at Redmond the next Monday (we moved Friday). Nothing is perfect, but the car helped us a lot. 30 days is a little low because you have to find a new apartment, and figure out where everything is and in the same time you start working. The first two months are more difficult but with the help of my wife and Microsoft it went pretty smooth.

Microsoft assigned us a personal assistant to get us our driving license, our social security number, our new apartment and to open our bank account. This person was a big help since we came from a different country. This personal assistant came with us during the driving test, came with us at every appointment with the government for the social security number, etc. That help was pretty precious and removed a lot of stress.

Also, Microsoft teams are very understandable about that you have to leave the job to do all preparation papers, tests, etc. They does not ask any question so it makes you feel right.

Apartment at Redmond

Microsoft offered us a temporary apartment for 45 days. They suggest us to start finding an apartment as soon as we get there cause it can takes time before finding something you want. For us, we started way before coming to Washington. We had a list of 30 apartments in a spreadsheet with different criteria. For us, the location was a big concern since we do not wanted to have a car there. Even with all the researches and countless hours of simulation, we got an apartment that wasn’t in our list. The problem between Internet and being on place is that with Internet you cannot see how the lighting is really, what is the real condition of the apartment, what is really available, etc. Prices are also not what is provided on Internet. The personal assistant was also able to tell us some feedback from previous renters. Before leaving we were expecting to pay around 1500$US for a 2 bedrooms. We wanted to have a 2 bedrooms because we are planning to have our first child in the first year. Well, we finished to pay 1810$. The reason is that apartment in the range of 1500$ for 2 bedrooms are not located in place that you can easily do your grocery by walk. We are living right in the downtown of Redmond, within 8 minutes from a grocery. We could also go to two others, cheaper, groceries at 20 and 25 minutes of walk — we never go to those grocery, it is too far. We are also located near of the transit center. It takes me 1 minute walk to get plenty of bus. Three buses can get me to Microsoft in less than 18 minutes. Having an apartment in the range of Microsoft by bus under 30 minutes and having a grocery under 10 minutes walk has a price. The following picture illustrate the apartment location and some facilities. The marker #1 is the apartment, the market #2 is the grocery that we go every week. The third one is the transit center. The Redmond Town Center is flagged with a 4, this is a mall center. Finally, the fifth marker show you the second closest grocery that is too far for us to go by walk, possible but too far.


We also learn that we have to pay for the water/sewage and for the electricity. The bill depends of your consumption and the season. I would say that you can add about 250$ per months for both. So you have to pay a little bit less than 2100$ for a 2 bedrooms per month. Living in Redmond or Bellevue is about the same price. You have to get farther to have 2 bedrooms apartment more affordable but that come with a cost of time and a cost of car. For example, living in the temporary house, would cost around 1600$ but I had to walk 20 minutes and take 2 bus. A total of 1 hour 10 minute. Does not make sense for me. Also, no grocery without having to walk for 30 minutes. Not possible without car. Also, even with a car, it took me about 30 minutes in medium traffic (from Kirkland to Redmond).

With the temporary house not very convenient, we moved the week we found the apartment in Redmond. Do not forget that if I take the temporary car to get to Microsoft that my wife was stuck without transportation for the whole day. We moved within 25 days even if we had the apartment for 45 days.


Microsoft rental car is very convenient at first to get all the missing stuff you need. Even if you come with your stuff from your country, you will need foods and essential products to clean, etc. My wife got the car scratched in a parking whilst she was doing some errands and Microsoft insurance paid everything. Once moved, I kept the car for my wife and took the bus. Microsoft pay for all its employee a monthly bus card. This is awesome and save you about 100$ per month. Buses are very great in the King County (Redmond, Bellevue, Seattle area). Microsoft is located near of the Overlake Transit Center. My building is the 18, so I can walk from the Overlake Transit Center to the building in less than 2 minutes. Since we are living next to a transit center, to go to another transit center is pretty easy. I have the 545, 542 and B-Line that goes in either direction every 10 to 30 minutes. I rarely have to wait because I can just take any of them. Going to downtown Seattle take 35 minutes during the weekend. Perfect to go shopping or simply take a walk there. I prefer doing 35 minutes once in a while than every day, in the traffic living in Seattle takes more than 50 minutes of bus and this is if you live at the center of Seattle which is very expensive. So after 7 months, I can tell you that it is possible to live without a car in the area. Not always easy, but possible. Even going to the Tacoma Airport is not a big deal. You need to take the train (which is cover with the bus pass) and than take 1 bus (545). It takes about 1 hour 20 minutes. It is long but we do that travel only once per year.

Cost of Living

The cost of living is more as you have read about the apartment. They know Microsoft employees want to live near by and they increase the price of a lot of thing. The grocery costs about 15% more than in Canada. On the other side, Microsoft pays a lot of things like the bus pass and the gym membership. Washington state does not have state tax. Winter are not hard, so electricity bills are not that high. Redmond library is free with a free access to Internet and to print. In the US, Netflix is fine so you do not need to have a cable subscription, just Internet which can be found for a good speed under 65$/month and Netflix is 9$/months. I got my cellphone and my wife’s cellphone for 10$ each per month with Republic Wireless which give me unlimited phone and SMS across the US. Overall, it is not bad.

However, the situation that my wife and I are is different. We still need to pay the mortgage on our Canadian house and on the revenue building we have. My wife couldn’t get a working visa, so she cannot work. That mean that I have to support for our Canadian dept, but also every bills here. To be honest, we are kind of short right now with the baby coming. However, we really like the experience so far.

Microsoft is very generous. They help with the health insurance, give free cold vaccine, give a lot of reward if you participates in events, etc.

Life Outside Microsoft

King county is a pretty area. Lots of mountains where you can do hiking, lots of trails where you can do bike or rollerblade. The city of Redmond organizes multiple events during Christmas or have outside movies every Friday during summer. It has, during weekends, outside farm market and recurrent city events. Seattle is near (35 minutes bus), you can go there to do what every big cities offer. What is interesting is that you always feel in the nature. Lots of trees, mountains and water around. The city is well organized with a big skate park, a golf course and a huge parc called Marymoore. To give you an idea, Redmond is small but big in the same time. Small in size but attract big even like the Cirque du Soleil which is in town now.


I can write for a long time about the past few months. However, even if at some point I hesitated to come, I am more than happy to be there for the few years that we will be in the US. We enjoy the American culture which is pretty diversified from everybody coming around the world to work for Microsoft. We enjoy the weather that goes rarely under 3 Celsius. I will try to take the time to write more about my working experience soon.

Creating an Home Page with Multiples Section with Parallax

The front page of your site must contains all the information to allow the user to do an action. In the creation of a web application, the front page must states clearly what the application is doing, give some highlight of the benefits of the application, displays images and videos. You can have multiple pages to shows all different topics or you can have a long scrollable page. This article explains how to create a long scrolling page.

An important aspect of long scrolling page is to still have a good user experience. That mean to have inner page navigation, being able to scroll with the mouse wheel but also from the scroll bar. These days, it is also important to be mobile compatible which mean that it must be swippable.

The first step is to download some libraries. Here is a list of libraries used in this tutorial.

JQuery is there because I am already using the library and is useful in some part of this process. Mostly because we will associate Swiper and Stellar with JQuery to Html elements. Swiper is used as a pillar in this one page scenario. The reason is that it is the JavaScript library that transform the default web browser into a Power Point presentation. The Stellar library is used to improve the experience by adding the parallax effect when scrolling from top to bottom and the other way around. Let’s start with the JavaScript configuration and then the Html. Keep in mind that some decisions are based on specific choices that are custom to the website I am creating — mostly optional in a default case.

var mySwiper = new Swiper('.swiper-container', {
    pagination: '.pagination',
    paginationClickable: true,
    mode: 'vertical',
    speed: 1000,
    mousewheelControl: true,
    onSlideChangeStart: function(swiper) {
        var slideIndex = swiper.activeIndex;
        $('#pagination-nav li').removeClass("active");
        $('#pagination-nav li:eq(' + slideIndex + ')').addClass("active");
    hashNav: true,
    grabCursor: true

The creation of the Swiper object takes an element to be used for the Power Point container. In that case, I specify a class that will be used. It could have been an unique Id too. The second parameter is for settings. The first one is optional and allow to have an automatic pagination which is represented by little dot. One dot per Html’s slide, the active one will be with a different dot color. The next image show you what it creates for you. Indeed, you can configure the visual representation of the pagination the way you want with CSS.


/*Little dot for the navigation.
  This must always be there above all slides
.pagination {
  position: absolute;
  z-index: 20;
  left: 10px;
  top: 40px;

/*Every page has a little switch at the top left corner*/
.swiper-pagination-switch {
  display: block;
  width: 18px;
  height: 18px;
  border-radius: 8px;
  background: #555;
  margin: 0 0px 5px;
  opacity: 0.8;
  border: 1px solid #fff;
  cursor: pointer;
  box-shadow: 2px 5px 7px rgb(23, 38, 95);

/*The selected slide has a switch of a different color*/
.swiper-active-switch {
  background: #fff;

The css code here is the one for the switches. I decided to have mine fix at the top of the screen with vertical alignment since I am scrolling vertically with Swiper. The direction is set inside the Json’s setting with also the speed between slide. I strongly suggest to set something between 500ms and 1500ms. Smaller does not look good with the parallax effect and too slow make it non usable for your user. The event about slide starting to change is for an optional behavior. This project has in this page a sticky menu that is using BootStrap and I wanted to make change the current tab. The event remove all class that specify the active slide and set the current one. The CSS takes care of highlighting the correct one.


Next inside of the Swiper JavaScript code, in the document ready, we can set the Stellar code.

var property = 'transform';
    scrollProperty: property,
    positionProperty: property,
    horizontalScrolling: false

The Stellar library code is pretty short and works with the Html with a specific data attribute. You must select the parent container that contains all slides. The JavaScript will loops through all html element and will apply some parallax effect on all elements with the data-stellar-ratio.


Every sections Html code looks as follow:

<div id="about" class="swiper-slide blue-slide swiper-slide-visible swiper-slide-active">
    <article class="container all-information-from-slide">
        <div class="row">
            <header class="col-md-6 col-md-push-6">
                <h1>@Index.AboutMenu<span class="smaller" data-stellar-ratio="1.3">@UI.WebSiteTitle</span></h1>
                <h2 data-stellar-ratio="1.2">@Index.AboutSlideSubTitle</h2>
            <div class="slide1-image slide-image" data-stellar-ratio="1.9" >
                <img src="~/Content/Images/FrontPage/aboutImage.png" alt="Stock Virtual Portefolio Screenshot" />
            <div class="slide1-image-shadow slide-image-shadow" data-stellar-ratio="1.7">
                <img src="~/Content/Images/FrontPage/Shadow300pixel.png" alt="Shadow" />
        <div class="container row">
            <section class="entry-content row" data-stellar-ratio="1.1">
                <p class="col-md-6 col-md-push-6">@Index.AboutSlideDescription</p>
            <a class="next-slide-button" data-stellar-ratio="1.2"><i class="fa fa-arrow-circle-down fa-5"></i></a>

The slide must have an unique identifier and the class swiper-slide. Everything inside is really custom. I am using the container class, row class and col class just because I am using BootStrapper inside the slide to align my text. The data attribute for Stellar allows to have different speeds between Html elements. The Id is also important because inside the Swipe setting, we specify the use of hasNav which is a custom plugin that I have modified a little. The default plugin change the browser Url with the hashtag of the tag (slide id). Instead of using just the hash tag, I make it use the bang-hash-tag. This way, we do not have weird scroll behavior with the library and still be able to give the url to anyone. Also, the Url is indexable by search engine! All-wins.


Here is the result of the first slide. You can see at the left the pagination with the little round switched. At the left is the image that is floating. I have set also an other image for the shadow under it. Both have different stellar ratio which create a nice effect. The right side contains different Html element, like headers and paragraphs. This way, we can set different ratio number and have everything float during scrolling in a different speed. For the full visual experience here is a short video.