text:
namespace tesseract {

static INT_VAR(textord_tabfind_show_images, false, "Show image blobs");

// Fraction of width or height of on pixels that can be discarded from a
// roughly rectangular image.
const double kMinRectangularFraction = 0.125;
// Fraction of width or height to consider image completely used.
const double kMaxRectangularFraction = 0.75;
// Fraction of width or height to allow transition from kMinRectangularFraction
// to kMaxRectangularFraction, equivalent to a dy/dx skew.
const double kMaxRectangularGradient = 0.1; // About 6 degrees.
// Minimum image size to be worth looking for images on.
const int kMinImageFindSize = 100;
// Pixel padding for noise blobs and partitions when rendering on the image
// mask to encourage them to join together. Make it too big and images
// will fatten out too much and have to be clipped to text.
const int kNoisePadding = 4;

// Scans horizontally on x=[x_start,x_end), starting with y=*y_start,
// stepping y+=y_step, until y=y_end. *ystart is input/output.
// If the number of black pixels in a row, pix_count fits this pattern:
// 0 or more rows with pix_count < min_count then
// <= mid_width rows with min_count <= pix_count <= max_count then
// a row with pix_count > max_count then
// true is returned, and *y_start = the first y with pix_count >= min_count.
static bool HScanForEdge(uint32_t *data, int wpl, int x_start, int x_end, int min_count,
                         int mid_width, int max_count, int y_end, int y_step, int *y_start) {
  int mid_rows = 0;
  for (int y = *y_start; y != y_end; y += y_step) {
    // Need pixCountPixelsInRow(pix, y, &pix_count, nullptr) to count in a
    // subset.
    int pix_count = 0;
    uint32_t *line = data + wpl * y;
    for (int x = x_start; x < x_end; ++x) {
      if (GET_DATA_BIT(line, x)) {
        ++pix_count;
      }
    }
    if (mid_rows == 0 && pix_count < min_count) {
      continue; // In the min phase.
    }
    if (mid_rows == 0) {
      *y_start = y; // Save the y_start where we came out of the min phase.
    }
    if (pix_count > max_count) {
      return true; // Found the pattern.
    }
    ++mid_rows;
    if (mid_rows > mid_width) {
      break; // Middle too big.
    }
  }
  return false; // Never found max_count.
}

// Scans vertically on y=[y_start,y_end), starting with x=*x_start,
// stepping x+=x_step, until x=x_end. *x_start is input/output.
// If the number of black pixels in a column, pix_count fits this pattern:
// 0 or more cols with pix_count < min_count then
// <= mid_width cols with min_count <= pix_count <= max_count then
// a column with pix_count > max_count then
// true is returned, and *x_start = the first x with pix_count >= min_count.
static bool VScanForEdge(uint32_t *data, int wpl, int y_start, int y_end, int min_count,
                         int mid_width, int max_count, int x_end, int x_step, int *x_start) {
  int mid_cols = 0;
  for (int x = *x_start; x != x_end; x += x_step) {
    int pix_count = 0;
    uint32_t *line = data + y_start * wpl;
    for (int y = y_start; y < y_end; ++y, line += wpl) {
      if (GET_DATA_BIT(line, x)) {
        ++pix_count;
      }
    }
    if (mid_cols == 0 && pix_count < min_count) {
      continue; // In the min phase.
    }
    if (mid_cols == 0) {
      *x_start = x; // Save the place where we came out of the min phase.
    }
    if (pix_count > max_count) {
      return true; // found the pattern.
    }
    ++mid_cols;
    if (mid_cols > mid_width) {
      break; // Middle too big.
    }
  }
  return false; // Never found max_count.
}

// Returns true if there is a rectangle in the source pix, such that all
// pixel rows and column slices outside of it have less than
// min_fraction of the pixels black, and within max_skew_gradient fraction
// of the pixels on the inside, there are at least max_fraction of the
// pixels black. In other words, the inside of the rectangle looks roughly
// rectangular, and the outside of it looks like extra bits.
// On return, the rectangle is defined by x_start, y_start, x_end and y_end.
// Note: the algorithm is iterative, allowing it to slice off pixels from
// one edge, allowing it to then slice off more pixels from another edge.
static bool pixNearlyRectangular(Image pix, double min_fraction, double max_fraction,
                                 double max_skew_gradient, int *x_start, int *y_start,
                                 int *x_end, int *y_end) {
  ASSERT_HOST(pix != nullptr);
  *x_start = 0;
  *x_end = pixGetWidth(pix);
  *y_start = 0;
  *y_end = pixGetHeight(pix);

  uint32_t *data = pixGetData(pix);
  int wpl = pixGetWpl(pix);
  bool any_cut = false;
  bool left_done = false;
  bool right_done = false;
  bool top_done = false;
  bool bottom_done = false;
  do {
    any_cut = false;
    // Find the top/bottom edges.
    int width = *x_end - *x_start;
    int min_count = static_cast<int>(width * min_fraction);
    int max_count = static_cast<int>(width * max_fraction);
    int edge_width = static_cast<int>(width * max_skew_gradient);
    if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width, max_count, *y_end, 1,
                     y_start) &&
        !top_done) {
      top_done = true;
      any_cut = true;
    }
    --(*y_end);
    if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width, max_count, *y_start, -1,
                     y_end) &&
        !bottom_done) {
      bottom_done = true;
      any_cut = true;
    }
    ++(*y_end);

    // Find the left/right edges.
    int height = *y_end - *y_start;
    min_count = static_cast<int>(height * min_fraction);
    max_count = static_cast<int>(height * max_fraction);
    edge_width = static_cast<int>(height * max_skew_gradient);
    if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width, max_count, *x_end, 1,
                     x_start) &&
        !left_done) {
      left_done = true;
      any_cut = true;
    }
    --(*x_end);
    if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width, max_count, *x_start, -1,
                     x_end) &&
        !right_done) {
      right_done = true;
      any_cut = true;
    }
    ++(*x_end);
  } while (any_cut);

  // All edges must satisfy the condition of sharp gradient in pixel density
  // in order for the full rectangle to be present.
  return left_done && right_done && top_done && bottom_done;
}

// Generates a Boxa, Pixa pair from the input binary (image mask) pix,
// analogous to pixConnComp, except that connected components which are nearly
// rectangular are replaced with solid rectangles.
// The returned boxa, pixa may be nullptr, meaning no images found.
// If not nullptr, they must be destroyed by the caller.
// Resolution of pix should match the source image (Tesseract::pix_binary_)
// so the output coordinate systems match.
static void ConnCompAndRectangularize(Image pix, DebugPixa *pixa_debug, Boxa **boxa,
                                      Pixa **pixa) {
  *boxa = nullptr;
  *pixa = nullptr;

  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pix, "Conncompimage");
  }
  // Find the individual image regions in the mask image.
  *boxa = pixConnComp(pix, pixa, 8);
  // Rectangularize the individual images. If a sharp edge in vertical and/or
  // horizontal occupancy can be found, it indicates a probably rectangular
  // image with unwanted bits merged on, so clip to the approximate rectangle.
  int npixes = 0;
  if (*boxa != nullptr && *pixa != nullptr) {
    npixes = pixaGetCount(*pixa);
  }
  for (int i = 0; i < npixes; ++i) {
    int x_start, x_end, y_start, y_end;
    Image img_pix = pixaGetPix(*pixa, i, L_CLONE);
    if (textord_tabfind_show_images && pixa_debug != nullptr) {
      pixa_debug->AddPix(img_pix, "A component");
    }
    if (pixNearlyRectangular(img_pix, kMinRectangularFraction, kMaxRectangularFraction,
                             kMaxRectangularGradient, &x_start, &y_start, &x_end, &y_end)) {
      Image simple_pix = pixCreate(x_end - x_start, y_end - y_start, 1);
      pixSetAll(simple_pix);
      img_pix.destroy();
      // pixaReplacePix takes ownership of the simple_pix.
      pixaReplacePix(*pixa, i, simple_pix, nullptr);
      img_pix = pixaGetPix(*pixa, i, L_CLONE);
      // Fix the box to match the new pix.
      l_int32 x, y, width, height;
      boxaGetBoxGeometry(*boxa, i, &x, &y, &width, &height);
      Box *simple_box = boxCreate(x + x_start, y + y_start, x_end - x_start, y_end - y_start);
      boxaReplaceBox(*boxa, i, simple_box);
    }
    img_pix.destroy();
  }
}

// Finds image regions within the BINARY source pix (page image) and returns
// the image regions as a mask image.
// The returned pix may be nullptr, meaning no images found.
// If not nullptr, it must be PixDestroyed by the caller.
// If textord_tabfind_show_images, debug images are appended to pixa_debug.
Image ImageFind::FindImages(Image pix, DebugPixa *pixa_debug) {
  // Not worth looking at small images.
  if (pixGetWidth(pix) < kMinImageFindSize || pixGetHeight(pix) < kMinImageFindSize) {
    return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
  }

  // Reduce by factor 2.
  Image pixr = pixReduceRankBinaryCascade(pix, 1, 0, 0, 0);
  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pixr, "CascadeReduced");
  }

  // Get the halftone mask directly from Leptonica.
  //
  // Leptonica will print an error message and return nullptr if we call
  // pixGenHalftoneMask(pixr, nullptr, ...) with too small image, so we
  // want to bypass that.
  if (pixGetWidth(pixr) < kMinImageFindSize || pixGetHeight(pixr) < kMinImageFindSize) {
    pixr.destroy();
    return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
  }
  // Get the halftone mask.
  l_int32 ht_found = 0;
  Pixa *pixadb = (textord_tabfind_show_images && pixa_debug != nullptr) ? pixaCreate(0) : nullptr;
  Image pixht2 = pixGenerateHalftoneMask(pixr, nullptr, &ht_found, pixadb);
  if (pixadb) {
    Image pixdb = pixaDisplayTiledInColumns(pixadb, 3, 1.0, 20, 2);
    if (textord_tabfind_show_images && pixa_debug != nullptr) {
      pixa_debug->AddPix(pixdb, "HalftoneMask");
    }
    pixdb.destroy();
    pixaDestroy(&pixadb);
  }
  pixr.destroy();
  if (!ht_found && pixht2 != nullptr) {
    pixht2.destroy();
  }
  if (pixht2 == nullptr) {
    return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
  }

  // Expand back up again.
  Image pixht = pixExpandReplicate(pixht2, 2);
  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pixht, "HalftoneReplicated");
  }
  pixht2.destroy();

  // Fill to capture pixels near the mask edges that were missed
  Image pixt = pixSeedfillBinary(nullptr, pixht, pix, 8);
  pixht |= pixt;
  pixt.destroy();

  // Eliminate lines and bars that may be joined to images.
  Image pixfinemask = pixReduceRankBinaryCascade(pixht, 1, 1, 3, 3);
  pixDilateBrick(pixfinemask, pixfinemask, 5, 5);
  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pixfinemask, "FineMask");
  }
  Image pixreduced = pixReduceRankBinaryCascade(pixht, 1, 1, 1, 1);
  Image pixreduced2 = pixReduceRankBinaryCascade(pixreduced, 3, 3, 3, 0);
  pixreduced.destroy();
  pixDilateBrick(pixreduced2, pixreduced2, 5, 5);
  Image pixcoarsemask = pixExpandReplicate(pixreduced2, 8);
  pixreduced2.destroy();
  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pixcoarsemask, "CoarseMask");
  }
  // Combine the coarse and fine image masks.
  pixcoarsemask &= pixfinemask;
  pixfinemask.destroy();
  // Dilate a bit to make sure we get everything.
  pixDilateBrick(pixcoarsemask, pixcoarsemask, 3, 3);
  Image pixmask = pixExpandReplicate(pixcoarsemask, 16);
  pixcoarsemask.destroy();
  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pixmask, "MaskDilated");
  }
  // And the image mask with the line and bar remover.
  pixht &= pixmask;
  pixmask.destroy();
  if (textord_tabfind_show_images && pixa_debug != nullptr) {
    pixa_debug->AddPix(pixht, "FinalMask");
  }
  // Make the result image the same size as the input.
  Image result = pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
  result |= pixht;
  pixht.destroy();
  return result;
}

