DynamicData 8.4.1

dotnet add package DynamicData --version 8.4.1
NuGet\Install-Package DynamicData -Version 8.4.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DynamicData" Version="8.4.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DynamicData --version 8.4.1
#r "nuget: DynamicData, 8.4.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DynamicData as a Cake Addin
#addin nuget:?package=DynamicData&version=8.4.1

// Install DynamicData as a Cake Tool
#tool nuget:?package=DynamicData&version=8.4.1

Build Coverage Reliability Rating Duplicated Lines (%) Vulnerabilities Security Rating <a href="https://reactiveui.net/slack"> <img src="https://img.shields.io/badge/chat-slack-blue.svg"> </a> NuGet Stats Downloads <br /> <br /> <a href="https://github.com/reactiveui/DynamicData"> <img width="170" height="170" src="https://github.com/reactiveui/styleguide/blob/master/logo_dynamic_data/logo.svg"/> </a>

Dynamic Data

Dynamic Data is a portable class library which brings the power of Reactive Extensions (Rx) to collections.

Rx is extremely powerful but out of the box provides nothing to assist with managing collections. In most applications there is a need to update the collections dynamically. Typically a collection is loaded and after the initial load, asynchronous updates are received. The original collection will need to reflect these changes. In simple scenarios the code is simple. However, typical applications are much more complicated and may apply a filter, transform the original dto and apply a sort. Even with these simple every day operations the complexity of the code is quickly magnified. Dynamic data has been developed to remove the tedious code of dynamically maintaining collections. It has grown to become functionally very rich with at least 60 collection based operations which amongst other things enable filtering, sorting, grouping, joining different sources, transforms, binding, pagination, data virtualisation, expiration, disposal management plus more.

The concept behind using dynamic data is you maintain a data source (either SourceCache<TObject, TKey> or SourceList<TObject>), then chain together various combinations of operators to declaratively manipulate and shape the data without the need to directly manage any collection.

As an example the following code will filter trades to select only live trades, creates a proxy for each live trade, and finally orders the results by most recent first. The resulting trade proxies are bound on the dispatcher thread to an observable collection. Also since the proxy is disposable DisposeMany() will ensure the proxy is disposed when no longer used.

ReadOnlyObservableCollection<TradeProxy> list;

var myTradeCache = new SourceCache<Trade, long>(trade => trade.Id);
var myOperation = myTradeCache.Connect() 
		.Filter(trade=>trade.Status == TradeStatus.Live) 
		.Transform(trade => new TradeProxy(trade))
		.Sort(SortExpressionComparer<TradeProxy>.Descending(t => t.Timestamp))
		.ObserveOnDispatcher()
		.Bind(out list) 
		.DisposeMany()
		.Subscribe()

The magic is that as myTradeCache is maintained the target observable collection looks after itself.

This is a simple example to show how using Dynamic Data's collections and operators make in-memory data management extremely easy and can reduce the size and complexity of your code base by abstracting complicated and often repetitive operations.

Sample Projects

Get in touch

If you have any questions, want to get involved or would simply like to keep abreast of developments, you are welcome to join the slack community Reactive UI Slack. I am also available @RolandPheasant There is a blog at https://dynamic-data.org/ but alas it is hopelessly out of date.

Table of Contents

Create Dynamic Data Collections

The Observable List

Create an observable list like this:

var myInts = new SourceList<int>();

The observable list provides the direct edit methods you would expect. For example:

myInts.AddRange(Enumerable.Range(0, 10000)); 
myInts.Add(99999); 
myInts.Remove(99999);

The AddRange, Add and Remove methods above will each produce a distinct change notification. In order to increase efficiency when making multiple amendments, the list provides a means of batch editing. This is achieved using the .Edit method which ensures only a single change notification is produced.

myInts.Edit(innerList =>
{
   innerList.Clear();
   innerList.AddRange(Enumerable.Range(0, 10000));
});

