All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
PAGE_RES_IT Class Reference

#include <pageres.h>

Public Member Functions

 PAGE_RES_IT ()
 
 PAGE_RES_IT (PAGE_RES *the_page_res)
 
bool operator== (const PAGE_RES_IT &other) const
 
bool operator!= (const PAGE_RES_IT &other) const
 
int cmp (const PAGE_RES_IT &other) const
 
WERD_RESrestart_page ()
 
WERD_RESrestart_page_with_empties ()
 
WERD_RESstart_page (bool empty_ok)
 
WERD_RESrestart_row ()
 
WERD_RESInsertSimpleCloneWord (const WERD_RES &clone_res, WERD *new_word)
 
void ReplaceCurrentWord (tesseract::PointerVector< WERD_RES > *words)
 
void DeleteCurrentWord ()
 
void MakeCurrentWordFuzzy ()
 
WERD_RESforward ()
 
WERD_RESforward_with_empties ()
 
WERD_RESforward_paragraph ()
 
WERD_RESforward_block ()
 
WERD_RESprev_word () const
 
ROW_RESprev_row () const
 
BLOCK_RESprev_block () const
 
WERD_RESword () const
 
ROW_RESrow () const
 
BLOCK_RESblock () const
 
WERD_RESnext_word () const
 
ROW_RESnext_row () const
 
BLOCK_RESnext_block () const
 
void rej_stat_word ()
 
void ResetWordIterator ()
 

Public Attributes

PAGE_RESpage_res
 

Detailed Description

Definition at line 656 of file pageres.h.

Constructor & Destructor Documentation

PAGE_RES_IT::PAGE_RES_IT ( )
inline

Definition at line 660 of file pageres.h.

660  {
661  } // empty contructor
PAGE_RES_IT::PAGE_RES_IT ( PAGE_RES the_page_res)
inline

Definition at line 663 of file pageres.h.

663  { // page result
664  page_res = the_page_res;
665  restart_page(); // ready to scan
666  }
PAGE_RES * page_res
Definition: pageres.h:658
WERD_RES * restart_page()
Definition: pageres.h:680

Member Function Documentation

BLOCK_RES* PAGE_RES_IT::block ( ) const
inline

Definition at line 739 of file pageres.h.

739  { // block of cur. word
740  return block_res;
741  }
int PAGE_RES_IT::cmp ( const PAGE_RES_IT other) const

Definition at line 1200 of file pageres.cpp.

1200  {
1201  ASSERT_HOST(page_res == other.page_res);
1202  if (other.block_res == NULL) {
1203  // other points to the end of the page.
1204  if (block_res == NULL)
1205  return 0;
1206  return -1;
1207  }
1208  if (block_res == NULL) {
1209  return 1; // we point to the end of the page.
1210  }
1211  if (block_res == other.block_res) {
1212  if (other.row_res == NULL || row_res == NULL) {
1213  // this should only happen if we hit an image block.
1214  return 0;
1215  }
1216  if (row_res == other.row_res) {
1217  // we point to the same block and row.
1218  ASSERT_HOST(other.word_res != NULL && word_res != NULL);
1219  if (word_res == other.word_res) {
1220  // we point to the same word!
1221  return 0;
1222  }
1223 
1224  WERD_RES_IT word_res_it(&row_res->word_res_list);
1225  for (word_res_it.mark_cycle_pt(); !word_res_it.cycled_list();
1226  word_res_it.forward()) {
1227  if (word_res_it.data() == word_res) {
1228  return -1;
1229  } else if (word_res_it.data() == other.word_res) {
1230  return 1;
1231  }
1232  }
1233  ASSERT_HOST("Error: Incomparable PAGE_RES_ITs" == NULL);
1234  }
1235 
1236  // we both point to the same block, but different rows.
1237  ROW_RES_IT row_res_it(&block_res->row_res_list);
1238  for (row_res_it.mark_cycle_pt(); !row_res_it.cycled_list();
1239  row_res_it.forward()) {
1240  if (row_res_it.data() == row_res) {
1241  return -1;
1242  } else if (row_res_it.data() == other.row_res) {
1243  return 1;
1244  }
1245  }
1246  ASSERT_HOST("Error: Incomparable PAGE_RES_ITs" == NULL);
1247  }
1248 
1249  // We point to different blocks.
1250  BLOCK_RES_IT block_res_it(&page_res->block_res_list);
1251  for (block_res_it.mark_cycle_pt();
1252  !block_res_it.cycled_list(); block_res_it.forward()) {
1253  if (block_res_it.data() == block_res) {
1254  return -1;
1255  } else if (block_res_it.data() == other.block_res) {
1256  return 1;
1257  }
1258  }
1259  // Shouldn't happen...
1260  ASSERT_HOST("Error: Incomparable PAGE_RES_ITs" == NULL);
1261  return 0;
1262 }
WERD_RES_LIST word_res_list
Definition: pageres.h:131
BLOCK_RES_LIST block_res_list
Definition: pageres.h:62
PAGE_RES * page_res
Definition: pageres.h:658
#define ASSERT_HOST(x)
Definition: errcode.h:84
ROW_RES_LIST row_res_list
Definition: pageres.h:110
#define NULL
Definition: host.h:144
void PAGE_RES_IT::DeleteCurrentWord ( )