// Given an input pix, and a bounding rectangle, the sides of the rectangle
// are shrunk inwards until they bound any black pixels found within the
// original rectangle. Returns false if the rectangle contains no black
// pixels at all.
bool ImageFind::BoundsWithinRect(Image pix, int *x_start, int *y_start, int *x_end, int *y_end) {
  Box *input_box = boxCreate(*x_start, *y_start, *x_end - *x_start, *y_end - *y_start);
  Box *output_box = nullptr;
  pixClipBoxToForeground(pix, input_box, nullptr, &output_box);
  bool result = output_box != nullptr;
  if (result) {
    l_int32 x, y, width, height;
    boxGetGeometry(output_box, &x, &y, &width, &height);
    *x_start = x;
    *y_start = y;
    *x_end = x + width;
    *y_end = y + height;
    boxDestroy(&output_box);
  }
  boxDestroy(&input_box);
  return result;
}

// Given a point in 3-D (RGB) space, returns the squared Euclidean distance
// of the point from the given line, defined by a pair of points in the 3-D
// (RGB) space, line1 and line2.
double ImageFind::ColorDistanceFromLine(const uint8_t *line1, const uint8_t *line2,
                                        const uint8_t *point) {
  int line_vector[kRGBRMSColors];
  int point_vector[kRGBRMSColors];
  for (int i = 0; i < kRGBRMSColors; ++i) {
    line_vector[i] = static_cast<int>(line2[i]) - static_cast<int>(line1[i]);
    point_vector[i] = static_cast<int>(point[i]) - static_cast<int>(line1[i]);
  }
  line_vector[L_ALPHA_CHANNEL] = 0;
  // Now the cross product in 3d.
  int cross[kRGBRMSColors];
  cross[COLOR_RED] = line_vector[COLOR_GREEN] * point_vector[COLOR_BLUE] -
                     line_vector[COLOR_BLUE] * point_vector[COLOR_GREEN];
  cross[COLOR_GREEN] = line_vector[COLOR_BLUE] * point_vector[COLOR_RED] -
                       line_vector[COLOR_RED] * point_vector[COLOR_BLUE];
  cross[COLOR_BLUE] = line_vector[COLOR_RED] * point_vector[COLOR_GREEN] -
                      line_vector[COLOR_GREEN] * point_vector[COLOR_RED];
  cross[L_ALPHA_CHANNEL] = 0;
  // Now the sums of the squares.
  double cross_sq = 0.0;
  double line_sq = 0.0;
  for (int j = 0; j < kRGBRMSColors; ++j) {
    cross_sq += static_cast<double>(cross[j]) * cross[j];
    line_sq += static_cast<double>(line_vector[j]) * line_vector[j];
  }
  if (line_sq == 0.0) {
    return 0.0;
  }
  return cross_sq / line_sq; // This is the squared distance.
}

// ================ CUTTING POLYGONAL IMAGES FROM A RECTANGLE ================
// The following functions are responsible for cutting a polygonal image from
// a rectangle: CountPixelsInRotatedBox, AttemptToShrinkBox, CutChunkFromParts
// with DivideImageIntoParts as the master.
// Problem statement:
// We start with a single connected component from the image mask: we get
// a Pix of the component, and its location on the page (im_box).
// The objective of cutting a polygonal image from its rectangle is to avoid
// interfering text, but not text that completely overlaps the image.
//     ------------------------------      ------------------------------
//     |   Single input partition   |      | 1 Cut up output partitions |
//     |                            |      ------------------------------
//   Av|oid                         |    Avoid |                        |
//     |                            |          |________________________|
//  Int|erfering                    |   Interfering  |                  |
//     |                            |           _____|__________________|
//    T|ext                         |     Text |                        |
//     |        Text-on-image       |          |     Text-on-image      |
//     ------------------------------          --------------------------
// DivideImageIntoParts does this by building a ColPartition_LIST (not in the
// grid) with each ColPartition representing one of the rectangles needed,
// starting with a single rectangle for the whole image component, and cutting
// bits out of it with CutChunkFromParts as needed to avoid text. The output
// ColPartitions are supposed to be ordered from top to bottom.

// The problem is complicated by the fact that we have rotated the coordinate
// system to make text lines horizontal, so if we need to look at the component
// image, we have to rotate the coordinates. Throughout the functions in this
// section im_box is the rectangle representing the image component in the
// rotated page coordinates (where we are building our output ColPartitions),
// rotation is the rotation that we used to get there, and rerotation is the
// rotation required to get back to original page image coordinates.
// To get to coordinates in the component image, pix, we rotate the im_box,
// the point we want to locate, and subtract the rotated point from the top-left
// of the rotated im_box.
// im_box is therefore essential to calculating coordinates within the pix.

// Returns true if there are no black pixels in between the boxes.
// The im_box must represent the bounding box of the pix in tesseract
// coordinates, which may be negative, due to rotations to make the textlines
// horizontal. The boxes are rotated by rotation, which should undo such
// rotations, before mapping them onto the pix.
bool ImageFind::BlankImageInBetween(const TBOX &box1, const TBOX &box2, const TBOX &im_box,
                                    const FCOORD &rotation, Image pix) {
  TBOX search_box(box1);
  search_box += box2;
  if (box1.x_gap(box2) >= box1.y_gap(box2)) {
    if (box1.x_gap(box2) <= 0) {
      return true;
    }
    search_box.set_left(std::min(box1.right(), box2.right()));
    search_box.set_right(std::max(box1.left(), box2.left()));
  } else {
    if (box1.y_gap(box2) <= 0) {
      return true;
    }
    search_box.set_top(std::max(box1.bottom(), box2.bottom()));
    search_box.set_bottom(std::min(box1.top(), box2.top()));
  }
  return CountPixelsInRotatedBox(search_box, im_box, rotation, pix) == 0;
}

// Returns the number of pixels in box in the pix.
// rotation, pix and im_box are defined in the large comment above.
int ImageFind::CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation,
                                       Image pix) {
  // Intersect it with the image box.
  box &= im_box; // This is in-place box intersection.
  if (box.null_box()) {
    return 0;
  }
  box.rotate(rotation);
  TBOX rotated_im_box(im_box);
  rotated_im_box.rotate(rotation);
  Image rect_pix = pixCreate(box.width(), box.height(), 1);
  pixRasterop(rect_pix, 0, 0, box.width(), box.height(), PIX_SRC, pix,
              box.left() - rotated_im_box.left(), rotated_im_box.top() - box.top());
  l_int32 result;
  pixCountPixels(rect_pix, &result, nullptr);
  rect_pix.destroy();
  return result;
}

// The box given by slice contains some black pixels, but not necessarily
// over the whole box. Shrink the x bounds of slice, but not the y bounds
// until there is at least one black pixel in the outermost columns.
// rotation, rerotation, pix and im_box are defined in the large comment above.
static void AttemptToShrinkBox(const FCOORD &rotation, const FCOORD &rerotation, const TBOX &im_box,
                               Image pix, TBOX *slice) {
  TBOX rotated_box(*slice);
  rotated_box.rotate(rerotation);
  TBOX rotated_im_box(im_box);
  rotated_im_box.rotate(rerotation);
  int left = rotated_box.left() - rotated_im_box.left();
  int right = rotated_box.right() - rotated_im_box.left();
  int top = rotated_im_box.top() - rotated_box.top();
  int bottom = rotated_im_box.top() - rotated_box.bottom();
  ImageFind::BoundsWithinRect(pix, &left, &top, &right, &bottom);
  top = rotated_im_box.top() - top;
  bottom = rotated_im_box.top() - bottom;
  left += rotated_im_box.left();
  right += rotated_im_box.left();
  rotated_box.set_to_given_coords(left, bottom, right, top);
  rotated_box.rotate(rotation);
  slice->set_left(rotated_box.left());
  slice->set_right(rotated_box.right());
}

