Your SlideShare is downloading. ×
Dynamics NAV, Windows Azure & Windows Phone 7, Eric Wauters
Upcoming SlideShare
Loading in...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Dynamics NAV, Windows Azure & Windows Phone 7, Eric Wauters


Published on

Published in: Technology, Business

1 Like
  • Be the first to comment

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide
  • Key Characteristics:On-demand self-service. A consumer can unilaterally provision computing capabilities, such as server time and network storage, as needed without requiring human interaction with each service’s provider. Standard network access. Capabilities are available over the network and accessed through standard mechanisms that promote use by heterogeneous thin or thick client platforms (e.g., mobile phones, laptops, and PDAs).Location independent resource pooling. The provider’s computing resources are pooled to serve all consumers using a multi-tenant model, with different physical and virtual resources dynamically assigned and reassigned according to consumer demand. The customer generally has no control or knowledge over the exact location of the provided resources. Examples of resources include storage, processing, memory, network bandwidth, and virtual machines.Rapid elasticity. Capabilities can be rapidly and elastically provisioned to quickly scale up and rapidly released to quickly scale down. To the consumer, the capabilities available for rent often appear to be infinite and can be purchased in any quantity at any time.Pay per use.Capabilities are charged using a metered, fee-for-service, or advertising based billing model to promote optimization of resource use. Examples are measuring the storage, bandwidth, and computing resources consumed and charging for the number of active user accounts per month. Clouds within an organization accrue cost between business units and may or may not use actual currency.
  • 1. Speed to ValueProbably the most important advantage of Cloud Computing is its ability to deploy live applications rapidly without the traditional procurement and deploy-ment cycles required to get an application into production. In pilots for our clients, we have reduced deployment times by up to seventy percent.2. FlexibilityAzure has a massive capacity, allowing for easy flex up (and down) of application workload. This flexibility opens the door to solutions not previously possible: we now can develop a hybrid approach in which you maintain fixed compute capacity in Capgemini or your own data centers while using the cloud to cope with spikes.3. Cost ReductionThe shared use of Cloud Computing infrastructure yields unmatched economies of scale in data center delivery. Speed of deployment combined with a pay-as-you-go approach means much lower costs compared to traditional models.4. CapEx AvoidanceWith a pay-per-use pricing model free of upfront investment in servers or other hardware and software, this service allows IT spending to be shifted from capital to operational expenditure and reduces barriers to adoption. Barriers to exit are also eliminated as it is possible to switch off projects and applications at any time. With up to 80% of enterprise IT budgets spent on maintenance, you can free up funding for other areas.5. Cross organizational collaboration6. Greener ITThe compute density, optimization, and capacity utilization of the cloud is much higher than that of traditional data centers. Cloud Computing represents a way today to provide compute capacity to enterprises concerned about energy efficiency and reducing carbon emissions.
  • Windows Phone app: Settings.cs
  • Please do not delete thisslide – On Screen whenpresentationended.
  • Transcript

    • 1. Integrating Windows Phone 7 toMicrosoft Dynamics NAV 2009R2 Eric Wauters Development Manager iFacto Business Solutions NV Waldo’s blog ( 1
    • 2. Integrating Windows Phone 7 toMicrosoft Dynamics NAV 2009R2 Eric Wauters Backup for Freddy Kristiansen 2
    • 3. Agenda• Cloud? What is that all about? We’re all in .. but in what?• Building a Windows Phone app that connects to NAV using the cloud.
    • 4. Cloud computing? Cloud computing is a pay-per-use model for enabling available, convenient, on-demand network access to a shared pool of configurable computing resources(e.g., networks, servers, storage, applications, services) that canbe rapidly provisioned and released with minimal management effort or service provider interaction.
    • 5. Cloud Computing?
    • 6. Cloud Computing? On-demand self-serviceCharacteristics Standard network access Location independent resource pooling Rapid elasticity Pay per use
    • 7. Enterprise Cloud Triggers – Drivers 1 Speed to Value 2 Flexibility 3 Cross Organizational Collaboration 4 Cost Reduction 5 CapEx Avoidance 6 Green IT
    • 8. CapEx Avoidance – Traditional IT Allocated Load Forecast IT-capacities “Under-supply“ of capacities “Waste“ of Fixed cost of IT- IT CAPACITY capacities capacities Barrier forinnovations Actual Load TIME
    • 9. CapEx Avoidance – Cloud Load Allocated IT Forecast capacities No “under-supply“ IT CAPACITY Reduction of Possible “over-supply“ reduction of IT- capacities in case of reduced Reduction load of initialinvestments Actual Load Time
    • 10. Microsoft Online Services Platform
    • 12. Components in play• NAV – Service Dispatchers RoleCenter – Customizations – Web Services, .net interop• Proxy – C# Windows Service – Connecting to NAV Web Services – Exposing API on the Service Bus• Windows Phone 7 – Silverlight Application• Cloud – Windows Azure Account
    • 13. Components - flow Windows Azure Firewall Storage Services Services Service Bus Proxy NAV Service Tier
    • 15. NAV customizations• Service Order card – On Creating/Modifying Service Orders • Send notifications (.net interop) – Related Information – Images • Download images from Azure storage • Service Order Image table• Exposes Web Services – For the Proxy • Customer Card Page • Service Order Card Page NAV Service • Special build Codeunit Tier
    • 16. Windows Phone 7 Application• Connecting to NAV Web Services – Via the Service Bus • Get Service Orders • Accept Service Order • Change status on Service Order • Attach images and notes to service orders • Register notification channel (plumbing)• Connecting to Azure Storage – To storage images
    • 17. Windows Phone 7• Free Developer tools – – .net, C#, Silverlight – Microsoft• A TON of stuff on how to develop applications for Windows Phone already out there
    • 18. Https Web Services Proxy - API[ServiceContract]public interface IServiceOrderProxyClass{ [OperationContract] ServiceOrder[] GetServiceOrders(string username, string password); [OperationContract] bool AcceptServiceOrder(string username, string password, string no); [OperationContract] void ChangeServiceOrderStatus(string username, string password, string no, stringstatus); [OperationContract] void AttachServiceOrderImage(string username, string password, string no, stringblobName); [OperationContract] void AttachServiceOrderNote(string username, string password, string no, string note); [OperationContract] void RegisterWp7ChannelUri(string username, string password, string channelUri);}
    • 19. Https Web Services Proxy• Exposes endpoint on the Service Bus• Connects to NAV Web Services• Dedicated for Service Orders scenario• Only expose necessary API – Isolating NAV from attacks• Removes complexity• Reduces roundtrips• Loose coupling (device / NAV) – Possible to use other devices
    • 20. Windows Azure Account• Windows Azure AppFabric (Service Bus) – For communication between phone and on-premise NAV • IssuerName, IssuerSecret• Windows Azure Storage – For image storing / retrieving • AccountName, AccessKey
    • 21. WalkthroughSTEP BY STEP
    • 22. Exposing an API on Windows Azure AppFabric Firewall Service Bus Proxy NAV Service Tier
    • 23. Exposing an API on Windows Azure AppFabric var serviceHost = new ServiceHost(new ServiceOrderProxyClass()); // sb:// binding Uri sbUri = ServiceBusEnvironment.CreateServiceUri("sb", "iFactoCloudDemo• Proxy ", instanceId); var sbBinding = new – Create ServiceHost NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType .None); – Add ServiceBus Endpoints serviceHost.AddServiceEndpoint(typeof(IServiceOrderProxyClass), sbBinding, sbUri ); – Set Shared Secret credentials on endpoints // https:// binding (for Windows Phone etc.) • IssuerName, IssuerSecret Uri httpsUri = ServiceBusEnvironment.CreateServiceUri("https", "iFactoCloudDemo ", "https/" + instanceId); – httpsBinding = new var Start Servicehost BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.Transport,• Windows Azure AppFabric SDK RelayClientAuthenticationType.None); serviceHost.AddServiceEndpoint(typeof(IServiceOrderProxyClass), httpsBinding, ht tpsUri); – 6a03-1490-4283-908f-c8bf0bfad8a5 // Setup Shared Secret Credentials for hosting endpoints on the Service Bus TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior(); sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret; sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = issuerName; sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret =
    • 24. Register Notification Channel Firewall Service Bus Proxy NAV Service Tier
    • 25. Register Notification Channel RegisterWp7ChannelUri(Application : Text[40];ChannelUri : Text[250])• Phone public void RegisterWp7ChannelUri(string username, string password, string channelUri Wp7Channel.SETRANGE(UserID, USERID); { Wp7Channel.SETRANGE(Application, Application); – CreatesWp7Channel.FINDFIRST THEN var servicea= new ServiceOrderRef.ServiceOrder(); Phone API IF NotificationChannel using Windows Authenticate(service, username, password); BEGIN – Invokes RegisterWp7ChannelUri in Proxy through Web Services service.RegisterWp7ChannelUri("ServiceOrders", channelUri); Wp7Channel.ChannelUri := ChannelUri; } Wp7Channel.MODIFY();• Proxy ... END ELSE BEGIN HttpNotificationChannel.Find("waldo.ServiceOrders"); CLEAR(Wp7Channel); – Authenticates null) user if (myChannel == phone Wp7Channel.INIT(); { Wp7Channel.UserID := USERID; – myChannelRegisterWp7ChannelUri in Codeunit through Web Services Invokes = new HttpNotificationChannel("waldo.ServiceOrders"); Wp7Channel.Application := Application; } Wp7Channel.ChannelUri := ChannelUri;• NAV SendURIToService(myChannel.ChannelUri); ... Wp7Channel.INSERT(); END; – Update/Insert record in Wp7Channel table private void SendURIToService(Uri uri) { var client = App.GetServiceOrderProxyClient(); client.RegisterWp7ChannelUriAsync(App.Settings.UserName, App.Settings.Password, uri }
    • 26. Send Notification Firewall Service Bus Proxy NAV Service Tier
    • 27. Send Toast Notification• DoSendToastNotification(Wp7Channel NAV : Record Wp7Channel;Priority : Integer;Text1 : Text[40];Text2 : Text[40]) IF – Loop through Wp7Channel table Wp7Channel.NextAttempt > CURRENTDATETIME THEN EXIT; – Using a WP7Helper class to send the notification (.Net Interop) status := Wp7Helper.SendToastNotification(Wp7Channel.ChannelUri, Priority, Text1, Text2); • Create XML Document //MESSAGE(FORMAT(status)); CASE status OF • Error handling 1: BEGIN // Invalid Uri Wp7Channel.DELETE(); • Send request using HttpWebRequest / HttpWebResponse END; 2: BEGIN // Queue Full - Wait one hour before reattempting this Uri Wp7Channel.NextAttempt := CURRENTDATETIME + 3600000; BroadcastToastNotification(Application : Text[40];Header : Text[40];Text : Wp7Channel.MODIFY; Text[40]) END; Wp7Channel.SETRANGE(Wp7Channel.Application, Application); 3: BEGIN // Service Unavailable - Wait one hour before reattempting this Uri IF Wp7Channel.FINDSET THEN BEGIN Wp7Channel.NextAttempt := CURRENTDATETIME + 3600000; REPEAT Wp7Channel.MODIFY; Wp7Notifications.DoSendToastNotification(Wp7Channel.ChannelUri,2,Header,Text); END; UNTIL Wp7Channel.NEXT = 0; END; END;
    • 28. Get Service Orders Firewall Service Bus Proxy NAV Service Tier
    • 29. GetServiceOrders public ServiceOrder[] GetServiceOrders(string username, string password) private double CalculateDistance(double lat1, double lon1, double lat2, dou {• Phone ... { double theta = lon1 - lon2; var myFilter = new ServiceOrderCardRef.ServiceOrderCard_Filter(); double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + – Invoke GetServiceOrders in Proxy through Web Services myFilter.Field = ServiceOrderCardRef.ServiceOrderCard_Fields.Assigned_User_ID; Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Co myFilter.Criteria rad2deg(Math.Acos(dist)) * 60 * 1.1515; dist = = "@" + service.GetMyUserID();• Proxy varLoadServiceOrders() K) void myFilters (unit == if = new ServiceOrderCardRef.ServiceOrderCard_Filter[] { myFilter }; { var myOrders dist = dist * 1.609344; = serviceOrderService.ReadMultiple(myFilters, null, 0); void client_GetServiceOrdersCompleted(object sender, ServiceOrderProxy.GetServiceOrdersCompletedEventArgs e) – Reads Service (dist); from card page var client return Orders = App.GetServiceOrderProxyClient(); { var unassignedFilter = new ServiceOrderCardRef.ServiceOrderCard_Filter(); client.GetServiceOrdersCompleted += } unassignedFilter.Field = this.All.Clear(); • new Assigned to me ServiceOrderCardRef.ServiceOrderCard_Fields.Assigned_User_ID; foreach (ServiceOrderProxy.ServiceOrder serviceOrder in e.Result) EventHandler<ServiceOrderProxy.GetServiceOrdersCompletedEventArgs>(client_GetServi private double deg2rad(double deg) unassignedFilter.Criteria = "="; { • Assigned to ceOrdersCompleted); nobody { var unassignedFilters = = serviceOrder.Distance new ServiceOrderCardRef.ServiceOrderCard_Filter[] { client.GetServiceOrdersAsync(App.Settings.UserName, App.Settings.Password); return (deg * Math.PI / 180.0); unassignedFilter }; } – Builds and returns ServiceOrderProxyClass collection CalculateDistance(CurrentLocation.Latitude, CurrentLocation.Longitude, } var unassignedOrders = serviceOrderService.ReadMultiple(unassignedFilters, null, 0); • With Customer info read from Customer Card serviceOrder.Latitude, serviceOrder.Longitude, unit); this.All.Add(serviceOrder); var serviceOrders = new ServiceOrder[myOrders.Length + unassignedOrders.Length];• Phone } for (int i = 0; i < UpdateCollections(); myOrders.Length; i++) } serviceOrders[i] = ServiceOrder.CreateServiceOrderClass(myOrders[i], – Calculate distance from current location to each service location customerCardService.Read(myOrders[i].Customer_No)); – Update Collections (assigned, prioritized,i++) for (int i = 0; i < unassignedOrders.Length; closest) serviceOrders[i + myOrders.Length] = ServiceOrder.CreateServiceOrderClass(unassignedOrders[i],
    • 30. Accept Service Order Firewall Service Bus Proxy NAV Service Tier
    • 31. Accept Service Order public bool AcceptServiceOrder(string username, string • Phone password, string no) { var service = new ServiceOrderRef.ServiceOrder(); – Ask user if he wants to accept thevoid client_AcceptServiceOrderCompleted(objectService Order Authenticate(service, username, password);sender, ServiceOrderProxy.AcceptServiceOrderCompletedEventArgs e){ – serviceOrderService = new var Invoke AcceptServiceOrder in Proxy through Web Services Deployment.Current.Dispatcher.BeginInvoke(() => ServiceOrderCardRef.ServiceOrderCard_Service(); • Proxy {void acceptAction_Click(object sender, EventArgs e)password); Authenticate(serviceOrderService, username, if (e.Result){ – serviceOrder = you want to accept this Service Order?", "Accept", if{(MessageBox.Show("Do serviceOrderService.Read(no); through Web Services var Read the Service Order from the Card Page MessageBoxButton.OKCancel) == MessageBoxResult.OK) you!"); MessageBox.Show("ServiceOrder is now assigned to if (!string.IsNullOrEmpty(serviceOrder.Assigned_User_ID)) { this.AssignedToMe = true; } –client =false; Order is assigned already – return false return Service If the App.GetServiceOrderProxyClient(); varserviceOrder.Assigned_User_ID = service.GetMyUserID(); else client.AcceptServiceOrderCompleted += – try Set the Assigned_User_ID MessageBox.Show("ServiceOrder was already assigned to someone else"); new { App.ViewModel.LoadData();EventHandler<ServiceOrderProxy.AcceptServiceOrderCompletedEventArgs>(client_AcceptServi – serviceOrderService.Update(ref serviceOrder);ceOrderCompleted); Service Order again – if error – return false Write the UpdateApplicationBarButtons(); return true; }); }} • Phoneclient.AcceptServiceOrderAsync(App.Settings.UserName, App.Settings.Password, this.Servi catchceOrder.No); { } – return false; Display message and refresh data} } }
    • 32. Change Service Order Status Firewall Service Bus Proxy NAV Service Tier
    • 33. Change Service Order Statuspublic void ChangeServiceOrderStatus(string username, string password, string• Phoneno, string statusStr){ var– Change status on = new ServiceOrderCardRef.ServiceOrderCard_Service(); serviceOrderService Service Order internally Authenticate(serviceOrderService, username, password); – Invoke ChangeServiceOrderStatus in Proxy through Web Services var status = (Status)Enum.Parse(typeof(Status), statusStr.Replace(• Proxy, _),void ChangeServiceOrderStatus(ServiceOrderProxy.ServiceOrderprivate true);serviceOrder, string serviceOrderService.Read(no); var serviceOrder = status){ serviceOrder.Status = status; – Read Service Order from the Card Page through Web Services serviceOrderService.Update(ref serviceOrder.Status = status; serviceOrder);} var client = App.GetServiceOrderProxyClient(); – Set the Statusclient.ChangeServiceOrderStatusAsync(App.Settings.UserName, App.Settings.Password, – Update Starting Date/Time or Finishing Date/Time if necessary serviceOrder.No, status);} – Write the Service Order again
    • 34. Capture and Upload Image Firewall Storage Service Bus Proxy NAV Service Tier
    • 35. Capture and upload Imagevoid cameraTask_Completed(object sender, PhotoResult e) ... • Delay’s Blog{CameraCaptureTask cameraTask; ... (e.TaskResult == TaskResult.OK) if { – cameraTask = new CameraCaptureTask();void// Using WriteableBitmaps SaveJpeg to resize PutBlobAction(Stream s, byte[] photo) cameraTask.Completed += new EventHandler<PhotoResult>(cameraTask_Completed); – Blob API for Windows Phone{...var bitmapImage = new BitmapImage();7 bitmapImage.SetSource(e.ChosenPhoto); s.Write(photo, 0, photo.Length);} • Ms-PL ( bitmap = new WriteableBitmap(bitmapImage); cameraAction_Click(object sender, EventArgs e){ var ms = new MemoryStream();{} • Phonevoidbitmap.SaveJpeg(ms, 1024,camera0, 90); the picture cameraTask.Show(); //shows 768, to take PutBlobCompleted() var photo = ms.ToArray(); Deployment.Current.Dispatcher.BeginInvoke(() => // – Capture Image Upload photoAttachServiceOrderImage(this.ServiceOrder, blobInfo.Name));} blobClient = new – Resize imageAzureBlobStoreClient(AzureStorageAccountName, AzureStoragePrimaryAccessKey, "images");private void PutBlobFailed(Exception ex){ • to save time when uploading blobInfo = new BlobInfo(Guid.NewGuid().ToString()); Deployment.Current.Dispatcher.BeginInvoke(() (s)MessageBox.Show("No photo), blobClient.PutBlob(blobInfo, photo.Length, => => PutBlobAction(s, – Uploadconnectivity.”)); image (ex) => PutBlobFailed(ex)); PutBlobCompleted, to Azure Storage} }}
    • 36. Attach Image / Note Firewall Storage Service Bus Proxy NAV Service Tier
    • 37. Attach Image / Note AttachServiceOrderImage(No : Code[20];Image : Text[40]) ServiceOrderImage.INIT;• Phone ServiceOrderImage."Document No." := No; ServiceOrderImage."Image ID" := Image; ServiceOrderImage.INSERT(TRUE); – Invoke AttachServiceOrderImage/Note in Proxy through Web Services with Uri to Azure Storage blob or note AttachServiceOrderNote(No : Code[20];Note : Text[250]) ServiceHeader.GET(ServiceHeader."Document Type"::Order, No); – Display message box when RecRef.GETTABLE(ServiceHeader); image uploaded RecordLink.INIT();• Proxy RecordLink.Type := RecordLink.Type::Note;privatevoid AttachServiceOrderImage(string username, string password, stringpublic void AttachServiceOrderImage(ServiceOrderProxy.ServiceOrder Save_Click(object sender, EventArgs e) RecordLink.Created := CURRENTDATETIME;serviceOrder, string ID" := USERID;{ RecordLink."User blobName)no, string blobName){ var – InvokeApp.GetServiceOrderProxyClient(); in NAV Codeunit through Web client = AttachServiceOrderImage/Note RecordLink.URL1 := dynamicsnav://freddyk- var client ==App.GetServiceOrderProxyClient(); service new ServiceOrderRef.ServiceOrder(); Services with Uri or notepassword); appfabr:7047/DynamicsNAV/+COMPANYNAME+/runpage?page=5900&pers client.AttachServiceOrderImageCompleted +=client.AttachServiceOrderNoteAsync(App.Settings.UserName, App.Settings.Password, ID, Authenticate(service, username, onalization=5900&+ newthis.textBox1.Text); service.AttachServiceOrderImage(no, blobName);• NAVEventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_AttachServiceOrder} NavigationService.GoBack(); bookmark=+FORMAT(RecRef.RECORDID,0,10)+&mode=edit;ImageCompleted);} RecordLink.Description := Service Order - +No; – Insert Image := in ServiceOrderImage Table or password, stringpublic void AttachServiceOrderNote(string username, string add note to RecordLink RecordLink.Company Uri COMPANYNAME;client.AttachServiceOrderImageAsync(App.Settings.UserName, App.Settings.Password, serno, RecordLink."Record ID" := RecRef.RECORDID; string note) tableviceOrder.No, blobName);{ CLEAR(RecordLink.Note);} var service +Note; Note := = new ServiceOrderRef.ServiceOrder(); Authenticate(service, username, password); Note[1] := STRLEN(Note)-1;void client_AttachServiceOrderImageCompleted(object service.AttachServiceOrderNote(no, note); NoteText.ADDTEXT(Note);sender, System.ComponentModel.AsyncCompletedEventArgs e)} RecordLink.Note.CREATEOUTSTREAM(NoteStream);{ NoteText.WRITE(NoteStream);
    • 38. Download and display image Firewall Storage Service Bus Proxy NAV Service Tier
    • 39. Download and display imagepublic class AzureStorage{• NAV string AccountName; – Create .net string AccessKey; class AzureStorage • Using AccountName and AccessKey public AzureStorage(string AccountName, string AccessKey) { • Wrapper AccountName; this.AccountName =for AzureBlobStoreClient (Delay’s Blog) this.AccessKey = AccessKey; – Download OnAction()<Action1170000001> - all blobs for a specific Service Order to the Service Tier }AzureStorage := – Use GetBlob(string to show images name, ClientAzureStorage.AzureStorage(AzureStorageAccountName, AzureStorageAccessKey); public void File.Download container, string on the string filename)ServiceOrderImage.SETRANGE(ServiceOrderImage."Document No.", "No."); {IF NOT ServiceOrderImage.FIND(-) THEN EnsureContainerIsCreated(container);BEGIN var blobClient = new AzureBlobStoreClient(AccountName, AccessKey, container); MESSAGE(No Images attached); var blobInfo = new BlobInfo(name);END blobClient.GetBlob(blobInfo, (s) => GetBlobAction(s, filename)); ELSEREPEAT } AzureStorage.GetBlob(images, ServiceOrderImage."ImageID", TEMPORARYPATH+ServiceOrderImage."Image ID"+.jpg); ... toFile := ServiceOrderImage."Image ID"+.jpg; FILE.DOWNLOAD(TEMPORARYPATH+ServiceOrderImage."Image ID"+.jpg, Service OrderImage,, , toFile);UNTIL ServiceOrderImage.NEXT = 0;
    • 40. More info• Will soon be published on: –• Related info: – Vjeko’s blog ( – Waldo’s blog ( – Mibuso – – ... 44
    • 41. Questions? 45
    • 42. Thanks to• Diamond Sponsors• Gold Sponsors