Definition at line 1449 of file pageres.cpp.

1449  {
1450  // Check that this word is as we expect. part_of_combos are NEVER iterated
1451  // by the normal iterator, so we should never be trying to delete them.
1452  ASSERT_HOST(!word_res->part_of_combo);
1453  if (!word_res->combination) {
1454  // Combinations own their own word, so we won't find the word on the
1455  // row's word_list, but it is legitimate to try to delete them.
1456  // Delete word from the ROW when not a combination.
1457  WERD_IT w_it(row()->row->word_list());
1458  for (w_it.mark_cycle_pt(); !w_it.cycled_list(); w_it.forward()) {
1459  if (w_it.data() == word_res->word) {
1460  break;
1461  }
1462  }
1463  ASSERT_HOST(!w_it.cycled_list());
1464  delete w_it.extract();
1465  }
1466  // Remove the WERD_RES for the new_word.
1467  // Remove the WORD_RES from the ROW_RES.
1468  WERD_RES_IT wr_it(&row()->word_res_list);
1469  for (wr_it.mark_cycle_pt(); !wr_it.cycled_list(); wr_it.forward()) {
1470  if (wr_it.data() == word_res) {
1471  word_res = NULL;
1472  break;
1473  }
1474  }
1475  ASSERT_HOST(!wr_it.cycled_list());
1476  delete wr_it.extract();
1478 }
void ResetWordIterator()
Definition: pageres.cpp:1532
#define ASSERT_HOST(x)
Definition: errcode.h:84
BOOL8 part_of_combo
Definition: pageres.h:316
BOOL8 combination
Definition: pageres.h:315
ROW_RES * row() const
Definition: pageres.h:736
WERD * word
Definition: pageres.h:175
#define NULL
Definition: host.h:144
WERD_RES* PAGE_RES_IT::forward ( )
inline

Definition at line 713 of file pageres.h.

713  { // Get next word.
714  return internal_forward(false, false);
715  }
WERD_RES * PAGE_RES_IT::forward_block ( )

Definition at line 1666 of file pageres.cpp.

1666  {
1667  while (block_res == next_block_res) {
1668  internal_forward(false, true);
1669  }
1670  return internal_forward(false, true);
1671 }
WERD_RES * PAGE_RES_IT::forward_paragraph ( )

Definition at line 1651 of file pageres.cpp.

1651  {
1652  while (block_res == next_block_res &&
1653  (next_row_res != NULL && next_row_res->row != NULL &&
1654  row_res->row->para() == next_row_res->row->para())) {
1655  internal_forward(false, true);
1656  }
1657  return internal_forward(false, true);
1658 }
PARA * para() const
Definition: ocrrow.h:115
ROW * row
Definition: pageres.h:127
#define NULL
Definition: host.h:144
WERD_RES* PAGE_RES_IT::forward_with_empties ( )
inline

Definition at line 717 of file pageres.h.

717  {
718  return internal_forward(false, true);
719  }
WERD_RES * PAGE_RES_IT::InsertSimpleCloneWord ( const WERD_RES clone_res,
WERD new_word 
)

Definition at line 1268 of file pageres.cpp.