// The meat of cutting a polygonal image around text.
// This function covers the general case of cutting a box out of a box
// as shown:
// Input                               Output
// ------------------------------      ------------------------------
// |   Single input partition   |      | 1 Cut up output partitions |
// |                            |      ------------------------------
// |         ----------         |      ---------           ----------
// |         |  box   |         |      |   2   |   box     |    3   |
// |         |        |         |      |       |  is cut   |        |
// |         ----------         |      ---------   out     ----------
// |                            |      ------------------------------
// |                            |      |   4                        |
// ------------------------------      ------------------------------
// In the context that this function is used, at most 3 of the above output
// boxes will be created, as the overlapping box is never contained by the
// input.
// The above cutting operation is executed for each element of part_list that
// is overlapped by the input box. Each modified ColPartition is replaced
// in place in the list by the output of the cutting operation in the order
// shown above, so iff no holes are ever created, the output will be in
// top-to-bottom order, but in extreme cases, hole creation is possible.
// In such cases, the output order may cause strange block polygons.
// rotation, rerotation, pix and im_box are defined in the large comment above.
static void CutChunkFromParts(const TBOX &box, const TBOX &im_box, const FCOORD &rotation,
                              const FCOORD &rerotation, Image pix, ColPartition_LIST *part_list) {
  ASSERT_HOST(!part_list->empty());
  ColPartition_IT part_it(part_list);
  do {
    ColPartition *part = part_it.data();
    TBOX part_box = part->bounding_box();
    if (part_box.overlap(box)) {
      // This part must be cut and replaced with the remains. There are
      // up to 4 pieces to be made. Start with the first one and use
      // add_before_stay_put. For each piece if it has no black pixels
      // left, just don't make the box.
      // Above box.
      if (box.top() < part_box.top()) {
        TBOX slice(part_box);
        slice.set_bottom(box.top());
        if (ImageFind::CountPixelsInRotatedBox(slice, im_box, rerotation, pix) > 0) {
          AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
          part_it.add_before_stay_put(
              ColPartition::FakePartition(slice, PT_UNKNOWN, BRT_POLYIMAGE, BTFT_NONTEXT));
        }
      }
      // Left of box.
      if (box.left() > part_box.left()) {
        TBOX slice(part_box);
        slice.set_right(box.left());
        if (box.top() < part_box.top()) {
          slice.set_top(box.top());
        }
        if (box.bottom() > part_box.bottom()) {
          slice.set_bottom(box.bottom());
        }
        if (ImageFind::CountPixelsInRotatedBox(slice, im_box, rerotation, pix) > 0) {
          AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
          part_it.add_before_stay_put(
              ColPartition::FakePartition(slice, PT_UNKNOWN, BRT_POLYIMAGE, BTFT_NONTEXT));
        }
      }
      // Right of box.
      if (box.right() < part_box.right()) {
        TBOX slice(part_box);
        slice.set_left(box.right());
        if (box.top() < part_box.top()) {
          slice.set_top(box.top());
        }
        if (box.bottom() > part_box.bottom()) {
          slice.set_bottom(box.bottom());
        }
        if (ImageFind::CountPixelsInRotatedBox(slice, im_box, rerotation, pix) > 0) {
          AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
          part_it.add_before_stay_put(
              ColPartition::FakePartition(slice, PT_UNKNOWN, BRT_POLYIMAGE, BTFT_NONTEXT));
        }
      }
      // Below box.
      if (box.bottom() > part_box.bottom()) {
        TBOX slice(part_box);
        slice.set_top(box.bottom());
        if (ImageFind::CountPixelsInRotatedBox(slice, im_box, rerotation, pix) > 0) {
          AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
          part_it.add_before_stay_put(
              ColPartition::FakePartition(slice, PT_UNKNOWN, BRT_POLYIMAGE, BTFT_NONTEXT));
        }
      }
      part->DeleteBoxes();
      delete part_it.extract();
    }
    part_it.forward();
  } while (!part_it.at_first());
}

// Starts with the bounding box of the image component and cuts it up
// so that it doesn't intersect text where possible.
// Strong fully contained horizontal text is marked as text on image,
// and does not cause a division of the image.
// For more detail see the large comment above on cutting polygonal images
// from a rectangle.
// rotation, rerotation, pix and im_box are defined in the large comment above.
static void DivideImageIntoParts(const TBOX &im_box, const FCOORD &rotation,
                                 const FCOORD &rerotation, Image pix,
                                 ColPartitionGridSearch *rectsearch, ColPartition_LIST *part_list) {
  // Add the full im_box partition to the list to begin with.
  ColPartition *pix_part =
      ColPartition::FakePartition(im_box, PT_UNKNOWN, BRT_RECTIMAGE, BTFT_NONTEXT);
  ColPartition_IT part_it(part_list);
  part_it.add_after_then_move(pix_part);

  rectsearch->StartRectSearch(im_box);
  ColPartition *part;
  while ((part = rectsearch->NextRectSearch()) != nullptr) {
    TBOX part_box = part->bounding_box();
    if (part_box.contains(im_box) && part->flow() >= BTFT_CHAIN) {
      // This image is completely covered by an existing text partition.
      for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
        ColPartition *pix_part = part_it.extract();
        pix_part->DeleteBoxes();
        delete pix_part;
      }
    } else if (part->flow() == BTFT_STRONG_CHAIN) {
      // Text intersects the box.
      TBOX overlap_box = part_box.intersection(im_box);
      // Intersect it with the image box.
      int black_area = ImageFind::CountPixelsInRotatedBox(overlap_box, im_box, rerotation, pix);
      if (black_area * 2 < part_box.area() || !im_box.contains(part_box)) {
        // Eat a piece out of the image.
        // Pad it so that pieces eaten out look decent.
        int padding = part->blob_type() == BRT_VERT_TEXT ? part_box.width() : part_box.height();
        part_box.set_top(part_box.top() + padding / 2);
        part_box.set_bottom(part_box.bottom() - padding / 2);
        CutChunkFromParts(part_box, im_box, rotation, rerotation, pix, part_list);
      } else {
        // Strong overlap with the black area, so call it text on image.
        part->set_flow(BTFT_TEXT_ON_IMAGE);
      }
    }
    if (part_list->empty()) {
      break;
    }
  }
}

// Search for the rightmost text that overlaps vertically and is to the left
// of the given box, but within the given left limit.
static int ExpandImageLeft(const TBOX &box, int left_limit, ColPartitionGrid *part_grid) {
  ColPartitionGridSearch search(part_grid);
  ColPartition *part;
  // Search right to left for any text that overlaps.
  search.StartSideSearch(box.left(), box.bottom(), box.top());
  while ((part = search.NextSideSearch(true)) != nullptr) {
    if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
      const TBOX &part_box(part->bounding_box());
      if (part_box.y_gap(box) < 0) {
        if (part_box.right() > left_limit && part_box.right() < box.left()) {
          left_limit = part_box.right();
        }
        break;
      }
    }
  }
  if (part != nullptr) {
    // Search for the nearest text up to the one we already found.
    TBOX search_box(left_limit, box.bottom(), box.left(), box.top());
    search.StartRectSearch(search_box);
    while ((part = search.NextRectSearch()) != nullptr) {
      if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
        const TBOX &part_box(part->bounding_box());
        if (part_box.y_gap(box) < 0) {
          if (part_box.right() > left_limit && part_box.right() < box.left()) {
            left_limit = part_box.right();
          }
        }
      }
    }
  }
  return left_limit;
}

// Search for the leftmost text that overlaps vertically and is to the right
// of the given box, but within the given right limit.
static int ExpandImageRight(const TBOX &box, int right_limit, ColPartitionGrid *part_grid) {
  ColPartitionGridSearch search(part_grid);
  ColPartition *part;
  // Search left to right for any text that overlaps.
  search.StartSideSearch(box.right(), box.bottom(), box.top());
  while ((part = search.NextSideSearch(false)) != nullptr) {
    if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
      const TBOX &part_box(part->bounding_box());
      if (part_box.y_gap(box) < 0) {
        if (part_box.left() < right_limit && part_box.left() > box.right()) {
          right_limit = part_box.left();
        }
        break;
      }
    }
  }
  if (part != nullptr) {
    // Search for the nearest text up to the one we already found.
    TBOX search_box(box.left(), box.bottom(), right_limit, box.top());
    search.StartRectSearch(search_box);
    while ((part = search.NextRectSearch()) != nullptr) {
      if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
        const TBOX &part_box(part->bounding_box());
        if (part_box.y_gap(box) < 0) {
          if (part_box.left() < right_limit && part_box.left() > box.right()) {
            right_limit = part_box.left();
          }
        }
      }
    }
  }
  return right_limit;
}

// Search for the topmost text that overlaps horizontally and is below
// the given box, but within the given bottom limit.
static int ExpandImageBottom(const TBOX &box, int bottom_limit, ColPartitionGrid *part_grid) {
  ColPartitionGridSearch search(part_grid);
  ColPartition *part;
  // Search right to left for any text that overlaps.
  search.StartVerticalSearch(box.left(), box.right(), box.bottom());
  while ((part = search.NextVerticalSearch(true)) != nullptr) {
    if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
      const TBOX &part_box(part->bounding_box());
      if (part_box.x_gap(box) < 0) {
        if (part_box.top() > bottom_limit && part_box.top() < box.bottom()) {
          bottom_limit = part_box.top();
        }
        break;
      }
    }
  }
  if (part != nullptr) {
    // Search for the nearest text up to the one we already found.
    TBOX search_box(box.left(), bottom_limit, box.right(), box.bottom());
    search.StartRectSearch(search_box);
    while ((part = search.NextRectSearch()) != nullptr) {
      if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
        const TBOX &part_box(part->bounding_box());
        if (part_box.x_gap(box) < 0) {
          if (part_box.top() > bottom_limit && part_box.top() < box.bottom()) {
            bottom_limit = part_box.top();
          }
        }
      }
    }
  }
  return bottom_limit;
}

// Search for the bottommost text that overlaps horizontally and is above
// the given box, but within the given top limit.
static int ExpandImageTop(const TBOX &box, int top_limit, ColPartitionGrid *part_grid) {
  ColPartitionGridSearch search(part_grid);
  ColPartition *part;
  // Search right to left for any text that overlaps.
  search.StartVerticalSearch(box.left(), box.right(), box.top());
  while ((part = search.NextVerticalSearch(false)) != nullptr) {
    if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
      const TBOX &part_box(part->bounding_box());
      if (part_box.x_gap(box) < 0) {
        if (part_box.bottom() < top_limit && part_box.bottom() > box.top()) {
          top_limit = part_box.bottom();
        }
        break;
      }
    }
  }
  if (part != nullptr) {
    // Search for the nearest text up to the one we already found.
    TBOX search_box(box.left(), box.top(), box.right(), top_limit);
    search.StartRectSearch(search_box);
    while ((part = search.NextRectSearch()) != nullptr) {
      if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_CHAIN) {
        const TBOX &part_box(part->bounding_box());
        if (part_box.x_gap(box) < 0) {
          if (part_box.bottom() < top_limit && part_box.bottom() > box.top()) {
            top_limit = part_box.bottom();
          }
        }
      }
    }
  }
  return top_limit;
}

// Expands the image box in the given direction until it hits text,
// limiting the expansion to the given limit box, returning the result
// in the expanded box, and
// returning the increase in area resulting from the expansion.
static int ExpandImageDir(BlobNeighbourDir dir, const TBOX &im_box, const TBOX &limit_box,
                          ColPartitionGrid *part_grid, TBOX *expanded_box) {
  *expanded_box = im_box;
  switch (dir) {
    case BND_LEFT:
      expanded_box->set_left(ExpandImageLeft(im_box, limit_box.left(), part_grid));
      break;
    case BND_RIGHT:
      expanded_box->set_right(ExpandImageRight(im_box, limit_box.right(), part_grid));
      break;
    case BND_ABOVE:
      expanded_box->set_top(ExpandImageTop(im_box, limit_box.top(), part_grid));
      break;
    case BND_BELOW:
      expanded_box->set_bottom(ExpandImageBottom(im_box, limit_box.bottom(), part_grid));
      break;
    default:
      return 0;
  }
  return expanded_box->area() - im_box.area();
}

