public static IObservable <TSource> Shift <TSource>(
            this IObservable <TSource> source,
            long count,
            IScheduler scheduler)
        {
            return(Observable.Create <TSource>(observer =>
            {
                var limited_queue = new FixedSizedQueue <TSource>(count);
                return source.Subscribe(value =>
                {
                    if (limited_queue.Shift(value, out var outObj))
                    {
                        observer.OnNext(outObj);
                    }
                },
                                        observer.OnError,

                                        /* Immediate abort semantics of Rx requires us to propagate
                                         * errors immediately (i.e., without draining the queue).
                                         * (Exception ex) =>
                                         * {
                                         * limited_queue
                                         * .Subscribe(Observer
                                         *   .Create<TSource>(data => observer.OnNext(data),
                                         *                    () => observer.OnError(ex)),
                                         *                    scheduler);
                                         * }*/
                                        () => { limited_queue.ToObservable(scheduler).Subscribe(observer); });
            }));
        }
        public static IObservable <TAccumulate> WindowAggregate <TSource, TAccumulate>(
            this IObservable <TSource> source,
            long windowSize,
            TAccumulate seed,
            Func <TAccumulate, TSource, TSource, long, TAccumulate> accumulator,
            Func <TAccumulate, TSource, long, long, TAccumulate> windowDrainer)
        {
            if (accumulator == null)
            {
                throw new ArgumentNullException("WindowAggregate: accumulator can't be null");
            }
            if (windowDrainer == null)
            {
                throw new ArgumentNullException("WindowAggregate: windowDrainer can't be null");
            }

            return(Observable.Create <TAccumulate>(observer =>
            {
                var limitedQueue = new FixedSizedQueue <TSource>(windowSize);

                return source.Subscribe(
                    value =>
                {
                    try
                    {
                        seed = limitedQueue.Shift(value, out var outObj)
                                ? accumulator(seed, value, outObj, limitedQueue.Count)
                                : windowDrainer(seed, value, limitedQueue.Count, limitedQueue.Count - 1);
                        observer.OnNext(seed);
                    }
                    catch (Exception ex)
                    {
                        observer.OnError(ex);
                    }
                },
                    observer.OnError,
                    () =>
                {
                    try
                    {
                        long count = limitedQueue.Count;
                        while (limitedQueue.TryDequeue(out var outObj))
                        {
                            count--;
                            seed = windowDrainer(seed, outObj, count, count + 1);
                            observer.OnNext(seed);
                        }

                        if (count != 0)
                        {
                            observer.OnError(
                                new ApplicationException(
                                    "WindowAggregte: OnCompleted: Unable to deque all elements"));
                        }
                        else
                        {
                            observer.OnCompleted();
                        }
                    }
                    catch (Exception ex)
                    {
                        observer.OnError(ex);
                    }
                });
            }));
        }