1269  {
1270  // Make a WERD_RES for the new_word.
1271  WERD_RES* new_res = new WERD_RES(new_word);
1272  new_res->CopySimpleFields(clone_res);
1273  new_res->combination = true;
1274  // Insert into the appropriate place in the ROW_RES.
1275  WERD_RES_IT wr_it(&row()->word_res_list);
1276  for (wr_it.mark_cycle_pt(); !wr_it.cycled_list(); wr_it.forward()) {
1277  WERD_RES* word = wr_it.data();
1278  if (word == word_res)
1279  break;
1280  }
1281  ASSERT_HOST(!wr_it.cycled_list());
1282  wr_it.add_before_then_move(new_res);
1283  if (wr_it.at_first()) {
1284  // This is the new first word, so reset the member iterator so it
1285  // detects the cycled_list state correctly.
1287  }
1288  return new_res;
1289 }
void ResetWordIterator()
Definition: pageres.cpp:1532
#define ASSERT_HOST(x)
Definition: errcode.h:84
BOOL8 combination
Definition: pageres.h:315
ROW_RES * row() const
Definition: pageres.h:736
WERD_RES * word() const
Definition: pageres.h:733
void CopySimpleFields(const WERD_RES &source)
Definition: pageres.cpp:241
void PAGE_RES_IT::MakeCurrentWordFuzzy ( )

Definition at line 1482 of file pageres.cpp.

1482  {
1483  WERD* real_word = word_res->word;
1484  if (!real_word->flag(W_FUZZY_SP) && !real_word->flag(W_FUZZY_NON)) {
1485  real_word->set_flag(W_FUZZY_SP, true);
1486  if (word_res->combination) {
1487  // The next word should be the corresponding part of combo, but we have
1488  // already stepped past it, so find it by search.
1489  WERD_RES_IT wr_it(&row()->word_res_list);
1490  for (wr_it.mark_cycle_pt();
1491  !wr_it.cycled_list() && wr_it.data() != word_res; wr_it.forward()) {
1492  }
1493  wr_it.forward();
1494  ASSERT_HOST(wr_it.data()->part_of_combo);
1495  real_word = wr_it.data()->word;
1496  ASSERT_HOST(!real_word->flag(W_FUZZY_SP) &&
1497  !real_word->flag(W_FUZZY_NON));
1498  real_word->set_flag(W_FUZZY_SP, true);
1499  }
1500  }
1501 }
#define ASSERT_HOST(x)
Definition: errcode.h:84
BOOL8 combination
Definition: pageres.h:315
ROW_RES * row() const
Definition: pageres.h:736
Definition: werd.h:60
WERD * word
Definition: pageres.h:175
BOOL8 flag(WERD_FLAGS mask) const
Definition: werd.h:128
void set_flag(WERD_FLAGS mask, BOOL8 value)
Definition: werd.h:129
BLOCK_RES* PAGE_RES_IT::next_block ( ) const
inline

Definition at line 748 of file pageres.h.

748  { // block of next word
749  return next_block_res;
750  }
ROW_RES* PAGE_RES_IT::next_row ( ) const
inline

Definition at line 745 of file pageres.h.

745  { // row of next word
746  return next_row_res;
747  }
WERD_RES* PAGE_RES_IT::next_word ( ) const
inline

Definition at line 742 of file pageres.h.

742  { // next word
743  return next_word_res;
744  }
bool PAGE_RES_IT::operator!= ( const PAGE_RES_IT other) const
inline

Definition at line 672 of file pageres.h.

672 {return !(*this == other); }
bool PAGE_RES_IT::operator== ( const PAGE_RES_IT other) const

Definition at line 1194 of file pageres.cpp.

1194  {
1195  return word_res == other.word_res &&
1196  row_res == other.row_res &&
1197  block_res == other.block_res;
1198 }
BLOCK_RES* PAGE_RES_IT::prev_block ( ) const
inline

Definition at line 730 of file pageres.h.

730  { // block of prev word
731  return prev_block_res;
732  }
ROW_RES* PAGE_RES_IT::prev_row ( ) const
inline

Definition at line 727 of file pageres.h.

727  { // row of prev word
728  return prev_row_res;
729  }
WERD_RES* PAGE_RES_IT::prev_word ( ) const
inline

Definition at line 724 of file pageres.h.

724  { // previous word
725  return prev_word_res;
726  }
void PAGE_RES_IT::rej_stat_word ( )

