Commit fb922e9

mo <email@solidware.ca>
2011-03-27 06:08:03
tried saving income account, but the unit of work doesnt seem to cascade down the object hierarchy.
1 parent e456b56
product/desktop.ui/bootstrappers/Bootstrapper.cs
@@ -16,6 +16,7 @@ using solidware.financials.windows.ui.handlers;
 using solidware.financials.windows.ui.presenters;
 using solidware.financials.windows.ui.presenters.specifications;
 using solidware.financials.windows.ui.views;
+using utility;
 
 namespace solidware.financials.windows.ui.bootstrappers
 {
@@ -98,7 +99,7 @@ namespace solidware.financials.windows.ui.bootstrappers
         static void register_for_message_to_listen_for(ContainerBuilder builder)
         {
             builder.RegisterType<PublishEventHandler<AddedNewFamilyMember>>().As<Handles<AddedNewFamilyMember>>();
-            builder.RegisterType<PublishEventHandler<AddIncomeCommandMessage>>().As<Handles<AddIncomeCommandMessage>>();
+            builder.RegisterType<PublishEventHandler<IncomeMessage>>().As<Handles<IncomeMessage>>();
         }
 
         static void server_registration(ContainerBuilder builder)
@@ -122,6 +123,10 @@ namespace solidware.financials.windows.ui.bootstrappers
             var interceptor = new UnitOfWorkInterceptor(new DB40UnitOfWorkFactory(new DB4OConnectionFactory(), Lazy.load<Context>()) );
             builder.RegisterProxy<Handles<FamilyMemberToAdd>, AddNewFamilyMemberHandler>(interceptor);
             builder.RegisterProxy<Handles<FindAllFamily>, FindAllFamilyHandler>(interceptor);
+            builder.RegisterProxy<Handles<FindAllIncome>, FindAllIncomeHandler>(interceptor);
+            builder.RegisterProxy<Handles<AddIncomeCommandMessage>, AddIncomeCommandMessageHandler>(interceptor);
+
+            builder.RegisterType<ConfigureServiceMappings>().As<NeedStartup>();
             new DB4OBootstrapper().run();
         }
     }
product/desktop.ui/bootstrappers/ComposeShell.cs
@@ -3,6 +3,7 @@ using gorilla.infrastructure.container;
 using solidware.financials.windows.ui.presenters;
 using solidware.financials.windows.ui.views;
 using solidware.financials.windows.ui.views.icons;
+using utility;
 
 namespace solidware.financials.windows.ui.bootstrappers
 {
product/desktop.ui/bootstrappers/ConfigureMappings.cs
@@ -1,9 +1,7 @@
 using System;
-using System.Collections.Generic;
-using gorilla.utility;
 using solidware.financials.messages;
-using solidware.financials.service.domain;
 using solidware.financials.windows.ui.model;
+using utility;
 
 namespace solidware.financials.windows.ui.bootstrappers
 {
@@ -20,15 +18,6 @@ namespace solidware.financials.windows.ui.bootstrappers
                     last_name = x.last_name,
                 };
             });
-            Map<Person, AddedNewFamilyMember>(x =>
-            {
-                return new AddedNewFamilyMember
-                {
-                    id = x.id,
-                    first_name = x.first_name,
-                    last_name = x.last_name,
-                };
-            });
         }
 
         void Map<Input, Output>(Func<Input, Output> conversion)
@@ -36,45 +25,4 @@ namespace solidware.financials.windows.ui.bootstrappers
             MapperRegistery.Register(conversion);
         }
     }
-
-    static public class MapperRegistery
-    {
-        static Dictionary<MapKey, object> mappings = new Dictionary<MapKey, object>();
-
-        static public void Register<Input, Output>(Func<Input, Output> conversion)
-        {
-            mappings.Add(new MapKey<Input, Output>(), conversion);
-        }
-
-        static public Output Map<Input, Output>(Input item)
-        {
-            var converter = mappings[new MapKey<Input, Output>()];
-            return converter.downcast_to<Func<Input, Output>>()(item);
-        }
-    }
-
-    public interface MapKey
-    {
-    }
-
-    public class MapKey<Input, Output> : MapKey
-    {
-        public bool Equals(MapKey<Input, Output> obj)
-        {
-            return !ReferenceEquals(null, obj);
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != typeof (MapKey<Input, Output>)) return false;
-            return Equals((MapKey<Input, Output>) obj);
-        }
-
-        public override int GetHashCode()
-        {
-            return GetType().GetHashCode();
-        }
-    }
 }