// Expands the image partition into any non-text until it touches text.
// The expansion proceeds in the order of increasing increase in area
// as a heuristic to find the best rectangle by expanding in the most
// constrained direction first.
static void MaximalImageBoundingBox(ColPartitionGrid *part_grid, TBOX *im_box) {
  bool dunnit[BND_COUNT];
  memset(dunnit, 0, sizeof(dunnit));
  TBOX limit_box(part_grid->bleft().x(), part_grid->bleft().y(), part_grid->tright().x(),
                 part_grid->tright().y());
  TBOX text_box(*im_box);
  for (int iteration = 0; iteration < BND_COUNT; ++iteration) {
    // Find the direction with least area increase.
    int best_delta = -1;
    BlobNeighbourDir best_dir = BND_LEFT;
    TBOX expanded_boxes[BND_COUNT];
    for (int dir = 0; dir < BND_COUNT; ++dir) {
      auto bnd = static_cast<BlobNeighbourDir>(dir);
      if (!dunnit[bnd]) {
        TBOX expanded_box;
        int area_delta = ExpandImageDir(bnd, text_box, limit_box, part_grid, &expanded_boxes[bnd]);
        if (best_delta < 0 || area_delta < best_delta) {
          best_delta = area_delta;
          best_dir = bnd;
        }
      }
    }
    // Run the best and remember the direction.
    dunnit[best_dir] = true;
    text_box = expanded_boxes[best_dir];
  }
  *im_box = text_box;
}

// Helper deletes the given partition but first marks up all the blobs as
// noise, so they get deleted later, and disowns them.
// If the initial type of the partition is image, then it actually deletes
// the blobs, as the partition owns them in that case.
static void DeletePartition(ColPartition *part) {
  BlobRegionType type = part->blob_type();
  if (type == BRT_RECTIMAGE || type == BRT_POLYIMAGE) {
    // The partition owns the boxes of these types, so just delete them.
    part->DeleteBoxes(); // From a previous iteration.
  } else {
    // Once marked, the blobs will be swept up by TidyBlobs.
    part->set_flow(BTFT_NONTEXT);
    part->set_blob_type(BRT_NOISE);
    part->SetBlobTypes();
    part->DisownBoxes(); // Created before FindImagePartitions.
  }
  delete part;
}

// The meat of joining fragmented images and consuming ColPartitions of
// uncertain type.
// *part_ptr is an input/output BRT_RECTIMAGE ColPartition that is to be
// expanded to consume overlapping and nearby ColPartitions of uncertain type
// and other BRT_RECTIMAGE partitions, but NOT to be expanded beyond
// max_image_box. *part_ptr is NOT in the part_grid.
// rectsearch is already constructed on the part_grid, and is used for
// searching for overlapping and nearby ColPartitions.
// ExpandImageIntoParts is called iteratively until it returns false. Each
// time it absorbs the nearest non-contained candidate, and everything that
// is fully contained within part_ptr's bounding box.
// TODO(rays) what if it just eats everything inside max_image_box in one go?
static bool ExpandImageIntoParts(const TBOX &max_image_box, ColPartitionGridSearch *rectsearch,
                                 ColPartitionGrid *part_grid, ColPartition **part_ptr) {
  ColPartition *image_part = *part_ptr;
  TBOX im_part_box = image_part->bounding_box();
  if (textord_tabfind_show_images > 1) {
    tprintf("Searching for merge with image part:");
    im_part_box.print();
    tprintf("Text box=");
    max_image_box.print();
  }
  rectsearch->StartRectSearch(max_image_box);
  ColPartition *part;
  ColPartition *best_part = nullptr;
  int best_dist = 0;
  while ((part = rectsearch->NextRectSearch()) != nullptr) {
    if (textord_tabfind_show_images > 1) {
      tprintf("Considering merge with part:");
      part->Print();
      if (im_part_box.contains(part->bounding_box())) {
        tprintf("Fully contained\n");
      } else if (!max_image_box.contains(part->bounding_box())) {
        tprintf("Not within text box\n");
      } else if (part->flow() == BTFT_STRONG_CHAIN) {
        tprintf("Too strong text\n");
      } else {
        tprintf("Real candidate\n");
      }
    }
    if (part->flow() == BTFT_STRONG_CHAIN || part->flow() == BTFT_TEXT_ON_IMAGE ||
        part->blob_type() == BRT_POLYIMAGE) {
      continue;
    }
    TBOX box = part->bounding_box();
    if (max_image_box.contains(box) && part->blob_type() != BRT_NOISE) {
      if (im_part_box.contains(box)) {
        // Eat it completely.
        rectsearch->RemoveBBox();
        DeletePartition(part);
        continue;
      }
      int x_dist = std::max(0, box.x_gap(im_part_box));
      int y_dist = std::max(0, box.y_gap(im_part_box));
      int dist = x_dist * x_dist + y_dist * y_dist;
      if (dist > box.area() || dist > im_part_box.area()) {
        continue; // Not close enough.
      }
      if (best_part == nullptr || dist < best_dist) {
        // We keep the nearest qualifier, which is not necessarily the nearest.
        best_part = part;
        best_dist = dist;
      }
    }
  }
  if (best_part != nullptr) {
    // It needs expanding. We can do it without touching text.
    TBOX box = best_part->bounding_box();
    if (textord_tabfind_show_images > 1) {
      tprintf("Merging image part:");
      im_part_box.print();
      tprintf("with part:");
      box.print();
    }
    im_part_box += box;
    *part_ptr = ColPartition::FakePartition(im_part_box, PT_UNKNOWN, BRT_RECTIMAGE, BTFT_NONTEXT);
    DeletePartition(image_part);
    part_grid->RemoveBBox(best_part);
    DeletePartition(best_part);
    rectsearch->RepositionIterator();
    return true;
  }
  return false;
}

// Helper function to compute the overlap area between the box and the
// given list of partitions.
static int IntersectArea(const TBOX &box, ColPartition_LIST *part_list) {
  int intersect_area = 0;
  ColPartition_IT part_it(part_list);
  // Iterate the parts and subtract intersecting area.
  for (part_it.mark_cycle_pt(); !part_it.cycled_list(); part_it.forward()) {
    ColPartition *image_part = part_it.data();
    TBOX intersect = box.intersection(image_part->bounding_box());
    intersect_area += intersect.area();
  }
  return intersect_area;
}

// part_list is a set of ColPartitions representing a polygonal image, and
// im_box is the union of the bounding boxes of all the parts in part_list.
// Tests whether part is to be consumed by the polygonal image.
// Returns true if part is weak text and more than half of its area is
// intersected by parts from the part_list, and it is contained within im_box.
static bool TestWeakIntersectedPart(const TBOX &im_box, ColPartition_LIST *part_list,
                                    ColPartition *part) {
  if (part->flow() < BTFT_STRONG_CHAIN) {
    // A weak partition intersects the box.
    const TBOX &part_box = part->bounding_box();
    if (im_box.contains(part_box)) {
      int area = part_box.area();
      int intersect_area = IntersectArea(part_box, part_list);
      if (area < 2 * intersect_area) {
        return true;
      }
    }
  }
  return false;
}

// A rectangular or polygonal image has been completed, in part_list, bounding
// box in im_box. We want to eliminate weak text or other uncertain partitions
// (basically anything that is not BRT_STRONG_CHAIN or better) from both the
// part_grid and the big_parts list that are contained within im_box and
// overlapped enough by the possibly polygonal image.
static void EliminateWeakParts(const TBOX &im_box, ColPartitionGrid *part_grid,
                               ColPartition_LIST *big_parts, ColPartition_LIST *part_list) {
  ColPartitionGridSearch rectsearch(part_grid);
  ColPartition *part;
  rectsearch.StartRectSearch(im_box);
  while ((part = rectsearch.NextRectSearch()) != nullptr) {
    if (TestWeakIntersectedPart(im_box, part_list, part)) {
      BlobRegionType type = part->blob_type();
      if (type == BRT_POLYIMAGE || type == BRT_RECTIMAGE) {
        rectsearch.RemoveBBox();
        DeletePartition(part);
      } else {
        // The part is mostly covered, so mark it. Non-image partitions are
        // kept hanging around to mark the image for pass2
        part->set_flow(BTFT_NONTEXT);
        part->set_blob_type(BRT_NOISE);
        part->SetBlobTypes();
      }
    }
  }
  ColPartition_IT big_it(big_parts);
  for (big_it.mark_cycle_pt(); !big_it.cycled_list(); big_it.forward()) {
    part = big_it.data();
    if (TestWeakIntersectedPart(im_box, part_list, part)) {
      // Once marked, the blobs will be swept up by TidyBlobs.
      DeletePartition(big_it.extract());
    }
  }
}

// Helper scans for good text partitions overlapping the given box.
// If there are no good text partitions overlapping an expanded box, then
// the box is expanded, otherwise, the original box is returned.
// If good text overlaps the box, true is returned.
static bool ScanForOverlappingText(ColPartitionGrid *part_grid, TBOX *box) {
  ColPartitionGridSearch rectsearch(part_grid);
  TBOX padded_box(*box);
  padded_box.pad(kNoisePadding, kNoisePadding);
  rectsearch.StartRectSearch(padded_box);
  ColPartition *part;
  bool any_text_in_padded_rect = false;
  while ((part = rectsearch.NextRectSearch()) != nullptr) {
    if (part->flow() == BTFT_CHAIN || part->flow() == BTFT_STRONG_CHAIN) {
      // Text intersects the box.
      any_text_in_padded_rect = true;
      const TBOX &part_box = part->bounding_box();
      if (box->overlap(part_box)) {
        return true;
      }
    }
  }
  if (!any_text_in_padded_rect) {
    *box = padded_box;
  }
  return false;
}

// Renders the boxes of image parts from the supplied list onto the image_pix,
// except where they interfere with existing strong text in the part_grid,
// and then deletes them.
// Box coordinates are rotated by rerotate to match the image.
static void MarkAndDeleteImageParts(const FCOORD &rerotate, ColPartitionGrid *part_grid,
                                    ColPartition_LIST *image_parts, Image image_pix) {
  if (image_pix == nullptr) {
    return;
  }
  int imageheight = pixGetHeight(image_pix);
  ColPartition_IT part_it(image_parts);
  for (; !part_it.empty(); part_it.forward()) {
    ColPartition *part = part_it.extract();
    TBOX part_box = part->bounding_box();
    BlobRegionType type = part->blob_type();
    if (!ScanForOverlappingText(part_grid, &part_box) || type == BRT_RECTIMAGE ||
        type == BRT_POLYIMAGE) {
      // Mark the box on the image.
      // All coords need to be rotated to match the image.
      part_box.rotate(rerotate);
      int left = part_box.left();
      int top = part_box.top();
      pixRasterop(image_pix, left, imageheight - top, part_box.width(), part_box.height(), PIX_SET,
                  nullptr, 0, 0);
    }
    DeletePartition(part);
  }
}