Definition at line 1673 of file pageres.cpp.

1673  {
1674  inT16 chars_in_word;
1675  inT16 rejects_in_word = 0;
1676 
1677  chars_in_word = word_res->reject_map.length ();
1678  page_res->char_count += chars_in_word;
1679  block_res->char_count += chars_in_word;
1680  row_res->char_count += chars_in_word;
1681 
1682  rejects_in_word = word_res->reject_map.reject_count ();
1683 
1684  page_res->rej_count += rejects_in_word;
1685  block_res->rej_count += rejects_in_word;
1686  row_res->rej_count += rejects_in_word;
1687  if (chars_in_word == rejects_in_word)
1688  row_res->whole_word_rej_count += rejects_in_word;
1689 }
inT32 length() const
Definition: rejctmap.h:237
REJMAP reject_map
Definition: pageres.h:271
inT32 char_count
Definition: pageres.h:60
inT32 whole_word_rej_count
Definition: pageres.h:130
PAGE_RES * page_res
Definition: pageres.h:658
inT32 char_count
Definition: pageres.h:100
inT32 rej_count
Definition: pageres.h:61
inT32 rej_count
Definition: pageres.h:129
inT32 char_count
Definition: pageres.h:128
inT32 rej_count
Definition: pageres.h:101
inT16 reject_count()
Definition: rejctmap.h:243
short inT16
Definition: host.h:100
void PAGE_RES_IT::ReplaceCurrentWord ( tesseract::PointerVector< WERD_RES > *  words)

Definition at line 1321 of file pageres.cpp.