If myInts is to be exposed publicly it can be made read only using .AsObservableList

IObservableList<int> readonlyInts = myInts.AsObservableList();

which hides the edit methods.

The list's changes can be observed by calling myInts.Connect() like this:

IObservable<IChangeSet<int>> myIntsObservable = myInts.Connect();

This creates an observable change set for which there are dozens of operators. The changes are transmitted as an Rx observable, so they are fluent and composable.

The Observable Cache

Create an observable cache like this:

var myCache = new SourceCache<TObject,TKey>(t => key);

There are direct edit methods, for example

myCache.Clear();
myCache.AddOrUpdate(myItems);

The Clear and AddOrUpdate methods above will each produce a distinct change notification. In order to increase efficiency when making multiple amendments, the cache provides a means of batch editing. This is achieved using the .Edit method which ensures only a single change notification is produced.

myCache.Edit(innerCache =>
			  {
			      innerCache.Clear();
			      innerCache.AddOrUpdate(myItems);
			  });

If myCache is to be exposed publicly it can be made read only using .AsObservableCache

IObservableCache<TObject,TKey> readonlyCache = myCache.AsObservableCache();

which hides the edit methods.

The cache is observed by calling myCache.Connect() like this:

IObservable<IChangeSet<TObject,TKey>> myCacheObservable = myCache.Connect();

This creates an observable change set for which there are dozens of operators. The changes are transmitted as an Rx observable, so they are fluent and composable.

Creating Observable Change Sets

As stated in the introduction of this document, Dynamic Data is based on the concept of creating and manipulating observable change sets.

The primary method of creating observable change sets is to connect to instances of ISourceCache<T,K> and ISourceList<T>. There are alternative methods to produce observables change sets however, depending on the data source.

Connect to a Cache or List

Calling Connect() on a ISourceList<T> or ISourceCache<T,K> will produce an observable change set.

var myObservableChangeSet = myDynamicDataSource.Connect();

Create an Observable Change Set from an Rx Observable

Given either of the following observables:

IObservable<T> myObservable;
IObservable<IEnumerable<T>> myObservable;

an observable change set can be created like by calling .ToObservableChangeSet like this:

var myObservableChangeSet = myObservable.ToObservableChangeSet(t=> t.key);

Create an Observable Change Set from an Rx Observable with an Expiring Cache

The problem with the example above is that the internal backing cache of the observable change set will grow in size forever. To counter this behavior, there are overloads of .ToObservableChangeSet where a size limitation or expiry time can be specified for the internal cache.

To create a time expiring cache, call .ToObservableChangeSet and specify the expiry time using the expireAfter argument:

var myConnection = myObservable.ToObservableChangeSet(t=> t.key, expireAfter: item => TimeSpan.FromHours(1));

To create a size limited cache, call .ToObservableChangeSet and specify the size limit using the limitSizeTo argument:

var myConnection = myObservable.ToObservableChangeSet(t=> t.key, limitSizeTo:10000);

There is also an overload to specify expiration by both time and size.

Create an Observable Change Set from an Observable Collection

var myObservableCollection = new ObservableCollection<T>();

To create a cache based observable change set, call .ToObservableChangeSet and specify a key selector for the backing cache

var myConnection = myObservableCollection.ToObservableChangeSet(t => t.Key);

or to create a list based observable change set call .ToObservableChangeSet with no arguments

var myConnection = myObservableCollection.ToObservableChangeSet();

This method is only recommended for simple queries which act only on the UI thread as ObservableCollection is not thread safe.

Create an Observable Change Set from an Binding List

var myBindingList = new BindingList<T>();

To create a cache based observable change set, call .ToObservableChangeSet and specify a key selector for the backing cache

var myConnection = myBindingList.ToObservableChangeSet(t => t.Key);

or to create a list based observable change set call .ToObservableChangeSet with no arguments

var myConnection = myBindingList.ToObservableChangeSet();