// Locates all the image partitions in the part_grid, that were found by a
// previous call to FindImagePartitions, marks them in the image_mask,
// removes them from the grid, and deletes them. This makes it possible to
// call FindImagePartitions again to produce less broken-up and less
// overlapping image partitions.
// rerotation specifies how to rotate the partition coords to match
// the image_mask, since this function is used after orientation correction.
void ImageFind::TransferImagePartsToImageMask(const FCOORD &rerotation, ColPartitionGrid *part_grid,
                                              Image image_mask) {
  // Extract the noise parts from the grid and put them on a temporary list.
  ColPartition_LIST parts_list;
  ColPartition_IT part_it(&parts_list);
  ColPartitionGridSearch gsearch(part_grid);
  gsearch.StartFullSearch();
  ColPartition *part;
  while ((part = gsearch.NextFullSearch()) != nullptr) {
    BlobRegionType type = part->blob_type();
    if (type == BRT_NOISE || type == BRT_RECTIMAGE || type == BRT_POLYIMAGE) {
      part_it.add_after_then_move(part);
      gsearch.RemoveBBox();
    }
  }
  // Render listed noise partitions to the image mask.
  MarkAndDeleteImageParts(rerotation, part_grid, &parts_list, image_mask);
}

// Removes and deletes all image partitions that are too small to be worth
// keeping. We have to do this as a separate phase after creating the image
// partitions as the small images are needed to join the larger ones together.
static void DeleteSmallImages(ColPartitionGrid *part_grid) {
  if (part_grid != nullptr) {
    return;
  }
  ColPartitionGridSearch gsearch(part_grid);
  gsearch.StartFullSearch();
  ColPartition *part;
  while ((part = gsearch.NextFullSearch()) != nullptr) {
    // Only delete rectangular images, since if it became a poly image, it
    // is more evidence that it is somehow important.
    if (part->blob_type() == BRT_RECTIMAGE) {
      const TBOX &part_box = part->bounding_box();
      if (part_box.width() < kMinImageFindSize || part_box.height() < kMinImageFindSize) {
        // It is too small to keep. Just make it disappear.
        gsearch.RemoveBBox();
        DeletePartition(part);
      }
    }
  }
}

// Runs a CC analysis on the image_pix mask image, and creates
// image partitions from them, cutting out strong text, and merging with
// nearby image regions such that they don't interfere with text.
// Rotation and rerotation specify how to rotate image coords to match
// the blob and partition coords and back again.
// The input/output part_grid owns all the created partitions, and
// the partitions own all the fake blobs that belong in the partitions.
// Since the other blobs in the other partitions will be owned by the block,
// ColPartitionGrid::ReTypeBlobs must be called afterwards to fix this
// situation and collect the image blobs.
void ImageFind::FindImagePartitions(Image image_pix, const FCOORD &rotation,
                                    const FCOORD &rerotation, TO_BLOCK *block, TabFind *tab_grid,
                                    DebugPixa *pixa_debug, ColPartitionGrid *part_grid,
                                    ColPartition_LIST *big_parts) {
  int imageheight = pixGetHeight(image_pix);
  Boxa *boxa;
  Pixa *pixa;
  ConnCompAndRectangularize(image_pix, pixa_debug, &boxa, &pixa);
  // Iterate the connected components in the image regions mask.
  int nboxes = 0;
  if (boxa != nullptr && pixa != nullptr) {
    nboxes = boxaGetCount(boxa);
  }
  for (int i = 0; i < nboxes; ++i) {
    l_int32 x, y, width, height;
    boxaGetBoxGeometry(boxa, i, &x, &y, &width, &height);
    Image pix = pixaGetPix(pixa, i, L_CLONE);
    TBOX im_box(x, imageheight - y - height, x + width, imageheight - y);
    im_box.rotate(rotation); // Now matches all partitions and blobs.
    ColPartitionGridSearch rectsearch(part_grid);
    rectsearch.SetUniqueMode(true);
    ColPartition_LIST part_list;
    DivideImageIntoParts(im_box, rotation, rerotation, pix, &rectsearch, &part_list);
    if (textord_tabfind_show_images && pixa_debug != nullptr) {
      pixa_debug->AddPix(pix, "ImageComponent");
      tprintf("Component has %d parts\n", part_list.length());
    }
    pix.destroy();
    if (!part_list.empty()) {
      ColPartition_IT part_it(&part_list);
      if (part_list.singleton()) {
        // We didn't have to chop it into a polygon to fit around text, so
        // try expanding it to merge fragmented image parts, as long as it
        // doesn't touch strong text.
        ColPartition *part = part_it.extract();
        TBOX text_box(im_box);
        MaximalImageBoundingBox(part_grid, &text_box);
        while (ExpandImageIntoParts(text_box, &rectsearch, part_grid, &part)) {
          ;
        }
        part_it.set_to_list(&part_list);
        part_it.add_after_then_move(part);
        im_box = part->bounding_box();
      }
      EliminateWeakParts(im_box, part_grid, big_parts, &part_list);
      // Iterate the part_list and put the parts into the grid.
      for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
        ColPartition *image_part = part_it.extract();
        im_box = image_part->bounding_box();
        part_grid->InsertBBox(true, true, image_part);
        if (!part_it.at_last()) {
          ColPartition *neighbour = part_it.data_relative(1);
          image_part->AddPartner(false, neighbour);
          neighbour->AddPartner(true, image_part);
        }
      }
    }
  }
  boxaDestroy(&boxa);
  pixaDestroy(&pixa);
  DeleteSmallImages(part_grid);
#ifndef GRAPHICS_DISABLED
  if (textord_tabfind_show_images) {
    ScrollView *images_win_ = part_grid->MakeWindow(1000, 400, "With Images");
    part_grid->DisplayBoxes(images_win_);
  }
#endif
}

} // namespace tesseract.


text:
<?php

/**
 * TestimonialTable
 *
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class TestimonialTable extends Doctrine_Table
{
    /**
     * Returns an instance of this class.
     *
     * @return object TestimonialTable
     */
    public static function getInstance()
    {
        return Doctrine_Core::getTable('Testimonial');
    }
}

redpajama_set_name: RedPajamaGithub


text:
/**
 *    @file
 *          Utilities for accessing persisted device configuration on
 *          platforms based on the Silicon Labs SDK.
 */
/* this file behaves like a config.h, comes first */
#include <platform/internal/CHIPDeviceLayerInternal.h>

#include <platform/EFR32/EFR32Config.h>

#include <lib/core/CHIPEncoding.h>
#include <platform/internal/testing/ConfigUnitTest.h>

#include "FreeRTOS.h"
#include "nvm3.h"
#include "nvm3_default.h"
#include "nvm3_hal_flash.h"

// Substitute the GSDK weak nvm3_lockBegin and nvm3_lockEnd
// for an application controlled re-entrance protection
#define EFR32_SEM_TIMEOUT_ms 5
static SemaphoreHandle_t nvm3_Sem;
static StaticSemaphore_t nvm3_SemStruct;

void nvm3_lockBegin(void)
{
    VerifyOrDie(nvm3_Sem != NULL);
    xSemaphoreTake(nvm3_Sem, EFR32_SEM_TIMEOUT_ms);
}

void nvm3_lockEnd(void)
{
    VerifyOrDie(nvm3_Sem != NULL);
    xSemaphoreGive(nvm3_Sem);
}

namespace chip {
namespace DeviceLayer {
namespace Internal {

// Matter NVM3 space is placed in the silabs default nvm3 section shared with other stack.
// 'kMatterNvm3KeyDomain' identify the matter nvm3 domain.
// The NVM3 default section is placed at end of Flash minus 1 page byt the linker file
// See examples/platform/efr32/ldscripts/efr32mgXX.ld

CHIP_ERROR EFR32Config::Init()
{
    nvm3_Sem = xSemaphoreCreateBinaryStatic(&nvm3_SemStruct);

    if (nvm3_Sem == NULL)
    {
        return CHIP_ERROR_NO_MEMORY;
    }

    return MapNvm3Error(nvm3_open(nvm3_defaultHandle, nvm3_defaultInit));
}

void EFR32Config::DeInit()
{
    vSemaphoreDelete(nvm3_Sem);
    nvm3_close(nvm3_defaultHandle);
}

CHIP_ERROR EFR32Config::ReadConfigValue(Key key, bool & val)
{
    CHIP_ERROR err;
    uint32_t objectType;
    size_t dataLen;
    bool tmpVal;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Get nvm3 object info.
    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    SuccessOrExit(err);

    // Read nvm3 bytes into tmp.
    err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &tmpVal, dataLen));
    SuccessOrExit(err);
    val = tmpVal;

exit:
    return err;
}

CHIP_ERROR EFR32Config::ReadConfigValue(Key key, uint32_t & val)
{
    CHIP_ERROR err;
    uint32_t objectType;
    size_t dataLen;
    uint32_t tmpVal;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Get nvm3 object info.
    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    SuccessOrExit(err);

    // Read nvm3 bytes into tmp.
    err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &tmpVal, dataLen));
    SuccessOrExit(err);
    val = tmpVal;

exit:
    return err;
}

CHIP_ERROR EFR32Config::ReadConfigValue(Key key, uint64_t & val)
{
    CHIP_ERROR err;
    uint32_t objectType;
    size_t dataLen;
    uint64_t tmpVal;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Get nvm3 object info.
    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    SuccessOrExit(err);

    // Read nvm3 bytes into tmp.
    err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &tmpVal, dataLen));
    SuccessOrExit(err);
    val = tmpVal;

exit:
    return err;
}

CHIP_ERROR EFR32Config::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
{
    CHIP_ERROR err;
    uint32_t objectType;
    size_t dataLen;

    outLen = 0;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Get nvm3 object info.
    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    SuccessOrExit(err);
    VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);

    if (buf != NULL)
    {
        // Read nvm3 bytes directly into the output buffer- check buffer is
        // long enough to take the string (nvm3 string does not include the
        // terminator char).
        VerifyOrExit((bufSize > dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);

        err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, buf, dataLen));
        SuccessOrExit(err);

        outLen      = ((dataLen == 1) && (buf[0] == 0)) ? 0 : dataLen;
        buf[outLen] = 0; // Add the terminator char.
    }
    else
    {
        if (dataLen > 1)
        {
            outLen = dataLen;
        }
        else
        {
            // Read the first byte of the nvm3 string into a tmp var.
            char firstByte;
            err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &firstByte, 1));
            SuccessOrExit(err);

            outLen = (firstByte == 0) ? 0 : dataLen;
        }
    }

exit:
    return err;
}

CHIP_ERROR EFR32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
{
    CHIP_ERROR err;
    uint32_t objectType;
    size_t dataLen;

    outLen = 0;
    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Get nvm3 object info.
    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    SuccessOrExit(err);
    VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);

    if (buf != NULL)
    {
        // Read nvm3 bytes directly into output buffer- check buffer is long
        // enough to take the data.
        VerifyOrExit((bufSize >= dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);

        err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, buf, dataLen));
        SuccessOrExit(err);

        outLen = dataLen;
    }

exit:
    return err;
}