\ No newline at end of file
product/desktop.ui/bootstrappers/DefaultMapper.cs
@@ -1,4 +1,5 @@
 using gorilla.utility;
+using utility;
 
 namespace solidware.financials.windows.ui.bootstrappers
 {
product/desktop.ui/bootstrappers/WireUpSubscribers.cs
@@ -1,6 +1,7 @@
 using gorilla.infrastructure.container;
 using solidware.financials.infrastructure.eventing;
 using solidware.financials.windows.ui.events;
+using utility;
 
 namespace solidware.financials.windows.ui.bootstrappers
 {
product/desktop.ui/presenters/TaxSummaryPresenter.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using solidware.financials.infrastructure;
 using solidware.financials.infrastructure.eventing;
 using solidware.financials.messages;
 using solidware.financials.windows.ui.events;
@@ -7,17 +8,20 @@ using solidware.financials.windows.ui.model;
 
 namespace solidware.financials.windows.ui.presenters
 {
-    public class TaxSummaryPresenter : Observable<TaxSummaryPresenter>, TabPresenter, EventSubscriber<AddIncomeCommandMessage>, EventSubscriber<SelectedFamilyMember>
+    public class TaxSummaryPresenter : Observable<TaxSummaryPresenter>, TabPresenter, EventSubscriber<IncomeMessage>, EventSubscriber<SelectedFamilyMember>
     {
         UICommandBuilder builder;
+        ServiceBus bus;
 
-        public TaxSummaryPresenter(UICommandBuilder builder)
+        public TaxSummaryPresenter(UICommandBuilder builder, ServiceBus bus)
         {
             this.builder = builder;
+            this.bus = bus;
         }
 
         public void present()
         {
+            bus.publish<FindAllIncome>();
         }
 
         public string Header
@@ -27,19 +31,24 @@ namespace solidware.financials.windows.ui.presenters
 
         public TaxesForIndividual Selected { get; set; }
 
-        public void notify(AddIncomeCommandMessage message)
+        public void notify(IncomeMessage message)
         {
-            Selected.AddIncome(message.Amount);
+            TaxesFor(message.PersonId).AddIncome(message.Amount);
         }
 
         public void notify(SelectedFamilyMember message)
         {
-            if (!family.ContainsKey(message.id))
-                family[message.id] = new TaxesForIndividual(message.id);
-            Selected = family[message.id];
+            Selected = TaxesFor(message.id);
             update(x => x.Selected);
         }
 
+        TaxesForIndividual TaxesFor(Guid id)
+        {
+            if (!family.ContainsKey(id))
+                family[id] = new TaxesForIndividual(id);
+            return family[id];
+        }
+
         IDictionary<Guid, TaxesForIndividual> family = new Dictionary<Guid, TaxesForIndividual>();
     }
 }
\ No newline at end of file
product/desktop.ui/solidware.financials.csproj
@@ -110,8 +110,6 @@
     <Compile Include="bootstrappers\ComposeShell.cs" />
     <Compile Include="bootstrappers\ConfigureMappings.cs" />
     <Compile Include="bootstrappers\DefaultMapper.cs" />
-    <Compile Include="bootstrappers\NeedsShutdown.cs" />
-    <Compile Include="bootstrappers\NeedStartup.cs" />
     <Compile Include="bootstrappers\WireUpSubscribers.cs" />
     <Compile Include="CancelCommand.cs" />
     <Compile Include="Dialog.cs" />
@@ -272,6 +270,10 @@
       <Project>{9928913D-5BCE-422F-9A12-13A10ACE836D}</Project>
       <Name>service</Name>
     </ProjectReference>
+    <ProjectReference Include="..\utility\utility.csproj">
+      <Project>{B5534C03-58F9-4515-A213-EFDDC2BC3E63}</Project>
+      <Name>utility</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
product/messages/AddIncomeCommandMessage.cs
@@ -9,4 +9,10 @@ namespace solidware.financials.messages
         public Guid PersonId { get; set; }
         public decimal Amount { get; set; }
     }
+
+    public class IncomeMessage : ValueType<IncomeMessage>, Event
+    {
+        public Guid PersonId { get; set; }
+        public decimal Amount { get; set; }
+    }
 }
\ No newline at end of file
product/messages/FindAllFamily.cs
@@ -3,4 +3,7 @@
     public class FindAllFamily
     {
     }
