public LineScroller(FileInfo file, IObservable <ILineProvider> latest, IObservable <ScrollRequest> scrollRequest, ILogger logger, IScheduler scheduler = null) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (latest == null) { throw new ArgumentNullException(nameof(latest)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } logger.Info($"Constructing file tailer for {file.FullName}"); var lines = new SourceList <Line>(); Lines = lines.AsObservableList(); var locker = new object(); scrollRequest = scrollRequest.Synchronize(locker); var aggregator = latest.CombineLatest(scrollRequest, (currentLines, scroll) => currentLines.ReadLines(scroll).ToArray()) .Subscribe(currentPage => { var previous = lines.Items.ToArray(); var added = currentPage.Except(previous, Line.TextStartComparer).ToArray(); var removed = previous.Except(currentPage, Line.TextStartComparer).ToArray(); lines.Edit(innerList => { if (removed.Any()) { innerList.RemoveMany(removed); } if (added.Any()) { innerList.AddRange(added); } }); }); _cleanUp = new CompositeDisposable(Lines, lines, aggregator); }
public OcsSession() { _ocs = new SourceList <AnalysisData>(); _nnMean = new SourceList <AnalysisData>(); _sdNn = new SourceList <AnalysisData>(); _meanEda = new SourceList <AnalysisData>(); _peakEda = new SourceList <AnalysisData>(); Ocs = _ocs.AsObservableList(); NnMean = _nnMean.AsObservableList(); SdNn = _sdNn.AsObservableList(); MeanEda = _meanEda.AsObservableList(); PeakEda = _peakEda.AsObservableList(); }
public DialogSelectNeuronsViewModel(string message, string avatarUrl, bool allowMultiSelect, INeuronQueryService neuronQueryService = null) : base(message) { this.avatarUrl = avatarUrl; this.AllowMultiSelect = allowMultiSelect; this.neuronQueryService = neuronQueryService ?? Locator.Current.GetService <INeuronQueryService>(); var list = new SourceList <Neuron>(); this.ReloadCommand = ReactiveCommand.Create(async() => await this.OnReloadClicked(list)); this.SelectCommand = ReactiveCommand.Create(this.OnSelectedClicked); this.UserDialogResult = null; this.cleanUp = list.AsObservableList().Connect() .Bind(out this.neurons) .DisposeMany() .Subscribe(); }
public void TheLightIsChangedWhenThereIsAMatch(string processName, string windowName) { var activeProcessesService = Substitute.For <IActiveProcessesService>(); var procs = new SourceList <string>(); procs.Add(processName); activeProcessesService.ProcessNames.Returns(procs.AsObservableList()); var windows = new SourceList <string>(); windows.Add(windowName); activeProcessesService.ProcessNames.Returns(windows.AsObservableList()); var phillipsHueService = Substitute.For <IPhillipsHueService>(); var lights = new SourceList <Light>(); var light = new Light() { Id = "5", Name = "Office Door", }; lights.Add(light); phillipsHueService.Lights.Returns(lights.AsObservableList()); var sut = new OnAirServiceBuilder() .WithActiveProcessesService(activeProcessesService) .WithPhillipsHueService(phillipsHueService) .Build(); // user interface is updated sut.IsOnAir.ShouldBeTrue(); // the correct light is turned on phillipsHueService.Received().SendCommandAsync( Arg.Is <LightCommand>(x => x.On.Value == true), Arg.Is <IEnumerable <string> >(x => x.Contains(light.Id))); // TODO: assert that the light is set to the correct color }
public LineScroller([NotNull] IObservable <ILineProvider> latest, [NotNull] IObservable <ScrollRequest> scrollRequest) { if (latest == null) { throw new ArgumentNullException(nameof(latest)); } if (scrollRequest == null) { throw new ArgumentNullException(nameof(scrollRequest)); } var lines = new SourceList <Line>(); Lines = lines.AsObservableList(); var locker = new object(); scrollRequest = scrollRequest.Synchronize(locker); latest = latest.Synchronize(locker); var aggregator = latest.CombineLatest(scrollRequest, (currentLines, scroll) => currentLines.ReadLines(scroll).ToArray()) .Subscribe(currentPage => { var previous = lines.Items.ToArray(); var added = currentPage.Except(previous, Line.TextStartComparer).ToArray(); var removed = previous.Except(currentPage, Line.TextStartComparer).ToArray(); lines.Edit(innerList => { if (removed.Any()) { innerList.RemoveMany(removed); } if (added.Any()) { innerList.AddRange(added); } }); }); _cleanUp = new CompositeDisposable(Lines, lines, aggregator); }
public EmpaticaSession() { _acceleration = new SourceList <Acceleration>(); _batteryLevel = new SourceList <BatteryLevel>(); _bvp = new SourceList <Bvp>(); _gsr = new SourceList <Gsr>(); _hr = new SourceList <Hr>(); _ibi = new SourceList <Ibi>(); _tag = new SourceList <Tag>(); _temperature = new SourceList <Temperature>(); Acceleration = _acceleration.AsObservableList(); BatteryLevel = _batteryLevel.AsObservableList(); Bvp = _bvp.AsObservableList(); Gsr = _gsr.AsObservableList(); Hr = _hr.AsObservableList(); Ibi = _ibi.AsObservableList(); Tag = _tag.AsObservableList(); Temperature = _temperature.AsObservableList(); }
public UserFileService(IAppFolderService appFolderService, IFileService fileService, IFileSystemWatcherService fileSystemWatcherService, IEncryptionService encryptionService) { _appFolderService = appFolderService; _fileService = fileService; _fileSystemWatcherService = fileSystemWatcherService; _encryptionService = encryptionService; _appFolderPath = _appFolderService.GetAppFolderPath(); string localFolderName = FileLocation.Local.FolderName(); string roamedFolderName = FileLocation.Roamed.FolderName(); var localFolderTask = CreateUserFolderAsync(localFolderName); var roamedFolderTask = CreateUserFolderAsync(roamedFolderName); FilesList = _filesList.AsObservableList(); Initialization = InitializeFileList(); }
public FileTailer(FileInfo file, IObservable<FileSearchResult> filter, IObservable<ScrollRequest> scrollRequest, ILogger logger, IScheduler scheduler = null) { if (file == null) throw new ArgumentNullException(nameof(file)); if (filter == null) throw new ArgumentNullException(nameof(filter)); if (logger == null) throw new ArgumentNullException(nameof(logger)); logger.Info($"Constructing file tailer for {file.FullName}"); var lines = new SourceList<Line>(); Lines = lines.AsObservableList(); var isBusy = new Subject<bool>(); IsSearching = isBusy.AsObservable(); var locker = new object(); scrollRequest = scrollRequest.Synchronize(locker); var fileWatcher = file.WatchFile(scheduler: scheduler) .DistinctUntilChanged() .TakeWhile(notification => notification.Exists).Repeat() .Replay(1).RefCount(); var indexer = fileWatcher.Index().Replay(1).RefCount(); //compare latest lines and latest filter and only take the filtered results it is not empty var latestLines = indexer.Cast<ILineProvider>().Synchronize(locker); var latestFilter = filter.Cast<ILineProvider>().Synchronize(locker); var latest = latestLines.CombineLatest(latestFilter, (l, f) => f.IsEmpty ? l : f); MatchedLines = latest.Select(provider => provider.Count); TotalLines = latestLines.Select(x => x.Count); FileSize = fileWatcher.Select(notification => notification.Size); IsLoading = indexer.Take(1).Select(_ => false).StartWith(true); var aggregator = latest.CombineLatest(scrollRequest, (currentLines, scroll) => { return currentLines.ReadLines(scroll).ToArray(); }) .Subscribe(currentPage => { var previous = lines.Items.ToArray(); var added = currentPage.Except(previous).ToArray(); var removed = previous.Except(currentPage).ToArray(); lines.Edit(innerList => { if (removed.Any()) innerList.RemoveMany(removed); if (added.Any()) innerList.AddRange(added); }); }); //var aggregator = latest.CombineLatest(scrollRequest, (currentLines, scroll) => //{ // //TODO: Read entire page, the check which lines should be added and which shold be removed // //as part of that work, get the maximum inded [this is the head!] // // Debug.WriteLine($"{scroll.Mode}, {scroll.FirstIndex}, {scroll.PageSize}"); // var currentPage = currentLines.GetIndicies(scroll).ToArray(); // var previous = lines.Items.Select(l => l.LineInfo).ToArray(); // var removed = previous.Except(currentPage, LineInfo.LineIndexComparer).ToArray(); // var added = currentPage.Except(previous, LineInfo.LineIndexComparer).ToArray(); // //calculated added and removed lines // var removedLines = lines.Items.Where(l => removed.Contains(l.LineInfo)).ToArray(); // Func<long, DateTime?> isTail = l => // { // //account for time with tail (i.e. add time to ILineProvider.TailStartsAt ) // var tail = currentLines.TailStartsAt; // var onTail = tail != -1 && l >= tail; // return onTail ? DateTime.Now : (DateTime?)null; // }; // //Console.WriteLine(); // //finally we can load the line from the file todo: Add encdoing back in // var newLines = file.ReadLine(added, (lineIndex, text, position) => new Line(lineIndex, text, isTail(position)), Encoding.UTF8).ToArray(); // return new { NewLines = newLines, OldLines = removedLines }; //}) //.Where(fn => fn.NewLines.Length + fn.OldLines.Length > 0) //.Subscribe(changes => //{ // //update observable list // lines.Edit(innerList => //{ // if (changes.OldLines.Any()) innerList.RemoveMany(changes.OldLines); // if (changes.NewLines.Any()) innerList.AddRange(changes.NewLines); //}); //}); _cleanUp = new CompositeDisposable(Lines, lines, aggregator, Disposable.Create(() => isBusy.OnCompleted())); }
public FileTailer(FileInfo file, IObservable<string> textToMatch, IObservable<ScrollRequest> scrollRequest, IScheduler scheduler=null) { if (file == null) throw new ArgumentNullException(nameof(file)); if (textToMatch == null) throw new ArgumentNullException(nameof(textToMatch)); //create list of lines which contain the observable text var matchedLines = textToMatch .Select(searchText => { Func<string, bool> predicate = null; if (!string.IsNullOrEmpty(searchText)) predicate = s => s.Contains(searchText, StringComparison.OrdinalIgnoreCase); return file.WatchFile(scheduler:scheduler ?? Scheduler.Default) .TakeWhile(notification => notification.Exists) .Repeat() .ScanFile(predicate); }).Switch() .Replay(1).RefCount(); MatchedLines = matchedLines.Select(x => x.MatchingLines.Length); TotalLines = matchedLines.Select(x => x.TotalLines); //todo: plug in file missing or error into the screen var lines = new SourceList<Line>(); Lines = lines.AsObservableList(); //this is the beast! Dynamically combine lines requested by the consumer //with the lines which exist in the file. This enables proper virtualisation of the file var scroller = matchedLines .CombineLatest(scrollRequest, (scanResult, request) => new {scanResult , request }) .Subscribe(x => { var mode = x.request.Mode; var pageSize = x.request.PageSize; var endOfTail = x.scanResult.EndOfTail; var isInitial = x.scanResult.Index==0; var allLines = x.scanResult.MatchingLines; var previousPage = lines.Items.Select(l => new LineIndex(l.Number, l.Index)).ToArray(); //Otherwise take the page size and start index from the request var currentPage = (mode == ScrollingMode.Tail ? allLines.Skip(allLines.Length-pageSize).Take(pageSize).ToArray() : allLines.Skip(x.request.FirstIndex).Take(pageSize)).ToArray(); var added = currentPage.Except(previousPage).ToArray(); var removed = previousPage.Except(currentPage).Select(li=>li.Line).ToArray(); if (added.Length + removed.Length == 0) return; try { var addedLines = file.ReadLines(added, (lineIndex, text) => { var isEndOfTail = !isInitial && lineIndex.Line > endOfTail; return new Line(lineIndex.Line, lineIndex.Index, text, isEndOfTail ? DateTime.Now : (DateTime?)null); }).ToArray(); //get old lines from the current collection var removedLines = lines.Items.Where(l => removed.Contains(l.Number)).ToArray(); //finally relect changes in the list lines.Edit(innerList => { innerList.RemoveMany(removedLines); innerList.AddRange(addedLines); }); } catch (Exception) { //Very small chance of an error here but if one is causght the next successful read will recify this //TODO: 1. Feedback to user that steaming has stopped //TODO: 2. Place the ReadLines(..) method with the select of an observable } }); _cleanUp = new CompositeDisposable(Lines, scroller, lines); }
public ParentDynamic() { Children = new SourceList <Person>(); ChildrenObservable = Children.AsObservableList(); }
public ParentDynamic(int id, IEnumerable <Person> children) { Children = new SourceList <Person>(); Children.AddRange(children); ChildrenObservable = Children.AsObservableList(); }
public FileTailer(FileInfo file, IObservable <string> textToMatch, IObservable <ScrollRequest> scrollRequest) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (textToMatch == null) { throw new ArgumentNullException(nameof(textToMatch)); } if (scrollRequest == null) { throw new ArgumentNullException(nameof(scrollRequest)); } // create list of lines which contain the observable text var matchedLines = textToMatch .Select(searchText => { Func <string, bool> predicate = null; if (!string.IsNullOrEmpty(searchText)) { // TODO: for now we use case insensitive search but we need to update it later on predicate = s => s.Contains(searchText, StringComparison.OrdinalIgnoreCase); } // todo: probably not the most efficient implementation to start reading the file all over again but works for now return(file.WatchFile().ScanFile(predicate)); }) .Switch() .Replay(1) // we use a replay here because we want to create a hot observable that all the subscribers share a single instance of .RefCount(); MatchedLinesCount = matchedLines.Select(x => x.MatchingLines.Length); // count of lines TotalLinesCount = matchedLines.Select(x => x.TotalLines); var lines = new SourceList <Line>(); // this is where the DynamicData magic happens! Lines = lines.AsObservableList(); // convert the sourceList to observableList // Dynamically combine lines requested by the consumer with the lines which exist in the file. This enables // proper virtualization of the file var scroller = matchedLines .CombineLatest(scrollRequest, (matched, request) => new { matched, request }) .Subscribe(x => { var mode = x.request.Mode; var pageSize = x.request.PageSize; var endOfTail = x.matched.EndOfTail; var isInitial = x.matched.Index == 0; var allLines = x.matched.MatchingLines; var previousPage = lines.Items.Select(l => l.Number).ToArray(); // if tailing, take the end only // otherwise take the page size and start index from the request var currentPage = (mode == ScrollingMode.Tail ? allLines.Skip(allLines.Length - pageSize).ToArray() : allLines.Skip(x.request.FirstIndex - 1).Take(pageSize)).ToArray(); var added = currentPage.Except(previousPage).ToArray(); var removed = previousPage.Except(currentPage).ToArray(); // read new lines from the file var addedLines = file.ReadLines(added, i => !isInitial && i > endOfTail).ToArray(); // get old lines from the current collection var removedLines = lines.Items.Where(l => removed.Contains(l.Number)).ToArray(); // finally relect changes in the list lines.Edit(innerList => { innerList.RemoveMany(removedLines); innerList.AddRange(addedLines); }); }); _cleanup = new CompositeDisposable(Lines, scroller, lines); }
public FileTailer(FileInfo file, IObservable<string> textToMatch, IObservable<ScrollRequest> scrollRequest, IScheduler scheduler=null) { if (file == null) throw new ArgumentNullException(nameof(file)); if (textToMatch == null) throw new ArgumentNullException(nameof(textToMatch)); var lines = new SourceList<Line>(); Lines = lines.AsObservableList(); var locker = new object(); scrollRequest = scrollRequest.Synchronize(locker); var metronome = Observable .Interval(TimeSpan.FromMilliseconds(250), scheduler ?? Scheduler.Default) .ToUnit() .Replay().RefCount(); //temp mess for a few days var indexer = file.WatchFile(metronome) .TakeWhile(notification => notification.Exists) .Repeat() .Index() .Synchronize(locker) .Replay(1).RefCount(); var matcher = textToMatch.Select(searchText => { if (string.IsNullOrEmpty(searchText) || searchText.Length < 3) return Observable.Return(LineMatches.None); return file.WatchFile(metronome) .TakeWhile(notification => notification.Exists) .Repeat() .Match(s => s.Contains(searchText, StringComparison.OrdinalIgnoreCase)); }).Switch() .Synchronize(locker) .Replay(1).RefCount(); //count matching lines (all if no filter is specified) MatchedLines = indexer.CombineLatest(matcher, (indicies, matches) => matches == LineMatches.None ? indicies.Count : matches.Count); //count total line TotalLines = indexer.Select(x => x.Count); FileSize = file.WatchFile(metronome).Select(notification => notification.Size); var aggregator = indexer.CombineLatest(matcher, scrollRequest,(idx, mtch, scroll) => new CombinedResult(scroll, mtch, idx)) .Select(result => { var scroll = result.Scroll; var indicies = result.Incidies; var matched = result.MatchedLines; IEnumerable<LineIndex> indices; if (result.MatchedLines.ChangedReason == LineMatchChangedReason.None) { indices = scroll.Mode == ScrollingMode.Tail ? indicies.GetTail(scroll) : indicies.GetFromIndex(scroll); } else { indices = scroll.Mode == ScrollingMode.Tail ? indicies.GetTail(scroll, matched) : indicies.GetFromIndex(scroll, matched); } var currentPage = indices.ToArray(); var previous = lines.Items.Select(l => l.LineIndex).ToArray(); var removed = previous.Except(currentPage).ToArray(); var removedLines = lines.Items.Where(l=> removed.Contains(l.LineIndex)).ToArray(); var added = currentPage.Except(previous).ToArray(); //finally we can load the line from the file var newLines = file.ReadLines(added, (lineIndex, text) => { var isEndOfTail = indicies.ChangedReason != LinesChangedReason.Loaded && lineIndex.Line > indicies.TailStartsAt; return new Line(lineIndex, text, isEndOfTail ? DateTime.Now : (DateTime?) null); }, indicies.Encoding).ToArray(); return new { NewLines = newLines, OldLines = removedLines }; }) .RetryWithBackOff((Exception error, int attempts) => { //todo: plug in file missing or error into the screen return TimeSpan.FromSeconds(1); }) .Where(fn=> fn.NewLines.Length + fn.OldLines.Length > 0) .Subscribe(changes => { //update observable list lines.Edit(innerList => { if (changes.OldLines.Any()) innerList.RemoveMany(changes.OldLines); if (changes.NewLines.Any()) innerList.AddRange(changes.NewLines); }); }); _cleanUp = new CompositeDisposable(Lines, lines, aggregator); }
public FileTailer(FileInfo file, IObservable <string> textToMatch, IObservable <ScrollRequest> scrollRequest, IScheduler scheduler = null) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (textToMatch == null) { throw new ArgumentNullException(nameof(textToMatch)); } //create list of lines which contain the observable text var matchedLines = textToMatch .Select(searchText => { Func <string, bool> predicate = null; if (!string.IsNullOrEmpty(searchText)) { predicate = s => s.Contains(searchText, StringComparison.OrdinalIgnoreCase); } return(file.WatchFile(scheduler: scheduler ?? Scheduler.Default) .TakeWhile(notification => notification.Exists) .Repeat() .ScanFile(predicate)); }).Switch() .Replay(1).RefCount(); MatchedLines = matchedLines.Select(x => x.MatchingLines.Length); TotalLines = matchedLines.Select(x => x.TotalLines); //todo: plug in file missing or error into the screen var lines = new SourceList <Line>(); Lines = lines.AsObservableList(); //this is the beast! Dynamically combine lines requested by the consumer //with the lines which exist in the file. This enables proper virtualisation of the file var scroller = matchedLines .CombineLatest(scrollRequest, (scanResult, request) => new { scanResult, request }) .Subscribe(x => { var mode = x.request.Mode; var pageSize = x.request.PageSize; var endOfTail = x.scanResult.EndOfTail; var isInitial = x.scanResult.Index == 0; var allLines = x.scanResult.MatchingLines; var previousPage = lines.Items.Select(l => new LineIndex(l.Number, l.Index)).ToArray(); //Otherwise take the page size and start index from the request var currentPage = (mode == ScrollingMode.Tail ? allLines.Skip(allLines.Length - pageSize).Take(pageSize).ToArray() : allLines.Skip(x.request.FirstIndex).Take(pageSize)).ToArray(); var added = currentPage.Except(previousPage).ToArray(); var removed = previousPage.Except(currentPage).Select(li => li.Line).ToArray(); if (added.Length + removed.Length == 0) { return; } try { var addedLines = file.ReadLines(added, (lineIndex, text) => { var isEndOfTail = !isInitial && lineIndex.Line > endOfTail; return(new Line(lineIndex.Line, lineIndex.Index, text, isEndOfTail ? DateTime.Now : (DateTime?)null)); }).ToArray(); //get old lines from the current collection var removedLines = lines.Items.Where(l => removed.Contains(l.Number)).ToArray(); //finally relect changes in the list lines.Edit(innerList => { innerList.RemoveMany(removedLines); innerList.AddRange(addedLines); }); } catch (Exception) { //Very small chance of an error here but if one is causght the next successful read will recify this //TODO: 1. Feedback to user that steaming has stopped //TODO: 2. Place the ReadLines(..) method with the select of an observable } }); _cleanUp = new CompositeDisposable(Lines, scroller, lines); }
public IObservableList <User> GetUsersStream() { return(_usersSource.AsObservableList()); }
public FileTailer(FileInfo file, IObservable<string> textToMatch, IObservable<ScrollRequest> scrollRequest, IScheduler scheduler=null) { if (file == null) throw new ArgumentNullException(nameof(file)); if (textToMatch == null) throw new ArgumentNullException(nameof(textToMatch)); var lines = new SourceList<Line>(); Lines = lines.AsObservableList(); var matcher = textToMatch.Select(searchText => { if (string.IsNullOrEmpty(searchText) || searchText.Length < 3) return Observable.Return(LineMatches.None); return file.WatchFile(scheduler: scheduler) .TakeWhile(notification => notification.Exists) .Repeat() .Match(s => s.Contains(searchText, StringComparison.OrdinalIgnoreCase)); }).Switch() .Replay(1).RefCount(); //temp mess for a few days var indexer = file.WatchFile(scheduler: scheduler) .TakeWhile(notification => notification.Exists) .Repeat() .Index() .Replay(1).RefCount(); //count matching lines (all if no filter is specified) MatchedLines = indexer.CombineLatest(matcher, (indicies, matches) => matches == LineMatches.None ? indicies.Count : matches.Count); //count total line TotalLines = indexer.Select(x => x.Count); //todo: plug in file missing or error into the screen var locker = new object(); var theBeast = indexer.Synchronize(locker) .CombineLatest(matcher.Synchronize(locker), scrollRequest.Synchronize(locker),(idx, mtch, scroll) => new CombinedResult(scroll, mtch, idx)) .Select(result => { var scroll = result.Scroll; var allLines = result.Incidies; var matched = result.MatchedLines; IEnumerable<LineIndex> indices; if (result.MatchedLines.ChangedReason == LineMatchChangedReason.None) { indices = scroll.Mode == ScrollingMode.Tail ? allLines.GetTail(scroll) : allLines.GetFromIndex(scroll); } else { indices = scroll.Mode == ScrollingMode.Tail ? allLines.GetTail(scroll, matched) : allLines.GetFromIndex(scroll, matched); } return file.ReadLines(indices, (lineIndex, text) => { var isEndOfTail = allLines.ChangedReason != LinesChangedReason.Loaded && lineIndex.Line > allLines.TailStartsAt; return new Line(lineIndex.Line, lineIndex.Index, text,isEndOfTail ? DateTime.Now : (DateTime?) null); }).ToArray(); }) //.RetryWithBackOff((error, attempts) => //{ // //TODO: Log // return TimeSpan.FromSeconds(1); //}) .Subscribe(newPage => { //update observable list lines.Edit(innerList => { var removed = innerList.Except(newPage).ToArray(); var added = newPage.Except(innerList).ToArray(); if (removed.Any()) innerList.RemoveMany(removed); if (added.Any()) innerList.AddRange(added); }); }); ////this is the beast! Dynamically combine lines requested by the consumer ////with the lines which exist in the file. This enables proper virtualisation of the file //var scroller = matchedLines // .CombineLatest(scrollRequest, (scanResult, request) => new {scanResult , request }) // .Subscribe(x => // { // var mode = x.request.Mode; // var pageSize = x.request.PageSize; // var endOfTail = x.scanResult.EndOfTail; // var isInitial = x.scanResult.Index==0; // var allLines = x.scanResult.MatchingLines; // var previousPage = lines.Items.Select(l => new LineIndex(l.Number, l.Index, 0, 0)).ToArray(); // //Otherwise take the page size and start index from the request // var currentPage = (mode == ScrollingMode.Tail // ? allLines.Skip(allLines.Length-pageSize).Take(pageSize).ToArray() // : allLines.Skip(x.request.FirstIndex).Take(pageSize)).ToArray(); // var added = currentPage.Except(previousPage).ToArray(); // var removed = previousPage.Except(currentPage).Select(li=>li.Line).ToArray(); // if (added.Length + removed.Length == 0) return; // try // { // var addedLines = file.ReadLines(added, (lineIndex, text) => // { // var isEndOfTail = !isInitial && lineIndex.Line > endOfTail; // return new Line(lineIndex.Line, lineIndex.Index, text, isEndOfTail ? DateTime.Now : (DateTime?)null); // }).ToArray(); // //get old lines from the current collection // var removedLines = lines.Items.Where(l => removed.Contains(l.Number)).ToArray(); // //finally relect changes in the list // lines.Edit(innerList => // { // innerList.RemoveMany(removedLines); // innerList.AddRange(addedLines); // }); // } // catch (Exception) // { // //Very small chance of an error here but if one is causght the next successful read will recify this // //TODO: 1. Feedback to user that steaming has stopped // //TODO: 2. Place the ReadLines(..) method with the select of an observable // } // }); _cleanUp = new CompositeDisposable(Lines, lines); }