/** Pulls bitmap from diskcache */
 private @Nullable ParcelFileDescriptor createPipe(final ArtInfo artInfo) {
   final byte[] bytes = mL2Cache.getBytes(artInfo.cacheKey());
   if (bytes == null) {
     return null;
   }
   try {
     final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
     final OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
     final ParcelFileDescriptor in = pipe[0];
     final Scheduler.Worker worker = mScheduler.createWorker();
     worker.schedule(
         new Action0() {
           @Override
           public void call() {
             try {
               IOUtils.write(bytes, out);
               out.flush();
             } catch (IOException e) {
               Timber.w("createPipe(e=%s) for %s", e.getMessage(), artInfo);
             } finally {
               IOUtils.closeQuietly(out);
               worker.unsubscribe();
             }
           }
         });
     return in;
   } catch (IOException e) {
     Timber.e(e, "createPipe() for %s", artInfo);
     return null;
   }
 }
  /**
   * Eagerly creates a pipe, then blocks on a background thread while we wait for the fetcher to
   * return the bitmap, simply closing the pipe if no art was found
   */
  private @Nullable ParcelFileDescriptor createPipe2(final ArtInfo artInfo) {
    try {
      final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
      final OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
      final ParcelFileDescriptor in = pipe[0];
      final Scheduler.Worker worker = mScheduler.createWorker();
      worker.schedule(
          new Action0() {
            @Override
            public void call() {
              OptionalBitmap bitmap = null;
              ArtworkFetcherService.Connection binder = null;
              try {
                // make a new request and wait for it to come in.
                binder = ArtworkFetcherService.bindService(getContext());
                final BlockingQueue<OptionalBitmap> queue = new LinkedBlockingQueue<>(1);
                final CompletionListener listener =
                    new CompletionListener() {
                      @Override
                      public void onError(Throwable e) {
                        Timber.w("onError(%s) for %s", e.getMessage(), artInfo);
                        queue.offer(new OptionalBitmap(null));
                      }

                      @Override
                      public void onNext(Bitmap o) {
                        queue.offer(new OptionalBitmap(o));
                      }
                    };
                if (!binder.getService().newRequest(artInfo, listener)) {
                  throw new InterruptedException("Enqueue failed");
                }
                bitmap = queue.take();
                if (bitmap.hasBitmap()) {
                  byte[] bytes = mL2Cache.bitmapToBytes(bitmap.getBitmap());
                  IOUtils.write(bytes, out);
                  out.flush();
                }
              } catch (InterruptedException | IOException e) {
                Timber.w("createPipe2(e=%s) for %s", e.getMessage(), artInfo);
                if (binder != null) {
                  binder.getService().cancelRequest(artInfo);
                }
              } finally {
                if (bitmap != null) bitmap.recycle();
                IOUtils.closeQuietly(binder);
                IOUtils.closeQuietly(out);
                worker.unsubscribe();
              }
            }
          });
      return in;
    } catch (IOException e) {
      Timber.e(e, "createPipe2() for %s", artInfo);
      return null;
    }
  }
 /**
  * Publishes a response with the attached observable.
  *
  * @param response the response to publish.
  * @param observable pushing into the event sink.
  */
 protected void publishResponse(
     final CouchbaseResponse response,
     final Subject<CouchbaseResponse, CouchbaseResponse> observable) {
   if (response.status() != ResponseStatus.RETRY && observable != null) {
     final Scheduler.Worker worker = env().scheduler().createWorker();
     worker.schedule(
         new Action0() {
           @Override
           public void call() {
             try {
               observable.onNext(response);
               observable.onCompleted();
             } catch (Exception ex) {
               LOGGER.warn("Caught exception while onNext on observable", ex);
               observable.onError(ex);
             } finally {
               worker.unsubscribe();
             }
           }
         });
   } else {
     responseBuffer.publishEvent(ResponseHandler.RESPONSE_TRANSLATOR, response, observable);
   }
 }