This method is only recommended for simple queries which act only on the UI thread as ObservableCollection is not thread safe.

Using the ObservableChangeSet static class

There is also another way to create observable change sets, and that is to use the ObservableChangeSet static class. This class is a facsimile of the Rx.Net Observable static class and provides an almost identical API.

An observable list can be created as follows:

  var myObservableList = ObservableChangeSet.Create<int>(observableList =>
  {
	  //some code to load data and subscribe
      var loader= myService.LoadMyDataObservable().Subscribe(observableList.Add);
      var subscriber = myService.GetMySubscriptionsObservable().Subscribe(observableList.Add);
      //dispose of resources
      return new CompositeDisposable(loader,subscriber );
  });

and creating a cache is almost identical except a key has to be specified

  var myObservableCache = ObservableChangeSet.Create<Trade, int>(observableCache =>
  {
	  //code omitted
  }, trade = > trade.Id);

There are several overloads ObservableChangeSet.Create which match the overloads which Observable.Create provides.

Consuming Observable Change Sets

The examples below illustrate the kind of things you can achieve after creating an observable change set. Now you can create an observable cache or an observable list, here are a few quick fire examples to illustrate the diverse range of things you can do. In all of these examples the resulting sequences always exactly reflect the items is the cache i.e. adds, updates and removes are always propagated.

Create a Derived List or Cache

This example shows how you can create derived collections from an observable change set. It applies a filter to a collection, and then creates a new observable collection that only contains items from the original collection that pass the filter. This pattern is incredibly useful when you want to make modifications to an existing collection and then expose the modified collection to consumers.

Even though the code in this example is very simple, this is one of the most powerful aspects of Dynamic Data.

Given a SourceList

var myList = new SourceList<People>();

You can apply operators, in this case the Filter() operator, and then create a new observable list with AsObservableList()

var oldPeople = myList.Connect().Filter(person => person.Age > 65).AsObservableList();

The resulting observable list, oldPeople, will only contain people who are older than 65.

The same pattern can be used with SourceCache by using .AsObservableCache() to create derived caches.

As an alternative to .Bind(out collection) you can use .BindToObservableList(out observableList) for both SourceList & SourceCache. This is useful for getting derived read-only lists from sources that use .AutoRefresh(), since collections do not support refresh notifications.

Filtering

Filter the observable change set by using the Filter operator

var myPeople = new SourceList<People>();
var myPeopleObservable = myPeople.Connect();

var myFilteredObservable = myPeopleObservable.Filter(person => person.Age > 50); 

or to filter a change set dynamically

IObservable<Func<Person,bool>> observablePredicate=...;
var myFilteredObservable = myPeopleObservable.Filter(observablePredicate); 
Sorting

Sort the observable change set by using the Sort operator

var myPeople = new SourceList<People>();
var myPeopleObservable = myPeople.Connect();
var mySortedObservable = myPeopleObservable.Sort(SortExpressionComparer.Ascending(p => p.Age)); 

or to dynamically change sorting

IObservable<IComparer<Person>> observableComparer=...;
var mySortedObservable = myPeopleObservable.Sort(observableComparer);

For more information on sorting see wiki

Grouping

The GroupOn operator pre-caches the specified groups according to the group selector.

var myOperation = personChangeSet.GroupOn(person => person.Status)

The value of the inner group is represented by an observable list for each matched group. When values matching the inner grouping are modified, it is the inner group which produces the changes. You can also use GroupWithImmutableState which will produce a grouping who's inner items are a fixed size array.

Transformation

The Transform operator allows you to map objects from the observable change set to another object

var myPeople = new SourceList<People>();
var myPeopleObservable = myPeople.Connect();
var myTransformedObservable = myPeopleObservable.Transform(person => new PersonProxy(person));

The TransformToTree operator allows you to create a fully formed reactive tree (only available for observable cache)

var myPeople = new SourceCache<Person, string>(p => p.Name);
var myTransformedObservable = myPeople.Connect().TransformToTree(person => person.BossId);

