protected ThreadModel[] readWakabaPage(
      String url,
      ProgressListener listener,
      CancellableTask task,
      boolean checkModified,
      UrlPageModel urlModel)
      throws Exception {
    HttpResponseModel responseModel = null;
    WakabaReader in = null;
    HttpRequestModel rqModel =
        HttpRequestModel.builder()
            .setGET()
            .setCheckIfModified(checkModified)
            .setNoRedirect(wakabaNoRedirect())
            .build();
    try {
      responseModel =
          HttpStreamer.getInstance().getFromUrl(url, rqModel, httpClient, listener, task);
      if (responseModel.statusCode == 200) {
        in = getWakabaReader(responseModel.stream, urlModel);
        if (task != null && task.isCancelled()) throw new Exception("interrupted");
        return in.readWakabaPage();
      } else {
        if (responseModel.notModified()) return null;

        if (canCloudflare()) {
          String html = null;
          try {
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
            IOUtils.copyStream(responseModel.stream, byteStream);
            html = byteStream.toString("UTF-8");
          } catch (Exception e) {
          }
          if (html != null) {
            if (responseModel.statusCode == 403 && html.contains("CAPTCHA")) {
              throw CloudflareException.withRecaptcha(
                  CLOUDFLARE_RECAPTCHA_KEY,
                  getUsingUrl() + CLOUDFLARE_RECAPTCHA_CHECK_URL_FMT,
                  CLOUDFLARE_COOKIE_NAME,
                  getChanName());
            } else if (responseModel.statusCode == 503 && html.contains("Just a moment...")) {
              throw CloudflareException.antiDDOS(url, CLOUDFLARE_COOKIE_NAME, getChanName());
            }
          }
        }
        throw new HttpWrongStatusCodeException(
            responseModel.statusCode,
            responseModel.statusCode + " - " + responseModel.statusReason);
      }
    } catch (Exception e) {
      if (responseModel != null) HttpStreamer.getInstance().removeFromModifiedMap(url);
      throw e;
    } finally {
      IOUtils.closeQuietly(in);
      if (responseModel != null) responseModel.release();
    }
  }
 public SerializablePage loadPage(InputStream in) {
   synchronized (serializeLock) {
     Input input = null;
     try {
       input = new Input(in);
       input.readString();
       kryo.readObject(input, UrlPageModel.class);
       return kryo.readObject(input, SerializablePage.class);
     } finally {
       IOUtils.closeQuietly(input);
     }
   }
 }
 public Pair<String, UrlPageModel> loadPageInfo(InputStream in) {
   synchronized (serializeLock) {
     Input input = null;
     try {
       input = new Input(in);
       String title = input.readString();
       UrlPageModel pageModel = kryo.readObject(input, UrlPageModel.class);
       return Pair.of(title, pageModel);
     } finally {
       IOUtils.closeQuietly(input);
     }
   }
 }
 public void savePage(
     OutputStream out, String title, UrlPageModel pageModel, SerializablePage page) {
   synchronized (serializeLock) {
     Output output = null;
     try {
       output = isHoneycomb() ? new KryoOutputHC(out) : new Output(out);
       output.writeString(title);
       kryo.writeObject(output, pageModel);
       kryo.writeObject(output, page);
     } finally {
       IOUtils.closeQuietly(output);
     }
   }
 }
  @Override
  public String sendPost(SendPostModel model, ProgressListener listener, CancellableTask task)
      throws Exception {
    String url = getUsingUrl() + "board.php";
    ExtendedMultipartBuilder postEntityBuilder =
        ExtendedMultipartBuilder.create()
            .setDelegates(listener, task)
            .addString("board", model.boardName)
            .addString("replythread", model.threadNumber == null ? "0" : model.threadNumber)
            .addString("em", model.sage ? "sage" : model.email)
            .addString("subject", model.subject)
            .addString("message", model.comment)
            .addString("recaptcha_response_field", model.captchaAnswer);
    if (model.attachments != null && model.attachments.length > 0)
      postEntityBuilder.addFile("imagefile", model.attachments[0], model.randomHash);
    else if (model.threadNumber == null) postEntityBuilder.addString("nofile", "on");

    postEntityBuilder.addString("postpassword", model.password);

    HttpRequestModel request =
        HttpRequestModel.builder().setPOST(postEntityBuilder.build()).setNoRedirect(true).build();
    HttpResponseModel response = null;
    try {
      response = HttpStreamer.getInstance().getFromUrl(url, request, httpClient, null, task);
      if (response.statusCode == 302) {
        for (Header header : response.headers) {
          if (header != null && HttpHeaders.LOCATION.equalsIgnoreCase(header.getName())) {
            return fixRelativeUrl(header.getValue());
          }
        }
      } else if (response.statusCode == 200) {
        ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
        IOUtils.copyStream(response.stream, output);
        String htmlResponse = output.toString("UTF-8");
        Matcher errorMatcher = ERROR_POSTING.matcher(htmlResponse);
        if (errorMatcher.find()) throw new Exception(errorMatcher.group(1).trim());
      } else throw new Exception(response.statusCode + " - " + response.statusReason);
    } finally {
      if (response != null) response.release();
    }
    return null;
  }
  private <T> T deserialize(File file, Class<T> type) {
    if (file == null || !file.exists()) {
      return null;
    }

    synchronized (serializeLock) {
      Input input = null;
      try {
        input = new Input(new FileInputStream(file));
        return kryo.readObject(input, type);
      } catch (Exception e) {
        Logger.e(TAG, e);
      } catch (OutOfMemoryError oom) {
        MainApplication.freeMemory();
        Logger.e(TAG, oom);
      } finally {
        IOUtils.closeQuietly(input);
      }
    }

    return null;
  }
 @Override
 public void run() {
   synchronized (serializeLock) {
     File file = fileCache.create(filename);
     Output output = null;
     try {
       output =
           isHoneycomb()
               ? new KryoOutputHC(new FileOutputStream(file))
               : new Output(new FileOutputStream(file));
       kryo.writeObject(output, obj);
     } catch (Exception e) {
       Logger.e(TAG, e);
     } catch (OutOfMemoryError oom) {
       MainApplication.freeMemory();
       Logger.e(TAG, oom);
     } finally {
       IOUtils.closeQuietly(output);
     }
     fileCache.put(file);
   }
 }