1322  {
1323  if (words->empty()) {
1325  return;
1326  }
1327  WERD_RES* input_word = word();
1328  // Set the BOL/EOL flags on the words from the input word.
1329  if (input_word->word->flag(W_BOL)) {
1330  (*words)[0]->word->set_flag(W_BOL, true);
1331  } else {
1332  (*words)[0]->word->set_blanks(1);
1333  }
1334  words->back()->word->set_flag(W_EOL, input_word->word->flag(W_EOL));
1335 
1336  // Move the blobs from the input word to the new set of words.
1337  // If the input word_res is a combination, then the replacements will also be
1338  // combinations, and will own their own words. If the input word_res is not a
1339  // combination, then the final replacements will not be either, (although it
1340  // is allowed for the input words to be combinations) and their words
1341  // will get put on the row list. This maintains the ownership rules.
1342  WERD_IT w_it(row()->row->word_list());
1343  if (!input_word->combination) {
1344  for (w_it.mark_cycle_pt(); !w_it.cycled_list(); w_it.forward()) {
1345  WERD* word = w_it.data();
1346  if (word == input_word->word)
1347  break;
1348  }
1349  // w_it is now set to the input_word's word.
1350  ASSERT_HOST(!w_it.cycled_list());
1351  }
1352  // Insert into the appropriate place in the ROW_RES.
1353  WERD_RES_IT wr_it(&row()->word_res_list);
1354  for (wr_it.mark_cycle_pt(); !wr_it.cycled_list(); wr_it.forward()) {
1355  WERD_RES* word = wr_it.data();
1356  if (word == input_word)
1357  break;
1358  }
1359  ASSERT_HOST(!wr_it.cycled_list());
1360  // Since we only have an estimate of the bounds between blobs, use the blob
1361  // x-middle as the determiner of where to put the blobs
1362  C_BLOB_IT src_b_it(input_word->word->cblob_list());
1363  src_b_it.sort(&C_BLOB::SortByXMiddle);
1364  C_BLOB_IT rej_b_it(input_word->word->rej_cblob_list());
1365  rej_b_it.sort(&C_BLOB::SortByXMiddle);
1366  for (int w = 0; w < words->size(); ++w) {
1367  WERD_RES* word_w = (*words)[w];
1368  // Compute blob boundaries.
1369  GenericVector<int> blob_ends;
1370  C_BLOB_LIST* next_word_blobs =
1371  w + 1 < words->size() ? (*words)[w + 1]->word->cblob_list() : NULL;
1372  ComputeBlobEnds(*word_w, next_word_blobs, &blob_ends);
1373  // Delete the fake blobs on the current word.
1374  word_w->word->cblob_list()->clear();
1375  C_BLOB_IT dest_it(word_w->word->cblob_list());
1376  // Build the box word as we move the blobs.
1377  tesseract::BoxWord* box_word = new tesseract::BoxWord;
1378  for (int i = 0; i < blob_ends.size(); ++i) {
1379  int end_x = blob_ends[i];
1380  TBOX blob_box;
1381  // Add the blobs up to end_x.
1382  while (!src_b_it.empty() &&
1383  src_b_it.data()->bounding_box().x_middle() < end_x) {
1384  blob_box += src_b_it.data()->bounding_box();
1385  dest_it.add_after_then_move(src_b_it.extract());
1386  src_b_it.forward();
1387  }
1388  while (!rej_b_it.empty() &&
1389  rej_b_it.data()->bounding_box().x_middle() < end_x) {
1390  blob_box += rej_b_it.data()->bounding_box();
1391  dest_it.add_after_then_move(rej_b_it.extract());
1392  rej_b_it.forward();
1393  }
1394  // Clip to the previously computed bounds. Although imperfectly accurate,
1395  // it is good enough, and much more complicated to determine where else
1396  // to clip.
1397  if (i > 0 && blob_box.left() < blob_ends[i - 1])
1398  blob_box.set_left(blob_ends[i - 1]);
1399  if (blob_box.right() > end_x)
1400  blob_box.set_right(end_x);
1401  box_word->InsertBox(i, blob_box);
1402  }
1403  // Fix empty boxes. If a very joined blob sits over multiple characters,
1404  // then we will have some empty boxes from using the middle, so look for
1405  // overlaps.
1406  for (int i = 0; i < box_word->length(); ++i) {
1407  TBOX box = box_word->BlobBox(i);
1408  if (box.null_box()) {
1409  // Nothing has its middle in the bounds of this blob, so use anything
1410  // that overlaps.
1411  for (dest_it.mark_cycle_pt(); !dest_it.cycled_list();
1412  dest_it.forward()) {
1413  TBOX blob_box = dest_it.data()->bounding_box();
1414  if (blob_box.left() < blob_ends[i] &&
1415  (i == 0 || blob_box.right() >= blob_ends[i - 1])) {
1416  if (i > 0 && blob_box.left() < blob_ends[i - 1])
1417  blob_box.set_left(blob_ends[i - 1]);
1418  if (blob_box.right() > blob_ends[i])
1419  blob_box.set_right(blob_ends[i]);
1420  box_word->ChangeBox(i, blob_box);
1421  break;
1422  }
1423  }
1424  }
1425  }
1426  delete word_w->box_word;
1427  word_w->box_word = box_word;
1428  if (!input_word->combination) {
1429  // Insert word_w->word into the ROW. It doesn't own its word, so the
1430  // ROW needs to own it.
1431  w_it.add_before_stay_put(word_w->word);
1432  word_w->combination = false;
1433  }
1434  (*words)[w] = NULL; // We are taking ownership.
1435  wr_it.add_before_stay_put(word_w);
1436  }
1437  // We have taken ownership of the words.
1438  words->clear();
1439  // Delete the current word, which has been replaced. We could just call
1440  // DeleteCurrentWord, but that would iterate both lists again, and we know
1441  // we are already in the right place.
1442  if (!input_word->combination)
1443  delete w_it.extract();
1444  delete wr_it.extract();
1446 }
int size() const
Definition: genericvector.h:72
tesseract::BoxWord * box_word
Definition: pageres.h:250
void ResetWordIterator()
Definition: pageres.cpp:1532
T & back() const
void set_right(int x)
Definition: rect.h:78
static int SortByXMiddle(const void *v1, const void *v2)
Definition: stepblob.h:119
void DeleteCurrentWord()
Definition: pageres.cpp:1449
inT16 right() const
Definition: rect.h:75
bool null_box() const
Definition: rect.h:46
void set_left(int x)
Definition: rect.h:71
#define ASSERT_HOST(x)
Definition: errcode.h:84
Definition: werd.h:35
BOOL8 combination
Definition: pageres.h:315
Definition: werd.h:36
inT16 left() const
Definition: rect.h:68
ROW_RES * row() const
Definition: pageres.h:736
Definition: werd.h:60
WERD * word
Definition: pageres.h:175
bool empty() const
Definition: genericvector.h:84
Definition: rect.h:30
BOOL8 flag(WERD_FLAGS mask) const
Definition: werd.h:128
#define NULL
Definition: host.h:144
C_BLOB_LIST * rej_cblob_list()
Definition: werd.h:95
C_BLOB_LIST * cblob_list()
Definition: werd.h:100
WERD_RES * word() const
Definition: pageres.h:733
void PAGE_RES_IT::ResetWordIterator ( )