Flatten a child enumerable

var myOperation = personChangeSet.TransformMany(person => person.Children) 
Aggregation

The Count, Max, Min, Avg, and StdDev operators allow you to perform aggregate functions on observable change sets

var myPeople = new SourceList<People>();
var myPeopleObservable = myPeople.Connect();

var countObservable = 	 myPeopleObservable.Count();
var maxObservable = 	 myPeopleObservable.Max(p => p.Age);
var minObservable = 	 myPeopleObservable.Min(p => p.Age);
var stdDevObservable =   myPeopleObservable.StdDev(p => p.Age);
var avgObservable = 	 myPeopleObservable.Avg(p => p.Age);

More aggregating operators will be added soon.

Logical Operators

The And, Or, Xor and Except operators allow you to perform logical operations on observable change sets

var peopleA = new SourceCache<Person,string>(p => p.Name);
var peopleB = new SourceCache<Person,string>(p => p.Name);

var observableA = peopleA.Connect();
var observableB = peopleB.Connect();

var inBoth = observableA.And(observableB);
var inEither= observableA.Or(observableB);
var inOnlyOne= observableA.Xor(observableB);
var inAandNotinB = observableA.Except(observableB);

A recent and very powerful feature is dynamic logical operators. From version 4.6 onwards you can dynamically include and exclude collections from the resulting list.

var list1 = new SourceList<int>();
var list2 = new SourceList<int>();
var list3  = new SourceList<int>();
	
var combined = new SourceList<ISourceList<int>>();

//child lists can be added or removed any time
combined.Add(list1);
combined.Add(list2);
combined.Add(list3);

//The operators look after themselves 
var inAll = combined.And();
var inAny = combined.Or();
var inOnlyOne= combined.Xor();
var inFirstAndNotAnyOther = combined.Except();

For more information on grouping see wiki

Disposal

The DisposeMany operator ensures that objects are disposed when removed from an observable stream

var myPeople = new SourceList<People>();
var myPeopleObservable = myPeople.Connect();
var myTransformedObservable = myPeopleObservable.Transform(person => new DisposablePersonProxy(person))
                                                .DisposeMany();

The DisposeMany operator is typically used when a transform function creates disposable objects.

Distinct Values

The DistinctValues operator will select distinct values from the underlying collection

var myPeople = new SourceList<People>();
var myPeopleObservable = myPeople.Connect();
var myDistinctObservable = myPeopleObservable.DistinctValues(person => person.Age);
Virtualisation

Virtualise data to restrict by index and segment size

IObservable<IVirtualRequest> request; //request stream
var virtualisedStream = someDynamicDataSource.Virtualise(request)

Virtualise data to restrict by index and page size

IObservable<IPageRequest> request; //request stream
var pagedStream = someDynamicDataSource.Page(request)

In either of the above, the result is re-evaluated when the request stream changes

Top is an overload of Virtualise() and will return items matching the first 'n' items.

var topStream = someDynamicDataSource.Top(10)
Observing Properties of Objects in a Collection

If the collection is made up of objects that implement INotifyPropertyChanged then the following operators are available

The WhenValueChanged operator returns an observable of the value of the specified property when it has changed

var ageChanged = peopleDataSource.Connect().WhenValueChanged(p => p.Age)

The WhenPropertyChanged operator returns an observable made up of the value of the specified property as well as it's parent object when the specified property has changed

var ageChanged = peopleDataSource.Connect().WhenPropertyChanged(p => p.Age)

The WhenAnyPropertyChanged operator returns an observable of objects when any of their properties have changed

var personChanged = peopleDataSource.Connect().WhenAnyPropertyChanged()
Observing item changes

Binding is a very small part of Dynamic Data. The above notify property changed overloads are just an example when binding. If you have a domain object which has children observables you can use MergeMany() which subscribes to and unsubscribes from items according to collection changes.