CHIP_ERROR EFR32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset)
{
    CHIP_ERROR err;
    uint32_t objectType;
    size_t dataLen;

    outLen = 0;
    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Get nvm3 object info.
    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    SuccessOrExit(err);

    if (buf != NULL)
    {
        // Read nvm3 bytes directly into output buffer- check buffer is long enough to take the data
        // else read what we can but return CHIP_ERROR_BUFFER_TOO_SMALL.
        size_t maxReadLength = dataLen - offset;
        if (bufSize >= maxReadLength)
        {
            err = MapNvm3Error(nvm3_readPartialData(nvm3_defaultHandle, key, buf, offset, maxReadLength));
            SuccessOrExit(err);
            outLen = maxReadLength;
        }
        else
        {
            err = MapNvm3Error(nvm3_readPartialData(nvm3_defaultHandle, key, buf, offset, bufSize));
            SuccessOrExit(err);
            // read was successful, but we did not read all the data from the object.
            err    = CHIP_ERROR_BUFFER_TOO_SMALL;
            outLen = bufSize;
        }
    }
exit:
    return err;
}

CHIP_ERROR EFR32Config::ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val)
{
    CHIP_ERROR err;
    uint32_t tmpVal;
    Key key = kMinConfigKey_MatterCounter + counterIdx;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Read bytes into tmp.
    err = MapNvm3Error(nvm3_readCounter(nvm3_defaultHandle, key, &tmpVal));
    SuccessOrExit(err);
    val = tmpVal;

exit:
    return err;
}

CHIP_ERROR EFR32Config::WriteConfigValue(Key key, bool val)
{
    CHIP_ERROR err;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_ERROR_INVALID_ARGUMENT); // Verify key id.

    err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, &val, sizeof(val)));
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR EFR32Config::WriteConfigValue(Key key, uint32_t val)
{
    CHIP_ERROR err;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, &val, sizeof(val)));
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR EFR32Config::WriteConfigValue(Key key, uint64_t val)
{
    CHIP_ERROR err;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, &val, sizeof(val)));
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR EFR32Config::WriteConfigValueStr(Key key, const char * str)
{
    return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0);
}

CHIP_ERROR EFR32Config::WriteConfigValueStr(Key key, const char * str, size_t strLen)
{
    CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    if (str != NULL)
    {
        // Write the string to nvm3 without the terminator char (apart from
        // empty strings where only the terminator char is stored in nvm3).
        err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, str, (strLen > 0) ? strLen : 1));
        SuccessOrExit(err);
    }

exit:
    return err;
}

CHIP_ERROR EFR32Config::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
{
    CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    // Only write NULL pointer if the given size is 0, since in that case, nothing is read at the pointer
    if ((data != NULL) || (dataLen == 0))
    {
        // Write the binary data to nvm3.
        err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, data, dataLen));
        SuccessOrExit(err);
    }

exit:
    return err;
}

CHIP_ERROR EFR32Config::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val)
{
    CHIP_ERROR err;
    Key key = kMinConfigKey_MatterCounter + counterIdx;

    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.

    err = MapNvm3Error(nvm3_writeCounter(nvm3_defaultHandle, key, val));
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR EFR32Config::ClearConfigValue(Key key)
{
    CHIP_ERROR err;

    // Delete the nvm3 object with the given key id.
    err = MapNvm3Error(nvm3_deleteObject(nvm3_defaultHandle, key));
    SuccessOrExit(err);

exit:
    return err;
}

bool EFR32Config::ConfigValueExists(Key key)
{
    uint32_t objectType;
    size_t dataLen;

    // Find object with key id.
    CHIP_ERROR err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
    return (err == CHIP_NO_ERROR);
}

CHIP_ERROR EFR32Config::FactoryResetConfig(void)
{
    // Deletes all nvm3 'Config' type objects.
    // Note- 'Factory' and 'Counter' type nvm3 objects are NOT deleted.

    CHIP_ERROR err;

    // Iterate over all the CHIP Config nvm3 records and delete each one...
    err = ForEachRecord(kMinConfigKey_MatterConfig, kMaxConfigKey_MatterConfig, false,
                        [](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
                            CHIP_ERROR err2;
                            // Delete the nvm3 object with the given key id.
                            err2 = ClearConfigValue(nvm3Key);
                            SuccessOrExit(err2);

                        exit:
                            return err2;
                        });

    // Return success at end of iterations.
    if (err == CHIP_END_OF_INPUT)
    {
        err = CHIP_NO_ERROR;
    }

    return err;
}

CHIP_ERROR EFR32Config::MapNvm3Error(Ecode_t nvm3Res)
{
    CHIP_ERROR err;

    switch (nvm3Res)
    {
    case ECODE_NVM3_OK:
        err = CHIP_NO_ERROR;
        break;
    case ECODE_NVM3_ERR_KEY_NOT_FOUND:
        err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
        break;
    default:
        err = CHIP_ERROR(ChipError::Range::kPlatform, (nvm3Res & 0xFF) + CHIP_DEVICE_CONFIG_EFR32_NVM3_ERROR_MIN);
        break;
    }

    return err;
}

CHIP_ERROR EFR32Config::ForEachRecord(Key firstNvm3Key, Key lastNvm3Key, bool addNewRecord, ForEachRecordFunct funct)
{
    // Iterates through the specified range of nvm3 object key ids.
    // Invokes the callers CB function when appropriate.

    CHIP_ERROR err = CHIP_NO_ERROR;

    for (Key nvm3Key = firstNvm3Key; nvm3Key <= lastNvm3Key; ++nvm3Key)
    {
        Ecode_t nvm3Res;
        uint32_t objectType;
        size_t dataLen;

        // Find nvm3 object with current nvm3 iteration key.
        nvm3Res = nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objectType, &dataLen);
        switch (nvm3Res)
        {
        case ECODE_NVM3_OK:
            if (!addNewRecord)
            {
                // Invoke the caller's function
                // (for retrieve,store,delete,enumerate GroupKey operations).
                err = funct(nvm3Key, dataLen);
            }
            break;
        case ECODE_NVM3_ERR_KEY_NOT_FOUND:
            if (addNewRecord)
            {
                // Invoke caller's function
                // (for add GroupKey operation).
                err = funct(nvm3Key, dataLen);
            }
            break;
        default:
            err = MapNvm3Error(nvm3Res);
            break;
        }

        SuccessOrExit(err);
    }

exit:;
    return err;
}

bool EFR32Config::ValidConfigKey(Key key)
{
    // Returns true if the key is in the Matter nvm3 reserved key range.
    // Additional check validates that the user consciously defined the expected key range
    if ((key >= kMatterNvm3KeyLoLimit) && (key <= kMatterNvm3KeyHiLimit) && (key >= kMinConfigKey_MatterFactory) &&
        (key <= kMaxConfigKey_MatterKvs))
    {
        return true;
    }

    return false;
}

void EFR32Config::RunConfigUnitTest()
{
    // Run common unit test.
    ::chip::DeviceLayer::Internal::RunConfigUnitTest<EFR32Config>();
}

void EFR32Config::RepackNvm3Flash(void)
{
    // Repack nvm3 flash if nvm3 space < headroom threshold.
    // Note- checking periodically during idle periods should prevent
    // forced repack events on any write operation.
    nvm3_repack(nvm3_defaultHandle);
}

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip


text:
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.camunda.bpm.engine.rest.sub.runtime;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.camunda.bpm.engine.rest.dto.runtime.JobDto;
import org.camunda.bpm.engine.rest.dto.runtime.JobDuedateDto;
import org.camunda.bpm.engine.rest.dto.runtime.JobPriorityDto;
import org.camunda.bpm.engine.rest.dto.runtime.RetriesDto;
import org.camunda.bpm.engine.rest.dto.runtime.JobSuspensionStateDto;

public interface JobResource {

  @GET
  @Produces(MediaType.APPLICATION_JSON)
  JobDto getJob();

  @GET
  @Path("/stacktrace")
  @Produces(MediaType.TEXT_PLAIN)
  String getStacktrace();

  @PUT
  @Path("/retries")
  @Consumes(MediaType.APPLICATION_JSON)
  void setJobRetries(RetriesDto dto);

  @POST
  @Path("/execute")
  void executeJob();

  @PUT
  @Path("/duedate")
  @Consumes(MediaType.APPLICATION_JSON)
  void setJobDuedate(JobDuedateDto dto);

  @PUT
  @Path("/suspended")
  @Consumes(MediaType.APPLICATION_JSON)
  void updateSuspensionState(JobSuspensionStateDto dto);

  @PUT
  @Path("/priority")
  @Consumes(MediaType.APPLICATION_JSON)
  void setJobPriority(JobPriorityDto dto);

}


text:
|LF_STANDARD|
|LF_SSL|
|?TREE=» <a class=tree href="/CMD_SHOW_DOMAIN?domain=`domain`">`domain` » <a class=tree href="/CMD_SSL?DOMAIN=`domain`">`LANG_SSL` » `LANG_CREATE_CSR`|
|?HELP_SECTION=`USER_HELPER`/ssl.html#install|
|HTM_USER_TOP|

|LANG_SSL_CSR|

					|*if NOTICE!=""|

|NOTICE|

					|*endif|

|LANG_HERE_IS_CSR|

					<form name=info>

							<textarea class="code_edit ssl_text" name=request rows=16>|REQUEST|</textarea>

<input type=button value="|LANG_COPY_TO|" onClick="copyCertificate(document.info.request)"> |LANG_IE_ONLY|

					</form>

|*if USERTYPE="admin"|

|LANG_ADMIN_SAVE_KEY|

|*endif|

|HTM_USER_BOTTOM|


text:
Get in touch

925.269.9510

info@martinezhero.org

    Joe DiMaggio Hometown Hero Project

    P.O. Box 1892

    Martinez, CA 94553-1892

Donate with Paypal

    <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top" style="margin-top:10px;">
      <input type="hidden" name="cmd" value="_s-xclick">
      <input type="hidden" name="hosted_button_id" value="HQ6K5B2LXG75S">
      <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">

    </form>

Copyright © 2016 Joe DiMaggio Hometown Hero Project


text:
/**
 * Controls Core module
 * other modules cas use it so simplify things
 */

'use strict';

var logger = require('./../libs/logger');

var Command = require('./controls/command').Command;
var Action = require('./controls/action').Action;

//trim some strings
if (!String.prototype.trim) {
	String.prototype.trim = function () {
		return this.replace(/^\s+|\s+$/g, '');
	};
}

function Controls(irc, actions, commands, dispatcher) {
	this._irc = irc;
	this.actions = actions;
	this.commands = commands;
	this.dispatcher = dispatcher;
}

Controls.prototype.addCommand = function (name, action, access) {
	name = name.replace(/[^a-zA-Z0-9_\-]+/g, '');
	if (typeof this.commands[name] !== 'undefined') {
		throw new Error('Command \'' + name + '\' already exists!');
	}
	this.commands[name] = new Command(name, action, access);
	this.dispatcher.emit('controls/addCommand', name);
	return this;
};

