internal override void BeginReplicating()
        {
            // If we're still waiting to create the remote db, do nothing now. (This method will be
            // re-invoked after that request finishes; see maybeCreateRemoteDB() above.)
            if (_creatingTarget)
            {
                Log.To.Sync.D(TAG, "creatingTarget == true, doing nothing");
                return;
            }

            _pendingSequences = new SortedDictionary <long, int>();
            if (!Int64.TryParse(LastSequence, out _maxPendingSequence))
            {
                Log.To.Sync.W(TAG, "{0} is not a valid last sequence, using 0", LastSequence);
                _maxPendingSequence = 0;
            }

            if (Filter != null)
            {
                _filter = LocalDatabase.GetFilter(Filter);
            }
            else
            {
                // If not filter function was provided, but DocIds were
                // specified, then only push the documents listed in the
                // DocIds property. It is assumed that if the users
                // specified both a filter name and doc ids that their
                // custom filter function will handle that. This is
                // consistent with the iOS behavior.
                if (DocIds != null && DocIds.Any())
                {
                    _filter = (rev, filterParams) => DocIds.Contains(rev.Document.Id);
                }
            }

            if (Filter != null && _filter == null)
            {
                Log.To.Sync.W(TAG, "{0}: No ReplicationFilter registered for filter '{1}'; ignoring", this, Filter);
            }

            // Process existing changes since the last push:
            long lastSequenceLong = 0;

            if (LastSequence != null)
            {
                lastSequenceLong = long.Parse(LastSequence);
            }

            if (ReplicationOptions.PurgePushed)
            {
                _purgeQueue = new Batcher <RevisionInternal>(new BatcherOptions <RevisionInternal> {
                    WorkExecutor = WorkExecutor,
                    Capacity     = EphemeralPurgeBatchSize,
                    Delay        = EphemeralPurgeDelay,
                    Processor    = PurgeRevs,
                    TokenSource  = CancellationTokenSource
                });
            }

            // Now listen for future changes (in continuous mode):
            // Note:  This needs to happen before adding the observer
            // or else there is a race condition.
            // A document could be added between the call to
            // ChangesSince and adding the observer, which would result
            // in a document being skipped
            if (Continuous)
            {
                _observing             = true;
                LocalDatabase.Changed += OnChanged;
            }

            var options = ChangesOptions.Default;

            options.IncludeConflicts = true;
            var  changes  = LocalDatabase.ChangesSinceStreaming(lastSequenceLong, options, _filter, FilterParams);
            bool hasItems = changes.Any();

            foreach (var change in changes)
            {
                Batcher.QueueObject(change);
                if (Status == ReplicationStatus.Stopped)
                {
                    Batcher.Clear();
                    return;
                }
            }

            if (hasItems)
            {
                Batcher.Flush();
            }

            if (Continuous)
            {
                if (!hasItems)
                {
                    Log.To.Sync.V(TAG, "No changes to push, switching to idle...");
                    FireTrigger(ReplicationTrigger.WaitingForChanges);
                }
            }
            else
            {
                if (!hasItems)
                {
                    Log.To.Sync.V(TAG, "No changes to push, firing StopGraceful...");
                    FireTrigger(ReplicationTrigger.StopGraceful);
                }
            }
        }