+    public class FindAllIncome
+    {
+    }
 }
\ No newline at end of file
product/service/domain/accounting/BOED.cs
@@ -4,7 +4,7 @@ namespace solidware.financials.service.domain.accounting
 {
     public class BOED : SimpleUnitOfMeasure
     {
-        public override string pretty_print(double amount)
+        public override string pretty_print(decimal amount)
         {
             throw new NotImplementedException();
         }
product/service/domain/accounting/ConversionRatio.cs
@@ -2,15 +2,15 @@ namespace solidware.financials.service.domain.accounting
 {
     public class ConversionRatio
     {
-        double rate;
+        decimal rate;
         static public readonly ConversionRatio Default = new ConversionRatio(1);
 
-        public ConversionRatio(double rate)
+        public ConversionRatio(decimal rate)
         {
             this.rate = rate;
         }
 
-        public double applied_to(double amount)
+        public decimal applied_to(decimal amount)
         {
             return amount*rate;
         }
product/service/domain/accounting/Currency.cs
@@ -12,7 +12,7 @@ namespace solidware.financials.service.domain.accounting
             this.pneumonic = pneumonic;
         }
 
-        public override string pretty_print(double amount)
+        public override string pretty_print(decimal amount)
         {
             return "{0:C} {1}".format(amount, this);
         }
product/service/domain/accounting/DetailAccount.cs
@@ -16,17 +16,17 @@ namespace solidware.financials.service.domain.accounting
             return new DetailAccount(unit_of_measure);
         }
 
-        public void deposit(double amount)
+        public void deposit(decimal amount)
         {
             deposit(amount, unit_of_measure);
         }
 
-        public void deposit(double amount, UnitOfMeasure units)
+        public void deposit(decimal amount, UnitOfMeasure units)
         {
             add(Entry.New<Deposit>(amount, units));
         }
 
-        public void withdraw(double amount, UnitOfMeasure units)
+        public void withdraw(decimal amount, UnitOfMeasure units)
         {
             add(Entry.New<Withdrawal>(amount, units));
         }
product/service/domain/accounting/Entry.cs
@@ -2,7 +2,7 @@ namespace solidware.financials.service.domain.accounting
 {
     public class Entry
     {
-        static public Entry New<Transaction>(double amount, UnitOfMeasure units) where Transaction : TransactionType, new()
+        static public Entry New<Transaction>(decimal amount, UnitOfMeasure units) where Transaction : TransactionType, new()
         {
             return New<Transaction>(new Quantity(amount, units));
         }
product/service/domain/accounting/MCF.cs
@@ -4,7 +4,7 @@ namespace solidware.financials.service.domain.accounting
 {
     public class MCF : SimpleUnitOfMeasure
     {
-        public override string pretty_print(double amount)
+        public override string pretty_print(decimal amount)
         {
             throw new NotImplementedException();
         }
product/service/domain/accounting/Quantity.cs
@@ -4,10 +4,10 @@ namespace solidware.financials.service.domain.accounting
 {
     public class Quantity : IEquatable<Quantity>
     {
-        double amount;
+        decimal amount;
         UnitOfMeasure units;
 
-        public Quantity(double amount, UnitOfMeasure units)
+        public Quantity(decimal amount, UnitOfMeasure units)
         {
             this.units = units;
             this.amount = amount;
@@ -28,7 +28,7 @@ namespace solidware.financials.service.domain.accounting
             return new Quantity(unit_of_measure.convert(amount, units), unit_of_measure);
         }
 
-        static public implicit operator double(Quantity quanity)
+        static public implicit operator decimal(Quantity quanity)
         {
             return quanity.amount;
         }
product/service/domain/accounting/SimpleUnitOfMeasure.cs
@@ -4,12 +4,12 @@ namespace solidware.financials.service.domain.accounting
 
     public abstract class SimpleUnitOfMeasure : UnitOfMeasure
     {
-        public double convert(double amount, UnitOfMeasure other)
+        public decimal convert(decimal amount, UnitOfMeasure other)
         {
             return rate_table(this, other).applied_to(amount);
         }
 
-        public abstract string pretty_print(double amount);
+        public abstract string pretty_print(decimal amount);
 
         static RateTable rate_table = (x, y) => ConversionRatio.Default;
 
product/service/domain/accounting/UnitOfMeasure.cs
@@ -2,8 +2,8 @@ namespace solidware.financials.service.domain.accounting
 {
     public interface UnitOfMeasure
     {
-        double convert(double amount, UnitOfMeasure other);
-        string pretty_print(double amount);
+        decimal convert(decimal amount, UnitOfMeasure other);
+        string pretty_print(decimal amount);
     }
 
 }
\ No newline at end of file
product/service/domain/Person.cs
@@ -1,3 +1,5 @@
+using solidware.financials.service.domain.accounting;
+
 namespace solidware.financials.service.domain
 {
     public class Person : Entity
@@ -9,11 +11,18 @@ namespace solidware.financials.service.domain
                        first_name = first_name,
                        last_name = last_name,
                        date_of_birth = date_of_birth,
+                       income_account = DetailAccount.New(Currency.CAD),
                    };
         }
 
-        public virtual string first_name { get; set; }
-        public virtual string last_name { get; set; }
-        public virtual Date date_of_birth { get; set; }
+        public virtual string first_name { get; private set; }
+        public virtual string last_name { get; private set; }
+        public virtual Date date_of_birth { get; private set; }
+        public virtual DetailAccount income_account { get; private set; }
+
+        public virtual DetailAccount IncomeAccount()
+        {
+            return income_account;
+        }
     }
 }
\ No newline at end of file
product/service/handlers/AddIncomeCommandMessageHandler.cs
@@ -1,14 +1,28 @@
-using System;
 using solidware.financials.infrastructure;
 using solidware.financials.messages;
+using solidware.financials.service.orm;
 
 namespace solidware.financials.service.handlers
 {
     public class AddIncomeCommandMessageHandler : Handles<AddIncomeCommandMessage>
     {
+        PersonRepository family;
+        ServiceBus bus;
+
+        public AddIncomeCommandMessageHandler(PersonRepository family, ServiceBus bus)
+        {
+            this.family = family;
+            this.bus = bus;
+        }
+
         public void handle(AddIncomeCommandMessage item)
         {
-            throw new NotImplementedException();
+            family.find_by(item.PersonId).IncomeAccount().deposit(item.Amount);
+            bus.publish<IncomeMessage>(x =>
+            {
+                x.Amount = item.Amount;
+                x.PersonId = item.PersonId;
+            });
         }
     }
 }
\ No newline at end of file
product/service/handlers/FindAllIncomeHandler.cs
@@ -0,0 +1,34 @@
+using System.Linq;
+using gorilla.utility;
+using solidware.financials.infrastructure;
+using solidware.financials.messages;
+using solidware.financials.service.orm;
+
+namespace solidware.financials.service.handlers
+{
+    public class FindAllIncomeHandler : Handles<FindAllIncome>
+    {
+        PersonRepository people;
+        Mapper mapper;
+        ServiceBus bus;
+
+        public FindAllIncomeHandler(PersonRepository people, Mapper mapper, ServiceBus bus)
+        {
+            this.people = people;
+            this.mapper = mapper;
+            this.bus = bus;
+        }
+
+        public void handle(FindAllIncome item)
+        {
+            people
+                .find_all()
+                .Select(x => new IncomeMessage
+                             {
+                                 PersonId = x.id,
+                                 Amount = x.income_account.balance(),
+                             })
+                .each(x => bus.publish(x));
+        }
+    }
+}
\ No newline at end of file
product/service/orm/DB4OConnectionFactory.cs
@@ -1,6 +1,7 @@
 using System;
 using System.IO;
 using Db4objects.Db4o;
+using Db4objects.Db4o.Config;
 
 namespace solidware.financials.service.orm
 {
@@ -16,11 +17,23 @@ namespace solidware.financials.service.orm
             if (null == connection)
             {
                 ensure_directories_exist();
-                connection = new DB4OConnection(Db4oEmbedded.OpenFile(database_path));
+                connection = new DB4OConnection(Db4oEmbedded.OpenFile(config(), database_path));
             }
             return connection;
         }
 
+        IEmbeddedConfiguration config()
+        {
+            var config = Db4oEmbedded.NewConfiguration();
+            config.File.GenerateUUIDs = ConfigScope.Individually;
+            config.IdSystem.UseInMemorySystem();
+            config.Common.ActivationDepth = int.MaxValue;
+            config.Common.DetectSchemaChanges = true;
+            config.Common.MaxStackDepth = int.MaxValue;
+            config.Common.UpdateDepth = int.MaxValue;
+            return config;
+        }
+
         void ensure_directories_exist()
         {
             var company_dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"mokhan.ca");
product/service/orm/DB4OPersonRepository.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using gorilla.utility;
 using solidware.financials.service.domain;
 using Db4objects.Db4o.Linq;
 
@@ -17,6 +18,7 @@ namespace solidware.financials.service.orm
 
         public void save(Person person)
         {
+            person.id = new Id<Guid>(Guid.NewGuid());
             session.Store(person);
         }
 
product/service/orm/PersonRepository.cs
@@ -6,8 +6,8 @@ namespace solidware.financials.service.orm
 {
     public interface PersonRepository
     {
-        void save(Person person);
         Person find_by(Guid id);
         IEnumerable<Person> find_all();
+        void save(Person person);
     }
 }
\ No newline at end of file
product/service/ConfigureServiceMappings.cs
@@ -0,0 +1,28 @@
+using System;
+using solidware.financials.messages;
+using solidware.financials.service.domain;
+using utility;
+
+namespace solidware.financials.service
+{
+    public class ConfigureServiceMappings : NeedStartup
+    {
+        public void run()
+        {
+            Map<Person, AddedNewFamilyMember>(x =>
+            {
+                return new AddedNewFamilyMember
+                       {
+                           id = x.id,
+                           first_name = x.first_name,
+                           last_name = x.last_name,
+                       };
+            });
+        }
+
+        void Map<Input, Output>(Func<Input, Output> conversion)
+        {
+            MapperRegistery.Register(conversion);
+        }
+    }
+}
\ No newline at end of file
product/service/service.csproj
@@ -57,6 +57,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ConfigureServiceMappings.cs" />
     <Compile Include="DB4OBootstrapper.cs" />
     <Compile Include="domain\accounting\Account.cs" />
     <Compile Include="domain\accounting\BOED.cs" />
@@ -112,6 +113,7 @@
     <Compile Include="domain\Entity.cs" />
     <Compile Include="domain\Person.cs" />
     <Compile Include="handlers\FindAllFamilyHandler.cs" />
+    <Compile Include="handlers\FindAllIncomeHandler.cs" />
     <Compile Include="orm\Connection.cs" />
     <Compile Include="orm\ConnectionFactory.cs" />
     <Compile Include="orm\DB4OConnection.cs" />
@@ -139,6 +141,10 @@
       <Project>{C3DF753C-7BB7-48E0-B87D-D37ED47EDF92}</Project>
       <Name>messages</Name>
     </ProjectReference>
+    <ProjectReference Include="..\utility\utility.csproj">
+      <Project>{B5534C03-58F9-4515-A213-EFDDC2BC3E63}</Project>
+      <Name>utility</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
product/specs/unit/service/domain/accounting/BOEDSpecs.cs
@@ -41,7 +41,7 @@ namespace specs.unit.service.domain.accounting
                 result.should_be_equal_to(6);
             };
 
-            static double result;
+            static decimal result;
         }
     }
 }
\ No newline at end of file
product/specs/unit/service/domain/accounting/CurrencySpecs.cs
@@ -18,12 +18,12 @@ namespace specs.unit.service.domain.accounting
         {
             Establish c = () =>
             {
-                SimpleUnitOfMeasure.provide_rate((x, y) => new ConversionRatio(1.05690034));
+                SimpleUnitOfMeasure.provide_rate((x, y) => new ConversionRatio(1.05690034m));
             };
 
             It should_return_the_correct_amount = () =>
             {
-                Currency.USD.convert(1, Currency.CAD).should_be_equal_to(1.05690034);
+                Currency.USD.convert(1, Currency.CAD).should_be_equal_to(1.05690034m);
             };
         }
 
@@ -32,12 +32,12 @@ namespace specs.unit.service.domain.accounting
         {
             Establish c = () =>
             {
-                SimpleUnitOfMeasure.provide_rate((x, y) => new ConversionRatio(0.95057));
+                SimpleUnitOfMeasure.provide_rate((x, y) => new ConversionRatio(0.95057m));
             };
 
             It should_return_the_correct_amount = () =>
             {
-                Currency.CAD.convert(1.05690034d, Currency.USD).should_be_equal_to(1.0046577561938002d);
+                Currency.CAD.convert(1.05690034m, Currency.USD).should_be_equal_to(1.0046577561938002m);
             };
         }
     }
product/specs/unit/service/domain/accounting/DetailAccountSpecs.cs
@@ -20,12 +20,12 @@ namespace specs.unit.service.domain.accounting
         {
             Because b = () =>
             {
-                sut.deposit(100.01, Currency.CAD);
+                sut.deposit(100.01m, Currency.CAD);
             };
 
             It should_adjust_the_balance = () =>
             {
-                sut.balance().should_be_equal_to(new Quantity(100.01, Currency.CAD));
+                sut.balance().should_be_equal_to(new Quantity(100.01m, Currency.CAD));
             };
         }
 
@@ -34,13 +34,13 @@ namespace specs.unit.service.domain.accounting
         {
             Because b = () =>
             {
-                sut.deposit(100.01);
-                sut.withdraw(10.00, Currency.CAD);
+                sut.deposit(100.01m);
+                sut.withdraw(10.00m, Currency.CAD);
             };
 
             It should_adjust_the_balance = () =>
             {
-                sut.balance().should_be_equal_to(new Quantity(90.01, Currency.CAD));
+                sut.balance().should_be_equal_to(new Quantity(90.01m, Currency.CAD));
             };
         }
     }