Controls.prototype.addAction = function (name, action, regexp, access) {
	name = name.replace(/[^a-zA-Z0-9_\-]+/g, '');
	if (typeof this.actions[name] !== 'undefined') {
		throw new Error('Action \'' + name + '\' already exists!');
	}
	this.actions[name] = new Action(name, action, regexp, access);
	this.dispatcher.emit('controls/addAction', name, regexp);
	return this;
};

Controls.prototype.removeCommand = function (name) {
	name = name.replace(/[^a-zA-Z0-9_\-]+/g, '');
	if (typeof this.commands[name] !== 'undefined') {
		delete this.commands[name];
		this.dispatcher.emit('controls/removeCommand', name);
	} else {
		throw new Error('Command \'' + name + '\' does not exists!');
	}
	return this;
};

Controls.prototype.removeAction = function (name) {
	name = name.replace(/[^a-zA-Z0-9_\-]+/g, '');
	if (typeof this.actions[name] !== 'undefined') {
		delete this.actions[name];
		this.dispatcher.emit('controls/removeAction', name);
	} else {
		throw new Error('Action \'' + name + '\' does not exists!');
	}
	return this;
};

Controls.prototype.removeActions = function (list) {
	if (!(list instanceof Array)) {
		throw new Error('You need to pass Array as first argument!');
	}
	list.forEach(function (name) {
		this.removeAction(name);
	}, this);
	return this;
};

Controls.prototype.removeCommands = function (list) {
	if (!(list instanceof Array)) {
		throw new Error('You need to pass Array as first argument!');
	}
	list.forEach(function (name) {
		this.removeCommand(name);
	}, this);
	return this;
};

Controls.prototype.parse = function (source, text) {
	if (typeof text !== 'string') {
		return;
	}

	text = text.trim();

	if (text.length <= 0) {
		return;
	}

	if (!source.channel) { //itz direct message
		this.processAction(source, text);
	} else if (source.channel && text.length > this.config.commandDelimiter.length && text.substr(0, this.config.commandDelimiter.length) === this.config.commandDelimiter) { //itz command in channel
		this.processCommand(source, text.substr(this.config.commandDelimiter.length));
	} else {
		var match = text.match(new RegExp('^' + this._irc.currentNick + '[ ;:,]+(.*)'));
		if (match !== null) { //itz higlight in channel
			this.processAction(source, match[1]);
		}
	}
};

