@Override
  public void onBindViewHolder(ViewHolder holder, int position) {
    Gank gank = mGankList.get(position);
    if (position == 0) {
      showCategory(holder);
    } else {
      boolean theCategoryOfLastEqualsToThis =
          mGankList.get(position - 1).type.equals(mGankList.get(position).type);
      if (!theCategoryOfLastEqualsToThis) {
        showCategory(holder);
      } else {
        hideCategory(holder);
      }
    }
    holder.category.setText(gank.type);
    SpannableStringBuilder builder =
        new SpannableStringBuilder(gank.desc)
            .append(
                StringStyles.format(
                    holder.gank.getContext(),
                    " (via. " + gank.who + ")",
                    R.style.ViaTextAppearance));
    CharSequence gankText = builder.subSequence(0, builder.length());

    holder.gank.setText(gankText);
    showItemAnim(holder.gank, position);
  }
 /**
  * get real translate charsequence
  *
  * @param content
  * @return
  */
 public static CharSequence getTranslateTxt(CharSequence content) {
   StringBuilder sBuilder = new StringBuilder();
   if (content instanceof SpannableStringBuilder) {
     SpannableStringBuilder spanSb = (SpannableStringBuilder) content;
     if (spanSb.toString().contains(EMHolderEntity.FINAL_HOLDER)) {
       for (int i = 0; i < spanSb.length(); i++) {
         ReplacementSpan[] spans = spanSb.getSpans(i, i + 1, ReplacementSpan.class);
         if (spans.length > 0) {
           if (spans[0] instanceof EMImageSpan) {
             EMImageSpan imgSpan = (EMImageSpan) spans[0];
             sBuilder.append(imgSpan.mTransferTxt);
           } else if (spans[0] instanceof DefEmojSpan) {
             DefEmojSpan defSpan = (DefEmojSpan) spans[0];
             sBuilder.append(defSpan.mTransferTxt);
           }
         } else {
           sBuilder.append(spanSb.subSequence(i, i + 1));
         }
       }
     } else {
       sBuilder.append(content);
     }
   }
   return sBuilder;
 }
 public void hidePost(String reason) {
   hidden = true;
   imagesLayout.setVisibility(View.GONE);
   SpannableStringBuilder builder =
       new SpannableStringBuilder("\nСообщение скрыто: " + reason + "\n");
   builder.setSpan(
       new ClickableSpan() {
         @Override
         public void onClick(View widget) {
           unhidePost();
         }
       },
       1,
       builder.length(),
       0);
   messageView.setText(builder.subSequence(0, builder.length()));
   return;
 }
  @Override
  public void applySpan(HtmlSpanner spanner, SpannableStringBuilder builder) {

    if (useStyle.getFontFamily() != null
        || useStyle.getFontStyle() != null
        || useStyle.getFontWeight() != null) {

      FontFamilySpan originalSpan = getFontFamilySpan(builder, start, end);
      FontFamilySpan newSpan;

      if (useStyle.getFontFamily() == null && originalSpan == null) {
        newSpan = new FontFamilySpan(this.defaultFont);
      } else if (useStyle.getFontFamily() != null) {
        newSpan = new FontFamilySpan(useStyle.getFontFamily());
      } else {
        newSpan = new FontFamilySpan(originalSpan.getFontFamily());
      }

      if (useStyle.getFontWeight() != null) {
        newSpan.setBold(useStyle.getFontWeight() == Style.FontWeight.BOLD);
      } else if (originalSpan != null) {
        newSpan.setBold(originalSpan.isBold());
      }

      if (useStyle.getFontStyle() != null) {
        newSpan.setItalic(useStyle.getFontStyle() == Style.FontStyle.ITALIC);
      } else if (originalSpan != null) {
        newSpan.setItalic(originalSpan.isItalic());
      }

      // Log.d("StyleCallback", "Applying FontFamilySpan from " + start + " to " + end + " on text "
      // + builder.subSequence(start, end));
      // Log.d("StyleCallback", "FontFamilySpan: " + newSpan );

      builder.setSpan(newSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    // If there's no border, we use a BackgroundColorSpan to draw colour behind the text
    if (spanner.isUseColoursFromStyle()
        && useStyle.getBackgroundColor() != null
        && useStyle.getBorderStyle() == null) {
      // Log.d("StyleCallback", "Applying BackgroundColorSpan with color " +
      // useStyle.getBackgroundColor() + " from " + start + " to " + end + " on text " +
      // builder.subSequence(start, end));
      builder.setSpan(
          new BackgroundColorSpan(useStyle.getBackgroundColor()),
          start,
          end,
          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    // If there is a border, the BorderSpan will also draw the background colour if needed.
    if (useStyle.getBorderStyle() != null) {
      builder.setSpan(
          new BorderSpan(useStyle, start, end, spanner.isUseColoursFromStyle()),
          start,
          end,
          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    if (useStyle.getFontSize() != null) {

      StyleValue styleValue = useStyle.getFontSize();

      if (styleValue.getUnit() == StyleValue.Unit.PS) {
        if (styleValue.getFloatValue() > 0) {
          // Log.d("StyleCallback", "Applying AbsoluteFloatSizeSpan with size " +
          // useStyle.getAbsoluteFontSize() + " from " + start + " to " + end + " on text " +
          // builder.subSequence(start, end));
          builder.setSpan(
              new AbsoluteFloatSizeSpan(styleValue.getFloatValue()),
              start,
              end,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
      } else if (styleValue.getUnit() == StyleValue.Unit.PX) {
        if (styleValue.getIntValue() > 0) {
          // Log.d("StyleCallback", "Applying AbsoluteSizeSpan with size " +
          // useStyle.getAbsoluteFontSize() + " from " + start + " to " + end + " on text " +
          // builder.subSequence(start, end));
          builder.setSpan(
              new AbsoluteSizeSpan(styleValue.getIntValue()),
              start,
              end,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
      } else {
        if (styleValue.getFloatValue() > 0f) {
          // Log.d("StyleCallback", "Applying RelativeSizeSpan with size " +
          // useStyle.getRelativeFontSize() + " from " + start + " to " + end + " on text " +
          // builder.subSequence(start, end));
          builder.setSpan(
              new RelativeSizeSpan(styleValue.getFloatValue()),
              start,
              end,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
      }
    }

    if (spanner.isUseColoursFromStyle() && useStyle.getColor() != null) {
      // Log.d("StyleCallback", "Applying ForegroundColorSpan from " + start + " to " + end + " on
      // text " + builder.subSequence(start, end) );
      builder.setSpan(
          new ForegroundColorSpan(useStyle.getColor()),
          start,
          end,
          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    if (useStyle.getTextAlignment() != null) {

      AlignmentSpan alignSpan = null;

      switch (useStyle.getTextAlignment()) {
        case LEFT:
          alignSpan = new AlignNormalSpan();
          break;
        case CENTER:
          alignSpan = new CenterSpan();
          break;
        case RIGHT:
          alignSpan = new AlignOppositeSpan();
          break;
      }

      // Log.d("StyleCallback", "Applying AlignmentSpan from " + start + " to " + end + " on text "
      // + builder.subSequence(start, end) );
      builder.setSpan(alignSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    if (useStyle.getTextIndent() != null) {

      StyleValue styleValue = useStyle.getTextIndent();

      int marginStart = start;
      while (marginStart < end && builder.charAt(marginStart) == '\n') {
        marginStart++;
      }

      int marginEnd = min(end, marginStart + 1);

      Log.d(
          "StyleCallback",
          "Applying LeadingMarginSpan from "
              + marginStart
              + " to "
              + marginEnd
              + " on text "
              + builder.subSequence(marginStart, marginEnd));

      if (styleValue.getUnit() == StyleValue.Unit.PX) {
        if (styleValue.getIntValue() > 0) {
          builder.setSpan(
              new LeadingMarginSpan.Standard(styleValue.getIntValue(), 0),
              marginStart,
              marginEnd,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

      } else {
        if (styleValue.getFloatValue() > 0f) {
          builder.setSpan(
              new LeadingMarginSpan.Standard(
                  (int) (HtmlSpanner.HORIZONTAL_EM_WIDTH * styleValue.getFloatValue()), 0),
              marginStart,
              marginEnd,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
      }
    }

    /* We ignore negative horizontal margins, since that would cause the text to be rendered off-screen */
    if (useStyle.getMarginLeft() != null) {
      StyleValue styleValue = useStyle.getMarginLeft();

      if (styleValue.getUnit() == StyleValue.Unit.PX) {
        if (styleValue.getIntValue() > 0) {
          builder.setSpan(
              new LeadingMarginSpan.Standard(styleValue.getIntValue()),
              start,
              end,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

      } else if (styleValue.getFloatValue() > 0f) {
        builder.setSpan(
            new LeadingMarginSpan.Standard(
                (int) (HtmlSpanner.HORIZONTAL_EM_WIDTH * styleValue.getFloatValue())),
            start,
            end,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
      }
    }
  }
  @Override
  public void setObject(Item item) {
    try {
      dobroitem = (DobroPostItem) item;
    } catch (ClassCastException e) {
      e.printStackTrace();
      return;
    }
    if (dobroitem == null || dobroitem.post == null) return;
    dobroitem.post.setLastContext(getContext());
    this.board = dobroitem.post.getBoardName();
    this.thread = dobroitem.post.getThreadDisplay_id();
    ((HorizontalScrollView) findViewById(R.id.horizScroll)).scrollTo(0, 0);

    CharSequence txt = dobroitem.post.getFormattedText();
    if (txt.length() > 800) {
      Pattern p1 = Pattern.compile("\\.|\n");
      Matcher m1 = p1.matcher(txt);
      Pattern p2 = Pattern.compile("\\b");
      Matcher m2 = p2.matcher(txt);
      if (m1.find(500) && m1.end() < 700) txt = txt.subSequence(0, m1.end());
      else if (m2.find(500) && m2.start() < 700) txt = txt.subSequence(0, m2.start());
      else txt = txt.subSequence(0, 500);
      messageView.setText(txt, BufferType.SPANNABLE);
      SpannableStringBuilder builder =
          new SpannableStringBuilder("\nСообщение слишком длинное. Полная версия");
      builder.setSpan(
          new ClickableSpan() {
            @Override
            public void onClick(View widget) {
              try {
                messageView.setText(dobroitem.post.getFormattedText(), BufferType.SPANNABLE);
              } catch (IndexOutOfBoundsException e) {

              }
            }
          },
          1,
          builder.length(),
          0);
      messageView.append(builder.subSequence(0, builder.length()));
    } else messageView.setText(txt, BufferType.SPANNABLE);
    // FIXME
    messageView.setMovementMethod(LinkMovementMethod.getInstance());
    messageView.setClickable(false);
    messageView.setFocusable(false);
    messageView.setFocusableInTouchMode(false);
    /*
    refsView.setMovementMethod(LinkMovementMethod.getInstance());
    refsView.setClickable(false);
    refsView.setFocusable(false);
    refsView.setFocusableInTouchMode(false);
    */
    //
    imagesLayout.removeAllViewsInLayout();
    if (dobroitem.post.isOp()) {
      numberView.setVisibility(GONE);
      titleView.setText(
          dobroitem.post.getSubject().length() == 0
              ? getContext().getString(R.string.untitled)
              : dobroitem.post.getSubject());
      titleView.setVisibility(VISIBLE);
    } else {
      int pos = dobroitem.post.getNumber();
      if (pos > 0) {
        numberView.setVisibility(VISIBLE);
        numberView.setText(String.valueOf(pos));
      } else numberView.setVisibility(GONE);
      titleView.setText("");
      titleView.setVisibility(GONE);
    }

    TypedValue backgroundRef = new TypedValue();
    getContext().getTheme().resolveAttribute(R.attr.dcPicrelatedColor, backgroundRef, true);
    int backgroundColor = getContext().getResources().getColor(backgroundRef.resourceId);
    SharedPreferences prefs = DobroApplication.getApplicationStatic().getDefaultPrefs();
    boolean show_info = prefs.getBoolean("show_fileinfo", true);
    boolean force_op_load = prefs.getBoolean("op_pictures_force", false);

    if (dobroitem.post.getFiles().length > 0) {
      for (DobroFile file : dobroitem.post.getFiles()) {
        CachedAsyncImageView imageView = new CachedAsyncImageView(getContext());
        VerticalTextView textView = null;
        String fname1 = file.getThumb().substring(file.getThumb().lastIndexOf("/") + 1);
        int e = fname1.lastIndexOf("s.");
        if (e > 0)
          fname1 = fname1.substring(0, e) + file.getSrc().substring(file.getSrc().lastIndexOf("."));
        String fname2 = file.getSrc().substring(file.getSrc().lastIndexOf("/") + 1);
        String size = humanReadableByteCount(file.getSize(), true);
        String date = getThumbnailDate(file.getThumb());
        if (date == null)
          try {
            date = file.getSrc().split("/")[2];
            date = date.substring(2) + "." + date.substring(0, 2);
          } catch (Exception ex) {
            date = "?";
          }
        imageView.setInfo(
            getContext()
                .getString(
                    R.string.file_info_parretn,
                    fname1,
                    fname2,
                    size,
                    date,
                    file.getRating(),
                    getMetadataText(file.getMetadata())));
        if (file.getMetadata().width != null)
          imageView.setSize(file.getMetadata().height, file.getMetadata().width);
        if (show_info) {
          textView = new VerticalTextView(getContext(), null);
          textView.setLinkedImageView(imageView);
          String text = "";
          if (dobroitem.post.getBoardName().equals("b")
              || dobroitem.post.getBoardName().equals("rf")) text += fname1;
          else text += fname2;
          text += "\n" + size;
          if (file.getMetadata() != null
              && file.getMetadata().width != null
              && file.getMetadata().height != null) {
            text +=
                ", "
                    + String.valueOf(file.getMetadata().width)
                    + "x"
                    + String.valueOf(file.getMetadata().height);
          }
          textView.setText(text);
          textView.setGravity(Gravity.BOTTOM);
          textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
        }
        imageView.setRating(file.getRat());
        imageView.setForceLoad(force_op_load && dobroitem.post.isOp());
        imageView.setUrl(file.getThumb());
        final String urlTag = file.getSrc();
        imageView.setTag(urlTag);
        imageView.setPadding(2, 2, 2, 2);
        imageView.setAdjustViewBounds(true);
        imageView.setMaxHeight(mImageHeight);
        imageView.setMaxWidth(mImageHeight);
        imageView.setBackgroundColor(backgroundColor);
        imageView.setScaleType(ScaleType.CENTER);
        imageView.setOnCreateContextMenuListener(imageView);
        float h = mImageHeight;
        int w =
            Math.min(
                Math.round((h / (float) file.getThumb_height()) * file.getThumb_width()),
                file.getThumb_width());
        imageView.setLayoutParams(new LayoutParams(w + 4, mImageHeight + 4));
        if (show_info) {
          textView.setWidth(mImageHeight + 4);
          textView.setLinkedImageView(imageView);
          imagesLayout.addView(textView);
        }
        imagesLayout.addView(imageView);
      }
      imagesLayout.setVisibility(VISIBLE);
    } else {
      imagesLayout.setVisibility(GONE);
    }
    if (prefs.getBoolean("youtube", true)) {
      Spanned s = null;
      boolean cast_ok = false;
      try {
        s = (Spanned) dobroitem.post.getFormattedText();
        cast_ok = true;
      } catch (ClassCastException e) {
        cast_ok = false;
      }
      if (cast_ok) {
        URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
        for (URLSpan span : spans) {
          String url = span.getURL();
          Pattern p = Pattern.compile("(youtube\\.com/watch\\?v=|youtu\\.be/)(\\S{11})");
          Matcher m = p.matcher(url);
          if (!m.find()) continue;
          String yt_id = m.group(2);
          String text = s.subSequence(s.getSpanStart(span), s.getSpanEnd(span)).toString();
          CachedAsyncImageView imageView = new CachedAsyncImageView(getContext());
          imageView.setLayoutParams(
              new LayoutParams((int) ((mImageHeight + 4) / 0.75), mImageHeight + 4));

          imageView.setRating(Rating.SWF);
          imageView.setForceLoad(false);
          imageView.setTag(url);
          imageView.setPadding(2, 2, 2, 2);
          imageView.setAdjustViewBounds(true);
          imageView.setMaxHeight(mImageHeight);
          imageView.setMaxWidth((int) ((mImageHeight + 4) / 0.75));

          imageView.setUrl("http://img.youtube.com/vi/" + yt_id + "/0.jpg");

          imageView.setBackgroundColor(backgroundColor);
          imageView.setScaleType(ScaleType.CENTER);

          VerticalTextView textView = new VerticalTextView(getContext(), null);
          textView.setGravity(Gravity.BOTTOM);
          textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
          textView.setText(text);
          textView.setLinkedImageView(imageView);
          textView.setWidth(mImageHeight + 4);

          if (show_info) imagesLayout.addView(textView);
          imagesLayout.addView(imageView);
          imagesLayout.setVisibility(VISIBLE);
        }
      }
    }
    metadataRightView.setText(
        getContext()
            .getString(
                R.string.post_date, String.valueOf(dobroitem.post.getDate().replace(' ', '\n'))));
    metadataLeftView.setText(
        dobroitem.post.getName()
            + "\n"
            + getContext()
                .getString(R.string.post_id, String.valueOf(dobroitem.post.getDisplay_id())));
    List<String> refs = dobroitem.post.getRefs();
    if (!refs.isEmpty()) {
      /*
      CharSequence seq = getContext().getText(R.string.answers);
      SpannableStringBuilder s = new SpannableStringBuilder(seq);
      s.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, seq.length(), 0);
      s.append(" ");
      for (String ref : refs) {
      	int start = s.length();
      	s.append(ref + ", ");
      	s.setSpan(
      			new DobroLinkSpan(dobroitem.post.getBoardName(), ref
      					.substring(2), getContext(), null), start, start
      					+ ref.length(), 0);
      }
      refsView.setText(s.subSequence(0, s.length() - 2),
      		BufferType.SPANNABLE);
       */
      refsButton.setText(String.format("/%d", refs.size()));
      refsButton.setVisibility(View.VISIBLE);
    } else refsButton.setVisibility(View.GONE);
    checkSpells();
  }