Definition at line 1532 of file pageres.cpp.

1532  {
1533  if (row_res == next_row_res) {
1534  // Reset the member iterator so it can move forward and detect the
1535  // cycled_list state correctly.
1536  word_res_it.move_to_first();
1537  for (word_res_it.mark_cycle_pt();
1538  !word_res_it.cycled_list() && word_res_it.data() != next_word_res;
1539  word_res_it.forward()) {
1540  if (!word_res_it.data()->part_of_combo) {
1541  if (prev_row_res == row_res) prev_word_res = word_res;
1542  word_res = word_res_it.data();
1543  }
1544  }
1545  ASSERT_HOST(!word_res_it.cycled_list());
1546  word_res_it.forward();
1547  } else {
1548  // word_res_it is OK, but reset word_res and prev_word_res if needed.
1549  WERD_RES_IT wr_it(&row_res->word_res_list);
1550  for (wr_it.mark_cycle_pt(); !wr_it.cycled_list(); wr_it.forward()) {
1551  if (!wr_it.data()->part_of_combo) {
1552  if (prev_row_res == row_res) prev_word_res = word_res;
1553  word_res = wr_it.data();
1554  }
1555  }
1556  }
1557 }
WERD_RES_LIST word_res_list
Definition: pageres.h:131
#define ASSERT_HOST(x)
Definition: errcode.h:84
WERD_RES* PAGE_RES_IT::restart_page ( )
inline

Definition at line 680 of file pageres.h.

680  {
681  return start_page(false); // Skip empty blocks.
682  }
WERD_RES * start_page(bool empty_ok)
Definition: pageres.cpp:1509
WERD_RES* PAGE_RES_IT::restart_page_with_empties ( )
inline

Definition at line 683 of file pageres.h.

683  {
684  return start_page(true); // Allow empty blocks.
685  }
WERD_RES * start_page(bool empty_ok)
Definition: pageres.cpp:1509
WERD_RES * PAGE_RES_IT::restart_row ( )

Definition at line 1636 of file pageres.cpp.

1636  {
1637  ROW_RES *row = this->row();
1638  if (!row) return NULL;
1639  for (restart_page(); this->row() != row; forward()) {
1640  // pass
1641  }
1642  return word();
1643 }
WERD_RES * forward()
Definition: pageres.h:713
WERD_RES * restart_page()
Definition: pageres.h:680
ROW_RES * row() const
Definition: pageres.h:736
#define NULL
Definition: host.h:144
WERD_RES * word() const
Definition: pageres.h:733
ROW_RES* PAGE_RES_IT::row ( ) const
inline

Definition at line 736 of file pageres.h.

736  { // row of current word
737  return row_res;
738  }
WERD_RES * PAGE_RES_IT::start_page ( bool  empty_ok)

Definition at line 1509 of file pageres.cpp.

1509  {
1510  block_res_it.set_to_list(&page_res->block_res_list);
1511  block_res_it.mark_cycle_pt();
1512  prev_block_res = NULL;
1513  prev_row_res = NULL;
1514  prev_word_res = NULL;
1515  block_res = NULL;
1516  row_res = NULL;
1517  word_res = NULL;
1518  next_block_res = NULL;
1519  next_row_res = NULL;
1520  next_word_res = NULL;
1521  internal_forward(true, empty_ok);
1522  return internal_forward(false, empty_ok);
1523 }
BLOCK_RES_LIST block_res_list
Definition: pageres.h:62
PAGE_RES * page_res
Definition: pageres.h:658
#define NULL
Definition: host.h:144
WERD_RES* PAGE_RES_IT::word ( ) const
inline

Definition at line 733 of file pageres.h.

733  { // current word
734  return word_res;
735  }

Member Data Documentation

PAGE_RES* PAGE_RES_IT::page_res

Definition at line 658 of file pageres.h.


The documentation for this class was generated from the following files: