diff --git a/README.md b/README.md
index 9c43230781..eb39fb9d8d 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,20 @@ This repository contains four libraries which are conceptually related in that t
Each will be described later in this README.
+## FREE Introduction to Rx.NET 2nd Edition eBook
+
+
+
+Reactive programming provides clarity when our code needs to respond to events. The Rx.NET libraries were designed to enable cloud-native applications to process live data in reliable, predictable ways.
+
+We've written a FREE book which explains the vital abstractions that underpin Rx, and shows how to exploit the powerful and extensive functionality built into the Rx.NET libraries.
+
+Based on Lee Campbell's 2010 book (kindly donated to the project), it has been re-written to bring it up to date with Rx.NET v6.0, .NET 8.0, and modern cloud native use cases such as IoT and real-time stream data processing.
+
+Introduction to Rx.NET is available [Online](https://introtorx.com/), [on GitHub](Rx.NET/Documentation/IntroToRx/), as [PDF](https://endjincdn.blob.core.windows.net/assets/ebooks/introduction-to-rx-dotnet/introduction-to-rx-dotnet-2nd-edition.pdf), and [EPUB](https://endjincdn.blob.core.windows.net/assets/ebooks/introduction-to-rx-dotnet/introduction-to-rx-dotnet-2nd-edition.epub).
+
+
+
## Getting the bits
Channel | Rx | AsyncRx | Ix | System.Linq.Async
@@ -26,7 +40,6 @@ For nightly builds, configure NuGet to use this feed: `https://pkgs.dev.azure.co
Catch us in the #rxnet channel over at http://reactiveui.net/slack
-
## A Brief Introduction to Rx
In this digital age, live data streams are ubiquitous. Financial applications depend on a swift response to timely information. Computer networks have always been able to provide extensive information about their health and operation. Utility companies such as water providers have vast numbers of devices monitoring their operations. User interface and game building frameworks report user interactions in great detail. Delivery vans continuously report their progress. Aircraft provide performance telemetry to detect potential maintenance issues before they become serious problems, and cars are now starting to do the same. Many of us wear or carry devices that track our physical activity and even [vital signs](https://www.youtube.com/watch?v=6yjl_h7-WYA&t=2443s). And the improvements in machine learning have enriched the insights that can be derived from the ever-increasing volume and variety of live data.
@@ -60,7 +73,7 @@ The two key features of Rx are:
Rx has been particularly successfully applied in user interfaces. (This is also true outside of .NET—[RxJS](https://rxjs.dev/) is a JavaScript spin-off of Rx, and it is very popular in user interface code.) The https://github.com/reactiveui/reactiveui makes deep use of Rx to support .NET UI development.
-To learn more, see this [Rx playlist](https://www.youtube.com/playlist?list=PLJt9xcgQpM60Fz20FIXBvj6ku4a7WOLGb).
+Ian Griffiths presented a concise 60 minute overview of [Reactive Extensions for .NET](https://endjin.com/what-we-think/talks/reactive-extensions-for-dotnet) at the dotnetsheff meetup in 2020. More videos are available on the [Rx playlist](https://www.youtube.com/playlist?list=PLJt9xcgQpM60Fz20FIXBvj6ku4a7WOLGb).
## AsyncRx.Net
@@ -140,6 +153,13 @@ Rx has been around for roughly a decade and a half, so we owe a great deal to it
## Roadmap
+As part of .NET Conf 2023, Ian Griffiths provided an update on the efforts to [modernize Rx.NET for v6.0 and the plans to for v7.0](https://endjin.com/what-we-think/talks/modernizing-reactive-extensions-for-dotnet).
+
+For more information, see the following discussions:
+
+- [Future Rx.NET Packaging](https://github.com/dotnet/reactive/discussions/2038)
+- [Rx.NET v6.0 & v7.0 high-level plan](https://github.com/dotnet/reactive/discussions/1868)
+
We have set out a [roadmap](Rx.NET/Documentation/Rx-Roadmap-2023.md) explaining our medium term plans for ongoing development of Rx. This diagram illustrates our view of the platforms on which Rx is used, and the planned support lifecycles for these various targets:

diff --git a/Rx.NET/Documentation/IntroToRx/00_Foreword.md b/Rx.NET/Documentation/IntroToRx/00_Foreword.md
index 3ba80fbad4..76ce1b1355 100644
--- a/Rx.NET/Documentation/IntroToRx/00_Foreword.md
+++ b/Rx.NET/Documentation/IntroToRx/00_Foreword.md
@@ -1,185 +1,54 @@
----
-title : Foreword
----
-
-#Introduction to Rx {#IntroductiontoRx .ignoreToc .kindleOnly}
-##Lee Campbell {.ignoreToc .kindleOnly text-align=center}
-
----
-
-#Preface {#Preface .SectionHeader}
-
-Reactive programming is not a new concept. I remember studying my first Event Driven
-module for Visual Basic 5 in 2000. Even then the technology (Visual Basic 5) was
-already considered somewhat dated. Long before VB5 and the turn of the millennium,
-we have seen languages supporting events. Over time languages like Smalltalk, Delphi
-and the .NET languages have popularized reactive or event-driven programming paradigms.
-This not to say that events are passé: current trends such as CEP (Complex
-Event Processing), CQRS (Command Query Responsibility Segregation) and rich immersive
-GUIs, all have events as a fundamental part of their makeup.
-
-The event driven paradigm allows for code to be invoked without the need for breaking
-encapsulation or applying expensive polling techniques. This is commonly implemented
-with the Observer pattern, events exposed directly in the language (e.g. C#) or
-other forms of callback via delegate registration. The Reactive Extensions extend
-the callback metaphor with LINQ to enable querying sequences of events and managing
-concurrency.
-
-The Reactive Extensions are effectively a library of implementations of the `IObservable`
-and `IObserver` interfaces for .NET, Silverlight and Windows Phone7.
-The libraries are also available in JavaScript. As a dynamic language, JavaScript
-had no need for the two interfaces so the JavaScript implementation could have been
-written long before .NET 4 was released. This book will introduce Rx via C#. Users
-of VB.NET, F# and other .NET languages hopefully will be able to extract the concepts
-and translate them to their particular language. JavaScript users should be able
-to gather the concepts from this book and apply them to their language. JavaScript
-users may however find some features are not supported, and some concepts, such
-as scheduling do not transcend platforms.
-
-As Rx is just a library, the team at Microsoft delivering Rx was able to isolate
-themselves from the release schedule of the .NET Framework. This proved important
-as the libraries saw fairly constant evolution since late 2009 through to their
-official release in mid 2011. This evolution has been largely enabled by the openness
-of the team and their ability to take onboard criticisms, suggestions and feature
-requests from the brave community of pre-release users.
-
-While Rx is _just a library_, it is a significant and bold move forward for
-the team at Microsoft and for any consumers of the library. Rx _will_ change
-the way you design and build software for the following reasons:
-
- * The way that it tackles the Observer pattern is a divorce from .NET events toward a Java-style interface pattern but far more refined.
- * The way it tackles concurrency is quite a shift how many .NET developers would have done it before.
- * The abundance of (extension) methods in the library.
- * The way in which it integrates with LINQ to leverage LINQ's composability & declarative style, makes Rx very usable and discoverable to those already familiar with LINQ and `IEnumerable`.
- * The way it can help any .NET developer that works with event driven and/or asynchronous programs. Developers of Rich Clients, Web Clients and Services alike can all benefit from Rx.
- * The future plans seem even grander, but that is a different book for some time in the future :-)
-
-This book aims to teach you:
-
- * about the new types that Rx will provide
- * about the extension methods and how to use them
- * how to manage subscriptions to "sequences" of data
- * how to visualize "sequences" of data and sketch your solution before coding it
- * how to deal with concurrency to your advantage and avoid common pitfalls
- * how to compose, aggregate and transform streams
- * how to test your Rx code
- * some guidance on best practices when using Rx.
-
-The best way to learn Rx is to use it. Reading the theory from this book will only
-help you be familiar with Rx, but will not really enable you to fully understand
-Rx. You can download the latest version of Rx from the Microsoft Data Developer
-site ()
-or if you use NuGet you can just download Rx via that.
-
-
-My experience with Rx is straight from the trenches. I worked on a team of exceptional
-developers on a project that was an early adopter of Rx (late 2009). The project
-was a financial services application that started off life as a Silverlight project
-then expanded into an integration project. We used Rx everywhere; client side in
-Silverlight 3/4, and server side in .NET 3.5/4.0. We used Rx eagerly and sometimes
-too eagerly. We were past leading edge, we were _bleeding_ edge. We were finding
-bugs in the early releases and posting proposed fixes to the guys at Microsoft.
-We were constantly updating to the latest version. It cost the project to be early
-adopters, but in time the payment was worth it. Rx allowed us to massively simplify
-an application that was inherently asynchronous, highly concurrent and targeted
-low latencies. Similar workflows that I had written in previous projects were pages
-of code long; now with Rx were several lines of LINQ. Trying to test asynchronous
-code on clients (WPF/Win Forms/Silverlight) was a constant challenge, but Rx solved
-that too. Today if you ask a question on the Rx Forums, you will most likely be
-answered by someone from that team (or Dave Sexton).
-
-
-
-#Acknowledgements {#Acknowledgements}
-
-I would like to take this quick pause to recognize the people that made this book
-possible. First is my poor wife for losing a husband to a dark room for several
-months. Her understanding and tolerance is much appreciated. To my old team "Alpha
-Alumni"; every developer on that team has helped me in some way to better myself
-as a developer. Specific mention goes to
-[James Miles](http://enumeratethis.com/),
-[Matt Barrett](http://weareadaptive.com/blog/),
-[John Marks](http://johnhmarks.wordpress.com/),
-Duncan Mole,
-Cathal Golden,
-[Keith Woods](http://keith-woods.com),
-[Ray Booysen](http://nondestructiveme.com) &
-[Olivier DeHeurles](http://odeheurles.com/)
-for all the deep dive sessions, emails, forum banter, BBM exchanges, lunch breaks
-and pub sessions spent trying to get our heads around Rx. To
-[Matt Davey](http://mdavey.wordpress.com)
-for being brave enough to support us in using Rx back in 2009.
-To the team at Microsoft that did the hard work and brought us Rx;
-[Jeffrey Van Gogh](http://blogs.msdn.com/b/jeffva/),
-[Wes Dyer](http://blogs.msdn.com/b/wesdyer/),
-[Erik Meijer](http://www.applied-duality.com/) &
-[Bart De Smet](http://blogs.bartdesmet.net/bart/).
-Extra special mention to Bart, there is just something about the
-[content](http://channel9.msdn.com/Tags/bart+de+smet) that Bart
-[produces](http://www.infoq.com/author/Bart-De-Smet) that clicks with me.
-Finally to the guys that helped edit the book;
-[Joe Albahari](http://www.albahari.com/)
-and Gregory Andrien. Joe is a veteran author of books such
-as the C# in a nutshell, C# pocket reference and LINQ pocket reference, and managed
-to find time to help out on this project while also releasing the latest versions
-of these books. For Gregory and I, this was a first for both of us, as editor and
-author respectively. Gregory committed many late nights to helping complete this
-project. There is also some sweet irony in having a French person as the editor.
-Even though English is not his native tongue, he clearly has a better grasp of it
-than I.
-
-
-It is my intention that from the experiences both good and bad, I can help speed
-up your understanding of Rx and lower that barrier to entry to using Rx. This will
-be a progressive step-by-step approach. It may seem slow in places, but the fundamentals
-are so important to have a firm grasp on the powerful features. I hope you will
-have the patience to join me all the way to the end.
-
-The content of this book was originally posted as a series of blog posts at
-[http://LeeCampbell.blogspot.com](http://leecampbell.blogspot.co.uk/2010/08/reactive-extensions-for-net.html)
-and has proved popular enough that I thought it warranted being reproduced as an e-book.
-In the spirit of other books such as
-Joe Albahari's [Threading in C#](http://www.albahari.com/threading/)
-and Scott Chacon's [Pro Git](http://git-scm.com/book) books, and considering
-the blog was free, I have made the first version of this book free.
-
-The version that this book has been written against is the .Net 4.0 targeted Rx
-assemblies version 1.0.10621.0 (NuGet: Rx-Main v1.0.11226).
-
-So, fire up Visual Studio and let's get started.
-
----
-
-
-
Additional recommended reading
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+# Introduction to Rx
+By Ian Griffiths and Lee Campbell
+
+---
+
+Reactive programming is not a new concept. Any kind of user interface development necessarily involves code that responds to events. Languages like [Smalltalk](https://en.wikipedia.org/wiki/Smalltalk), [Delphi](https://en.wikipedia.org/wiki/Delphi_(software)) and the .NET languages have popularized reactive or event-driven programming paradigms. Architectural patterns such as [CEP (Complex Event Processing)](https://en.wikipedia.org/wiki/Complex_event_processing), and [CQRS (Command Query Responsibility Segregation)](https://en.wikipedia.org/wiki/Command_Query_Responsibility_Segregation) have events as a fundamental part of their makeup. Reactive programming is a useful concept in any program that has to deal with things happening.
+
+> Reactive programming is a useful concept in any program that has to deal with things happening.
+
+The event driven paradigm allows for code to be invoked without the need for breaking encapsulation or applying expensive polling techniques. There are many common ways to implement this, including the [Observer pattern](https://en.wikipedia.org/wiki/Observer_pattern), [events exposed directly in the language (e.g. C#)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/) or other forms of callback via delegate registration. The Reactive Extensions extend the callback metaphor with LINQ to enable querying sequences of events and managing concurrency.
+
+The .NET runtime libraries have included the `IObservable` and `IObserver` interfaces that represent the core concept of reactive programming for well over a decade now. The Reactive Extensions for .NET (Rx.NET) are effectively a library of implementations of these interfaces. Rx.NET first appeared back in 2010 but since then, Rx libraries have become available for other languages, and this way of programming has become especially popular in JavaScript.
+
+This book will introduce Rx via C#. The concepts are universal, so users of other .NET languages such as VB.NET and F#, will be able to extract the concepts and translate them to their particular language.
+
+Rx.NET is just a library, originally created by Microsoft, but now an open source project supported entirely through community effort. (Rx's current lead maintainer, [Ian Griffiths](https://endjin.com/who-we-are/our-people/ian-griffiths/), is also the author of the latest revision of this book, and indeed the author of this very sentence.)
+
+If you have never used Rx before, it _will_ change the way you design and build software. It provides a well thought out abstraction for a fundamentally important idea in computing: sequences of events. These are as important as lists or arrays, but before Rx there was little direct support in libraries or languages, and what support there was tended to be rather ad hoc, and built on weak theoretical underpinnings. Rx changes that. The extent to which this Microsoft invention has been wholehearted adopted by some developer communities traditionally not especially Microsoft-friendly is a testament to the quality of its fundamental design.
+
+This book aims to teach you:
+
+ * about the types that Rx defines
+ * about the extension methods Rx provides, and how to use them
+ * how to manage subscriptions to event sources
+ * how to visualize "sequences" of data and sketch your solution before coding it
+ * how to deal with concurrency to your advantage and avoid common pitfalls
+ * how to compose, aggregate and transform streams
+ * how to test your Rx code
+ * some common best practices when using Rx
+
+The best way to learn Rx is to use it. Reading the theory from this book will only help you be familiar with Rx, but to fully understand it you should build things with it. So we warmly encourage you to build based on the examples in this book.
+
+# Acknowledgements
+
+Firstly, I ([Ian Griffiths](https://endjin.com/who-we-are/our-people/ian-griffiths/)) should make it clear that this revised edition builds on the excellent work of the original author [Lee Campbell](https://github.com/LeeCampbell). I am grateful that he generously allowed the Rx.NET project to make use of his content, enabling this new edition to come into existence.
+
+I would also like to recognize the people that made this book possible.
+
+Thanks to everyone at [endjin](https://endjin.com) and especially [Howard van Rooijen](https://endjin.com/who-we-are/our-people/howard-van-rooijen/) and [Matthew Adams](https://endjin.com/who-we-are/our-people/matthew-adams/)
+for funding not only the updates to this book, but also the ongoing development of Rx.NET itself. (And thanks for employing me too!). Thanks also to [Felix Corke](https://www.blackspike.com/) for his work on the design elements of the [web edition of the book](https://introtorx.com).
+
+Crucial to the first edition of the book, in addition to the author, [Lee Campbell](https://leecampbell.com/), were: James Miles, Matt Barrett, [John Marks](https://johnhmarks.wordpress.com/), Duncan Mole, Cathal Golden, Keith Woods, Ray Booysen, Olivier DeHeurles, [Matt Davey](https://mdavey.wordpress.com), [Joe Albahari](https://www.albahari.com/) and Gregory Andrien.
+
+Extra special thanks to the team at Microsoft that did the hard work and brought us Rx; [Jeffrey Van Gogh](https://www.linkedin.com/in/jeffrey-van-gogh-145673/), [Wes Dyer](https://www.linkedin.com/in/wesdyer/), [Erik Meijer](https://en.wikipedia.org/wiki/Erik_Meijer_%28computer_scientist%29) & [Bart De Smet](https://www.linkedin.com/in/bartdesmet/).
+
+Thanks also to those who continued to work on Rx.NET after it ceased to be directly supported by Microsoft, and became a community-based open source project. Many people were involved, and it's not practical to list every contributor here, but I'd like to say a particular thank you to [Bart De Smet](https://github.com/bartdesmet) (again, because he continued to work on the open source Rx long after moving onto other things internally at Microsoft) and also to [Claire Novotny](https://github.com/clairernovotny), [Daniel Weber](https://github.com/danielcweber), [David Karnok](https://github.com/akarnokd), [Brendan Forster](https://github.com/shiftkey), [Ani Betts](https://github.com/anaisbetts) and [Chris Pulman](https://www.linkedin.com/in/chrispulman/). We are also grateful to [Richard Lander](https://www.linkedin.com/in/richardlander/) and the [.NET Foundation](https://dotnetfoundation.org/) for helping us at [endjin](https://endjin.com) become the new stewards of the [Rx.NET project](https://github.com/dotnet/reactive), enabling it to continue to thrive.
+
+If you are interested in more information about the origins of Rx, you might find the [A Little History of Reaqtor](https://reaqtive.net/) ebook illuminating.
+
+The version that this book has been written against is `System.Reactive` version 6.0. The source for this book can be found at [https://github.com/dotnet/reactive/tree/main/Rx.NET/Documentation/IntroToRx](https://github.com/dotnet/reactive/tree/main/Rx.NET/Documentation/IntroToRx). If you find any bugs or other issues in this book, please [create an issue](https://github.com/dotnet/reactive/issues) at https://github.com/dotnet/reactive/. You might find the [Reactive X slack](reactivex.slack.com) to be a useful resource if you start using Rx.NET in earnest.
+
+So, fire up Visual Studio and let's get started.
+
+---
\ No newline at end of file
diff --git a/Rx.NET/Documentation/IntroToRx/01_WhyRx.md b/Rx.NET/Documentation/IntroToRx/01_WhyRx.md
index e86f8f53e6..590c349980 100644
--- a/Rx.NET/Documentation/IntroToRx/01_WhyRx.md
+++ b/Rx.NET/Documentation/IntroToRx/01_WhyRx.md
@@ -1,241 +1,122 @@
----
-title : Why Rx?
----
-
-#PART 1 - Getting started {#PART1 .SectionHeader}
-
-#Why Rx? {#WhyRx}
-
-Users expect real time data.
-They want their tweets now.
-Their order confirmed now.
-They need prices accurate as of now.
-Their online games need to be responsive.
-As a developer, you demand fire-and-forget messaging.
-You don't want to be blocked waiting for a result.
-You want to have the result pushed to you when it is ready.
-Even better, when working with result sets, you want to receive individual results as they are ready.
-You do not want to wait for the entire set to be processed before you see the first row.
-The world has moved to push; users are waiting for us to catch up.
-Developers have tools to push data, this is easy.
-Developers need tools to react to push data.
-
-Welcome to [Reactive Extensions for .NET](http://msdn.microsoft.com/en-us/devlabs/gg577609) (Rx).
-This book is aimed at any .NET developer curious about the `IObservable` and `IObserver`
- interfaces that have popped up in .NET 4.
-The Reactive Extensions libraries from Microsoft are the implementations of these interfaces that are quickly picking up traction with Server, Client and Web developers alike.
-Rx is a powerfully productive development tool.
-Rx enables developers to solve problems in an elegant, familiar and declarative style; often crucially with less code than was possible without Rx.
-By leveraging LINQ, Rx gets to boast the standard benefits of a LINQ implementation1.
-
-
-
-
Integrated
-
- LINQ is integrated into the C# language.
-
-
Unitive
-
- Using LINQ allows you to leverage your existing skills for querying data at rest
- (LINQ to SQL, LINQ to XML or LINQ to objects) to query data in motion. You could
- think of Rx as LINQ to events. LINQ allows you to transition from other paradigms
- into a common paradigm. For example you can transition a standard .NET event, an
- asynchronous method call, a `Task` or perhaps a 3rd party middleware API
- into a single common Rx paradigm. By leveraging our existing language of choice
- and using familiar operators like `Select`, `Where`, `GroupBy`
- etc, developers can rationalize and communicate designs or code in a common form.
-
-
Extensible
-
- You can extend Rx with your own custom query operators (extension methods).
-
-
Declarative
-
- LINQ allows your code to read as a declaration of _what_ your code does and
- leaves the _how_ to the implementation of the operators.
-
Composable
-
- LINQ features, such as extension methods, lambda syntax and query comprehension
- syntax, provide a fluent API for developers to consume. Queries can be constructed
- with numerous operators. Queries can then be composed together to further produce
- composite queries.
-
Transformative
-
- Queries can transform their data from one type to another. A query might translate
- a single value to another value, aggregated from a sequence of values to a single
- average value or expand a single data value into a sequence of values.
-
-
-
-##When is Rx appropriate? {#WhenRx}
-
-Rx offers a natural paradigm for dealing with sequences of events.
-A sequence can contain zero or more events.
-Rx proves to be most valuable when composing sequences of events.
-
-
-###Should use Rx {#Should}
-
-Managing events like these is what Rx was built for:
-
- * UI events like mouse move, button click
- * Domain events like property changed, collection updated, "Order Filled", "Registration accepted" etc.
- * Infrastructure events like from file watcher, system and WMI events
- * Integration events like a broadcast from a message bus or a push event from WebSockets API or other low latency middleware like [Nirvana](http://www.my-channels.com)
- * Integration with a CEP engine like [StreamInsight](http://www.microsoft.com/sqlserver/en/us/solutions-technologies/business-intelligence/complex-event-processing.aspx) or [StreamBase](http://www.streambase.com).
-
-Interestingly Microsoft's CEP product StreamInsight, which is part of the SQL Server family, also uses LINQ to build queries over streaming events of data.
-
-Rx is also very well suited for introducing and managing concurrency for the purpose of _offloading_.
-That is, performing a given set of work concurrently to free up the current thread.
-A very popular use of this is maintaining a responsive UI.
-
-You should consider using Rx if you have an existing `IEnumerable` that is attempting to model data in motion.
-While `IEnumerable` _can_ model data in motion (by using lazy evaluation like `yield return`), it probably won't scale.
-Iterating over an `IEnumerable` will consume/block a thread.
-You should either favor the non-blocking nature of Rx via either `IObservable` or consider the `async` features in .NET 4.5.
-
-###Could use Rx {#Could}
-
-Rx can also be used for asynchronous calls.
-These are effectively sequences of one event.
-
- * Result of a `Task` or `Task`
- * Result of an APM method call like `FileStream` BeginRead/EndRead
-
-You may find the using TPL, Dataflow or `async` keyword (.NET 4.5) proves to be a more natural way of composing asynchronous methods.
-While Rx can definitely help with these scenarios, if there are other more appropriate frameworks at your disposal you should consider them first.
-
-Rx can be used, but is less suited for, introducing and managing concurrency for the purposes of _scaling_ or performing _parallel_ computations.
-Other dedicated frameworks like TPL (Task Parallel Library) or C++ AMP are more appropriate for performing parallel compute intensive work.
-
-See more on TPL, Dataflow, `async` and C++ AMP at [Microsoft's Concurrency homepage](http://msdn.microsoft.com/en-us/concurrency).
-
-###Won't use Rx {#Wont}
-
-Rx and specifically `IObservable` is not a replacement for `IEnumerable`.
-I would not recommend trying to take something that is naturally pull based and force it to be push based.
-
- * Translating existing `IEnumerable` values to `IObservable` just so that the code base can be "more Rx"
- * Message queues.
- Queues like in MSMQ or a JMS implementation generally have transactionality and are by definition sequential.
- I feel `IEnumerable` is a natural fit for here.
-
-By choosing the best tool for the job your code should be easier to maintain, provide better performance and you will probably get better support.
-
-##Rx in action {#RxInAction}
-
-Adopting and learning Rx can be an iterative approach where you can slowly apply it to your infrastructure and domain.
-In a short time you should be able to have the skills to produce code, or reduce existing code, to queries composed of simple operators.
-For example this simple ViewModel is all I needed to code to integrate a search that is to be executed as a user types.
-
- public class MemberSearchViewModel : INotifyPropertyChanged
- {
- //Fields removed...
- public MemberSearchViewModel(IMemberSearchModel memberSearchModel,
- ISchedulerProvider schedulerProvider)
- {
- _memberSearchModel = memberSearchModel;
-
- //Run search when SearchText property changes
- this.PropertyChanges(vm => vm.SearchText)
- .Subscribe(Search);
- }
-
- //Assume INotifyPropertyChanged implementations of properties...
- public string SearchText { get; set; }
- public bool IsSearching { get; set; }
- public string Error { get; set; }
- public ObservableCollection Results { get; }
-
- //Search on background thread and return result on dispatcher.
- private void Search(string searchText)
- {
- using (_currentSearch) { }
- IsSearching = true;
- Results.Clear();
- Error = null;
-
- _currentSearch = _memberSearchModel.SearchMembers(searchText)
- .Timeout(TimeSpan.FromSeconds(2))
- .SubscribeOn(_schedulerProvider.TaskPool)
- .ObserveOn(_schedulerProvider.Dispatcher)
- .Subscribe(
- Results.Add,
- ex =>
- {
- IsSearching = false;
- Error = ex.Message;
- },
- () => { IsSearching = false; });
- }
-
- ...
- }
-
-While this code snippet is fairly small it supports the following requirements:
-
- * Maintains a responsive UI
- * Supports timeouts
- * Knows when the search is complete
- * Allows results to come back one at a time
- * Handles errors
- * Is unit testable, even with the concurrency concerns
- * If a user changes the search, cancel current search and execute new search with new text.
-
-To produce this sample is almost a case of composing the operators that match the requirements into a single query.
-The query is small, maintainable, declarative and far less code than "rolling your own".
-There is the added benefit of reusing a well tested API.
-The less code _you_ have to write, the less code _you_ have to test, debug and maintain.
-Creating other queries like the following is simple:
-
- * calculating a moving average of a series of values e.g. *service level agreements* for average latencies or downtime
- * combining event data from multiple sources e.g.: *search results* from Bing, Google and Yahoo, or *sensor data* from Accelerometer, Gyro, Magnetometer or temperatures
- * grouping data e.g. *tweets* by topic or user, or *stock prices* by delta or liquidity*
- * filtering data e.g. *online game servers* within a region, for a specific game or with a minimum number of participants.
-
-
-Push is here.
-Arming yourself with Rx is a powerful way to meet users' expectations of a push world.
-By understanding and composing the constituent parts of Rx you will be able to make short work of complexities of processing incoming events.
-Rx is set to become a day-to-day part of your coding experience.
-
-
----
-
-
+# PART 1 - Getting started
+
+Rx is a .NET library for processing event streams. Why might you want that?
+
+## Why Rx?
+
+Users want timely information. If you're waiting for a parcel to arrive, live reports of the delivery van's progress give you more freedom than a suspect 2 hour delivery window. Financial applications depend on continuous streams of up-to-date data. We expect our phones and computers to provide us with all sorts of important notifications. And some applications simply can't work without live information. Online collaboration tools and multiplayer games absolutely depend on the rapid distribution and delivery of data.
+
+In short, our systems need to react when interesting things happen.
+
+Live information streams are a basic, ubiquitous element of computer systems. Despite this, they are often a second class citizen in programming languages. Most languages support sequences of data through something like an array, which presumes that the data is sitting in memory ready for our code to read at its leisure. If your application deals with events, arrays might work for historical data, but they aren't a good way to represent events that occur while the application is running. And although streamed data is a pretty venerable concept in computing, it tends to be clunky, with the abstractions often surfaced through APIs that are poorly integrated with our programming language's type system.
+
+This is bad. Live data is critical to a wide range of applications. It should be as easy to work with as lists, dictionaries, and other collections.
+
+The [Reactive Extensions for .NET](https://github.com/dotnet/reactive) (Rx.NET or Rx for short, available as the [`System.Reactive` NuGet package](https://www.nuget.org/packages/System.Reactive/)) elevate live data sources to first class citizens. Rx does not require any special programming language support. It exploits .NET's type system to represent streams of data in a way that .NET languages such as C#, F#, and VB.NET can all work with as naturally as they use collection types.
+
+(A brief grammatical aside: although the phrase "Reactive Extensions" is plural, when we reduce it to just Rx.NET or Rx, we treat it as a singular noun. This is inconsistent, but saying "Rx are..." sounds plain weird.)
+
+For example, C# offers integrated query features that we might use to find all of the entries in a list that meet some criteria. If we have some `List trades` variable, we might write this:
+
+```csharp
+var bigTrades =
+ from trade in trades
+ where trade.Volume > 1_000_000;
+```
+
+With Rx, we could use this exact same code with live data. Instead of being a `List`, the `trades` variable could be an `IObservable`. `IObservable` is the fundamental abstraction in Rx. It is essentially a live version of `IEnumerable`. In this case, `bigTrades` would also be an `IObservable`, a live data source able to notify us of all trades whose `Volume` exceeds one million. Crucially, it can report each such trade immediately—this is what we mean by a 'live' data source.
+
+Rx is a powerfully productive development tool. It enables developers to work with live event streams using language features familiar to all .NET developers. It enables a declarative approach that often allows us to express complex behaviour more elegantly and with less code than would be possible without Rx.
+
+Rx builds on LINQ (Language Integrated Query). This enables us to use the query syntax shown above (or you can use the explicit function call approach that some .NET developers prefer). LINQ is widely used in .NET both for data access (e.g., in Entity Framework Core), but also for working with in-memory collections (with LINQ to Objects), meaning that experienced .NET developers will tend to feel at home with Rx. Crucially, LINQ is a highly composable design: you can connect operators together in any combination you like, expressing potentially complex processing in a straightforward way. This composability arises from the mathematical foundations of its design, but although you can learn about this aspect of LINQ if you want, it's not a prerequisite: developers who aren't interested in the mathematics behind it can just enjoy the fact that LINQ providers such as Rx provide a set of building blocks that can be plugged together in endless different ways, and it all just works.
+
+LINQ has proven track record of handling high very high volumes of data. Microsoft has used it extensively in the internal implementation of some of their systems, including services that support tens of millions of active users.
+
+## When is Rx appropriate?
+
+Rx is designed for processing sequences of events, meaning that it suits some scenarios better than others. The next sections describe some of these scenarios, and also cases in which it is a less obvious match but still worth considering. Finally, we describe some cases in which it is possible to use Rx but where alternatives are likely to be better.
+
+### Good Fit with Rx
+
+Rx is well suited to representing events that originate from outside of your code, and which your application needs to respond to, such as:
+
+- Integration events like a broadcast from a message bus, or a push event from WebSockets API, or a message received via MQTT or other low latency middleware like [Azure Event Grid](https://azure.microsoft.com/en-gb/products/event-grid/), [Azure Event Hubs](https://azure.microsoft.com/en-gb/products/event-hubs/) and [Azure Service Bus](https://azure.microsoft.com/en-gb/products/service-bus/), or a non-vendor specific representation such as [cloudevents](https://cloudevents.io/)
+- Telemetry from monitoring devices such as a flow sensor in a water utility's infrastructure, or the monitoring and diagnostic features in a broadband provider's networking equipment
+- Location data from mobile systems such as [AIS](https://github.com/ais-dotnet/) messages from ships, or automotive telemetry
+- Operating system events such as filesystem activity, or WMI events
+- Road traffic information, such as notifications of accidents or changes in average speed
+- Integration with a [Complex Event Processing (CEP)](https://en.wikipedia.org/wiki/Complex_event_processing) engine
+- UI events such as mouse movement or button clicks
+
+Rx is also good way to model domain events. These may occur as a result of some of the events just described, but after processing them to produce events that more directly represent application concepts. These might include:
+
+- Property or state changes on domain objects such as "Order Status Updated", or "Registration Accepted"
+- Changes to collections of domain objects, such as "New Registration Created"
+
+Events might also represent insights derived from incoming events (or historical data being analyzed at a later date) such as:
+
+- A broadband customer might have become an unwitting participant in a DDoS attack
+- Two ocean-going vessels have engaged in a pattern of movement often associated with illegal activity (e.g., travelling closely alongside one another for an extended period, long enough to transfer cargo or people, while far out at sea)
+- [CNC](https://en.wikipedia.org/wiki/Numerical_control) [Milling Machine](https://en.wikipedia.org/wiki/Milling_(machining)) MFZH12's number 4 axis bearing is exhibiting signs of wear at a significantly higher rate than the nominal profile
+- If the user wants to arrive on time at their meeting half way across town, the current traffic conditions suggest they should leave in the next 10 minutes
+
+These three sets of examples show how applications might progressively increase the value of the information as they process events. We start with raw events, which we then enhance to produce domain-specific events, and we then perform analysis to produce notifications that the application's users will really care about. Each stage of processing increases the value of the messages that emerge. Each stage will typically also reduce the volume of messages. If we presented the raw events in the first category directly to users, they might be overwhelmed by the volume of messages, making it impossible to spot the important events. But if we only present them with notifications when our processing has detected something important, this will enable them to work more efficiently and accurately, because we have dramatically improved the signal to noise ratio.
+
+The [`System.Reactive` library](https://www.nuget.org/packages/System.Reactive) provides tools for building exactly this kind of value-adding process, in which we tame high-volume raw event sources to produce high-value, live, actionable insights. It provides a suite of operators that enable our code to express this kind of processing declaratively, as you'll see in subsequent chapters.
+
+Rx is also well suited for introducing and managing concurrency for the purpose of _offloading_.
+That is, performing a given set of work concurrently, so that the thread that detected an event doesn't also have to be the thread that handles that event.
+A very popular use of this is maintaining a responsive UI. (UI event handling has become _such_ a popular use of Rx—both in .NET. but also in [RxJS](https://rxjs.dev/), which originated as an offshoot of Rx.NET—that it would be easy to think that this is what it's for. But its success there should not blind us to its wider applicability.)
+
+You should consider using Rx if you have an existing `IEnumerable` that is attempting to model live events.
+While `IEnumerable` _can_ model data in motion (by using lazy evaluation like `yield return`), there's a problem. If the code consuming the collection has reached the point where it wants the next item (e.g., because a `foreach` loop has just completed an iteration) but no item is yet available, the `IEnumerable` implementation would have no choice but to block the calling thread in its `MoveNext` until such time as data is available, which can cause scalability problems in some applications. Even in cases where thread blocking is acceptable (or if you use the newer `IAsyncEnumerable`, which can take advantage of C#'s `await foreach` feature to avoid blocking a thread in these cases) `IEnumerable` and `IAsyncEnumerable` are misleading types for representing live information sources. These interfaces represent a 'pull' programming model: code asks for the next item in the sequence. Rx is a more natural choice for modelling information sources that naturally produce information on their own schedule.
+
+### Possible Fit with Rx
+
+Rx can be used to represent asynchronous operations. .NET's `Task` or `Task` effectively represent a single event, and `IObservable` can be thought if as a generalization of this to a sequence of events. (The relationship between, say, `Task` and `IObservable` is similar to the relationship between `int` and `IEnumerable`.)
+
+This means that there are some scenarios that can be dealt with either using tasks and the `async` keyword or through Rx. If at any point in your processing you need to deal with multiple values as well as single ones, Rx can do both; tasks don't handle multiple items so well. You can have a `Task>`, which enables you to `await` for a collection, and that's fine if all the items in the collection can be collected in a single step. The limitation with this is that once the task has produced its `IEnumerable` result, your `await` has completed, and you're back to non-asynchronous iteration over that `IEnumerable`. If the data can't be fetched in a single step—perhaps the `IEnumerable` represents data from an API in which results are fetched in batches of 100 items at a time—its `MoveNext` will have to block your thread every time it needs to wait.
+
+For the first 5 years of its existence, Rx was arguably the best way to represent collections that wouldn't necessarily have all the items available immediately. However, the introduction of [`IAsyncEnumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerable-1) in .NET Core 3.0 and C# 8 provided a way to handle sequences while remaining in the world of `async`/`await` (and the [`Microsoft.Bcl.AsyncInterfaces` NuGet package](https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/) makes this available on .NET Framework and .NET Standard 2.0). So the choice to use Rx to now tends to boil down to whether a 'pull' model (exemplified by `foreach` or `await foreach`) or a 'push' model (in which code supplies callbacks to be invoked by the event source when items become available) is a better fit for the concepts being modelled.
+
+Another related feature that was added .NET since Rx first appears is [channels](https://learn.microsoft.com/en-us/dotnet/core/extensions/channels). These allow a source to produce object and a consumer to process them, so there's an obvious superficial similarity to Rx. However, a distinguishing feature of Rx is its support for composition with an extensive set of operators, something with no direct equivalent in channels. Channels on the other hand provide more options for adapting to variations in production and consumption rates.
+
+Earlier, I mentioned _offloading_: using Rx to push work onto other threads. Although this technique can enable Rx to introduce and manage concurrency for the purposes of _scaling_ or performing _parallel_ computations, other dedicated frameworks like [TPL (Task Parallel Library) Dataflow](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library) or [PLINQ](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/introduction-to-plinq) are more appropriate for performing parallel compute intensive work. However, TPL Dataflow offers some integration with Rx through its [`AsObserver`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.dataflow.dataflowblock.asobserver) and [`AsObservable`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.dataflow.dataflowblock.asobservable) extension methods. So it is common to use Rx to integrate TPL Dataflow with the rest of your application.
+
+### Poor Fit with Rx
+
+Rx's `IObservable` is not a replacement for `IEnumerable` or `IAsyncEnumerable`. It would be a mistake to take something that is naturally pull based and force it to be push based.
+
+Also, there are some situations in which the simplicity of Rx's programming model can work against you. For example, some message queuing technologies such as MSMQ are by definition sequential, and thus might look like a good fit for Rx. However, they are often chosen for their transaction handling support. Rx does not have any direct way to surface transaction semantics, so in scenarios that require this you might be better off just working directly with the relevant technology's API. (That said, [Reaqtor](https://reaqtive.net/) adds durability and persistence to Rx, so you might be able to use that to integrate these kinds of queueing systems with Rx.)
+
+By choosing the best tool for the job your code should be easier to maintain, it will likely provide better performance and you will probably get better support.
+
+## Rx in action
+
+You can get up and running with a simple Rx example very quickly. If you have the .NET SDK installed, you can run the following at a command line:
+
+```ps1
+mkdir TryRx
+cd TryRx
+dotnet new console
+dotnet add package System.Reactive
+```
+
+Alternatively, if you have Visual Studio installed, create a new .NET Console project, and then use the NuGet package manager to add a reference to `System.Reactive`.
+
+This code creates an observable source (`ticks`) that produces an event once every second. The code also passes a handler to that source that writes a message to the console for each event:
+
+```csharp
+using System.Reactive.Linq;
+
+IObservable ticks = Observable.Timer(
+ dueTime: TimeSpan.Zero,
+ period: TimeSpan.FromSeconds(1));
+
+ticks.Subscribe(
+ tick => Console.WriteLine($"Tick {tick}"));
+
+Console.ReadLine();
+```
+
+If this doesn't seem very exciting, it's because it's about as basic an example as it's possible to create, and at its heart, Rx has a very simple programming model. The power comes from composition—we can use the building blocks in the `System.Reactive` library to describe the processing that will takes us from raw, low-level events to high-value insights. But to do that, we must first understand [Rx's key types, `IObservable` and `IObserver`](02_KeyTypes.md).
\ No newline at end of file
diff --git a/Rx.NET/Documentation/IntroToRx/02_KeyTypes.md b/Rx.NET/Documentation/IntroToRx/02_KeyTypes.md
index 5699ff7680..7fdaa26c27 100644
--- a/Rx.NET/Documentation/IntroToRx/02_KeyTypes.md
+++ b/Rx.NET/Documentation/IntroToRx/02_KeyTypes.md
@@ -1,488 +1,584 @@
----
-title : Key Types
----
-
-
-#Key types {#KeyTypes}
-
-To use a framework you need to have a familiarty with the key features and their benefits.
-Without this you find yourself just pasting samples from forums and hacking code until it works, kind of.
-Then the next poor developer to maintain the code base ha to try to figure out what the intention of your code base was.
-Fate is only too kind when that maintenence developer is the same as the original developer.
-Rx is powerful, but also allows for a simplification of your code.
-To write good Reactive code you have to know the basics.
-
-There are two key types to understand when working with Rx, and a subset of auxiliary types that will help you to learn Rx more effectively.
-The `IObserver` and `IObservable` form the fundamental building blocks for Rx, while implementations of `ISubject` reduce the learning curve for developers new to Rx.
-
-Many are familiar with LINQ and its many popular forms like LINQ to Objects, LINQ to SQL & LINQ to XML.
-Each of these common implementations allows you query _data at rest_; Rx offers the ability to query _data in motion_.
-Essentially Rx is built upon the foundations of the [Observer](http://en.wikipedia.org/wiki/Observer_pattern) pattern.
-.NET already exposes some other ways to implement the Observer pattern such as multicast delegates or events (which are usually multicast delegates).
-Multicast delegates are not ideal however as they exhibit the following less desirable features;
-
-
- * In C#, events have a curious interface. Some find the `+=` and ` -=` operators an unnatural way to register a callback
- * Events are difficult to compose
- * Events don't offer the ability to be easily queried over time
- * Events are a common cause of accidental memory leaks
- * Events do not have a standard pattern for signaling completion
- * Events provide almost no help for concurrency or multithreaded applications. e.g. To raise an event on a separate thread requires you to do all of the plumbing
-
-Rx looks to solve these problems.
-Here I will introduce you to the building blocks and some basic types that make up Rx.
-
-##IObservable<T> {#IObservable}
-
-[`IObservable`](http://msdn.microsoft.com/en-us/library/dd990377.aspx "IObservable(Of T) interface - MSDN") is one of the two new core interfaces for working with Rx.
-It is a simple interface with just a [Subscribe](http://msdn.microsoft.com/en-us/library/dd782981(v=VS.100).aspx) method.
-Microsoft is so confident that this interface will be of use to you it has been included in the BCL as of version 4.0 of .NET.
-You should be able to think of anything that implements `IObservable` as a streaming sequence of `T` objects.
-So if a method returned an `IObservable` I could think of it as a stream of Prices.
-
- //Defines a provider for push-based notification.
- public interface IObservable
- {
- //Notifies the provider that an observer is to receive notifications.
- IDisposable Subscribe(IObserver observer);
- }
-
-
-
- .NET already has the concept of Streams with the type and sub types of `System.IO.Stream`.
- The `System.IO.Stream` implementations are commonly used to stream data (generally bytes) to or from an I/O device like a file, network or block of memory.
- `System.IO.Stream` implementations can have both the ability to read and write, and sometimes the ability to seek (i.e. fast forward through a stream or move backwards).
- When I refer to an instance of `IObservable` as a stream, it does not exhibit the seek or write functionality that streams do.
- This is a fundamental difference preventing Rx being built on top of the `System.IO.Stream` paradigm.
- Rx does however have the concept of forward streaming (push), disposing (closing) and completing (eof).
- Rx also extends the metaphor by introducing concurrency constructs, and query operations like transformation, merging, aggregating and expanding.
- These features are also not an appropriate fit for the existing `System.IO.Stream` types.
- Some others refer to instances of `IObservable` as Observable Collections, which I find hard to understand.
- While the observable part makes sense to me, I do not find them like collections at all.
- You generally cannot sort, insert or remove items from an `IObservable` instance like I would expect you can with a collection.
- Collections generally have some sort of backing store like an internal array.
- The values from an `IObservable` source are not usually pre-materialized as you would expect from a normal collection.
- There is also a type in WPF/Silverlight called an `ObservableCollection` that does exhibit collection-like behavior, and is very well suited to this description.
- In fact `IObservable` integrates very well with `ObservableCollection` instances.
- So to save on any confusion we will refer to instances of `IObservable` as *sequences*.
- While instances of `IEnumerable` are also sequences, we will adopt the convention that they are sequences of _data at rest_, and `IObservable` instances are sequences of _data in motion_.
-
-
-##IObserver<T> {#IObserver}
-
-[`IObserver`](http://msdn.microsoft.com/en-us/library/dd783449.aspx "IObserver(Of T) interface - MSDN") is the other one of the two core interfaces for working with Rx.
-It too has made it into the BCL as of .NET 4.0.
-Don't worry if you are not on .NET 4.0 yet as the Rx team have included these two interfaces in a separate assembly for .NET 3.5 and Silverlight users.
-`IObservable` is meant to be the "functional dual of `IEnumerable`".
-If you want to know what that last statement means, then enjoy the hours of videos on [Channel9](http://channel9.msdn.com/tags/Rx/) where they discuss the mathematical purity of the types.
-For everyone else it means that where an `IEnumerable` can effectively yield three things (the next value, an exception or the end of the sequence), so too can `IObservable` via `IObserver`'s three methods `OnNext(T)`, `OnError(Exception)` and `OnCompleted()`.
-
- //Provides a mechanism for receiving push-based notifications.
- public interface IObserver
- {
- //Provides the observer with new data.
- void OnNext(T value);
- //Notifies the observer that the provider has experienced an error condition.
- void OnError(Exception error);
- //Notifies the observer that the provider has finished sending push-based notifications.
- void OnCompleted();
- }
-
-Rx has an implicit contract that must be followed. An implementation of `IObserver` may have zero or more calls to `OnNext(T)` followed optionally by a call to either `OnError(Exception)` or `OnCompleted()`.
-This protocol ensures that if a sequence terminates, it is always terminated by an `OnError(Exception)`, *or* an `OnCompleted()`.
-This protocol does not however demand that an `OnNext(T)`, `OnError(Exception)` or `OnCompleted()` ever be called.
-This enables to concept of empty and infinite sequences.
-We will look into this more later.
-
-Interestingly, while you will be exposed to the `IObservable` interface frequently if you work with Rx, in general you will not need to be concerned with `IObserver`.
-This is due to Rx providing anonymous implementations via methods like `Subscribe`.
-
-###Implementing IObserver<T> and IObservable<T> {#ImplementingIObserverAndIObservable}
-
-It is quite easy to implement each interface.
-If we wanted to create an observer that printed values to the console it would be as easy as this.
-
- public class MyConsoleObserver : IObserver
- {
- public void OnNext(T value)
- {
- Console.WriteLine("Received value {0}", value);
- }
-
- public void OnError(Exception error)
- {
- Console.WriteLine("Sequence faulted with {0}", error);
- }
-
- public void OnCompleted()
- {
- Console.WriteLine("Sequence terminated");
- }
- }
-
-Implementing an observable sequence is a little bit harder.
-An overly simplified implementation that returned a sequence of numbers could look like this.
-
- public class MySequenceOfNumbers : IObservable
- {
- public IDisposable Subscribe(IObserver observer)
- {
- observer.OnNext(1);
- observer.OnNext(2);
- observer.OnNext(3);
- observer.OnCompleted();
- return Disposable.Empty;
- }
- }
-
-We can tie these two implementations together to get the following output
-
- var numbers = new MySequenceOfNumbers();
- var observer = new MyConsoleObserver();
- numbers.Subscribe(observer);
-
-Output:
-
-
-
Received value 1
-
Received value 2
-
Received value 3
-
Sequence terminated
-
-
-
-The problem we have here is that this is not really reactive at all.
-This implementation is blocking, so we may as well use an `IEnumerable` implementation like a `List` or an array.
-
-This problem of implementing the interfaces should not concern us too much.
-You will find that when you use Rx, you do not have the need to actually implement these interfaces, Rx provides all of the implementations you need out of the box.
-Let's have a look at the simple ones.
-
-
-##Subject<T> {#Subject}
-
-I like to think of the `IObserver` and the `IObservable` as the 'reader' and 'writer' or, 'consumer' and 'publisher' interfaces.
-If you were to create your own implementation of `IObservable` you may find that while you want to publicly expose the IObservable characteristics you still need to be able to publish items to the subscribers, throw errors and notify when the sequence is complete.
-Why that sounds just like the methods defined in `IObserver`!
-While it may seem odd to have one type implementing both interfaces, it does make life easy.
-This is what [subjects](http://msdn.microsoft.com/en-us/library/hh242969(v=VS.103).aspx "Using Rx Subjects - MSDN") can do for you.
-[`Subject`](http://msdn.microsoft.com/en-us/library/hh229173(v=VS.103).aspx "Subject(Of T) - MSDN") is the most basic of the subjects.
-Effectively you can expose your `Subject` behind a method that returns `IObservable` but internally you can use the `OnNext`, `OnError` and `OnCompleted` methods to control the sequence.
-
-In this very basic example, I create a subject, subscribe to that subject and then publish values to the sequence (by calling `subject.OnNext(T)`).
-
-
- static void Main(string[] args)
- {
- var subject = new Subject();
- WriteSequenceToConsole(subject);
-
- subject.OnNext("a");
- subject.OnNext("b");
- subject.OnNext("c");
- Console.ReadKey();
- }
-
- //Takes an IObservable as its parameter.
- //Subject implements this interface.
- static void WriteSequenceToConsole(IObservable sequence)
- {
- //The next two lines are equivalent.
- //sequence.Subscribe(value=>Console.WriteLine(value));
- sequence.Subscribe(Console.WriteLine);
- }
-
-
-Note that the `WriteSequenceToConsole` method takes an `IObservable` as it only wants access to the subscribe method.
-Hang on, doesn't the `Subscribe` method need an `IObserver` as an argument?
-Surely `Console.WriteLine` does not match that interface.
-Well it doesn't, but the Rx team supply me with an Extension Method to `IObservable` that just takes an [`Action`](http://msdn.microsoft.com/en-us/library/018hxwa8.aspx "Action(Of T) Delegate - MSDN").
-The action will be executed every time an item is published.
-There are [other overloads to the Subscribe extension method](http://msdn.microsoft.com/en-us/library/system.observableextensions(v=VS.103).aspx "ObservableExtensions class - MSDN") that allows you to pass combinations of delegates to be invoked for `OnNext`, `OnCompleted` and `OnError`.
-This effectively means I don't need to implement `IObserver`.
-Cool.
-
-As you can see, `Subject` could be quite useful for getting started in Rx programming.
-`Subject` however, is a basic implementation.
-There are three siblings to `Subject` that offer subtly different implementations which can drastically change the way your program runs.
-
-
-
-##ReplaySubject<T> {#ReplaySubject}
-
-[`ReplaySubject`](http://msdn.microsoft.com/en-us/library/hh211810(v=VS.103).aspx "ReplaySubject(Of T) - MSDN") provides the feature of caching values and then replaying them for any late subscriptions.
-Consider this example where we have moved our first publication to occur before our subscription
-
- static void Main(string[] args)
- {
- var subject = new Subject();
-
- subject.OnNext("a");
- WriteSequenceToConsole(subject);
-
- subject.OnNext("b");
- subject.OnNext("c");
- Console.ReadKey();
- }
-
-The result of this would be that 'b' and 'c' would be written to the console, but 'a' ignored.
-If we were to make the minor change to make subject a `ReplaySubject` we would see all publications again.
-
- var subject = new ReplaySubject();
-
- subject.OnNext("a");
- WriteSequenceToConsole(subject);
-
- subject.OnNext("b");
- subject.OnNext("c");
-
-This can be very handy for eliminating race conditions.
-Be warned though, the default constructor of the `ReplaySubject` will create an instance that caches every value published to it.
-In many scenarios this could create unnecessary memory pressure on the application.
-`ReplaySubject` allows you to specify simple cache expiry settings that can alleviate this memory issue.
-One option is that you can specify the size of the buffer in the cache.
-In this example we create the `ReplaySubject` with a buffer size of 2, and so only get the last two values published prior to our subscription:
-
- public void ReplaySubjectBufferExample()
- {
- var bufferSize = 2;
- var subject = new ReplaySubject(bufferSize);
-
- subject.OnNext("a");
- subject.OnNext("b");
- subject.OnNext("c");
- subject.Subscribe(Console.WriteLine);
- subject.OnNext("d");
- }
-
-Here the output would show that the value 'a' had been dropped from the cache, but values 'b' and 'c' were still valid.
-The value 'd' was published after we subscribed so it is also written to the console.
-
-
-
Output:
-
b
-
c
-
d
-
-
-Another option for preventing the endless caching of values by the `ReplaySubject`, is to provide a window for the cache.
-In this example, instead of creating a `ReplaySubject` with a buffer size, we specify a window of time that the cached values are valid for.
-
- public void ReplaySubjectWindowExample()
- {
- var window = TimeSpan.FromMilliseconds(150);
- var subject = new ReplaySubject(window);
-
- subject.OnNext("w");
- Thread.Sleep(TimeSpan.FromMilliseconds(100));
- subject.OnNext("x");
- Thread.Sleep(TimeSpan.FromMilliseconds(100));
- subject.OnNext("y");
- subject.Subscribe(Console.WriteLine);
- subject.OnNext("z");
- }
-
-In the above example the window was specified as 150 milliseconds.
-Values are published 100 milliseconds apart.
-Once we have subscribed to the subject, the first value is 200ms old and as such has expired and been removed from the cache.
-
-
-
Output:
-
x
-
y
-
z
-
-
-##BehaviorSubject<T> {#BehaviorSubject}
-
-[`BehaviorSubject`](http://msdn.microsoft.com/en-us/library/hh211949(v=VS.103).aspx "BehaviorSubject(Of T) - MSDN") is similar to `ReplaySubject` except it only remembers the last publication.
-`BehaviorSubject` also requires you to provide it a default value of `T`.
-This means that all subscribers will receive a value immediately (unless it is already completed).
-
-In this example the value 'a' is written to the console:
-
- public void BehaviorSubjectExample()
- {
- //Need to provide a default value.
- var subject = new BehaviorSubject("a");
- subject.Subscribe(Console.WriteLine);
- }
-
-In this example the value 'b' is written to the console, but not 'a'.
-
- public void BehaviorSubjectExample2()
- {
- var subject = new BehaviorSubject("a");
- subject.OnNext("b");
- subject.Subscribe(Console.WriteLine);
- }
-
-In this example the values 'b', 'c' & 'd' are all written to the console, but again not 'a'
-
- public void BehaviorSubjectExample3()
- {
- var subject = new BehaviorSubject("a");
-
- subject.OnNext("b");
- subject.Subscribe(Console.WriteLine);
- subject.OnNext("c");
- subject.OnNext("d");
- }
-
-Finally in this example, no values will be published as the sequence has completed.
-Nothing is written to the console.
-
- public void BehaviorSubjectCompletedExample()
- {
- var subject = new BehaviorSubject("a");
- subject.OnNext("b");
- subject.OnNext("c");
- subject.OnCompleted();
- subject.Subscribe(Console.WriteLine);
- }
-
-That note that there is a difference between a `ReplaySubject` with a buffer size of one (commonly called a 'replay one subject') and a `BehaviorSubject`.
-A `BehaviorSubject` requires an initial value.
-With the assumption that neither subjects have completed, then you can be sure that the `BehaviorSubject` will have a value.
-You cannot be certain with the `ReplaySubject` however.
-With this in mind, it is unusual to ever complete a `BehaviorSubject`.
-Another difference is that a replay-one-subject will still cache its value once it has been completed.
-So subscribing to a completed `BehaviorSubject` we can be sure to not receive any values, but with a `ReplaySubject` it is possible.
-
-`BehaviorSubject`s are often associated with class [properties](http://msdn.microsoft.com/en-us/library/65zdfbdt(v=vs.71).aspx).
-As they always have a value and can provide change notifications, they could be candidates for backing fields to properties.
-
-##AsyncSubject<T> {#AsyncSubject}
-
-[`AsyncSubject`](http://msdn.microsoft.com/en-us/library/hh229363(v=VS.103).aspx "AsyncSubject(Of T) - MSDN") is similar to the Replay and Behavior subjects in the way that it caches values, however it will only store the last value, and only publish it when the sequence is completed.
-The general usage of the `AsyncSubject` is to only ever publish one value then immediately complete.
-This means that is becomes quite comparable to `Task`.
-
-In this example no values will be published as the sequence never completes.
-No values will be written to the console.
-
- static void Main(string[] args)
- {
- var subject = new AsyncSubject();
- subject.OnNext("a");
- WriteSequenceToConsole(subject);
- subject.OnNext("b");
- subject.OnNext("c");
- Console.ReadKey();
- }
-
-In this example we invoke the `OnCompleted` method so the last value 'c' is written to the console:
-
- static void Main(string[] args)
- {
- var subject = new AsyncSubject();
-
- subject.OnNext("a");
- WriteSequenceToConsole(subject);
- subject.OnNext("b");
- subject.OnNext("c");
- subject.OnCompleted();
- Console.ReadKey();
- }
-
-##Implicit contracts {#ImplicitContracts}
-
-There are implicit contacts that need to be upheld when working with Rx as mentioned above.
-The key one is that once a sequence is completed, no more activity can happen on that sequence.
-A sequence can be completed in one of two ways, either by `OnCompleted()` or by `OnError(Exception)`.
-
-The four subjects described in this chapter all cater for this implicit contract by ignoring any attempts to publish values, errors or completions once the sequence has already terminated.
-
-Here we see an attempt to publish the value 'c' on a completed sequence.
-Only values 'a' and 'b' are written to the console.
-
- public void SubjectInvalidUsageExample()
- {
- var subject = new Subject();
-
- subject.Subscribe(Console.WriteLine);
-
- subject.OnNext("a");
- subject.OnNext("b");
- subject.OnCompleted();
- subject.OnNext("c");
- }
-
-##ISubject interfaces {#ISubject}
-
-While each of the four subjects described in this chapter implement the `IObservable` and `IObserver` interfaces, they do so via another set of interfaces:
-
-
- //Represents an object that is both an observable sequence as well as an observer.
- public interface ISubject
- : IObserver, IObservable
- {
- }
-
-As all the subjects mentioned here have the same type for both `TSource` and `TResult`, they implement this interface which is the superset of all the previous interfaces:
-
- //Represents an object that is both an observable sequence as well as an observer.
- public interface ISubject : ISubject, IObserver, IObservable
- {
- }
-
-These interfaces are not widely used, but prove useful as the subjects do not share a common base class.
-We will see the subject interfaces used later when we discover [Hot and cold observables](14_HotAndColdObservables.html).
-
-##Subject factory {#SubjectFactory}
-
-Finally it is worth making you aware that you can also create a subject via a factory method.
-Considering that a subject combines the `IObservable` and `IObserver` interfaces, it seems sensible that there should be a factory that allows you to combine them yourself.
-The `Subject.Create(IObserver, IObservable)` factory method provides just this.
-
- //Creates a subject from the specified observer used to publish messages to the subject
- // and observable used to subscribe to messages sent from the subject
- public static ISubject>TSource, TResult< Create>TSource, TResult<(
- IObserver>TSource< observer,
- IObservable>TResult< observable)
- {...}
-
-Subjects provide a convenient way to poke around Rx, however they are not recommended for day to day use.
-An explanation is in the [Usage Guidelines](18_UsageGuidelines.html) in the appendix.
-Instead of using subjects, favor the factory methods we will look at in [Part 2](04_CreatingObservableSequences.html).
-
-The fundamental types `IObserver` and `IObservable` and the auxiliary subject types create a base from which to build your Rx knowledge.
-It is important to understand these simple types and their implicit contracts.
-In production code you may find that you rarely use the `IObserver` interface and subject types, but understanding them and how they fit into the Rx eco-system is still important.
-The `IObservable` interface is the dominant type that you will be exposed to for representing a sequence of data in motion, and therefore will comprise the core concern for most of your work with Rx and most of this book.
-
----
-
-
-
Additional recommended reading
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+# Key types
+
+Rx is a powerful framework that can greatly simplify code that responds to events. But to write good Reactive code you have to understand the basic concepts. The fundamental building block of Rx is an interface called `IObservable`. Understanding this, and its counterpart `IObserver`, is the key to success with Rx.
+
+The preceding chapter showed this LINQ query expression as the first example:
+
+```csharp
+var bigTrades =
+ from trade in trades
+ where trade.Volume > 1_000_000;
+```
+
+Most .NET developers will be familiar with [LINQ](https://learn.microsoft.com/en-us/dotnet/csharp/linq/) in at least one of its many popular forms such as [LINQ to Objects](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/linq-to-objects), or [Entity Framework Core queries](https://learn.microsoft.com/en-us/ef/core/querying/). Most LINQ implementations allow you to query _data at rest_. LINQ to Objects works on arrays or other collections, and LINQ queries in Entity Framework Core run against data in a database, but Rx is different: it offers the ability to define queries over live event streams—what you might call _data in motion_.
+
+If you don't like the query expression syntax, you can write exactly equivalent code by invoking LINQ operators directly:
+
+```csharp
+var bigTrades = trades.Where(trade => trade.Volume > 1_000_000);
+```
+
+Whichever style we use, this is the LINQ way of saying that we want `bigTrades` to have just those items in `trades` where the `Volume` property is greater than one million.
+
+We can't tell exactly what these examples do because we can't see the type of the `trades` or `bigTrades` variables. The meaning of this code is going to vary greatly depending on these types. If we were using LINQ to objects, these would both likely be `IEnumerable`. That would mean that these variables both referred to objects representing collections whose contents we could enumerate with a `foreach` loop. This would represent _data at rest_, data that our code could inspect directly.
+
+But let's make it clear what the code means by being explicit about the type:
+
+```csharp
+IObservable bigTrades = trades.Where(trade => trade.Volume > 1_000_000);
+```
+
+This removes the ambiguity. It is now clear that we're not dealing with data at rest. We're working with an `IObservable`. But what exactly is that?
+
+## `IObservable`
+
+The [`IObservable` interface](https://learn.microsoft.com/en-us/dotnet/api/system.iobservable-1) represents Rx's fundamental abstraction: a sequence of values of some type `T`. In a very abstract sense, this means it represents the same thing as [`IEnumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1).
+
+The difference is in how code consumes those values. Whereas `IEnumerable` enables code to retrieve values (typically with a `foreach` loop), an `IObservable` provides values when they become available. This distinction is sometimes characterised as _push_ vs _pull_. We can _pull_ values out of an `IEnumerable` by executing a `foreach` loop, but an `IObservable` will _push_ values into our code.
+
+How can an `IObservable` push its values into our code? If we want these values, our code must _subscribe_ to the `IObservable`, which means providing it with some methods it can invoke. In fact, subscription is the only operation an `IObservable` directly supports. Here's the entire definition of the interface:
+
+```csharp
+public interface IObservable
+{
+ IDisposable Subscribe(IObserver observer);
+}
+```
+
+You can see [the source for `IObservable` on GitHub](https://github.com/dotnet/runtime/blob/b4008aefaf8e3b262fbb764070ea1dd1abe7d97c/src/libraries/System.Private.CoreLib/src/System/IObservable.cs). Notice that it is part of the .NET runtime libraries, and not the `System.Reactive` NuGet package. `IObservable` represents such a fundamentally important abstraction that it is baked into .NET. (So you might be wondering what the `System.Reactive` NuGet package is for. The .NET runtime libraries define only the `IObservable` and `IObserver` interfaces, and not the LINQ implementation. The `System.Reactive` NuGet package gives us LINQ support, and also deals with threading.)
+
+This interface's only method makes it clear what we can do with an `IObservable`: if we want to receive the events it has to offer, we can _subscribe_ to it. (We can also unsubscribe: the `Subscribe` method returns an `IDisposable`, and if we call `Dispose` on that it cancels our subscription.) The `Subscribe` method requires us to pass in an implementation of `IObserver`, which we will get to shortly.
+
+Observant readers will have noticed that an example in the preceding chapter looks like it shouldn't work. That code created an `IObservable` that produced events once per second, and then it subscribed to it with this code:
+
+```csharp
+ticks.Subscribe(
+ tick => Console.WriteLine($"Tick {tick}"));
+```
+
+That's passing a delegate, and not the `IObserver` that `IObservable.Subscribe` requires. We'll get to `IObserver` shortly, but all that's happening here is that this example is using an extension method from the `System.Reactive` NuGet package:
+
+```csharp
+// From the System.Reactive library's ObservableExtensions class
+public static IDisposable Subscribe(this IObservable source, Action onNext)
+```
+
+This is a helper method that wraps a delegate in an implementation of `IObserver` and then passes that to `IObservable.Subscribe`. The effect is that we can write just a simple method (instead of a complete implementation of `IObserver`) and the observable source will invoke our callback each time it wants to supply a value. It's more common to use this kind of helper than to implement Rx's interfaces ourselves.
+
+### Hot and Cold Sources
+
+Since an `IObservable` cannot supply us with values until we subscribe, the time at which we subscribe can be important. Imagine an `IObservable` describing trades occurring in some market. If the information it supplies is live, it's not going to tell you about any trades that occurred before you subscribed. In Rx, sources of this kind are described as being _hot_.
+
+Not all sources are _hot_. There's nothing stopping an `IObservable` always supplying the exact same sequence of events to any subscriber no matter when the call to `Subscribe` occurs. (Imagine an `IObservable` which, instead of reporting live information, generates notifications based on recorded historical trade data.) Sources where it doesn't matter at all when you subscribe are known as _cold_ sources.
+
+Here are some sources that might be represented as hot observables:
+
+* Measurements from a sensor
+* Price ticks from a trading exchange
+* An event source that distributes events immediately such as Azure Event Grid
+* mouse movements
+* timer events
+* broadcasts like ESB channels or UDP network packets
+
+And some examples of some sources that might make good cold observables:
+
+* the contents of a collection (such as is returned by the [`ToObservable` extension method for `IEnumerable`](03_CreatingObservableSequences.md#from-ienumerablet))
+* a fixed range of values, such as [`Observable.Range`](03_CreatingObservableSequences.md#observablerange) produces
+* events generated based on an algorithm, such as [`Observable.Generate`](03_CreatingObservableSequences.md#observablegenerate) produces
+* a factory for an asynchronous operation, such as [`FromAsync`](03_CreatingObservableSequences.md#from-task) returns
+* events produced by running conventional code such as a loop; you can create such sources with [`Observable.Create`](03_CreatingObservableSequences.md#observablecreate)
+* a streaming event provides such as Azure Event Hub or Kafka (or any other streaming-style source which holds onto events from the past to be able to deliver events from a particular moment in the stream; so _not_ an event source in the Azure Event Grid style)
+
+Not all sources are strictly completely _hot_ or _cold_. For example, you could imagine a slight variation on a live `IObservable` where the source always reports the most recent trade to new subscribers. Subscribers can count on immediately receiving something, and will then be kept up to date as new information arrives. The fact that new subscribers will always receive (potentially quite old) information is a _cold_-like characteristic, but it's only that first event that is _cold_. It's still likely that a brand new subscriber will have missed lots of information that would have been available to earlier subscribers, making this source more _hot_ than _cold_.
+
+There's an interesting special case in which a source of events has been designed to enable applications to receive every single event in order, exactly once. Event streaming systems such as Kafka or Azure Event Hub have this characteristic—they retain events for a while, to ensure that consumers don't miss out even if they fall behind from time to time. The standard input (_stdin_) for a process also has this characteristic: if you run a command line tool and start typing input before it is ready to process it, the operating system will hold that input in a buffer, to ensure that nothing is lost. Windows does something similar for desktop applications: each application thread gets a message queue so that if you click or type when it's not able to respond, the input will eventually be processed. We might think of these sources as _cold_-then-_hot_. They're like _cold_ sources in that we won't miss anything just because it took us some time to start receiving events, but once we start retrieving the data, then we can't generally rewind back to the start. So once we're up and running they are more like _hot_ events.
+
+This kind of _cold_-then-_hot_ source can present a problem if we want to attach multiple subscribers. If the source starts providing events as soon as subscription occurs, then that's fine for the very first subscriber: it will receive any events that were backed up waiting for us to start. But if we wanted to attach multiple subscribers, we've got a problem: that first subscriber might receive all the notifications that were sitting waiting in some buffer before we manage to attach the second subscriber. The second subscriber will miss out.
+
+In these cases, we really want some way to rig up all our subscribers before kicking things off. We want subscription to be separate from the act of starting. By default, subscribing to a source implies that we want it to start, but Rx defines a specialised interface that can give us more control: [`IConnectableObservable`](https://github.com/dotnet/reactive/blob/f4f727cf413c5ea7a704cdd4cd9b4a3371105fa8/Rx.NET/Source/src/System.Reactive/Subjects/IConnectableObservable.cs). This derives from `IObservable`, and adds just a single method, `Connect`:
+
+```csharp
+public interface IConnectableObservable : IObservable
+{
+ IDisposable Connect();
+}
+```
+
+This is useful in these scenarios where there will be some process that fetches or generates events and we need to make sure we're prepared before that starts. Because an `IConnectableObservable` won't start until you call `Connect`, it provides you with a way to attach however many subscribers you need before events begin to flow.
+
+The 'temperature' of a source is not necessarily evident from its type. Even when the underlying source is an `IConnectableObservable`, that can often be hidden behind layers of code. So whether a source is hot, cold, or something in between, most of the time we just see an `IObservable`. Since `IObservable` defines just one method, `Subscribe`, you might be wondering how we can do anything interesting with it. The power comes from the LINQ operators that the `System.Reactive` NuGet library supplies.
+
+### LINQ Operators and Composition
+
+So far I've shown only a very simple LINQ example, using the `Where` operator to filter events down to ones that meet certain criteria. To give you a flavour of how we can build more advanced functionality through composition, I'm going to introduce an example scenario.
+
+Suppose you want to write a program that watches some folder on a filesystem, and performs automatic processing any time something in that folder changes. For example, web developers often want to trigger automatic rebuilds of their client side code when they save changes in the editor so they can quickly see the effect of their changes. Filesystem changes often come in bursts. Text editors might perform a few distinct operations when saving a file. (Some save modifications to a new file, then perform a couple of renames once this is complete, because this avoids data loss if a power failure or system crash happens to occur at the moment you save the file.) So you typically won't want to take action as soon as you detect file activity. It would be better to give it a moment to see if any more activity occurs, and take action only after everything has settled down.
+
+So we should not react directly to filesystem activity. We want take action at those moments when everything goes quiet after a flurry of activity. Rx does not offer this functionality directly, but it's possible for us to create a custom operator by combing some of the built-in operators. The following code defines an Rx operator that detects and reports such things. If you're new to Rx (which seems likely if you're reading this) it probably won't be instantly obvious how this works. This is a significant step up in complexity from the examples I've shown so far because this came from a real application. But I'll walk through it step by step, so all will become clear.
+
+```csharp
+static class RxExt
+{
+ public static IObservable> Quiescent(
+ this IObservable src,
+ TimeSpan minimumInactivityPeriod,
+ IScheduler scheduler)
+ {
+ IObservable onoffs =
+ from _ in src
+ from delta in
+ Observable.Return(1, scheduler)
+ .Concat(Observable.Return(-1, scheduler)
+ .Delay(minimumInactivityPeriod, scheduler))
+ select delta;
+ IObservable outstanding = onoffs.Scan(0, (total, delta) => total + delta);
+ IObservable zeroCrossings = outstanding.Where(total => total == 0);
+ return src.Buffer(zeroCrossings);
+ }
+}
+```
+
+The first thing to say about this is that we are effectively defining a custom LINQ-style operator: this is an extension method which, like all of the LINQ operators Rx supplies, takes an `IObservable` as its implicit argument, and produces another observable source as its result. The return type is slightly different: it's `IObservable>`. That's because once we return to a state of inactivity, we will want to process everything that just happened, so this operator will produce a list containing every value that the source reported in its most recent flurry of activity.
+
+When we want to show how an Rx operator behaves, we typically draw a 'marble' diagram. This is a diagram showing one or more `IObservable` event sources, with each one being illustrated by a horizontal line. Each event that a source produces is illustrated by a circle (or 'marble') on that line, with the horizontal position representing timing. Typically, the line has a vertical bar on its left indicating the instant at which the application subscribed to the source, unless it happens to produce events immediately, in which case it will start with a marble. If the line has an arrowhead on the right, that indicates that the observable's lifetime extends beyond the diagram. Here's a diagram showing how the `Quiescent` operator above response to a particular input:
+
+
+
+This shows that the source (the top line) produced a couple of events (the values `1` and `2`, in this example), and then stopped for a bit. A little while after it stopped, the observable returned by the `Quiescent` operator (the lower line) produced a single event with a list containing both of those events (`[1,2]`). Then the source started up again, producing the values `3`, `4`, and `5` in fairly quick succession, and then going quiet for a bit. Again, once the quiet spell had gone on for long enough, the source returned by `Quiescent` produced a single event containing all of the source events from this second burst of activity (`[3,4,5]`). And then the final bit of source activity shown in this diagram consists of a single event, `6`, followed by more inactivity, and again, once the inactivity has gone on for long enough the `Quiescent` source produces a single event to report this. And since that last 'burst' of activity from the source contained only a single event, the list reported by this final output from the `Quiescent` observable is a list with a single value: `[6]`.
+
+So how does the code shown achieve this? The first thing to notice about the `Quiescent` method is that it's just using other Rx LINQ operators (the `Return`, `Scan`, `Where`, and `Buffer` operators are explicitly visible, and the query expression will be using the `SelectMany` operator, because that's what C# query expressions do when they contain two `from` clauses in a row) in a combination that produces the final `IObservable>` output.
+
+This is Rx's _compositional_ approach, and it is how we normally use Rx. We use a mixture of operators, combined (_composed_) in a way that produces the effect we want.
+
+But how does this particular combination produce the effect we want? There are a few ways we could get the behaviour that we're looking for from a `Quiescent` operator, but the basic idea of this particular implementation is that it keeps count of how many events have happened recently, and then produces a result every time that number drops back to zero. The `outstanding` variable refers to the `IObservable` that tracks the number of recent events, and this marble diagram shows what it produces in response to the same `source` events as were shown on the preceding diagram:
+
+
+
+I've colour coded the events this time so that I can show the relationship between `source` events and corresponding events produced by `outstanding`. Each time `source` produces an event, `outstanding` produces an event at the same time, in which the value is one higher than the preceding value produced by `outstanding`. But each such `source` event also causes `outstanding` to produce another event two seconds later. (It's two seconds because in these examples, I've presumed that the first argument to `Quiescent` is `TimeSpan.FromSeconds(2)`, as shown on the first marble diagram.) That second event always produces a value that is one lower than whatever the preceding value was.
+
+This means that each event to emerge from `outstanding` tells us how many events `source` produced within the last two seconds. This diagram shows that same information in a slightly different form: it shows the most recent value produced by `outstanding` as a graph. You can see the value goes up by one each time `source` produces a new value. And two seconds after each value produced by `source`, it drops back down by one.
+
+
+
+In simple cases like the final event `6`, in which it's the only event that happens at around that time, the `outstanding` value goes up by one when the event happens, and drops down again two seconds later. Over on the left of the picture it's a little more complex: we get two events in fairly quick succession, so the `outstanding` value goes up to one and then up to two, before falling back down to one and then down to zero again. The middle section looks a little more messy—the count goes up by one when the `source` produces event `3`, and then up to two when event `4` comes in. It then drops down to one again once two seconds have passed since the `3` event, but then another event, `5`, comes in taking the total back up to two. Shortly after that it drops back to one again because it has now been two seconds since the `4` event happened. And then a bit later, two seconds after the `5` event it drops back to zero again.
+
+That middle section is the messiest, but it's also most representative of the kind of activity this operator is designed to deal with. Remember, the whole point here is that we're expecting to see flurries of activity, and if those represents filesystem activity, they will tend to be slightly chaotic in nature, because storage devices don't always have entirely predictable performance characteristics (especially if it's a magnetic storage device with moving parts, or remote storage in which variable networking delays might come into play).
+
+With this measure of recent activity in hand, we can spot the end of bursts of activity by watching for when `outstanding` drops back to zero, which is what the observable referred to by `zeroCrossing` in the code above does. (That's just using the `Where` operator to filter out everything except the events where `outstanding`'s current value returns to zero.)
+
+But how does `outstanding` itself work? The basic approach here is that every time `source` produces a value, we actually create a brand new `IObservable`, which produces exactly two values. It immediately produces the value 1, and then after the specified timespan (2 seconds in these examples) it produces the value -1. That's what's going in in this clause of the query expression:
+
+```csharp
+from delta in Observable
+ .Return(1, scheduler)
+ .Concat(Observable
+ .Return(-1, scheduler)
+ .Delay(minimumInactivityPeriod, scheduler))
+```
+
+I said Rx is all about composition, and that's certainly the case here. We are using the very simple `Return` operator to create an `IObservable` that immediately produces just a single value and then terminates. This code calls that twice, once to produce the value `1` and again to produce the value `-1`. It uses the `Delay` operator so that instead of getting that `-1` value immediately, we get an observable that waits for the specified time period (2 seconds in these examples, but whatever `minimumInactivityPeriod` is in general) before producing the value. And then we use `Concat` to stitch those two together into a single `IObservable` that produces the value `1`, and then two seconds later produces the value `-1`.
+
+Although this produces a brand new `IObservable` for each `source` event, the `from` clause shown above is part of a query expression of the form `from ... from .. select`, which the C# compiler turns into a call to `SelectMany`, which has the effect of flattening those all back into a single observable, which is what the `onoffs` variable refers to. This marble diagram illustrates that:
+
+
+
+This also shows the `outstanding` observable again, but we can now see where that comes from: it is just the running total of the values emitted by the `onoffs` observable. This running total observable is created with this code:
+
+```csharp
+IObservable outstanding = onoffs.Scan(0, (total, delta) => total + delta);
+```
+
+Rx's `Scan` operator works much like the standard LINQ [`Aggregate`](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/aggregation-operations) operator, in that it cumulatively applies an operation (addition, in this case) to every single item in a sequence. The different is that whereas `Aggregate` produces just the final result once it reaches the end of the sequence, `Scan` shows all of its working, producing the accumulated value so far after each input. So this means that `outstanding` will produce an event every time `onoffs` produces one, and that event's value will be the running total—the sum total of every value from `onoffs` so far.
+
+So that's how `outstanding` comes to tell us how many events `source` produced within the last two seconds (or whatever `minimumActivityPeriod` has been specified).
+
+The final piece of the puzzle is how we go from the `zeroCrossings` (which produces an event every time the source has gone quiescent) to the output `IObservable>`, which provides all of the events that happened in the most recent burst of activity. Here we're just using Rx's `Buffer` operator, which is designed for exactly this scenario: it slices its input into chunks, producing an event for each chunk, the value of which is an `IList` containing the items for the chunk. `Buffer` can slice things up a few ways, but in this case we're using the form that starts a new slice each time some `IObservable` produces an item. Specifically, we're telling `Buffer` to slice up the `source` by creating a new chunk every time `zeroCrossings` produces a new event.
+
+(One last detail, just in case you saw it and were wondering, is that this method requires an `IScheduler`. This is an Rx abstraction for dealing with timing and concurrency. We need it because we need to be able to generate events after a one second delay, and that sort of time-driven activity requires a scheduler.)
+
+We'll get into all of these operators and the workings of schedulers in more detail in later chapters. For now, the key point is that we typically use Rx by creating a combination of LINQ operators that process and combine `IObservable` sources to define the logic that we require.
+
+Notice that nothing in that example actually called the one and only method that `IObservable` defines (`Subscribe`). There will always be something somewhere that ultimately consumes the events, but most of the work of using Rx tends to entail declaratively defining the `IObservable`s we need.
+
+Now that you've seen an example of what Rx programming looks like, we can address some obvious questions about why Rx exists at all.
+
+### What was wrong with .NET Events?
+
+.NET has had built-in support for events from the very first version that shipped over two decades ago—events are part of .NET's type system. The C# language has intrinsic support for this in the form of the `event` keyword, along with specialized syntax for subscribing to events. So why, when Rx turned up some 10 years later, did it feel the need to invent its own representation for streams of events? What was wrong with the `event` keyword?
+
+The basic problem with .NET events is that they get special handling from the .NET type system. Ironically, this makes them less flexible than if there had been no built-in support for the idea of events. Without .NET events, we would have needed some sort of object-based representation of events, at which point you can do all the same things with events that you can do with any other objects: you could store them in fields, pass them as arguments to methods, define methods on them and so on.
+
+To be fair to .NET version 1, it wasn't really possible to define a good object-based representation of events without generics, and .NET didn't get those until version 2 (three and a half years after .NET 1.0 shipped). Different event sources need to be able to report different data, and .NET events provided a way to parameterize events by type. But once generics came along, it became possible to define types such as `IObservable`, and the main advantage that events offered went away. (The other benefit was some language support for implementing and subscribing to events, but in principle that's something that could have been done for Rx if Microsoft had chosen to. It's not a feature that required events to be fundamentally different from other features of the type system.)
+
+Consider the example we've just worked through. It was possible to define our own custom LINQ operator, `Quiescent`, because `IObservable` is just an interface like any other, meaning that we're free to write extension methods for it. You can't write an extension method for an event.
+
+Also, we are able to wrap or adapt `IObservable` sources. `Quiescent` took an `IObservable` as an input, and combined various Rx operators to produce another observable as an output. Its input was a source of events that could be subscribed to, and its output was also a source of events that could be subscribed to. You can't do this with .NET events—you can't write a method that accepts an event as an argument, or that returns an event.
+
+These limitations are sometimes described by saying that .NET events are not _first class citizens_. There are things you can do with values or references in .NET that you can't do with events.
+
+If we represent an event source as a plain old interface, then it _is_ a first class citizen: it can use all of the functionality we expect with other objects and values precisely because it's not something special.
+
+### What about Streams?
+
+I've described `IObservable` as representing a _stream_ of events. This raises an obvious question: .NET already has [`System.IO.Stream`](https://learn.microsoft.com/en-us/dotnet/api/system.io.stream), so why not just use that?
+
+The short answer is that streams are weird because they represent an ancient concept in computing dating back long before the first ever Windows operating system shipped, and as such they have quite a lot of historical baggage. This means that even a scenario as simple as "I have some data, and want to make that available immediately to all interested parties" is surprisingly complex to implement though the `Stream` type.
+
+Moreover, `Stream` doesn't provide any way to indicate what type of data will emerge—it only knows about bytes. Since .NET's type system supports generics, it is natural to want the types that represent event streams to indicate the event type through a type parameter.
+
+So even if you did use `Stream` as part of your implementation, you'd want to introduce some sort of wrapper abstraction. If `IObservable` didn't exist, you'd need to invent it.
+
+It's certainly possible to use IO streams in Rx, but they are not the right primary abstraction.
+
+(If you are unconvinced, see [Appendix A: What's Wrong with Classic IO Streams](A_IoStreams.md) for a far more detailed explanation of exactly why `Stream` is not well suited to this task.)
+
+Now that we've seen why `IObservable` needs to exist, we need to look at its counterpart, `IObserver`.
+
+## `IObserver`
+
+Earlier, I showed the definition of `IObservable`. As you saw, it has just one method, `Subscribe`. And this method takes just one argument, of type [`IObserver`](https://learn.microsoft.com/en-us/dotnet/api/system.iobserver-1). So if you want to observe the events that an `IObservable` has to offer, you must supply it with an `IObserver`. In the examples so far, we've just supplied a simple callback, and Rx has wrapped that in an implementation of `IObserver` for us, but even though this is very often the way we will receive notifications in practice, you still need to understand `IObserver` to use Rx effectively. It is not a complex interface:
+
+```csharp
+public interface IObserver
+{
+ void OnNext(T value);
+ void OnError(Exception error);
+ void OnCompleted();
+}
+```
+
+As with `IObservable`, you can find [the source for `IObserver`](https://github.com/dotnet/runtime/blob/7cf329b773fa5ed544a9377587018713751c73e3/src/libraries/System.Private.CoreLib/src/System/IObserver.cs) in the .NET runtime GitHub repository, because both of these interfaces are built into the runtime libraries.
+
+If we wanted to create an observer that printed values to the console it would be as easy as this:
+
+```csharp
+public class MyConsoleObserver : IObserver
+{
+ public void OnNext(T value)
+ {
+ Console.WriteLine($"Received value {value}");
+ }
+
+ public void OnError(Exception error)
+ {
+ Console.WriteLine($"Sequence faulted with {error}");
+ }
+
+ public void OnCompleted()
+ {
+ Console.WriteLine("Sequence terminated");
+ }
+}
+```
+
+In the preceding chapter, I used a `Subscribe` extension method that accepted a delegate which it invoked each time the source produced an item. This method is defined by Rx's `ObservableExtensions` class, which also defines various other extension methods for `IObservable`. It includes overloads of `Subscribe` that enable me to write code that has the same effect as the preceding example, without needing to provide my own implementation of `IObserver`:
+
+```csharp
+source.Subscribe(
+ value => Console.WriteLine($"Received value {value}"),
+ error => Console.WriteLine($"Sequence faulted with {error}"),
+ () => Console.WriteLine("Sequence terminated")
+);
+```
+
+The overloads of `Subscribe` where we don't pass all three methods (e.g., my earlier example just supplied a single callback corresponding to `OnNext`) are equivalent to writing an `IObserver` implementation where one or more of the methods simply has an empty body. Whether we find it more convenient to write our own type that implements `IObserver`, or just supply callbacks for some or all of its `OnNext`, `OnError` and `OnCompleted` method, the basic behaviour is the same: an `IObservable` source reports each event with a call to `OnNext`, and tells us that the events have come to an end either by calling `OnError` or `OnCompleted`.
+
+If you're wondering whether the relationship between `IObservable` and `IObserver` is similar to the relationship between [`IEnumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1) and [`IEnumerator`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerator-1), then you're onto something. Both `IEnumerator` and `IObservable` represent _potential_ sequences. With both of these interfaces, they will only supply data if we ask them for it. To get values out of an `IEnumerable`, an `IEnumerator` needs to come into existence, and similarly, to get values out of an `IObservable` requires an `IObserver`.
+
+The difference reflects the fundamental _pull vs push_ difference between `IEnumerable` and `IObservable`. Whereas with `IEnumerable` we ask the source to create an `IEnumerator` for us which we can then use to retrieve items (which is what a C# `foreach` loop does), with `IObservable`, the source does not _implement_ `IObserver`: it expects _us_ to supply an `IObserver` and it will then push its values into that observer.
+
+So why does `IObserver` have these three methods? Remember when I said that in an abstract sense, `IObserver` represents the same thing as `IEnumerable