product/specs/unit/service/domain/accounting/SummaryAccountSpecs.cs
@@ -36,7 +36,7 @@ namespace specs.unit.service.domain.accounting
 
             It should_sum_the_balance_for_each_detail_account = () =>
             {
-                result.should_be_equal_to(new Quantity(100.00, Currency.CAD));
+                result.should_be_equal_to(new Quantity(100.00m, Currency.CAD));
             };
 
             static Quantity result;
product/utility/MapKey.cs
@@ -0,0 +1,27 @@
+namespace utility
+{
+    public class MapKey<Input, Output> : MapKey
+    {
+        public bool Equals(MapKey<Input, Output> obj)
+        {
+            return !ReferenceEquals(null, obj);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != typeof (MapKey<Input, Output>)) return false;
+            return Equals((MapKey<Input, Output>) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            return GetType().GetHashCode();
+        }
+    }
+
+    public interface MapKey
+    {
+    }
+}
\ No newline at end of file
product/utility/MapperRegistery.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using gorilla.utility;
+
+namespace utility
+{
+    static public class MapperRegistery
+    {
+        static Dictionary<MapKey, object> mappings = new Dictionary<MapKey, object>();
+
+        static public void Register<Input, Output>(Func<Input, Output> conversion)
+        {
+            mappings.Add(new MapKey<Input, Output>(), conversion);
+        }
+
+        static public Output Map<Input, Output>(Input item)
+        {
+            var converter = mappings[new MapKey<Input, Output>()];
+            return converter.downcast_to<Func<Input, Output>>()(item);
+        }
+    }
+}
\ No newline at end of file
product/desktop.ui/bootstrappers/NeedsShutdown.cs → product/utility/NeedsShutdown.cs
@@ -1,6 +1,6 @@
 using gorilla.utility;
 
