Changeset 3739


Ignore:
Timestamp:
Mar 23, 2014, 11:53:07 PM (4 years ago)
Author:
ksherdy
Message:

Added support for segment-at-a-time processing. Match strings at follows position.

Location:
proto/RE/demo
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • proto/RE/demo/grep.py

    r3736 r3739  
    7474        e  = 0
    7575        LF = 0
    76        
     76
    7777class Output():
    7878        matches                 = 0
    7979        lines                   = 0
    80         line_starts     = 0
     80        line_starts             = 0
    8181        line_ends               = 0
    82         byte_data               = 0
    83 
     82        all_starts              = 0
     83       
    8484def ClassifyBytes(basis_bits, lex): 
    8585        temp1 = (basis_bits.bit_1 &~ basis_bits.bit_0)
     
    110110       
    111111def Match(lex, output):
    112         m0 = lex.a
    113         m1 = pablo.Advance(m0) & lex.p
    114         m2 = pablo.Advance(m1) & lex.p
    115         m3 = pablo.Advance(m2) & lex.l
    116         m4 = pablo.Advance(m3) & lex.e
    117         output.matches = m4
     112    # Mark _follows.
     113        cursor = pablo.Advance(lex.a)
     114        cursor = pablo.Advance(cursor & lex.p)
     115        cursor = pablo.Advance(cursor & lex.p)
     116        cursor = pablo.Advance(cursor & lex.l)
     117        cursor = pablo.Advance(cursor & lex.e)
     118        output.matches = cursor
    118119
    119120def MatchLines(lex, output):
     121       
     122        all_line_starts   = pablo.ScanToFirst(~lex.LF) | (pablo.Advance(lex.LF) &~ lex.LF)
     123        output.all_starts = all_line_starts
     124        all_line_ends     = lex.LF
    120125
    121         line_start      = pablo.Advance(~0) ^ ~0 # pablo.First()
    122         cursor                  = line_start
     126        last_line_start   = pablo.ScanToFirst(all_line_starts) 
     127        cursor            = last_line_start
    123128
    124129        while(pablo.inFile(cursor)):
    125                 cursor = pablo.ScanTo(cursor, (lex.LF | output.matches))
    126                 if(cursor & lex.LF):
    127                         line_start = pablo.Advance(cursor)
    128                         cursor = line_start
     130               
     131                if(cursor & all_line_starts):
     132                        last_line_start = cursor
     133                       
    129134                if(cursor & output.matches):
    130                         output.line_starts  |= line_start
    131                         output.line_ends    |= pablo.AdvanceThenScanTo(cursor, lex.LF)
    132                         output.lines |= pablo.InclusiveSpan(output.line_starts, output.line_ends) # LF
    133                         cursor = pablo.Advance(cursor)
     135                        cursor = pablo.ScanTo(cursor, lex.LF)
     136                        output.lines |= pablo.InclusiveSpan(last_line_start, cursor) # LF | match
     137               
     138                cursor = pablo.AdvanceThenScanTo(cursor, all_line_starts | output.matches)
     139
     140        output.line_starts = output.lines & all_line_starts
     141        output.line_ends   = pablo.ScanTo(output.line_starts, output.lines & all_line_ends)
     142
     143
    134144
    135145###
     
    154164        MatchLines(lex, output)
    155165
    156         ### FilterMatchLines(data, output)
    157         ### WriteStreamOutput(Output)
     166    ### FilterMatchLines(data, output)
     167    ### WriteStreamOutput(Output)
    158168
    159169        ### if(options.count):
  • proto/RE/demo/grep_demo.py

    r3738 r3739  
    114114       
    115115def Match(lex, output):
    116         m0 = lex.a
    117         m1 = pablo.Advance(m0) & lex.p
    118         m2 = pablo.Advance(m1) & lex.p
    119         m3 = pablo.Advance(m2) & lex.l
    120         m4 = pablo.Advance(m3) & lex.e
    121         output.matches = m4
     116#   Mark '_follows'
     117        cursor = pablo.Advance(lex.a)
     118        cursor = pablo.Advance(cursor & lex.p)
     119        cursor = pablo.Advance(cursor & lex.p)
     120        cursor = pablo.Advance(cursor & lex.l)
     121        cursor = pablo.Advance(cursor & lex.e)
     122        output.matches = cursor
     123
     124#   Mark '_ends'
     125#       m0 = lex.a
     126#       m1 = pablo.Advance(m0) & lex.p
     127#       m2 = pablo.Advance(m1) & lex.p
     128#       m3 = pablo.Advance(m2) & lex.l
     129#       m4 = pablo.Advance(m3) & lex.e
     130#       output.matches = m4
    122131
    123132def MatchLines(lex, output):
    124         crt_line_start  = pablo.Advance(~0) ^ ~0 # line_start == pablo.First()
    125         cursor                  = crt_line_start
    126 
    127         LF_or_match     = lex.LF | output.matches
     133
     134        all_line_starts   = pablo.ScanToFirst(~lex.LF) | (pablo.Advance(lex.LF) &~ lex.LF)
     135        output.all_starts = all_line_starts
     136        all_line_ends     = lex.LF
     137
     138        last_line_start   = pablo.ScanToFirst(all_line_starts) 
     139        cursor            = last_line_start
    128140
    129141        while(pablo.inFile(cursor)):
    130                 cursor = pablo.ScanTo(cursor, LF_or_match)
    131                 if(cursor & lex.LF):
    132                         crt_line_start = pablo.Advance(cursor)
    133                         cursor = crt_line_start
     142               
     143                if(cursor & all_line_starts):
     144                        last_line_start = cursor
     145                       
    134146                if(cursor & output.matches):
    135 
    136                         output.line_starts  |= crt_line_start
    137                         output.line_ends    |= pablo.AdvanceThenScanTo(cursor, lex.LF)
    138 
    139                         output.lines |= pablo.InclusiveSpan(output.line_starts, output.line_ends) # LF
    140                         # output.lines |= pablo.SpanUpTo(line_start, cursor) &~ lex.LF                          # no LF
    141                         cursor = pablo.Advance(cursor)
    142 
    143 def MatchLines2(lex, output): # verbose with temporary streams
    144         line_start      = 0
    145         line_end        = 0
    146         line_start      = pablo.Advance(~line_start) ^ ~line_start # line_start == pablo.First()
    147         output.line_starts = line_start
    148 
    149         LF_or_match     = lex.LF | output.matches
    150         cursor                  = pablo.ScanToFirst(LF_or_match)
     147                        cursor = pablo.ScanTo(cursor, lex.LF)
     148                        output.lines |= pablo.InclusiveSpan(last_line_start, cursor) # LF | match
     149               
     150                cursor = pablo.AdvanceThenScanTo(cursor, all_line_starts | output.matches)
     151
     152        output.line_starts = output.lines & all_line_starts
     153        output.line_ends   = pablo.ScanTo(output.line_starts, output.lines & all_line_ends)
     154
     155###
     156###  KH: Fails to compile. Root cause not yet found.
     157###
     158def MatchLines2(lex, output):
     159
     160        all_line_starts   = pablo.ScanToFirst(~lex.LF) | (pablo.Advance(lex.LF) &~ lex.LF)
     161        output.all_starts = all_line_starts
     162        all_line_ends     = lex.LF
     163
     164        last_line_start   = pablo.ScanToFirst(all_line_starts) 
     165        cursor            = last_line_start
    151166
    152167        while(pablo.inFile(cursor)):
    153                 if(cursor & lex.LF):
    154                         line_start = pablo.Advance(cursor)
    155                         cursor = line_start
     168               
     169                if(cursor & all_line_starts):
     170                        last_line_start = cursor
     171                       
    156172                if(cursor & output.matches):
    157                         line_end = pablo.AdvanceThenScanTo(cursor, lex.LF)
    158                         output.line_starts  |= line_start
    159                         output.line_ends    |= line_end
    160 
    161                         output.lines |= pablo.InclusiveSpan(line_start, line_end) | line_end    # LF
    162                         # output.lines |= pablo.SpanUpTo(line_start, cursor) &~ lex.LF                  # no LF
    163                         cursor = line_end
    164                         cursor = pablo.ScanTo(cursor, LF_or_match)
    165                         # cursor = next_end
    166                                
     173                        output.line_starts |= last_line_start                   
     174                        cursor = pablo.ScanTo(cursor, lex.LF)
     175                        output.line_ends |= cursor
     176                        output.lines |= pablo.InclusiveSpan(last_line_start, cursor) # LF | match
     177               
     178                cursor = pablo.AdvanceThenScanTo(cursor, all_line_starts | output.matches)
     179               
    167180def FilterMatchLines(data, output):
    168181        output.byte_data = pablo.filter_bytes(data, ~output.lines)
     
    175188
    176189basis_bits      = Basis()
    177 lex             = Lex()
     190lex                 = Lex()
    178191output          = Output()
    179192
  • proto/RE/demo/grep_template_segment.cpp

    r3738 r3739  
    106106@stream_stmts
    107107
    108 // Segment-at-a-time bufferd processing parameters.
     108// Segment-at-a-time parameters.
    109109int bytes_read              = 0;
    110110int bytes_avail             = 0;
     
    114114int copy_back_offset        = 0;
    115115
    116 int block_index             = 0; // block index wrt current segment
    117 int block_base              = 0; // byte offset wrt current segment
     116int block_index             = 0; // wrt current segment
     117int block_base              = 0; // ?
    118118
    119119//int segment_index           = 0; // segment index wrt current buffer  // unused
     
    123123
    124124int match_offset            = 0;
    125 int line_start_offset            = 0; 
    126 int line_end_offset              = -1;
     125int line_start_offset       = 0;  // ?
     126int line_end_offset         = -1; // ?
    127127
    128128int line_starts_final_offset     = 0;
     
    216216    bytes_remaining = bytes_avail;
    217217   
     218    block_base      = 0;   
     219   
    218220    //if(feof(infile)) { KH: No! OPC /*bytes_remaining--;*/ }
    219221    if(ferror(infile)) { perror( "io error" ); exit(1); }
    220222
    221223    // Process full segment.
    222    
    223     block_base      = 0;
     224    
     225    //assert(("fread exceeded segment size.", bytes_avail <= SEGMENT_SIZE));
    224226   
    225227    if (bytes_avail == SEGMENT_SIZE) { // (bytes_remaining >= SEGMENT_SIZE)
    226        
     228     
    227229      if(only_matching) { 
    228230        match_scanner.init();
    229231      }
    230              
    231       line_starts_scanner.init();
    232       line_ends_scanner.init();
     232     
     233      if(!only_matching) {
     234        line_starts_scanner.init();
     235        line_ends_scanner.init();
     236      }
    233237
    234238      for(block_index = 0;
     
    237241
    238242        byte_data = &buffer[block_base];
    239         //Replaced with C++ stream function 'do_block()' calls.
     243       
     244        //Compiled to 'do_block()' calls.
    240245        @block_stmts
    241246
     
    252257      if(only_matching) {
    253258        while(match_scanner.has_next()) {
    254           match_offset = match_scanner.scan_to_next() - pattern_size + 1;
     259          match_offset = match_scanner.scan_to_next() - pattern_size;
    255260          if(byte_offset) {
    256261              int match_stream_offset = stream_base + match_offset;
     
    267272        copy_back_size      = pattern_size;           
    268273        copy_back_offset    = bytes_avail - copy_back_size;           
    269        
    270274      }
    271275 
    272276      if(!only_matching) {
    273          
    274           print_register<BitBlock>("starts", output.line_starts);
    275           print_register<BitBlock>("starts", output.line_ends);
     277
     278        assert(("Line length exceeds segment size.", line_ends_scanner.has_next() && line_starts_scanner.has_next())); 
     279         
     280        //if(has_line_start) {
     281            line_starts_final_offset = line_starts_scanner.get_final_pos();
     282        //}
     283        //if(has_line_end) {
     284            line_ends_final_offset = line_ends_scanner.get_final_pos();
     285        //}
     286           
     287        // if(!has_line_start && !has_line_end) {/* Set flag to buffer entire segment. */;}
     288         
     289        while(line_starts_scanner.has_next() && line_ends_scanner.has_next()) {
     290             
     291          line_start_offset  = line_starts_scanner.scan_to_next();
     292          line_end_offset    = line_ends_scanner.scan_to_next();
     293             
     294          if(byte_offset) {
     295            fprintf(outfile, "%d:", stream_base + line_start_offset);
     296          }
     297             
     298          fwrite(&buffer[line_start_offset], 1, line_end_offset - line_start_offset + 1, outfile);
     299        }
     300       
     301        copy_back_offset   = (line_starts_final_offset > line_ends_final_offset) ? line_starts_final_offset : (line_ends_final_offset + 1) ;
     302        copy_back_size     = bytes_avail - copy_back_offset;   
     303
     304      }
    276305     
    277           // both, either, or none (in the general case)     
    278           bool has_line_start   = line_starts_scanner.has_next();
    279           bool has_line_end     = line_ends_scanner.has_next();
    280          
    281           //if(has_line_start) {
    282               line_starts_final_offset = line_starts_scanner.get_final_pos();
    283           //}
    284           //if(has_line_end) {
    285               line_ends_final_offset = line_ends_scanner.get_final_pos();
    286           //}
    287           assert(("Line length exceeds segment size.", has_line_end));
    288           // if(!has_line_start && !has_line_end) {/* Set flag to buffer entire segment. */;}
    289          
    290           while(line_starts_scanner.has_next() && line_ends_scanner.has_next()) {
    291              
    292               line_start_offset  = line_starts_scanner.scan_to_next();
    293               line_end_offset    = line_ends_scanner.scan_to_next();
    294              
    295               if(byte_offset) {
    296                   fprintf(outfile, "%d:", stream_base + line_start_offset);
    297               }
    298              
    299               fwrite(&buffer[line_start_offset], 1, line_end_offset - line_start_offset, outfile);
    300               fprintf(outfile, "\n");
    301           }
    302          
    303           copy_back_offset   = (line_starts_final_offset > line_ends_final_offset) ? line_starts_final_offset : (line_ends_final_offset + 1);
    304           copy_back_size  = bytes_avail - copy_back_offset;   
    305          
    306           bytes_remaining -= SEGMENT_SIZE;
    307       }   
    308      
     306      bytes_remaining -= SEGMENT_SIZE;
    309307    }
    310308   
    311     // Process partial segment
     309    // Process a partial segment.
    312310    if(bytes_remaining > 0) {
    313        
     311
    314312        block_index = 0;   
    315313       
     
    318316        }
    319317       
    320         line_starts_scanner.init();
    321         line_ends_scanner.init();
    322 
     318        if(!only_matching) {
     319          line_starts_scanner.init();
     320          line_ends_scanner.init();
     321        }
     322       
    323323        // Process full blocks.
    324324        while (bytes_remaining >= BLOCK_SIZE) {
    325325          byte_data = &buffer[block_base];
    326           //Replaced with C++ stream function 'do_block()' calls.
     326         
     327          // Compiler 'do_block()' calls.
    327328          @block_stmts
    328329   
     
    331332          }       
    332333         
    333           line_starts_scanner.load_block(output.line_starts, block_index);
    334           line_ends_scanner.load_block(output.line_ends, block_index);
     334          if(!only_matching) {
     335            line_starts_scanner.load_block(output.line_starts, block_index);
     336            line_ends_scanner.load_block(output.line_ends, block_index);
     337          }
    335338   
    336339          block_base += BLOCK_SIZE;
    337340          bytes_remaining -= BLOCK_SIZE;
    338341          block_index++;
    339         }
    340 
    341         // Process the final partial block. // KH: Not required, remove.
    342         if(bytes_remaining > 0) {           
    343           BitBlock EOF_mask = bitblock::srl(simd<1>::constant<1>(), convert(BLOCK_SIZE-bytes_remaining));
    344          
    345           byte_data = &buffer[block_base];
    346           //Replaced with C++ stream function 'do_final_block()' calls.
    347           @final_block_stmts
    348    
    349           if(only_matching) {
    350             match_scanner.load_block(output.matches & EOF_mask, block_index);
    351           }
    352          
    353           line_starts_scanner.load_block(output.line_starts & EOF_mask, block_index);
    354           line_ends_scanner.load_block(output.line_ends & EOF_mask, block_index);         
    355          
    356           if(0) {
    357               print_register<BitBlock>("starts", output.line_starts);
    358               print_register<BitBlock>("ends", output.line_ends);
    359               print_register<BitBlock>("lex.LF", lex.LF);
    360               print_register<BitBlock>("mask", EOF_mask);
    361           }
    362         }
    363 
    364         if(only_matching) {
     342       }
     343
     344       // Process a partial final block. // KH: Not required.     
     345       BitBlock EOF_mask = bitblock::srl(simd<1>::constant<1>(), convert(BLOCK_SIZE - bytes_remaining));   
     346       byte_data = &buffer[block_base];
     347         
     348       // Compiler 'do_final_block()' calls.
     349       @final_block_stmts
     350   
     351       if(only_matching) {
     352          match_scanner.load_block(output.matches & EOF_mask, block_index);
     353       }
     354         
     355       if(!only_matching) {   
     356         line_starts_scanner.load_block(output.line_starts & EOF_mask, block_index);
     357         line_ends_scanner.load_block(output.line_ends & EOF_mask, block_index);           
     358       }
     359
     360       if(only_matching) {
    365361          while(match_scanner.has_next()) {
    366             match_offset = match_scanner.scan_to_next() - pattern_size + 1;
     362            match_offset = match_scanner.scan_to_next() - pattern_size;
    367363            if(byte_offset) {
    368364                int match_stream_offset = stream_base + match_offset;
    369365                fprintf(outfile, "%d:", match_stream_offset);
    370             } 
     366            }
    371367           
    372368            // KH: Lookahead.
     
    377373         
    378374          copy_back_size      = pattern_size;           
    379           copy_back_offset    = bytes_avail - copy_back_size;           
    380          
     375          copy_back_offset    = bytes_avail - copy_back_size;             
    381376        }
    382377     
    383378        if(!only_matching) {
    384        
    385             // both, either, or none (in the general case)     
    386             bool has_line_start   = line_starts_scanner.has_next();
    387             bool has_line_end     = line_ends_scanner.has_next();
    388379           
     380            assert(("Line length exceeds segment size.", line_ends_scanner.has_next() && line_starts_scanner.has_next())); 
     381                       
    389382            //if(has_line_start) {
    390383                line_starts_final_offset = line_starts_scanner.get_final_pos();
     
    393386                line_ends_final_offset = line_ends_scanner.get_final_pos();
    394387            //}
    395             //assert(("Line length exceeds segment size.", has_line_end));
     388               
    396389            // if(!has_line_start && !has_line_end) {/* Set flag to buffer entire segment. */;}
    397            
     390   
    398391            while(line_starts_scanner.has_next() && line_ends_scanner.has_next()) {
    399392               
     
    405398                }
    406399               
    407                 fwrite(&buffer[line_start_offset], 1, line_end_offset - line_start_offset, outfile);
    408                 fprintf(outfile, "\n");
     400                fwrite(&buffer[line_start_offset], 1, line_end_offset - line_start_offset + 1, outfile);
    409401            }
    410402
    411             copy_back_offset    = (line_starts_final_offset > line_ends_final_offset) ? line_starts_final_offset : (line_ends_final_offset + 1);
    412             copy_back_size      = bytes_avail - copy_back_offset;           
    413            
    414         }
    415 
     403            copy_back_offset   = (line_starts_final_offset > line_ends_final_offset) ? line_starts_final_offset : (line_ends_final_offset + 1) ;
     404            copy_back_size     = bytes_avail - copy_back_offset;
     405        }       
    416406    }
    417      
     407   
     408    if(0) {
     409        cout << "bytes_avail: " << bytes_avail << endl;
     410        cout << "line_starts_final_offset: " << line_starts_final_offset << endl;
     411        cout << "line_ends_final_offset: " << line_ends_final_offset << endl;
     412        cout << "offset: " << copy_back_offset << ", " << "size: " << copy_back_size << endl;
     413    }
     414   
    418415    memmove(&buffer[0], &buffer[copy_back_offset], copy_back_size);
     416   
     417    // pablo.ScanToFirst() must clear carry-in at the start of each segment.
     418    classifyBytes.clear();
     419    match.clear();
     420    matchLines.clear();
    419421   
    420422    stream_base += bytes_avail;
     
    422424  }
    423425
    424   if(infile) {  fclose(infile); }
     426  if(infile) { fclose(infile); }
    425427  if(outfile) { fclose(outfile); }
     428 
    426429  return 0;
    427430}
  • proto/RE/demo/src/Makefile

    r3738 r3739  
    6666
    6767clean:
    68         rm -f $(SRCFILE) $(OUTFILE) 0 1
     68        rm -f $(SRCFILE) $(OUTFILE) 0 1 2
    6969
  • proto/RE/demo/test/fruitlist4.dat

    r3738 r3739  
    1 applepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepinepineap
    2 crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple
    3 applepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepinepineap
    4 crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple
    5 applepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepinepineap
    6 crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple
    7 applepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepinepineap
    8 crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple
     1applepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepineapplepinepinea
     2crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab apple crab appl
     3
Note: See TracChangeset for help on using the changeset viewer.