var myoperation = somedynamicdatasource.Connect() 
			.MergeMany(trade => trade.SomeObservable());

This wires and unwires SomeObservable as the collection changes.

Observable list vs observable cache

I get asked about the differences between these a lot and the answer is really simple. If you have a unique id, you should use an observable cache as it is dictionary based which will ensure no duplicates can be added and it notifies on adds, updates and removes, whereas list allows duplicates and only has no concept of an update.

There is another difference. The cache side of dynamic data is much more mature and has a wider range of operators. Having more operators is mainly because I found it easier to achieve good all round performance with the key based operators and do not want to add anything to Dynamic Data which inherently has poor performance.

History of Dynamic Data

Even before Rx existed I had implemented a similar concept using old fashioned events but the code was very ugly and my implementation full of race conditions so it never existed outside of my own private sphere. My second attempt was a similar implementation to the first but using Rx when it first came out. This also failed as my understanding of Rx was flawed and limited and my design forced consumers to implement interfaces. Then finally I got my design head on and in 2011-ish I started writing what has become dynamic data. No inheritance, no interfaces, just the ability to plug in and use it as you please. All along I meant to open source it but having so utterly failed on my first 2 attempts I decided to wait until the exact design had settled down. The wait lasted longer than I expected and ended up taking over 2 years but the benefit is it has been trialled for 2 years on a very busy high volume low latency trading system which has seriously complicated data management. And what's more that system has gathered a load of attention for how slick and cool and reliable it is both from the user and IT point of view. So I present this library with the confidence of it being tried, tested, optimised and mature. I hope it can make your life easier like it has done for me.

Want to know more?

I could go on endlessly but this is not the place for full documentation. I promise this will come but for now I suggest downloading my WPF sample app (links at top of document) as I intend it to be a 'living document' and I promise it will be continually maintained.

Also, if you follow me on Twitter you will find out when new samples or blog posts have been updated.

Additionally, if you have read up to here and not pressed star then why not? Ha. A star may make me be more responsive to any requests or queries.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (82)

Showing the top 5 NuGet packages that depend on DynamicData:

Package Downloads
ReactiveUI The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

A MVVM framework that integrates with the Reactive Extensions for .NET to create elegant, testable User Interfaces that run on any mobile or desktop platform. This is the base package with the base platform implementations

ReactiveUI.WPF The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

Contains the ReactiveUI platform specific extensions for Windows Presentation Foundation (WPF)

Noggog.CSharpExt

Generic reusable classes and extension methods that apply to no specific project and flavored to taste

ReactiveUI.Testing The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

Provides extensions for testing ReactiveUI based applications

ReactiveUI.XamForms The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

Contains the ReactiveUI platform specific extensions for Xamarin Forms

GitHub repositories (35)

Showing the top 5 popular GitHub repositories that depend on DynamicData:

Repository Stars
Ryujinx/Ryujinx
Experimental Nintendo Switch Emulator written in C#
reactiveui/ReactiveUI
An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming. ReactiveUI allows you to abstract mutable state away from your user interfaces, express the idea around a feature in one readable place and improve the testability of your application.
LykosAI/StabilityMatrix
Multi-Platform Package Manager for Stable Diffusion
RolandPheasant/TailBlazer
A modern file tail utility based on Rx.Net which show cases reactive programming and Dynamic Data (see https://github.com/RolandPheasant/DynamicData)
zkSNACKs/WalletWasabi
Open-source, non-custodial, privacy preserving Bitcoin wallet for Windows, Linux, and Mac.
Version Downloads Last updated
8.4.1 36,362 3/20/2024
8.3.93 1,938 3/17/2024
8.3.27 244,957 12/11/2023
8.3.25 1,893 12/7/2023
8.1.1 73,449 10/19/2023
8.0.2 125,025 9/22/2023
8.0.1 1,102 9/22/2023
7.14.6 3,701 9/21/2023
7.14.2 283,557 5/22/2023
7.13.8 6,471 5/17/2023
7.13.5 116,399 4/7/2023
7.13.1 176,358 2/27/2023
7.12.11 318,569 11/25/2022
7.12.8 204,774 11/23/2022
7.12.1 98,150 10/18/2022
7.10.2 48,336 9/6/2022
7.9.14 23,013 8/18/2022
7.9.7 50,428 7/20/2022
7.9.5 781,740 7/12/2022
7.9.4 88,795 6/25/2022
7.9.1 186,008 6/9/2022
7.8.6 9,806 5/31/2022
7.8.5 8,695 5/24/2022
7.8.1 2,152 5/23/2022
7.7.14 11,374 5/10/2022
7.7.1 100,675 4/27/2022
7.6.7 374,390 4/13/2022
7.6.5 67,634 3/10/2022
7.6.2 3,390 3/8/2022
7.5.4 24,392 2/14/2022
7.5.2 168,040 2/13/2022
7.4.11 19,763 2/1/2022
7.4.9 140,999 12/18/2021
7.4.3 777,280 11/2/2021
7.4.1 55,484 10/19/2021
7.3.1 299,307 8/20/2021
7.2.1 134,576 6/28/2021
7.1.17 177,492 5/19/2021
7.1.16 126,779 5/1/2021
7.1.1 1,420,963 11/26/2020
6.17.14 703,804 10/10/2020
6.17.13 1,848 10/10/2020
6.17.12 1,819 10/10/2020
6.17.11 2,114 10/9/2020
6.17.8 4,396 10/6/2020
6.17.7 1,987 10/6/2020
6.17.3 1,987 10/6/2020
6.17.2 28,689 10/5/2020
6.16.9 47,654 9/4/2020
6.16.8 24,461 8/28/2020
6.16.6 442,051 8/16/2020
6.16.3 37,754 8/4/2020
6.16.2 60,496 7/28/2020
6.16.1 28,127 7/4/2020
6.15.4 4,733 6/30/2020
6.15.1 172,170 6/8/2020
6.14.20 2,180 6/8/2020
6.14.18 28,820 5/7/2020
6.14.14 120,716 4/23/2020
6.14.10 10,083 4/1/2020
6.14.8 164,918 2/6/2020
6.14.3 137,001 12/26/2019
6.14.1 40,700 12/5/2019
6.13.21 58,921 11/5/2019
6.13.20 56,519 10/28/2019
6.13.19 34,922 10/21/2019
6.13.18 65,480 10/12/2019
6.13.17 2,364 10/11/2019
6.13.16 2,019 10/11/2019
6.13.15 1,914 10/11/2019
6.13.14 2,089 10/10/2019
6.13.13 12,594 10/5/2019
6.13.12 2,013 10/5/2019
6.13.11 2,020 10/5/2019
6.13.9 255,699 9/26/2019
6.13.8 2,838 9/23/2019
6.13.7 2,126 9/23/2019
6.13.6 1,935 9/23/2019
6.13.5 13,121 9/20/2019
6.13.1 110,753 8/13/2019
6.12.13 33,954 8/5/2019
6.12.12 2,898 8/5/2019
6.12.11 3,885 8/5/2019
6.12.10 4,382 7/30/2019
6.12.9 12,530 7/19/2019
6.12.8 3,262 7/18/2019
6.12.7 3,199 7/16/2019
6.12.6 5,383 7/15/2019
6.12.5 3,388 7/11/2019
6.12.4 2,999 7/11/2019
6.12.3 2,913 7/11/2019
6.11.0.2613 64,940 7/8/2019
6.10.0.2604 64,849 6/10/2019
6.9.1.2588 124,291 4/22/2019
6.9.0.2586 55,185 4/13/2019
6.8.0.2561 96,618 2/20/2019
6.7.1.2534 160,184 12/16/2018
6.7.0.2529 93,192 11/14/2018
6.6.1.2507 13,963 10/28/2018
6.6.0.2492 8,021 10/13/2018
6.5.1.2479 14,405 9/10/2018
6.5.0.2474 12,979 9/9/2018
6.4.0.2419 213,972 6/12/2018
6.3.1.2409 8,724 5/22/2018
6.3.0.2400 4,531 5/10/2018
6.2.0.2388 6,763 5/2/2018
6.1.4.2381 5,473 3/21/2018
6.1.3.2378 4,063 3/19/2018
6.1.2.2373 6,465 3/16/2018
6.1.1.2369 6,712 2/12/2018
6.1.0.2366 3,856 2/8/2018
6.0.4.2351 9,720 11/16/2017
6.0.2.2345-beta 3,111 11/15/2017
6.0.1.2341-beta 3,089 11/14/2017
6.0.1.2317-beta 5,349 9/4/2017
6.0.0.2301-beta 3,026 8/23/2017
5.4.1.2196 7,447 7/11/2017
5.4.0.2168-beta 3,148 6/16/2017
5.3.0.2158 3,963 5/11/2017
5.3.0.2156 3,456 5/9/2017
5.2.1.2134 4,335 3/3/2017
5.2.0.2132 3,404 2/28/2017
5.1.4.2124 3,944 1/22/2017
5.1.3.2123-beta 2,983 1/22/2017
5.1.2.2117-beta 3,108 12/30/2016
5.1.1.2112-beta 3,119 12/28/2016
5.1.1.2111-beta 3,626 12/21/2016
5.1.0.2101-beta 3,060 12/15/2016
5.0.6.2090 4,033 11/29/2016
5.0.5.2089 3,392 11/29/2016
5.0.5.2078 3,935 10/27/2016
5.0.4.2075 3,352 10/24/2016
5.0.3.2070-beta 3,339 9/14/2016
5.0.2.2068-beta 3,075 9/11/2016
5.0.1.2066-beta 3,095 9/5/2016
5.0.1.2062-beta 3,113 8/23/2016
5.0.0.2007-beta 3,458 8/8/2016
4.15.0.2299 6,299 8/23/2017
4.14.0.1219 4,080 8/11/2017
4.13.2.1216 6,473 7/12/2017
4.13.1.1215 3,734 7/11/2017
4.13.0.1211-beta 3,293 6/16/2017
4.12.0.1210 4,210 5/9/2017
4.11.3.1209 8,898 3/31/2017
4.11.2.1205 4,036 3/20/2017
4.11.1.1203 3,965 3/3/2017
4.11.0.1199 4,532 2/28/2017
4.10.1.1194 4,062 1/22/2017
4.10.0.1191 4,008 12/30/2016
4.9.0.1189 6,400 10/6/2016
4.8.3.1187-beta 3,446 9/14/2016
4.8.2.1185-beta 3,298 9/13/2016
4.8.1.1181 4,147 8/23/2016
4.8.0.1177 4,093 8/8/2016
4.7.5.1167-beta 3,393 7/11/2016
4.7.5.1166-beta 3,268 7/8/2016
4.7.4.1160-beta 3,701 5/23/2016
4.7.3.1156-beta 3,318 5/16/2016
4.7.2.1154-beta 3,255 5/12/2016
4.7.1.1153 6,111 5/6/2016
4.7.0.1151-beta 3,330 4/26/2016
4.7.0.1147-beta 3,642 4/25/2016
4.7.0.1146-beta 3,375 4/23/2016
4.6.0.1134-beta 3,328 4/8/2016
4.6.0.1132 4,984 4/5/2016
4.5.0.1112 4,373 3/12/2016
4.4.0.1110-beta 3,644 2/6/2016
4.4.0.1108-beta 3,153 2/6/2016
4.4.0.1101-beta 3,107 1/18/2016
4.4.0.1099-beta 3,111 1/18/2016
4.4.0.1098-beta 3,163 1/18/2016
4.3.1.1090 4,942 11/21/2015
4.3.0.1088-Beta 2,236 11/15/2015
4.3.0.1087-Beta 2,123 11/15/2015
4.3.0.1086-Beta 2,084 10/17/2015
4.2.2.1081-Beta 2,058 10/12/2015
4.2.0.1068 4,918 8/8/2015
4.1.0.1037 4,280 8/3/2015
4.1.0.1034 3,760 8/3/2015
4.1.0.1032 3,607 7/30/2015
4.1.0.1029 3,683 7/30/2015
4.1.0.1027 3,582 7/27/2015
4.0.3.1128-beta 3,254 7/26/2015
4.0.3.1127-beta 3,190 7/25/2015
4.0.2.1111-beta 3,145 7/11/2015
4.0.2.1110-beta 3,277 7/5/2015
4.0.2.1106-beta 3,138 7/5/2015
4.0.2.1105-beta 3,140 7/4/2015
4.0.1.1089-beta 3,181 5/27/2015
4.0.1.1088-beta 3,370 5/27/2015
4.0.1.1078-beta 3,171 5/9/2015
4.0.0.1076-beta 3,139 5/9/2015
4.0.0.1065-beta 3,375 4/27/2015
4.0.0.1064-beta 3,381 4/17/2015
4.0.0.1062-beta 3,154 4/11/2015
4.0.0.1061-beta 3,340 3/29/2015
4.0.0.1060-beta 3,127 3/29/2015
4.0.0.1059-beta 3,242 3/28/2015
4.0.0.1049-beta 3,211 3/26/2015
4.0.0.1045-beta 3,282 3/17/2015
4.0.0.1041-beta 3,152 3/11/2015
4.0.0.1034-beta 3,131 3/10/2015
4.0.0.1033-beta 3,174 3/10/2015
3.3.1.1069 3,980 5/9/2015
3.3.0.1067 3,838 4/18/2015
3.2.2.1015 4,240 2/15/2015
3.2.1.1008 3,801 2/1/2015
3.2.0.1003 3,949 1/24/2015
3.2.0.82-beta 3,067 1/16/2015
3.2.0.81-beta 3,171 1/16/2015
3.2.0.80-beta 3,560 1/4/2015
3.2.0.78-beta 3,583 1/4/2015
3.2.0.77-beta 3,585 1/4/2015
3.2.0.47-beta 3,350 12/31/2014
3.1.1.221 4,051 1/16/2015
3.1.0.219 3,858 12/31/2014
3.1.0.46-beta 3,537 12/31/2014
3.1.0.45-beta 3,412 12/31/2014
3.1.0.43-beta 3,217 12/30/2014
3.1.0.42-beta 3,371 12/30/2014
3.0.3.24-beta 3,482 12/12/2014
3.0.3.22-beta 3,411 12/12/2014
3.0.2.216 3,925 12/12/2014
3.0.2.19-beta 3,390 12/8/2014
3.0.2.17-beta 3,357 12/8/2014
3.0.2.15-beta 3,406 12/6/2014
3.0.2.14-beta 3,294 12/5/2014
3.0.2.13-beta 3,372 12/5/2014
3.0.2.12-beta 3,267 11/30/2014
3.0.2.11-beta 3,299 11/30/2014
3.0.2.10-beta 3,271 11/30/2014
3.0.2.9-beta 3,325 11/30/2014
3.0.2.8-beta 3,160 11/30/2014
3.0.2.7-beta 3,361 11/30/2014
3.0.2.6-beta 3,352 11/28/2014
3.0.1.215 3,729 12/6/2014
3.0.1.214 3,761 12/5/2014
3.0.1.209 3,578 11/28/2014
3.0.1.207 3,577 11/28/2014
3.0.0.204 3,738 11/20/2014
3.0.0.203 3,596 11/20/2014
3.0.0.202 3,564 11/20/2014
3.0.0.196 5,706 11/20/2014