-namespace solidware.financials.windows.ui.bootstrappers
+namespace utility
 {
     public interface NeedsShutdown : Command {}
 }
\ No newline at end of file
product/desktop.ui/bootstrappers/NeedStartup.cs → product/utility/NeedStartup.cs
@@ -1,6 +1,6 @@
 using gorilla.utility;
 
-namespace solidware.financials.windows.ui.bootstrappers
+namespace utility
 {
     public interface NeedStartup : Command {}
 }
\ No newline at end of file
product/utility/utility.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{B5534C03-58F9-4515-A213-EFDDC2BC3E63}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>utility</RootNamespace>
+    <AssemblyName>utility</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="gorilla.utility">
+      <HintPath>..\..\thirdparty\commons\gorilla.utility.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MapKey.cs" />
+    <Compile Include="MapperRegistery.cs" />
+    <Compile Include="NeedsShutdown.cs" />
+    <Compile Include="NeedStartup.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
studio.sln
@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "messages", "product\message
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "infrastructure", "product\infrastructure\infrastructure.csproj", "{16D56F38-F4B0-4134-907A-837E4C62C7B7}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "utility", "product\utility\utility.csproj", "{B5534C03-58F9-4515-A213-EFDDC2BC3E63}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -71,6 +73,16 @@ Global
 		{16D56F38-F4B0-4134-907A-837E4C62C7B7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{16D56F38-F4B0-4134-907A-837E4C62C7B7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{16D56F38-F4B0-4134-907A-837E4C62C7B7}.Release|x86.ActiveCfg = Release|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{B5534C03-58F9-4515-A213-EFDDC2BC3E63}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE