Download presentation
Presentation is loading. Please wait.
Published byOliver Parrish Modified over 9 years ago
1
Curing Your Event Processing Blues with Reactive Extensions (Rx)
4/19/2017 6:11 AM Curing Your Event Processing Blues with Reactive Extensions (Rx) Bart J.F. De Smet Senior Software Development Engineer Microsoft Corporation © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
2
The Event Processing Landscape
GPS RSS feeds Stock tickers Social media UI events Server management
3
Reactive Extensions Architecture
LINQ to Events from quote in stock where quote.Symbol == “MSFT” select quote.Value Projection Filtering Aggregating Grouping Joins Windowing Sharing Sampling Throttling Timeout Merging Recovery Event Streams IObservable<T> IObserver<T> ISubject<T> Concurrency IScheduler Time Threads Cloud Dispatchers
4
Reactive Extensions Architecture
LINQ to Events from quote in stock where quote.Symbol == “MSFT” select quote.Value Projection Filtering Aggregating Grouping Joins Windowing Sharing Sampling Throttling Timeout Merging Recovery Event Streams IObservable<T> IObserver<T> ISubject<T> Concurrency IScheduler Time Threads Cloud Dispatchers
5
Event Streams Towards a unified programming model Observable Observer
Producers are observable sequences .NET events, WinRT events, sensor APIs, APM methods, tasks, etc. Consumers are observers Hooking up “continuations” or handlers Observable Observer Subscribe
6
Essential Interfaces namespace System {
public interface IObservable<out T> IDisposable Subscribe(IObserver<T> observer); } public interface IObserver<in T> void OnNext(T value); void OnError(Exception error); void OnCompleted();
7
OnNext* (OnError | OnCompleted)?
Notification Grammar OnNext(42) OnNext(43) OnCompleted source1 OnNext(“Hello”) OnError(error) source2 OnNext* (OnError | OnCompleted)?
8
Limitations of .NET Events
Can’t pass around Hidden data source exchange.StockTick += (sender, args) => { if (args.Quote.Symbol == “MSFT”) // Imperative code } }; exchange.StockTick -= /* what goes here? */; Lack of composition Hard resource maintenance
9
Observable Sequences to the Rescue
Source of Quotes Objects can be passed IObservable<Quote> stockQuotes = …; var msft = stockQuotes .Where(quote => quote.Symbol == “MSFT”); var subscription = msft.Subscribe(quote => /* … */); subscription.Dispose(); Can define query operators Easy resource maintenance
10
Are .NET Events Obsolete?
Code centric Design-time experience Not first class Non-compositional Lightweight Rigid execution model (IL) Observables Data centric No design-time experience First class objects Rich composition Slightly more cost Translatable with expression trees
11
Events versus Observables
4/19/2017 6:11 AM demo Events versus Observables Bart J.F. De Smet Senior Software Development Engineer Cloud Programmability Team © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
12
Reactive Extensions Architecture
LINQ to Events from quote in stock where quote.Symbol == “MSFT” select quote.Value Projection Filtering Aggregating Grouping Joins Windowing Sharing Sampling Throttling Timeout Merging Recovery Event Streams IObservable<T> IObserver<T> ISubject<T> Concurrency IScheduler Time Threads Cloud Dispatchers
13
Dictionary Suggest Asynchronous request “React” Dictionary web service
4/19/2017 6:11 AM Dictionary Suggest Asynchronous request IObservable<string> “React” React Dictionary web service Reaction Reactive Reactor IObservable<DictionaryWord[]> Data binding on UI thread © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
14
Converting Events and Asynchronous Methods
// Convert the TextChanged event to IObservable<string> var input = (from evt in Observable.FromEventPattern(txt, “TextChanged”) select ((TextBox)evt.Sender).Text) .Throttle(TimeSpan.FromSeconds(0.5)) .DistinctUntilChanged(); // Convert asynchronous proxy methods to Func<string, IObservable<string[]>> var lookup = Observable.FromAsyncPattern<string, string[]>(svc.BeginLookup, svc.EndLookup); // Compose both sources using a query var res = from term in input from words in lookup(term).TakeUntil(input) select words; No longer needed in Rx v2.0 for .NET 4.5, using Task<T>
15
Querying Event Streams
demo Querying Event Streams Bart J.F. De Smet Senior Software Development Engineer Cloud Programmability Team © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
16
Stock Trade Analysis from tick in ticks ticks MSFT 27.01 INTC 21.75
4/19/2017 6:11 AM Stock Trade Analysis MSFT 27.01 INTC 21.75 MSFT 27.96 MSFT 31.21 INTC 22.54 INTC 20.98 MSFT 30.73 ticks from tick in ticks © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
17
Stock Trade Analysis group tick by tick.Symbol ticks MSFT INTC MSFT
4/19/2017 6:11 AM Stock Trade Analysis MSFT 27.01 INTC 21.75 MSFT 27.96 MSFT 31.21 INTC 22.54 INTC 20.98 MSFT 30.73 ticks 27.01 27.96 31.21 30.73 MSFT 21.75 22.54 20.98 INTC from tick in ticks group tick by tick.Symbol © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
18
Stock Trade Analysis group tick by tick.Symbol into company
4/19/2017 6:11 AM Stock Trade Analysis MSFT 27.01 INTC 21.75 MSFT 27.96 MSFT 31.21 INTC 22.54 INTC 20.98 MSFT 30.73 ticks [27.01, 27.96] [27.96, 31.21] [31.21, 30.73] MSFT [21.75, 22.54] [22.54, 20.98] INTC from tick in ticks group tick by tick.Symbol into company from openClose in company.Buffer(2, 1) © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
19
4/19/2017 6:11 AM Stock Trade Analysis MSFT 27.01 INTC 21.75 MSFT 27.96 MSFT 31.21 INTC 22.54 INTC 20.98 MSFT 30.73 ticks 0.034 0.104 -0.015 MSFT 0.036 -0.069 INTC from tick in ticks group tick by tick.Symbol into company from openClose in company.Buffer(2, 1) let diff = (openClose[1] – openClose[0]) / openClose[0] © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
20
Stock Trade Analysis where diff > 0.1 ticks MSFT INTC MSFT 27.01
4/19/2017 6:11 AM Stock Trade Analysis MSFT 27.01 INTC 21.75 MSFT 27.96 MSFT 31.21 INTC 22.54 INTC 20.98 MSFT 30.73 ticks 0.034 0.104 -0.015 MSFT 0.036 -0.069 INTC from tick in ticks group tick by tick.Symbol into company from openClose in company.Buffer(2, 1) let diff = (openClose[1] – openClose[0]) / openClose[0] where diff > 0.1 © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
21
4/19/2017 6:11 AM Stock Trade Analysis MSFT 27.01 INTC 21.75 MSFT 27.96 MSFT 31.21 INTC 22.54 INTC 20.98 MSFT 30.73 ticks res Company = MSFT Increase = 0.104 from tick in ticks group tick by tick.Symbol into company from openClose in company.Buffer(2, 1) let diff = (openClose[1] – openClose[0]) / openClose[0] where diff > 0.1 select new { Company = company.Key, Increase = diff } © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
22
Complex Event Processing
4/19/2017 6:11 AM demo Complex Event Processing Bart J.F. De Smet Senior Software Development Engineer Cloud Programmability Team © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
23
Reactive Extensions Architecture
LINQ to Events from quote in stock where quote.Symbol == “MSFT” select quote.Value Projection Filtering Aggregating Grouping Joins Windowing Sharing Sampling Throttling Timeout Merging Recovery Event Streams IObservable<T> IObserver<T> ISubject<T> Concurrency IScheduler Time Threads Cloud Dispatchers
24
The Role of Schedulers Parameterize Concurrency
// // Runs a timer on the default scheduler IObservable<long> Timer(TimeSpan dueTime); // Every operator that introduces concurrency // has an overload with an IScheduler IObservable<long> Timer(TimeSpan dueTime, IScheduler scheduler);
25
The Role of Schedulers Synchronization
var xs = Observable.Return(42, Scheduler.ThreadPool); xs.Subscribe(x => lbl.Text = "Answer = " + x); xs.ObserveOn( frm ) .Subscribe(x => lbl.Text = "Answer = " + x); xs.ObserveOn(new ControlScheduler(frm)) .Subscribe(x => lbl.Text = "Answer = " + x);
26
The IScheduler Interface
public interface IScheduler { DateTimeOffset Now { get; } IDisposable Schedule<TState>( TState state, Func<IScheduler, TState, IDisposable> action); IDisposable Schedule<TState>( TimeSpan dueTime, TState state, IDisposable Schedule<TState>( DateTimeOffset dueTime, TState state, }
27
Operational Layering of Rx
public static IObservable<T> Return<T>(T value, IScheduler scheduler) { return Observable.Create<T>(observer => // Serialize state to scheduler; return ability to cancel return scheduler.Schedule(new { value, observer }, (_, x) => x.observer.OnNext(x.value); x.observer.OnCompleted(); return Disposable.Empty; // No recursive work }); }
28
Virtualizing Time for Testing
var scheduler = new TestScheduler(); var input = scheduler.CreateHotObservable( OnNext(300, “Bart De Smet”), OnNext(400, “Erik Meijer”), OnCompleted<string>(500) ); var results = scheduler.Start(() => from name in input select name.Length); results.Messages.AssertEqual( OnNext(300, 12), OnNext(400, 11), OnCompleted<int>(500)
29
Testing in Virtual Time
4/19/2017 6:11 AM demo Testing in Virtual Time Bart J.F. De Smet Senior Software Development Engineer Cloud Programmability Team © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
30
Expression Tree Representation of Queries
Runtime translation of reactive queries Like IQueryable<T> for classic LINQ Examples: LINQ to WMI Events Translates LINQ queries into WQL statements LINQ to PowerShell Translates LINQ queries into PowerShell pipelines LINQ to Twitter Translates LINQ queries into Twitter queries Etc.
31
The IQbservable<T> Interface
public interface IQbservable<out T> : IObservable<T> { Type ElementType { get; } Expression Expression { get; } IQbservableProvider Provider { get; } } public interface IQbservableProvider IQbservable<T> CreateQuery<T>(Expression expression);
32
The Query Processing Landscape
Local execution (in-process IL) Query language translation IQueryable<T> IQbservable<T> Expression trees LINQ to SQL (T-SQL) Expression trees LINQ to WMI (WQL) LINQ IEnumerable<T> IObservable<T> Iterators (yield) LINQ to Objects Observable.Create LINQ to Events (Rx) Pull-based Push-based
33
demo LINQ to WMI Events Bart J.F. De Smet
4/19/2017 6:11 AM demo LINQ to WMI Events Bart J.F. De Smet Senior Software Development Engineer Cloud Programmability Team © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
34
announcing StreamInsight v2.1
Now with support for hosting Rx v1.0 queries using IQbservable<T> © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
35
The Future of Rx Support for .NET Framework 4.5
Synergy with asynchronous programming features Prefer using Task<T> for single-value asynchrony Deprecation of FromAsyncPattern Convert to IObservable<T> for more power Use IObservable<T> for event streams Await support returns last value Reduce blocking operations Deprecation of First, Last, Single, ForEach Leveraging new platform capabilities E.g. ExceptionDispatchInfo
36
The Asynchronous Programming Landscape
Single value (1) Multiple values (*) IEnumerable<T> IObservable<T> var res = from p in products where p.Name == “Rx” select p.Price; foreach (var x in res) … var res = from s in stocks where s.Symbol == “MSFT” select q.Quote res.Subscribe(x => … Func<T> Task<T> var y = f(x); var z = g(y); var y = await fAsync(x); var z = await gAsync(y); Synchronous Asynchronous
37
Imperative glue ~ WaitForMultipleObjectsEx
Async without Rx… async Task<string> GetHtmlAsync(Uri url) { var client = new WebClient(); var download = client.DownloadStringAsync(url); var timeout = Task.Delay(TimeSpan.FromSeconds(30)); if (await Task.WhenAny(download, timeout) == timeout) throw new TimeoutException(); var html = await download; return html; } Imperative glue ~ WaitForMultipleObjectsEx
38
Async with Rx… Better together!
async Task<string> GetHtmlAsync(Uri url) { var client = new WebClient(); var download = client.DownloadStringAsync(url) .ToObservable() .Timeout(TimeSpan.FromSeconds(30)); var html = await download; return html; } Composition of query operators Await support for IObservable<T>
39
The Future of Rx Interoperability with WinRT
Use WinRT-style events with FromEventPattern Different method signatures in IL New IScheduler implementations For WinRT ThreadPool and CoreDispatcher ObserveOnDispatcher and SubscribeOnDispatcher support Conversions of IAsync* types Smooth interop with WinRT asynchronous operations Support for progress tracking using IObservable<T>
40
The Future of Rx Towards Portable Library Support
System.Reactive.PlatformServices Platform Enlightenments System.Reactive.Providers Expression tree support Windows.Threading System.Reactive. Windows.Forms System.Reactive. WindowsRuntime System.Reactive. System.Reactive. Remoting System.Reactive.Linq Query operators System.Reactive.Core Base classes, core schedulers, extensions methods System.Reactive.Interfaces Stable interfaces for forward compatibility
41
The Future of Rx Performance
Reducing locking in subjects [3x] Faster producers [ x] New ISchedulerLongRunning interface Pipeline throughput [4x] One call frame per operator Reduced wrapping of observers Less operators defined in terms of others Eliminating redundant locks Eradicating time skew due to timing issues Play nicer with GC
42
demo Preview of Rx v2.0 Bart J.F. De Smet
4/19/2017 6:11 AM demo Preview of Rx v2.0 Bart J.F. De Smet Senior Software Development Engineer Cloud Programmability Team © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
43
Summary Tame your event streams using Rx and LINQ! Download Rx today!
Through (search for Rx SDK) Using (search for Rx-Main) Now available: Rx v2.0 RC Watch videos at Visit our forums on MSDN
44
Related Content DEV414 – LINQ, Take Two – Realizing the LINQ to Everything Dream Find Me Later This Week In The Ask The Experts Area
45
Resources Learning TechNet http://europe.msteched.com
Connect. Share. Discuss. Microsoft Certification & Training Resources TechNet Resources for IT Professionals Resources for Developers
46
Submit your evals online
4/19/2017 6:11 AM Evaluations Submit your evals online © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
47
4/19/2017 6:11 AM © 2012 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION. © 2009 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.