private static SourceEnd addStream(SourceEnd src) {

    SinkEnd snk = createPair();

    Replicator r2 = new Replicator();
    AsyncDrain ad = new AsyncDrain();

    r2.getSource().connect(snk);
    src.connect(r2.getSink1());
    ad.getSource1().connect(r2.getSink2());

    return ad.getSource2();
  }
  private static SinkEnd createPair() {
    Writer wrt = new ContinuousWriter(1);
    //        {
    //            @Override
    //            public void updateState() {
    //                System.out.println("updating <"+getEnds().get(0).getName()+">");
    //                if (limit == 1)
    //                    System.out.println("<"+getEnds().get(0).getName()+">");
    //                super.updateState();
    //            }
    //        };
    //        OwnerManager.register(wrt.getSink());
    writers[counter] = wrt.getSink();
    counter++;

    Reader rdr =
        new ContinuousReader(1) {
          @Override
          public void updateState() {
            //                System.out.println("updating ["+getEnds().get(0).getName()+"]");
            //                System.out.println("["+getEnds().get(0).getName()+"/"+limit+"(before
            // update)]");
            if (limit == 1) {
              //                    System.out.println("["+getEnds().get(0).getName()+"]");
              PairwiseAsynchrounous.pending--;
              if (PairwiseAsynchrounous.pending == 0) {
                System.out.print((System.currentTimeMillis() - PairwiseAsynchrounous.start) + ", ");
                if (thread != null) PairwiseAsynchrounous.thread.interrupt();
                //                        OwnerManager.kill();
              }
            }
            super.updateState();
          }

          @Override
          public String toString() {
            return "CReader" + super.toString();
          }
        };

    Replicator r1 = new Replicator();

    wrt.getSink().connect(r1.getSource());
    r1.getSink1().connect(rdr.getSource());

    return r1.getSink2();
  }
    @Override
    public synchronized Replicator get() {
      if (replicator == null) {
        LocalStore localStore = injector.getInstance(localStoreKey);
        HttpClient httpClient = injector.getInstance(httpClientKey);
        StoreConfig storeConfig = injector.getInstance(storeConfigKey);

        replicator =
            new Replicator(
                name, nodeInfo, serviceSelector, httpClient, localStore, storeConfig, monitor);
        replicator.start();
      }

      return replicator;
    }
  @Test
  public void demonstrateDelete() {
    probe = new JavaTestKit(system);

    // #delete
    final ActorRef replicator = DistributedData.get(system).replicator();
    final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
    final Key<ORSet<String>> set2Key = ORSetKey.create("set2");

    replicator.tell(new Delete<PNCounter>(counter1Key, Replicator.writeLocal()), self());

    final WriteConsistency writeMajority = new WriteMajority(Duration.create(5, SECONDS));
    replicator.tell(new Delete<PNCounter>(counter1Key, writeMajority), self());
    // #delete
  }
 @PreDestroy
 public synchronized void shutdown() {
   if (replicator != null) {
     replicator.shutdown();
   }
 }
  @Test
  public void demonstrateUpdate() {
    probe = new JavaTestKit(system);

    // #update
    final Cluster node = Cluster.get(system);
    final ActorRef replicator = DistributedData.get(system).replicator();

    final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
    final Key<GSet<String>> set1Key = GSetKey.create("set1");
    final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
    final Key<Flag> activeFlagKey = FlagKey.create("active");

    replicator.tell(
        new Replicator.Update<PNCounter>(
            counter1Key,
            PNCounter.create(),
            Replicator.writeLocal(),
            curr -> curr.increment(node, 1)),
        self());

    final WriteConsistency writeTo3 = new WriteTo(3, Duration.create(1, SECONDS));
    replicator.tell(
        new Replicator.Update<GSet<String>>(
            set1Key, GSet.create(), writeTo3, curr -> curr.add("hello")),
        self());

    final WriteConsistency writeMajority = new WriteMajority(Duration.create(5, SECONDS));
    replicator.tell(
        new Replicator.Update<ORSet<String>>(
            set2Key, ORSet.create(), writeMajority, curr -> curr.add(node, "hello")),
        self());

    final WriteConsistency writeAll = new WriteAll(Duration.create(5, SECONDS));
    replicator.tell(
        new Replicator.Update<Flag>(
            activeFlagKey, Flag.create(), writeAll, curr -> curr.switchOn()),
        self());
    // #update

    probe.expectMsgClass(UpdateSuccess.class);
    // #update-response1
    receive(
        ReceiveBuilder.match(
                UpdateSuccess.class,
                a -> a.key().equals(counter1Key),
                a -> {
                  // ok
                })
            .build());
    // #update-response1

    // #update-response2
    receive(
        ReceiveBuilder.match(
                UpdateSuccess.class,
                a -> a.key().equals(set1Key),
                a -> {
                  // ok
                })
            .match(
                UpdateTimeout.class,
                a -> a.key().equals(set1Key),
                a -> {
                  // write to 3 nodes failed within 1.second
                })
            .build());
    // #update-response2
  }
  @SuppressWarnings({"unused", "unchecked"})
  @Test
  public void demonstrateGet() {
    probe = new JavaTestKit(system);

    // #get
    final ActorRef replicator = DistributedData.get(system).replicator();
    final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
    final Key<GSet<String>> set1Key = GSetKey.create("set1");
    final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
    final Key<Flag> activeFlagKey = FlagKey.create("active");

    replicator.tell(new Replicator.Get<PNCounter>(counter1Key, Replicator.readLocal()), self());

    final ReadConsistency readFrom3 = new ReadFrom(3, Duration.create(1, SECONDS));
    replicator.tell(new Replicator.Get<GSet<String>>(set1Key, readFrom3), self());

    final ReadConsistency readMajority = new ReadMajority(Duration.create(5, SECONDS));
    replicator.tell(new Replicator.Get<ORSet<String>>(set2Key, readMajority), self());

    final ReadConsistency readAll = new ReadAll(Duration.create(5, SECONDS));
    replicator.tell(new Replicator.Get<Flag>(activeFlagKey, readAll), self());
    // #get

    // #get-response1
    receive(
        ReceiveBuilder.match(
                GetSuccess.class,
                a -> a.key().equals(counter1Key),
                a -> {
                  GetSuccess<PNCounter> g = a;
                  BigInteger value = g.dataValue().getValue();
                })
            .match(
                NotFound.class,
                a -> a.key().equals(counter1Key),
                a -> {
                  // key counter1 does not exist
                })
            .build());
    // #get-response1

    // #get-response2
    receive(
        ReceiveBuilder.match(
                GetSuccess.class,
                a -> a.key().equals(set1Key),
                a -> {
                  GetSuccess<GSet<String>> g = a;
                  Set<String> value = g.dataValue().getElements();
                })
            .match(
                GetFailure.class,
                a -> a.key().equals(set1Key),
                a -> {
                  // read from 3 nodes failed within 1.second
                })
            .match(
                NotFound.class,
                a -> a.key().equals(set1Key),
                a -> {
                  // key set1 does not exist
                })
            .build());
    // #get-response2

  }