Archive for the ‘MVC’ category

Wonderful Wednesday

November 25th, 2009

Working hard… sorta of – it’s the day before Thanksgiving and many people aren’t working today – makes for a long weekend for many.

Well, I’m still working, so thought I’d post some updates from the week since my last ‘Saturday Splash’.

Couple of items this week of interest:

Saturday Night Live : ‘China Cold Open’

http://www.hulu.com/watch/110317/saturday-night-live-china-cold-open

Telerik ASP.NET MVC Controls

Telerik has some free open source mvc controls available: http://demos.telerik.com/aspnet-mvc/

  • Pure ASP.NET MVC components

    Built on top of ASP.NET MVC to leverage its values – lightweight rendering, clean HTML, separation of concerns, and testability.

  • Completely Open Source

    The Extensions are licensed under the widely adopted GPLv2. A commercial license with support is also available.

  • Exceptional Performance

    No postbacks, no ViewState, and no page lifecycle. The Web Asset Managers optimize the delivery of CSS and JavaScript, so no precious HTTP requests are wasted.

  • Based on jQuery

    Telerik Extensions draw on the power of jQuery for visual effects and DOM manipulations.

  • Search Engine Optimized

    The Extensions render clean, semantic HTML, which is essential for indexing your content in the major search engines.

  • Cross-browser support

    Telerik Extensions for ASP.NET MVC support all major browsers – Internet Explorer, Firefox, Safari, Opera and Google Chrome.

  • One of the biggest concerns for those hooked (more like stuck – lol) on webforms is ‘but what about my controls’?’.  Sad but true, however, with asp.net mvc it’s much easier to create controls.  Combine those with a powerful javascript library like jQuery and it can be magic.

    Take for instance the Telerik grid (by the way, you can get a similiar grid from MVCContrib, which I use, which this code is nearly the same… hmm… wonder if the same guy made them for Telerik – lol):

    <%= Html.Telerik().Grid<Order>(Model)
            .Name("Grid")
            .Columns(columns =>
            {
                columns.Add(o => o.OrderID).Width(100);
                columns.Add(o => o.Customer.ContactName).Width(200);
                columns.Add(o => o.ShipAddress);
                columns.Add(o => o.OrderDate).Format("{0:MM/dd/yyyy}").Width(120);
            })
            .ServerBinding(serverBinding => serverBinding.Action("FirstLook", "Grid", new { ajax = ViewData["ajax"] }))
            .Ajax(ajax => ajax.Enabled((bool)ViewData["ajax"]).Action("_FirstLook", "Grid"))
            .Scrollable(scrolling => scrolling.Enabled((bool)ViewData["scrolling"]))
            .Sortable(sorting => sorting.Enabled((bool)ViewData["sorting"]))
            .Pageable(paging => paging.Enabled((bool)ViewData["paging"]))
            .Filterable(filtering => filtering.Enabled((bool)ViewData["filtering"]))
    %>
    
    

    Simple to use, and very powerful… and free. Check out the link above to view the other available controls.

    Update: http://blogs.telerik.com/AtanasKorchev/Posts/08-11-06/ASP_NET_Ajax_Controls_in_ASP_NET_MVC.aspx

    From that link above:

    …I am glad to inform you that RadScriptManager provides support forASP.NET MVC view and master pages. What this means is that RadControls for ASP.NET Ajax can be used in ASP.NET MVC…

    
    

    (Learn more from Atanas Korchev’s blog here – he has some good posts surrounding asp.net mvc with Telerik)

    
    

    RIA Services: A DomainService IS A WCF Service – Add Service Reference

    Brad Abrams has a good post on showing how a RIA.NET Domain Service IS a WCF Service:

    http://blogs.msdn.com/brada/archive/2009/11/22/ria-services-a-domainservice-is-a-wcf-service-add-service-reference.aspx

    This is a recent change in RIA.NET – and I should add, several other services like ADO.NET Data Services – where they are using WCF ‘under the covers’ as their communication protocol.  I think this is a good move – it provides a very standard way to communicate across the wire regardless of which flavor you choose.

    Using JsonP with WCF and jQuery

    Ben Dewey has an excellent blog post on how to use JsonP with WCF and jQuery in the new release of .NET 4.0.  As he explains, the WCF team has added support for JsonP.  Since jQuery ships with a getJSON ajax function, it makes this a piece o’ pie  :)

    ASPNET MVC from Basic to Tips and Tricks

    Michael Johson has a good writeup on tips and tricks with asp.net mvc.  I think he is spot on in all his recommendations.  Much of what he write about is best practices with asp.net mvc.

    As more and more asp.net developers see the light of mvc, we’ll need more posts like this to keep them writing good mvc code  :)

    Refactor or Rewrite

    Another good infoq article – this one on ‘refactor or rewrite’.   I’ve had this same conversation several times in my career – as I’ve seen projects really expand and bolt more and more functionality, which ends up changing the overall scope of the application – making it harder to maintain and understand.  Obviously many companies are scared to rewrite an app from scratch.

    Other

    Google: Last but not least, I’ve really enjoyed my switch to using google products.  I switched my email address over to gmail, I’m using google reader, google docs, etc…  and finally I’m using Google Chrome in full force now.  I miss two items from Firefox that I’m looking for replacements… (1) Firebug –which is the greatest and best web dev tool ever… and (2) FireFTP.  For now, I just pop open Firefox when I need it.  I think Chrome is more stable, uses less memory, and is faster.

    I deployed a test of the Google chrome on a web project.  This enable me to keep chrome as the website engine, and allow the client to use IE still as the main browser.  Certain pages, like reporting services, just use vanilla IE to print reports, etc..

    Lastly, I had a good talk with a member of the Microsoft Patterns and Practices team last week.  I had been critical in a blog post about their releases, etc…  As always, talking directly to someone helps tremendously.  We were able to voice our concerns (I invited a few coworkers) and where we think they could do better.  It was well taken.  That team is very customer focused, and they want and value community feedback.  This helped change some of my views.   One area I want to get more involved with is growing their web client guidance – expanding it to asp.net mvc – and their Prism for Silverlight.  Just wanted to express that the P&P team is hard at work and I was able to get more clarification on the role they play at Microsoft.  As fyi – they are an extension I believe of the product teams, and yet rather than just one product, they have several under their belt – that keeps them quite busy  :)

    That is all for this week – I hope everyone has a Happy Thanksgiving.  This is my favorite holiday – family and good food, time to be thankful for all we have.  The Lord has been good to my family and myself.  Just pray for all those that don’t have a family to be with and for those less fortunate.  I also pray for those out of work to be able to find some work.  This economy has been very hard on our community.  God Bless!

    Using NCommon – Unit Of Work, Repository, etc…

    March 27th, 2009

     

    ***Update***

    The NCommon codebase has been moved from CodePlex to Google Code.  You can get this code here:

    http://code.google.com/p/ncommon/

    Any links below have not been updated

    —-

    I was looking for a good repository for using Entity Framework in a proof of concept project.  I stumbled upon a project called ‘NCommon’.   The beauty of this framework is that is appears to support Entity Framework, Linq to Sql, and NHibernate.

    The basis of NCommon is that it helps build a ‘domain driven’ architecture.  A summary from the link above describes the major parts of NCommon:

    NCommon is a library that contains implementations of commonly used design patterns when developing applications. So far NCommon provides the following:

    • Framework for implementing a Unit of Work Pattern
    • Framework for implementing a Repository pattern that utilizes Linq
    • Framework for implementing a Validations and Business Rules
    • Implementation of the Specification pattern using Expressions
    • Utility class to help store application specific data in the Thread Local Storage / Current Web Request and AppDomain Level Storage
    • A Guard class that mimics common guard statements that verify parameter values and throws exceptions if values are not acceptable.

    NCommon includes a sample website – done with asp.net mvc.  I setup a ‘test’ (it’s not really a test, more of a ‘ok, looks good, how does it work’)

    My sample snippet is a call to retrieve and address entity and update it’s state:

    Step one:  Register the Unit of Work and Repository with your IOC container of choice – in this case I use Castle Windsor, you can use any IOC however, since NCommon uses the Microsoft ServiceLocator.  (Here is an example done in Unity)

    image

    Since I have chosen to try Entity Framework, I’m registering the ‘EFUnitOfWorkFactory’ and the ‘EFRepository’ – again, you could use Linq2Sql or NHibernate here.  The unit of work factory is, of course, in charge of creating the unit of work  :)

    Step Two:  This is some underlying plumbing that occurs, I’m telling the ServiceLocator what IOC container I’m using for NCommon, additionally, I’m telling the EFUnitOfWorkFactory what EF DataContext I’m using (‘BistroEntities’ is my ObjectContext for my EF test project):

    image

    I’ll show in a bit what happens at a asp.net mvc level, but this is the core ‘setup’ involved – this is done once in your application, after that you never look at it again   :)

    Now, let’s show how I can use this ‘unit of work’ with a ‘repository’ pattern:

    image

    First off, I want to define in the code that I’m beginning a unit of work.  Martin Fowler tells us all about ‘Unit of Work’ :

    Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

    Obviously we want this in our application !  ( I should say you ‘need’ this – lol)

    In my senario above, I’m only making one ‘save’ call, however, I could have a situation where I’m saving a collection of entities – the address, a company update, an employee update, a audit trail save, etc… This is all accomplished through the UnitOfWorkScope – it is handling the underlying Transaction as well.  The UnitOfWorkScope does a lookup to the ServiceLocator to find the corresponding type of unit of work.

    Secondly, I’m instantiating a new EFRepository.  In the asp.net mvc sample, you’ll see this will be associated to a controller by using dependency injection.  It would look something like this:

    public AddressController : Controller
    {
           private readonly EFRepository<Address> _addressRepository
           public AddressController(EFRepository<Address> addressRepository)
           {
                  _addressRepository = addressRepository;
    …

    (Basically, the container handles the instantiation of the repository on your behalf via dependency injection)

    The entity is retrieved, updated, and saved.

    Notice the Unit of work ‘Save’ call:  This save call is committing the underlying transaction.  If I left this out…the save wouldn’t occur  :)

    So, how does this work in the NCommon sample website code?

    Obviously the real question is, ‘how do we set this up to use in our application’:

    In the asp.net mvc application you must set it up in the global.cs file – where the application starts basically: (note, the NCommon sample code uses NHibernate):

    image

    I’ll skip over the NHibernate specific parts here, you can download the sample, the key item here is telling the Store about the NHibernate ISession (for EF/Linq2Sql this is ‘similiar’ to your context object):

    image

    The next section is the registration (again, see the sample code)

    image

    As with above, you can see the registration of the NHUnitOfWorkFactory and the NHRepository.

    These get registered along with the controller registration that asp.net mvc offers as well as the ServiceLocator registration of our container.

    Lastly then we move to the controller itself, again, looking at the NCommon sample web application:

    image

    Since the controller is registered, and the IRepository is registered, this is ‘autowired’ to find in the container the IRepository instance and create it on your behalf.

    Lastly, we use it:

    image

    I think this is a fantastic setup and architecture – I would probably insert a ‘service layer’ in between my controller and my repository however.  (and if you have seen my other posts, I think something like RIA.NET – which I think should be called ‘DomainServices.NET’ comes into play…eventually…)

    Thanks to Ritesh Rao for his NCommon library as well as for his help in getting starting with NCommon

    MvcContrib Grid

    March 5th, 2009

    One of my favorite controls available in the MvcContrib is the Grid component.

    I’ve been using it for quite awhile.  They have decided to rewrite, but thankfully they include the older grid for legacy purposes  – which will allow me to refactor and take advantage of the new grid.

    Information on the new Grid – documentation for it – can be found here:

    http://www.jeremyskinner.co.uk/2009/02/08/rewriting-the-mvccontrib-grid/

    It’s built using a nice fluent interface style:

    ie.

    <%= Html.Grid(Model.People).Columns(column => {
         		column.For(x => x.Id).Named("Person ID");
         		column.For(x => x.Name);
         		column.For(x => x.DateOfBirth).Format("{0:d}");
         	})
            .Attributes(style => "width:100%")
         	.Empty("There are no people.")
         	.RowStart(row => "<tr foo='bar'>") %>

     

    It has paging support as well:

    <%= Html.Grid(Model.People).Columns(column => {
         		column.For(x => x.Id).Named("Person ID");
         		column.For(x => x.Name);
         		column.For(x => x.DateOfBirth).Format("{0:d}");
    }) %>   <%= Html.Pager(Model.People) %>

    All of this information can be found at the link above.

    As per the release page of MvcContrib, if you have been using the previous Grid, you can reference it’s new namespace:

    The original grid has been moved to the MvcContrib.UI.LegacyGrid namespace and will continue to function as before. The new grid is located in MvcContrib.UI.Grid

    This will look like the following in your web.config:

    <add namespace="MvcContrib"/>

    <add namespace="MvcContrib.UI.Html"/>

    <add namespace="MvcContrib.UI.Grid"/>

    <add namespace="MvcContrib.UI.LegacyGrid"/>

    (And by the way: definitely add namespaces in the web.config vs. the individual pages !  YAGNI lol)

    More on ASP.NET MVC XForms

    December 23rd, 2008

    I did some review of the code for the ASP.NET MVC XForms that is available on Codeplex.  I’ve blogged about this project before and finally got the chance to try it out in more detail.

    It’s really put together quite well!  My basic usage to start is a better way to create form in asp.net mvc using fluent ‘chaining’.

    Here is a simple example:

    image

    One piece ‘missing’ for me was how to take an existing jQuery plugins (in this case, MaskInput by Digital Bush) and use them in the XForms framework.  In the above example, I need to extend the form.Input with my own ‘Mask’ functionality.

    To understand how to apply this mask, it works like this:

    $(function(){
          $(“#DOB”).mask(“99/99/9999”);
    });  //this is fired when dom is done loading, prior to page being displayed

    Jon Curtis, the maker of XForms got me going in the right direction:

    I like the idea of a Mask extension, perhaps you would like to contribute and add it to the framework?
    The MVC XForms core functionality is in the Mvc.XForms namespace. This has to match the w3c XForms spec. I created the Mvc.XForms.UI namespace for extensions to the framework that might be commonly used; currently there is only the grid control. This would be the place for the mask.
    The best way to implement this would probably be to wrap a rebuild action (which fires when the xform is rebuilt). Something like (untested):
    public static InputSettings Mask(this InputSettings settings, string mask) {
        var script = string.Format("function (ev) { $(ev.target).mask(‘{0}’); }", mask);
        settings.Action(XForms.Rebuild, script);
        return settings;
    }
    I’m open to suggestions how to make the framework and javascript API more extensible. This is one of the goals of the project and I think there is still a way to go to achieve this. Another key thing is I would like to keep the script as minimal as possible and not implement things that have been done before. Where we can use jQuery, use jQuery. So use the mask plugin.

     

    So, I proceeded… (this does require a js reference to the plugin).  Within the XForm.UI assembly I created the following:

    image

    The XFormsEvent.Rebuild injected the script into the jQuery ‘ready’ function – which was perfect for what I needed.

    The end result:

    image

    As you see, I was able to apply the mask to the DOB field.   (Also, you can see the ‘help’ feature)

    The framework takes care of wrapping everything up (hence the slightly different format for calling mask from above).

    Here is more on XForms and Extending the Framework by Jon Curtis

    Next step for me… creating a formatter to make sure my incoming datetime is 99/99/9999  :)

    Scott Guthrie on Upcoming ASP.NET Release Candidate

    December 19th, 2008

    Scott shared today on some changes coming to the asp.net mvc release candidate.

    I. He starts with the option (default now) of ‘no-code behind’ pages.  Very nice!

    ie. Inherits=”System.Web.Mvc.ViewPage<Model>”

    (I’m not sure how this will work with generics (ie. a simple view of IList<Things>)

    Personally I think this is a great move.  99% of my files don’t have code behind – and the only ones that ‘did’ were refactored (I had used a repeater on a few pages, then later replaced with the MvcContrib Grid)

    II. The HTML/Ajax helpers will now enable expression syntax.

    I’ve been doing something similiar lately after examing how the MvcContrib Gridview was built, in order to do other controls with jquery, ie. TabViews, Treeviews, etc…

    I hope and think that this will greatly speed up the development of those controls.

    III. Scaffolding support

    This one looks interesting – definitely check it out.  At the very least, I see it as a RAD capability, that would then allow easy modification if needed. 

    IV. MSBuild Tasks for the View

    (Hey Ryan!) – this is excellent news!  I’ve told my friend Ryan several times – ‘I wish the build would pick up on any html helper errors’.  This will save a ton of time, as it wouldn’t be until runtime that a problem would be spotted (although Resharper was good as picking it up – *if* you saw it – lol)

    So, looks like more goodies, the framework begins to flush out a bit – looks all good – and nothing that appears to be major breaking changes (whew).  But we’ll see… the cost of doing MVC… 100% worth it.

    :)

    ASP.NET Mvc App on Windows Azure

    December 19th, 2008

    Although I haven’t used ‘Windows Azure’ (aka the cloud), I have seen several examples. 

    Maarten Balliauw shares an informative 5 part blog series on getting his ASP.NET MVC ‘CarTrackr’ to run in the cloud.

    Good stuff – thanks Maarten!

    Areas in ASP.NET

    December 14th, 2008

    I probably spoke or mentioned of this before, however I really started to use Phil Haacks ‘Controller Grouping’, aka ‘Areas’ sample code – and I really like the concept.

    I’m using this currently to consolidate my library of html helpers, to build up samples of using asp.net mvc with jQuery, ExtJs, etc…

    The beauty of this is how ‘pluggable’ areas are – each with their own set of unique files: controllers, views, models with a centralized way of accessing them.

    As a former Monorails user, I find it extremely important and hope that this is actually built into asp.net mvc.

    The scenario that areas address is being able to partition your application into discrete areas of functionality. It helps make managing a large application more manageable and allows for creating distinct applets that you can drop into an application.

    From the blog you can download a sample prototype here.

    I’m going to continue building up my ‘samples’ project with areas and see how it plays out, any gotcha’s on the way, etc…

    I’d say that even if you don’t use the areas, building this in as a easy way to expand your solution is a great concept.

    Great stuff!

    (Here is another take on this approach by Steve Sanderson)

    ASP.NET MVC XForms

    December 6th, 2008

    Jon Curtis has blogged about his XForms for Asp.net MVC

    From his blog:

    What is it?

    MVC XForms is a simple, strongly-typed UI framework for MVC based on the W3C XForms specification. It provides a base set of form controls that allow updating of any complex model object, even complex nested lists. The goals are:

    • To allow automatic form population, deserialization and validation based on the (arbitrarily complex) model.
    • To produce semantic HTML forms using the logic of XForms.
    • To output clean, terse HTML.
    • No javascript, unless necessary and always optional and unobtrusive.
    • To enable clean, terse view code.
    • To make the framework as extensible and customisable as possible without compromising simplicity or the above goals.
    • Use convention over configuration and a fluent API.

    An example of usage:

    <%@ Page Language="C#" Inherits="Mvc.XForms.Examples.Customer.Details" MasterPageFile="~/Views/Shared/Site.Master" %>
    <asp:Content ContentPlaceHolderID="Content" runat="server">
    <% Html.XForm(ViewData.Model.Customer).Form(form => { %>
        <%= form.Input(c => c.Name) %>
        <%= form.Input(c => c.DateOfBirth) %>
        <%= form.Select1(a => a.Country, ViewData.Model.Countries, c => c.ID, c => c.Name) %>
        <%= form.Input(c => c.IsActive).Label("Is Active?") %>
        <%= form.Submit() %>
    <% }); %>
    </asp:Content>

    And it’s corresponding output:

    <form action="" method="post" class="xf xform">
        <div class="xf input text">
            <label for="Name">Name</label>
            <input id="Name" type="text" name="Name" value=""/>
        </div>
        <div class="xf input date">
            <label for="DateOfBirth">Date Of Birth</label>
            <input id="DateOfBirth" type="text" name="DateOfBirth" value=""/>
        </div>
        <div class="xf select1">
            <select id="Country" name="Country">
                <option value="1" selected="selected">UK</option>
                <option value="2">USA</option>
                <option value="3">France</option>
                <option value="4">Italy</option>
            </select>
        </div>
        <div class="xf input boolean">
            <input id="IsActive" type="checkbox" value="true" name="IsActive"/>
            <input type="hidden" value="false" name="IsActive"/>
            <label for="IsActive">Is Active?</label>
        </div>
        <div class="xf submit">
            <input type="submit"/>
        </div>
    </form>

    I like this syntax (actually reminds me somewhat of the asp.net mvc grid I like in codeplex)

    Jon has created a CodePlex site for the XForms located here.

    I’m really going to be watching this project – good work Jon!

    ASP.NET MVC – Castle Binders from MvcContrib

    November 10th, 2008

    Unfortunately, there is no wiki documentation, etc… on the Castle Binders in the MvcContrib.  So I thought I’d hop in and write up a sample for anyone else interested in using these binders:

    First, for some background information from the Castle website : http://www.castleproject.org/monorail/documentation/trunk/usersguide/smartcontroller.html

    These binders were originally created for Monorail, and outside of a few items, most of that documentation applies to using with MvcContrib.

    I’m using the latest MvcContrib from the trunk (SVN) at :

    http://mvccontrib.googlecode.com/svn/trunk

    After building the MvcContrib, there assemblies referenced are from:

    trunk\src\MvcContrib.Castle\bin\Release (I just added them all to a new Mvc project)

    (I’ll include the source here if you just want to download and try it)

    The goal of the binders is to provide the ability to include a strongly typed object as the recipient to a form post to an action.  As described in the document above, the default would be:

    ie.

    Person person = new Person();
    person.FirstName = Request.Form[“FirstName”];

    Step One: Create Controller implementing the ICastleBindingContainer interface

    image

    Step Two : Create Actions to handle the Form post

    image

    (note: the HttpVerbs allow you to specify one named Action – for different uses: the Get is for the form load, the Post is for the form post)

    The post action of BindersView takes a ‘Person’ object.   We use the ‘CastleBind’ attribute to specify the binding.

    There are a few optional parameters with the CastleBind: The prefix to use, and the Exclude option. 

    image

    This allows you to specify a prefix of any name in the form itself (I show form next).  The exclude allows for properties to not be included in the post request.

    (For example, if you have a sensitive property of Person, ie. social security – you can exclude it from the binding)

    Step Three : The Model

    image 

    Step Four : The Form

    Let’s show the form now:

    image

    The first form fields represent the ‘Person’, and I’m also including form fields for the spouse to be added.

    Note the ‘person.FirstName’ – the prefix is required.  Also, the Spouse object is referenced as ‘person.Spouse.FirstName’.  This will help instruct how to bind to the object.

    (You can read more about this in the Castle documention  link above)

    Let’s run it:

    image

    On save:

    image

    As you can see – it has bound to the person object as expected.

    I hope this helps show, in a simple example, how to use the Castle Binders in MvcContrib.

    (source here)

    jQuery and Asp.NET MVC – sending Json to an Action – Revisited

    November 4th, 2008

    Part I here – where I prove myself wrong …. so, let’s refactor with some help from Omar Al Zabir

    First, the new javascript:

    image

    The main difference here is that the contentType must be spelled out explicitly. 

    Secondly – the Json object must be wrapping up in a string.

    Mark Gibson has a jQuery plugin to the rescue – $.ToJSON:

    Mark Gibson put together a re-purposed json.js direct from Douglas Crockford’s early implementation of json.js as a jQuery plugin located here. I simply took Douglas Crockford’s ‘2008-02-14′ json2.js release and did the same re-purposing as Mark Gibson did just to have the updated features of the new json2.js code. One of those features included the ability to detect enumerable object to differentiate between Array() and Object(), [] vs {}.

    The code below only offers the $.toJSON() jQuery function to take a Javascript object serialize it into a JSON string and return said string. This is hugely important for our AJAX functionality which posts JSON data instead of itemized form fields in the POST data string.

     

    So, now we need to pass this data to our Person object on the action.  But we need to get access to that data and serialize it to the object – this is where Omar gets all the credit, but I modify the Json Serializer to use Json.NET:

    image

    I must say, every time I dig into the Action Filter’s I learn something new – and thanks to Omar, I realized that you can take a parameter on the action and set it’s value – very slick – with the filterContext.ActionParameters call – (side note: now I have to re-read how Model Binders work as well)

    So, we read the inputstream (Stream object) into a string – which is our json string – and then we Deserialize the object into the type we set on the filter  – and take that type and pass it to the parameter defined:

    Here is the updated Action method:

    image

    Presto!  The magic occurs and we now have a Person object that is filled.

    Thanks for getting me started Mike, thanks to Omar for his good article on filters, thanks to Ryan for pointing out the ‘hey, you screenshot shows it’s not json and you said it did’ (oops – lol)*, and thanks to Json.NET and the ToJson .js jQuery plugin!

    It’s late here, so goodnight and enjoy – I’ll update the code :

    Source code

    (for Ryan)

    image