Controls.prototype.processCommand = function (source, text) {
	var args = text.match(/[^\s\"\']+|\"([^\"]*)\"|\'([^\']*)\'/g);
	if (args === null) {
		return;
	}
	args = args.map(function (v) {
		return v.replace(/\"|\'/g, '');
	});
	var command = args.shift();
	//execute the command
	return Object.keys(this.commands).some(function (name) {
		if (this.commands[name] && command === this.commands[name].name) {
			if (this.checkAccess(source, this.commands[name])) { //run the command only if the user has access
				var execute = this.commands[name].action,
					dispatcher = this.dispatcher;
				setImmediate(function () {
					logger.debug('Processing Command \'' + name + '\'');
					execute(source, args, text, command);
					dispatcher.emit('controls/command', name, source, args, text, command);
				});
			} else {
				logger.debug('Command \'' + name + '\' access for user \'' + source + '\' denied!');
				source.notice('Command Access denied! Do i know you?');
			}
			return true; //stop searching
		}
		return false; //try next
	}, this);
};

Controls.prototype.processAction = function (source, text) {
	//proces all actions that triggers rule
	var found = false;
	Object.keys(this.actions).forEach(function (name) {
		if (this.actions[name]) {
			var args = text.match(this.actions[name].rule);
			if (args !== null) {
				if (this.checkAccess(source, this.actions[name])) { //run the action only if the user has access
					var execute = this.actions[name].action,
						dispatcher = this.dispatcher;
					setImmediate(function () {
						logger.debug('Processing Action \'' + name + '\'');
						execute(source, args, text);
						dispatcher.emit('controls/action', name, source, args, text);
					});
					found = true;
				} else {
					logger.debug('Action \'' + name + '\' access for user \'' + source + '\' denied!');
					source.notice('Action Access denied! Derpy in action!');
				}
			}
		}
	}, this);
	return found;
};

Controls.prototype.checkAccess = function (source, CorA) {
	//allow access if no rule
	if (!CorA.access) {
		return true;
	}

	//shell can run everything
	if (source.toString() === 'ItzAInternallPonyShell') {
		return true;
	}

	//array means list of allowed groups
	if (CorA.access instanceof Array) {
		return CorA.access.some(function (name) {
			if (this.config.groups[name]) {
				return this.config.groups[name].some(function (user) {
					return source.toString().match(user) !== null;
				});
			}
			return false;
		}, this);
	}

	//else try matching it directly
	return source.toString().match(CorA.access) !== null;
};

module.exports.init = function (reload) {
	if (!reload) {
		this.actions = {};
		this.commands = {};
	}
	if (typeof this.config.groups !== 'object') {
		this.config.groups = {};
	}
	if (typeof this.config.commandDelimiter !== 'string') {
		this.config.commandDelimiter = '.';
	}

	this.controls = new Controls(this.require('irc'), this.actions, this.commands, this.dispatcher);

	var module = this;

	Object.defineProperty(this.controls, 'config', {
		enumerable: true,
		configurable: false,
		get: function () {
			return module.config;
		}
	});

	Object.defineProperty(this.controls, 'commandDelimiter', {
		enumerable: true,
		configurable: false,
		get: function () {
			return module.config.commandDelimiter;
		}
	});

	if (!reload) {
		Object.defineProperty(this, 'commandDelimiter', {
			enumerable: true,
			configurable: false,
			get: function () {
				return module.config.commandDelimiter;
			}
		});
	}

	//export some functions from Controls
	//require('./../libs/helpers').export(this, this.controls, ['addCommand', 'addAction', 'removeCommand', 'removeAction', 'removeCommands', 'removeActions']);
	require('./../libs/helpers').export(this, this.controls, ['removeCommand', 'removeAction', 'removeCommands', 'removeActions']);

	/**
	 * bind the controls to module core
	 */

	if (!reload) {
		this.moduleActions = {};
		this.moduleCommands = {};
	}

	var proto = require('./../libs/module').Module.prototype;
	proto.addCommand = function (name) {
		name = name.replace(/[^a-zA-Z0-9_\-]+/g, '');
		var args = arguments;
		var that = this;
		process.nextTick(function () {
			module.controls.addCommand.apply(module.controls, args);
			if (typeof module.moduleCommands[that.name] === 'undefined') {
				module.moduleCommands[that.name] = {};
			}
			module.moduleCommands[that.name][name] = name;
		});
		return this;
	};
	proto.addAction = function (name) {
		name = name.replace(/[^a-zA-Z0-9_\-]+/g, '');
		var args = arguments;
		var that = this;
		process.nextTick(function () {
			module.controls.addAction.apply(module.controls, args);
			if (typeof module.moduleActions[that.name] === 'undefined') {
				module.moduleActions[that.name] = {};
			}
			module.moduleActions[that.name][name] = name;
		});
		return this;
	};
	proto.removeCommand = function () {
		module.controls.removeCommand.apply(module.controls, arguments);
		return this;
	};
	proto.removeAction = function () {
		module.controls.removeAction.apply(module.controls, arguments);
		return this;
	};

	this.addCommand = this.addAction = function () {
		throw new Error('Deprecated! Dont use \'controls\' module directly!');
	};

	//clean up the module commands/actions on unload

	function clean(name) {
		if (typeof module.moduleActions[name] !== 'undefined') {
			Object.keys(module.moduleActions[name]).forEach(function (action) {
				if (typeof module.actions[action] !== 'undefined') {
					module.controls.removeAction(action);
				}
			});
			delete module.moduleActions[name];
		}
		if (typeof module.moduleCommands[name] !== 'undefined') {
			Object.keys(module.moduleCommands[name]).forEach(function (command) {
				if (typeof module.commands[command] !== 'undefined') {
					module.controls.removeCommand(command);
				}
			});
			delete module.moduleCommands[name];
		}
	}

	this.dispatcher.on('module-unload', clean).on('module-reload', clean);

	//bind
	this.dispatcher.on('irc/PRIVMSG', this.controls.parse.bind(this.controls)).on('irc/NOTICE', this.controls.parse.bind(this.controls));
};

module.exports.halt = function () {
	var proto = require('./../libs/module').Module.prototype;
	delete proto.addCommand;
	delete proto.addAction;
	delete proto.removeCommand;
	delete proto.removeAction;
};


text:
package org.apache.jmeter.util;

import java.io.Serializable;

import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jorphan.util.JMeterException;
import org.apache.jorphan.util.JOrphanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class BeanShellTestElement extends AbstractTestElement
    implements Serializable, Cloneable, ThreadListener, TestStateListener
{
    private static final Logger log = LoggerFactory.getLogger(BeanShellTestElement.class);

    private static final long serialVersionUID = 4;

    //++ For TestBean implementations only
    private String parameters; // passed to file or script

    private String filename; // file to source (overrides script)

    private String script; // script (if file not provided)

    private boolean resetInterpreter = false;
    //-- For TestBean implementations only

    private transient BeanShellInterpreter bshInterpreter = null;

    private transient boolean hasInitFile = false;

    public BeanShellTestElement() {
        super();
        init();
    }

    protected abstract String getInitFileProperty();

    /**
     * Get the interpreter and set up standard script variables.
     *

     * Sets the following script variables:
     *

     *
ctx

     *
Label

     *
prev

     *
props

     *
vars

     *

     * @return the interpreter
     */
    protected BeanShellInterpreter getBeanShellInterpreter() {
        if (isResetInterpreter()) {
            try {
                bshInterpreter.reset();
            } catch (ClassNotFoundException e) {
                log.error("Cannot reset BeanShell: {}", e.toString()); // NOSONAR last arg would be exception
            }
        }

        JMeterContext jmctx = JMeterContextService.getContext();
        JMeterVariables vars = jmctx.getVariables();

        try {
            bshInterpreter.set("ctx", jmctx);//$NON-NLS-1$
            bshInterpreter.set("Label", getName()); //$NON-NLS-1$
            bshInterpreter.set("prev", jmctx.getPreviousResult());//$NON-NLS-1$
            bshInterpreter.set("props", JMeterUtils.getJMeterProperties());
            bshInterpreter.set("vars", vars);//$NON-NLS-1$
        } catch (JMeterException e) {
            log.warn("Problem setting one or more BeanShell variables {}", e.toString()); // NOSONAR last arg would be exception
        }
        return bshInterpreter;
    }

    private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
        parameters=""; // ensure variables are not null
        filename="";
        script="";
        try {
            String initFileName = JMeterUtils.getProperty(getInitFileProperty());
            hasInitFile = initFileName != null;
            bshInterpreter = new BeanShellInterpreter(initFileName, log);
        } catch (ClassNotFoundException e) {
            log.error("Cannot find BeanShell: {}", e.toString()); // NOSONAR last arg would be exception
        }
    }

    protected Object readResolve() {
        init();
        return this;
    }

    @Override
    public Object clone() {
        BeanShellTestElement o = (BeanShellTestElement) super.clone();
        o.init();
       return o;
    }

    /**
     * Process the file or script from the test element.
     *

     * Sets the following script variables:
     *

     *
FileName

     *
Parameters

     *
bsh.args

     *

     * @param bsh the interpreter, not {@code null}
     * @return the result of the script, may be {@code null}
     *
     * @throws JMeterException when working with the bsh fails
     */
    protected Object processFileOrScript(BeanShellInterpreter bsh) throws JMeterException{
        String fileName = getFilename();
        String params = getParameters();

        bsh.set("FileName", fileName);//$NON-NLS-1$
        // Set params as a single line
        bsh.set("Parameters", params); // $NON-NLS-1$
        // and set as an array
        bsh.set("bsh.args",//$NON-NLS-1$
                JOrphanUtils.split(params, " "));//$NON-NLS-1$

        if (fileName.length() == 0) {
            return bsh.eval(getScript());
        }
        return bsh.source(fileName);
    }

    /**
     * Return the script (TestBean version).
     * Must be overridden for subclasses that don't implement TestBean
     * otherwise the clone() method won't work.
     *
     * @return the script to execute
     */
    public String getScript(){
        return script;
    }

    /**
     * Set the script (TestBean version).
     * Must be overridden for subclasses that don't implement TestBean
     * otherwise the clone() method won't work.
     *
     * @param s the script to execute (may be blank)
     */
    public void setScript(String s){
        script=s;
    }

    @Override
    public void threadStarted() {
        tryEvalNoLog("threadStarted()"); // $NON-NLS-1$
    }

    @Override
    public void threadFinished() {
        tryEvalNoLog("threadFinished()"); // $NON-NLS-1$
    }

    @Override
    public void testEnded() {
        tryEvalNoLog("testEnded()"); // $NON-NLS-1$
    }

    @Override
    public void testEnded(String host) {
        tryEval("testEnded(\"" + host + "\")"); // $NON-NLS-1$
    }

    @Override
    public void testStarted() {
        tryEvalNoLog("testStarted()");// $NON-NLS-1$
    }

    @Override
    public void testStarted(String host) {
        tryEval("testStarted(\"" + host + "\")"); // $NON-NLS-1$
    }

    private void tryEval(String code) {
        if (bshInterpreter == null || !hasInitFile) {
            return;
        }
        try {
            bshInterpreter.eval(code);
        } catch (JMeterException e) {
            if (log.isDebugEnabled()) {
                log.debug("{} : {}", getClass().getName(), e.getLocalizedMessage()); // $NON-NLS-1$
            }
        }
    }

    private void tryEvalNoLog(String code) {
        if (bshInterpreter == null || !hasInitFile) {
            return;
        }
        try {
            bshInterpreter.evalNoLog(code);
        } catch (JMeterException e) {
            if (log.isDebugEnabled()) {
                log.debug("{} : {}", getClass().getName(), e.getLocalizedMessage()); // $NON-NLS-1$
            }
        }
    }

    // Overridden by non-TestBean implementations to return the property value instead
    public String getParameters() {
        return parameters;
    }

    public void setParameters(String s) {
        parameters = s;
    }

    // Overridden by non-TestBean implementations to return the property value instead
    public String getFilename() {
        return filename;
    }

    public void setFilename(String s) {
        filename = s;
    }

    public boolean isResetInterpreter() {
        return resetInterpreter;
    }

    public void setResetInterpreter(boolean b) {
        resetInterpreter = b;
    }
}


text:
define(["./ng-class"], function($__0) {
  "use strict";
  if (!$__0 || !$__0.__esModule)
    $__0 = {default: $__0};
  var NgClass = $__0.NgClass;
  var NgNsName = (function($__super) {
    function NgNsName(uri) {
      $traceurRuntime.superConstructor(NgNsName).call(this, NgNsName);
      this.className = 'NgNsName';
      this.uri = uri;
    }
    return ($traceurRuntime.createClass)(NgNsName, {contains: function(nameClass, qName) {
        return nameClass.uri === qName.uri;
      }}, {}, $__super);
  }(NgClass));
  return {
    get NgNsName() {
      return NgNsName;
    },
    __esModule: true
  };
});


text:
require 'spec_helper'

describe Tomato do
  subject { Tomato.new }

  it "should build an anonymous Ruby object to mirror anonymous JS objects" do
    pending
  end

  it "should convert JS regexps to Ruby ones" do
    pending "api support"
    subject.run("/./").should == /./
  end

  it "should raise ArgumentError given too few arguments to #run" do
    proc { Tomato.new.run }.should raise_error(ArgumentError)
  end

  it "should raise ArgumentError given too many arguments to #run" do
    proc { Tomato.new.run(1, 2, 3) }.should raise_error(ArgumentError)
  end

  it "should raise an error calling a missing method" do
    proc { subject.run("(nothing());") }.should raise_error(Tomato::Error)
  end

  it "should raise an error given bad syntax" do
    proc { subject.run("1a = 3b5;") }.should raise_error(Tomato::Error)
  end

  it 'should execute basic javascript' do
    # Basically, this demonstrates that initialization of the engine and actually *running* crap works.
    # Additionally, "(1+1);" is valid JavaScript so should not raise any other form of error.
      proc { subject.run("(1+1);").to_s.should == '2' }.should_not raise_error
  end

  it 'should return nil if result is null' do
      subject.run("(null);").should be_nil
  end

  it "should return :undefined if result is undefined" do
      subject.run("({}.x);").should == :undefined
  end

  it "should return true if result is true" do
      subject.run("(true);").should == true
  end

  it "should return false if result is true" do
      subject.run("(false);").should == false
  end

  it "should return a string if the result is a string" do
      subject.run("('hi');").should == "hi"
  end

  it "should return a string if the result is a function" do
      subject.run("(function() { });").should == "function () { }"
  end

  it "should return an array if the result is an array" do
      subject.run("([1, 2, 3]);").should == [1, 2, 3]
  end

  it "should return a Fixnum if the result is an integer" do
      subject.run("(1);").should == 1
      subject.run("(1);").should be_kind_of(Fixnum)
  end

  it "should return a Float if the result is a float or double" do
      subject.run("(1.05);").should == 1.05
      subject.run("(1.05);").should be_kind_of(Float)
  end

  it "should return a Date if the result is a date" do
    # JavaScript doesn't measure time in microseconds like ruby does, so we have to convert to milliseconds and lose
    # some precision in the process.
    time_in_millis = (Time.now.to_f * 1000.0).to_i
    code = "(new Date(#{time_in_millis}));"
    (subject.run(code).to_f * 1000.0).to_i.should == time_in_millis
  end

  it "should handle 64 bit integers" do
    subject.run("(9223372036854775806);").should == 9223372036854775806
#    /* TODO FIXME: There's no way to know if we're facing a Uint64. It works as a Float but user may not expect a Float... */
#    subject.run("(9223372036854775806);").should_not be_kind_of(Float) # and should be a Bignum, if we're feeling picky.
  end
end


text:
package io.github.privacystreams.commons.list;

import java.util.List;

/**
 * Count the number of valid fields in a stream.
 */
final class FieldCounter extends NumListProcessor<Integer> {

    FieldCounter(String numListField) {
        super(numListField);
    }

    @Override
    protected Integer processNumList(List<Number> numList) {
        return numList == null ? null : numList.size();
    }
}


text:
import json
import re
from collections import Mapping, Sequence
from flask.testing import FlaskClient

from .utils import UNDEFINED

# -----------------------------------------------------------------------------

class ApiClient(FlaskClient):
    """A `flask.testing.FlaskClient` with a few conveniences:

    * Prefixes paths
    * Sets ``Content-Type`` to "application/json"
    * Envelopes ``data`` within a "data" key in the request payload
    """

    def open(self, path, *args, **kwargs):
        full_path = "{}{}".format(
            self.application.extensions["resty"].api.prefix, path
        )

        if "data" in kwargs:
            kwargs.setdefault("content_type", "application/json")
            if kwargs["content_type"] == "application/json":
                kwargs["data"] = json.dumps({"data": kwargs["data"]})

        return super().open(full_path, *args, **kwargs)

# -----------------------------------------------------------------------------

class Predicate:
    """A helper object to do predicate assertion"""

    def __init__(self, predicate):
        self.predicate = predicate

    def __eq__(self, other):
        return self.predicate(other)

    def __ne__(self, other):
        return not self.predicate(other)

def InstanceOf(type):
    return Predicate(lambda value: isinstance(value, type))

def Matching(expected_regex):
    return Predicate(re.compile(expected_regex).match)

def assert_shape(actual, expected):
    """Assert that ``actual`` and ``expected`` have the same data shape."""
    if isinstance(expected, Mapping):
        assert isinstance(actual, Mapping)
        # Unlike all the others, this checks that the actual items are a
        # superset of the expected items, rather than that they match.
        for key, value in expected.items():
            if value is not UNDEFINED:
                assert key in actual
                assert_shape(actual[key], value)
            else:
                assert key not in actual
    elif isinstance(expected, (str, bytes)):
        assert expected == actual
    elif isinstance(expected, Sequence):
        assert isinstance(actual, Sequence)
        assert len(actual) == len(expected)
        for actual_item, expected_item in zip(actual, expected):
            assert_shape(actual_item, expected_item)
    elif isinstance(expected, float):
        assert abs(actual - expected) < 1e-6
    else:
        assert expected == actual

def Shape(expected):
    def predicate(actual):
        assert_shape(actual, expected)
        return True

    return Predicate(predicate)

# -----------------------------------------------------------------------------

def get_raw_body(response):
    return response.get_data(as_text=True)

def get_body(response):
    assert response.mimetype == "application/json"
    return json.loads(get_raw_body(response))

def get_data(response):
    return get_body(response)["data"]

def get_errors(response):
    return get_body(response)["errors"]

def get_meta(response):
    return get_body(response)["meta"]

def assert_response(
    response,
    expected_status_code,
    expected_data=UNDEFINED,
    *,
    get_data=get_data,
    get_errors=get_errors,
):
    """Assert on the status and contents of a response.

    If specified, expected_data is checked against either the data or the
    errors in the response body, depending on the response status. This check
    ignores extra dictionary items in the response contents.
    """
    status_code = response.status_code
    assert status_code == expected_status_code

    if not response.content_length:
        response_data = UNDEFINED
    elif 200 <= response.status_code < 300:
        response_data = get_data(response)
    elif response.status_code >= 400:
        response_data = get_errors(response)
    else:
        response_data = response.data

    if expected_data is not UNDEFINED:
        if not isinstance(expected_data, Predicate):
            expected_data = Shape(expected_data)

        assert response_data == expected_data

    return response_data