pax_global_header00006660000000000000000000000064131677422160014523gustar00rootroot0000000000000052 comment=5e153da50c4f015ad78e9d5527b01b8511e1aceb mediawiki-php-wikidiff2-1.5.1/000077500000000000000000000000001316774221600161335ustar00rootroot00000000000000mediawiki-php-wikidiff2-1.5.1/.gitignore000066400000000000000000000004661316774221600201310ustar00rootroot00000000000000.svn *~ *.kate-swp .*.swp .idea *.in *.lo *.la *.m4 Makefile* config.* CMake* *.iml *.so install_manifest.txt .deps configure install-sh libtool ltmain.sh missing mkinstalldirs run-test run-tests.php .libs autom4te.cache build modules tests/*.diff tests/*.exp tests/*.log tests/*.out tests/*.php tests/*.sh mediawiki-php-wikidiff2-1.5.1/.gitreview000066400000000000000000000001471316774221600201430ustar00rootroot00000000000000[gerrit] host=gerrit.wikimedia.org port=29418 project=mediawiki/php/wikidiff2.git defaultbranch=master mediawiki-php-wikidiff2-1.5.1/CREDITS000066400000000000000000000000111316774221600171430ustar00rootroot00000000000000wikidiff2mediawiki-php-wikidiff2-1.5.1/DiffEngine.h000066400000000000000000000472271316774221600203160ustar00rootroot00000000000000/** * GPL blah blah, see below for history */ #ifndef DIFFENGINE_H #define DIFFENGINE_H //#define USE_JUDY #include #include #include #include #include #include #include #include #ifdef USE_JUDY #include "JudyHS.h" #endif #include "Wikidiff2.h" #include "Word.h" #include "textutil.h" // helper function to calculate similarity of text lines, based on existing diff code. // used in DiffEngine and Wikidiff2. double calculateSimilarity(TextUtil::WordVector& words1, TextUtil::WordVector& words2, long long bailoutComplexity, int *opCountPtr = nullptr); /** * Diff operation * * from and to are vectors containing pointers to the objects passed in from_lines and to_lines * * op is one of the following * copy: A sequence of lines (in from and to) which are the same in both files. * del: A sequence of lines (in from) which were in the first file but not the second. * add: A sequence of lines (in to) which were in the second file but not the first. * change: A sequence of lines which are different between the two files. Lines from the * first file are in from, lines from the second are in to. The two vectors need * not be the same length. */ template class DiffOp { public: typedef std::vector > PointerVector; DiffOp(int op_, const PointerVector & from_, const PointerVector & to_) : op(op_), from(from_), to(to_) {} enum {copy, del, add, change}; int op; PointerVector from; PointerVector to; }; /** * Basic diff template class. After construction, edits will contain a vector of DiffOpTemplate * objects representing the diff */ template class Diff { public: typedef std::vector > ValueVector; typedef std::vector, WD2_ALLOCATOR > DiffOpVector; Diff(const ValueVector & from_lines, const ValueVector & to_lines, long long bailoutComplexity = 0); virtual void add_edit(const DiffOp & edit) { edits.push_back(edit); } unsigned size() { return edits.size(); } DiffOp & operator[](int i) {return edits[i];} DiffOpVector edits; }; /** * Class used internally by Diff to actually compute the diffs. * * The algorithm used here is mostly lifted from the perl module * Algorithm::Diff (version 1.06) by Ned Konz, which is available at: * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip * * More ideas are taken from: * http://www.ics.uci.edu/~eppstein/161/960229.html * * Some ideas are (and a bit of code) are from from analyze.c, from GNU * diffutils-2.7, which can be found at: * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz * * This implementation is largely due to Geoffrey T. Dairiki, who wrote this * diff engine for phpwiki 1-3.3. It was then adopted by MediaWiki. * * Finally, it was ported to C++ by Tim Starling in February 2006 * * @access private */ template class DiffEngine { public: // Vectors typedef std::vector BoolVector; // skip the allocator here to get the specialisation typedef std::vector > PointerVector; typedef std::vector > ValueVector; typedef std::vector > IntVector; typedef std::vector, WD2_ALLOCATOR > > IntPairVector; // Maps #ifdef USE_JUDY typedef JudyHS MatchesMap; #else typedef std::map, WD2_ALLOCATOR > MatchesMap; #endif // Sets typedef std::set, WD2_ALLOCATOR > IntSet; #ifdef USE_JUDY typedef JudySet ValueSet; #else typedef std::set, WD2_ALLOCATOR > ValueSet; #endif DiffEngine() : done(false) {} void clear(); void diff (const ValueVector & from_lines, const ValueVector & to_lines, Diff & diff, long long bailoutComplexity = 0); int lcs_pos (int ypos); void compareseq (int xoff, int xlim, int yoff, int ylim); void shift_boundaries (const ValueVector & lines, BoolVector & changed, const BoolVector & other_changed); protected: int diag (int xoff, int xlim, int yoff, int ylim, int nchunks, IntPairVector & seps); BoolVector xchanged, ychanged; PointerVector xv, yv; IntVector xind, yind; IntVector seq; IntSet in_seq; int lcs; bool done; enum {MAX_CHUNKS=8}; void detectDissimilarChanges(PointerVector& del, PointerVector& add, Diff& diff, long long bailoutComplexity); bool looksLikeChange(const T& del, const T& add, long long bailoutComplexity); }; //----------------------------------------------------------------------------- // DiffEngine implementation //----------------------------------------------------------------------------- template void DiffEngine::clear() { xchanged.clear(); ychanged.clear(); xv.clear(); yv.clear(); xind.clear(); yind.clear(); seq.clear(); in_seq.clear(); done = false; } // for a DiffOp::change, decide whether it should be treated as a successive add and delete based on similarity. template inline bool DiffEngine::looksLikeChange(const T& del, const T& add, long long bailoutComplexity) { TextUtil::WordVector words1, words2; TextUtil::explodeWords(del, words1); TextUtil::explodeWords(add, words2); return calculateSimilarity(words1, words2, bailoutComplexity) > 0.25; } // go through list of changed lines. if they are too dissimilar, convert to del+add. template inline void DiffEngine::detectDissimilarChanges(PointerVector& del, PointerVector& add, Diff& diff, long long bailoutComplexity) { int i; static PointerVector empty; for (i = 0; i(DiffOp::del, d, empty)); diff.add_edit(DiffOp(DiffOp::add, empty, a)); } if (i) { add.erase(add.begin(), add.begin()+i); del.erase(del.begin(), del.begin()+i); } } template<> inline void DiffEngine::detectDissimilarChanges(PointerVector& del, PointerVector& add, Diff& diff, long long bailoutComplexity) { // compiles to no-op in Word specialization. } template void DiffEngine::diff (const ValueVector & from_lines, const ValueVector & to_lines, Diff & diff, long long bailoutComplexity /* = 0 */) { int n_from = (int)from_lines.size(); int n_to = (int)to_lines.size(); // If this diff engine has been used before for a diff, clear the member variables if (done) { clear(); } xchanged.resize(n_from); ychanged.resize(n_to); seq.resize(std::max(n_from, n_to) + 1); // Skip leading common lines. int skip, endskip; for (skip = 0; skip < n_from && skip < n_to; skip++) { if (from_lines[skip] != to_lines[skip]) break; xchanged[skip] = ychanged[skip] = false; } // Skip trailing common lines. int xi = n_from, yi = n_to; for (endskip = 0; --xi > skip && --yi > skip; endskip++) { if (from_lines[xi] != to_lines[yi]) break; xchanged[xi] = ychanged[yi] = false; } long long complexity = (long long)(n_from - skip - endskip) * (n_to - skip - endskip); // If too complex, just output "whole left side replaced with right" if (bailoutComplexity > 0 && complexity > bailoutComplexity) { PointerVector del; PointerVector add; for (xi = 0; xi < n_from; xi++) { del.push_back(&from_lines[xi]); } for (yi = 0; yi < n_to; yi++) { add.push_back(&to_lines[yi]); } diff.add_edit(DiffOp(DiffOp::change, del, add)); done = true; return; } // Ignore lines which do not exist in both files. ValueSet xhash, yhash; for (xi = skip; xi < n_from - endskip; xi++) { xhash.insert(from_lines[xi]); } for (yi = skip; yi < n_to - endskip; yi++) { const T & line = to_lines[yi]; if ( (ychanged[yi] = (xhash.find(line) == xhash.end())) ) continue; yhash.insert(line); yv.push_back(&line); yind.push_back(yi); } for (xi = skip; xi < n_from - endskip; xi++) { const T & line = from_lines[xi]; if ( (xchanged[xi] = (yhash.find(line) == yhash.end())) ) continue; xv.push_back(&line); xind.push_back(xi); } // Find the LCS. compareseq(0, xv.size(), 0, yv.size()); // Merge edits when possible shift_boundaries(from_lines, xchanged, ychanged); shift_boundaries(to_lines, ychanged, xchanged); // Compute the edit operations. xi = yi = 0; while (xi < n_from || yi < n_to) { assert(yi < n_to || xchanged[xi]); assert(xi < n_from || ychanged[yi]); // Skip matching "snake". PointerVector del; PointerVector add; PointerVector empty; while (xi < n_from && yi < n_to && !xchanged[xi] && !ychanged[yi]) { del.push_back(&from_lines[xi]); add.push_back(&to_lines[yi]); ++xi; ++yi; } if (del.size()) { diff.add_edit(DiffOp(DiffOp::copy, del, add)); del.clear(); add.clear(); } // Find deletes & adds. while (xi < n_from && xchanged[xi]) del.push_back(&from_lines[xi++]); while (yi < n_to && ychanged[yi]) add.push_back(&to_lines[yi++]); detectDissimilarChanges(del, add, diff, bailoutComplexity); if (del.size() && add.size()) #ifdef DIFFENGINE__EVERY_CHANGE_IS_AN_ADD_AND_DELETE // for generating a worst-case benchmark of the "show moved paragraphs" patch (gerrit change 319866) { diff.add_edit(DiffOp(DiffOp::del, del, empty)); diff.add_edit(DiffOp(DiffOp::add, empty, add)); } #else diff.add_edit(DiffOp(DiffOp::change, del, add)); #endif else if (del.size()) diff.add_edit(DiffOp(DiffOp::del, del, empty)); else if (add.size()) diff.add_edit(DiffOp(DiffOp::add, empty, add)); } done = true; } /* Divide the Largest Common Subsequence (LCS) of the sequences * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally * sized segments. * * Returns (LCS, SEPS). LCS is the length of the LCS. SEPS is an * array of NCHUNKS+1 (X, Y) indexes giving the diving points between * sub sequences. The first sub-sequence is contained in [X0, X1), * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on. Note * that (X0, Y0) == (XOFF, YOFF) and * (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM). * * This function assumes that the first lines of the specified portions * of the two files do not match, and likewise that the last lines do not * match. The caller must trim matching lines from the beginning and end * of the portions it is going to specify. */ template int DiffEngine::diag (int xoff, int xlim, int yoff, int ylim, int nchunks, IntPairVector & seps) { using std::swap; using std::make_pair; using std::copy; bool flip = false; MatchesMap ymatches; if (xlim - xoff > ylim - yoff) { // Things seems faster (I'm not sure I understand why) // when the shortest sequence in X. flip = true; swap(xoff, yoff); swap(xlim, ylim); } if (flip) for (int i = ylim - 1; i >= yoff; i--) ymatches[*xv[i]].push_back(i); else for (int i = ylim - 1; i >= yoff; i--) ymatches[*yv[i]].push_back(i); int nlines = ylim - yoff; lcs = 0; seq[0] = yoff - 1; in_seq.clear(); // 2-d array, line major, chunk minor IntVector ymids(nlines * nchunks); int numer = xlim - xoff + nchunks - 1; int x = xoff, x1, y1; for (int chunk = 0; chunk < nchunks; chunk++) { if (chunk > 0) for (int i = 0; i <= lcs; i++) ymids.at(i * nchunks + chunk-1) = seq[i]; x1 = xoff + (int)((numer + (xlim-xoff)*chunk) / nchunks); for ( ; x < x1; x++) { const T & line = flip ? *yv[x] : *xv[x]; #ifdef USE_JUDY IntVector * pMatches = ymatches.Get(line); if (!pMatches) continue; #else typename MatchesMap::iterator iter = ymatches.find(line); if (iter == ymatches.end()) continue; IntVector * pMatches = &(iter->second); #endif IntVector::iterator y; int k = 0; for (y = pMatches->begin(); y != pMatches->end(); ++y) { if (!in_seq.count(*y)) { k = lcs_pos(*y); assert(k > 0); copy(ymids.begin() + (k-1) * nchunks, ymids.begin() + k * nchunks, ymids.begin() + k * nchunks); ++y; break; } } for ( ; y != pMatches->end(); ++y) { if (*y > seq[k-1]) { assert(*y < seq[k]); // Optimization: this is a common case: // next match is just replacing previous match. in_seq.erase(seq[k]); seq[k] = *y; in_seq.insert(*y); } else if (!in_seq.count(*y)) { k = lcs_pos(*y); assert(k > 0); copy(ymids.begin() + (k-1) * nchunks, ymids.begin() + k * nchunks, ymids.begin() + k * nchunks); } } } } seps.clear(); seps.resize(nchunks + 1); seps[0] = flip ? make_pair(yoff, xoff) : make_pair(xoff, yoff); IntVector::iterator ymid = ymids.begin() + lcs * nchunks; for (int n = 0; n < nchunks - 1; n++) { x1 = xoff + (numer + (xlim - xoff) * n) / nchunks; y1 = ymid[n] + 1; seps[n+1] = flip ? make_pair(y1, x1) : make_pair(x1, y1); } seps[nchunks] = flip ? make_pair(ylim, xlim) : make_pair(xlim, ylim); return lcs; } template int DiffEngine::lcs_pos (int ypos) { int end = lcs; if (end == 0 || ypos > seq[end]) { seq[++lcs] = ypos; in_seq.insert(ypos); return lcs; } int beg = 1; while (beg < end) { int mid = (beg + end) / 2; if ( ypos > seq[mid] ) beg = mid + 1; else end = mid; } assert(ypos != seq[end]); in_seq.erase(seq[end]); seq[end] = ypos; in_seq.insert(ypos); return end; } /* Find LCS of two sequences. * * The results are recorded in the vectors {x,y}changed[], by * storing a 1 in the element for each line that is an insertion * or deletion (ie. is not in the LCS). * * The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. * * Note that XLIM, YLIM are exclusive bounds. * All line numbers are origin-0 and discarded lines are not counted. */ template void DiffEngine::compareseq (int xoff, int xlim, int yoff, int ylim) { using std::pair; IntPairVector seps; int lcs; // Slide down the bottom initial diagonal. while (xoff < xlim && yoff < ylim && *xv[xoff] == *yv[yoff]) { ++xoff; ++yoff; } // Slide up the top initial diagonal. while (xlim > xoff && ylim > yoff && *xv[xlim - 1] == *yv[ylim - 1]) { --xlim; --ylim; } if (xoff == xlim || yoff == ylim) lcs = 0; else { // This is ad hoc but seems to work well. //nchunks = sqrt(min(xlim - xoff, ylim - yoff) / 2.5); //nchunks = max(2,min(8,(int)nchunks)); int nchunks = std::min(MAX_CHUNKS-1, std::min(xlim - xoff, ylim - yoff)) + 1; lcs = diag(xoff, xlim, yoff, ylim, nchunks, seps); } if (lcs == 0) { // X and Y sequences have no common subsequence: // mark all changed. while (yoff < ylim) ychanged[yind[yoff++]] = true; while (xoff < xlim) xchanged[xind[xoff++]] = true; } else { // Use the partitions to split this problem into subproblems. IntPairVector::iterator pt1, pt2; pt1 = pt2 = seps.begin(); while (++pt2 != seps.end()) { compareseq (pt1->first, pt2->first, pt1->second, pt2->second); pt1 = pt2; } } } /* Adjust inserts/deletes of identical lines to join changes * as much as possible. * * We do something when a run of changed lines include a * line at one end and has an excluded, identical line at the other. * We are free to choose which identical line is included. * `compareseq' usually chooses the one at the beginning, * but usually it is cleaner to consider the following identical line * to be the "change". * * This is extracted verbatim from analyze.c (GNU diffutils-2.7). */ template void DiffEngine::shift_boundaries (const ValueVector & lines, BoolVector & changed, const BoolVector & other_changed) { int i = 0; int j = 0; int len = (int)lines.size(); int other_len = (int)other_changed.size(); while (1) { /* * Scan forwards to find beginning of another run of changes. * Also keep track of the corresponding point in the other file. * * Throughout this code, i and j are adjusted together so that * the first i elements of changed and the first j elements * of other_changed both contain the same number of zeros * (unchanged lines). * Furthermore, j is always kept so that j == other_len or * other_changed[j] == false. */ while (j < other_len && other_changed[j]) j++; while (i < len && ! changed[i]) { i++; j++; while (j < other_len && other_changed[j]) j++; } if (i == len) break; int start = i, runlength, corresponding; // Find the end of this run of changes. while (++i < len && changed[i]) continue; do { /* * Record the length of this run of changes, so that * we can later determine whether the run has grown. */ runlength = i - start; /* * Move the changed region back, so long as the * previous unchanged line matches the last changed one. * This merges with previous changed regions. */ while (start > 0 && lines[start - 1] == lines[i - 1]) { changed[--start] = true; changed[--i] = false; while (start > 0 && changed[start - 1]) start--; while (other_changed[--j]) continue; } /* * Set CORRESPONDING to the end of the changed run, at the last * point where it corresponds to a changed run in the other file. * CORRESPONDING == LEN means no such point has been found. */ corresponding = j < other_len ? i : len; /* * Move the changed region forward, so long as the * first changed line matches the following unchanged one. * This merges with following changed regions. * Do this second, so that if there are no merges, * the changed region is moved forward as far as possible. */ while (i < len && lines[start] == lines[i]) { changed[start++] = false; changed[i++] = true; while (i < len && changed[i]) i++; j++; if (j < other_len && other_changed[j]) { corresponding = i; while (j < other_len && other_changed[j]) j++; } } } while (runlength != i - start); /* * If possible, move the fully-merged run of changes * back to a corresponding run in the other file. */ while (corresponding < i) { changed[--start] = 1; changed[--i] = 0; while (other_changed[--j]) continue; } } } //----------------------------------------------------------------------------- // Diff implementation //----------------------------------------------------------------------------- template Diff::Diff(const ValueVector & from_lines, const ValueVector & to_lines, long long bailoutComplexity) { DiffEngine engine; engine.diff(from_lines, to_lines, *this, bailoutComplexity); } inline double calculateSimilarity(TextUtil::WordVector& words1, TextUtil::WordVector& words2, long long bailoutComplexity, int *opCountPtr /* = nullptr*/) { typedef Diff WordDiff; WordDiff diff(words1, words2, bailoutComplexity); int charsTotal = 0; int opCharCount[4] = { 0 }; double similarity; auto countOpChars = [] (DiffEngine::PointerVector& p) { return std::accumulate(p.begin(), p.end(), 0, [] (int a, const Word *b) { return a + (b->suffixEnd - b->bodyStart); }); }; for (int i = 0; i < diff.size(); ++i) { int op = diff[i].op; int charCount; switch (diff[i].op) { case DiffOp::del: case DiffOp::copy: charCount = countOpChars(diff[i].from); break; case DiffOp::add: charCount = countOpChars(diff[i].to); break; case DiffOp::change: charCount = std::max(countOpChars(diff[i].from), countOpChars(diff[i].to)); break; } opCharCount[op] += charCount; charsTotal += charCount; } if (opCharCount[DiffOp::copy] == 0) { similarity = 0.0; } else { if (charsTotal) { similarity = double(opCharCount[DiffOp::copy]) / charsTotal; } else { similarity = 0.0; } } if (opCountPtr) { for(int i = 0; i < sizeof(opCharCount)/sizeof(opCharCount[0]); ++i) { opCountPtr[i] = opCharCount[i]; } } return similarity; } #endif mediawiki-php-wikidiff2-1.5.1/DiffTest/000077500000000000000000000000001316774221600176435ustar00rootroot00000000000000mediawiki-php-wikidiff2-1.5.1/DiffTest/Api.php000066400000000000000000000004201316774221600210610ustar00rootroot00000000000000page = $page; $this->prevId = $prevId; $this->nextId = $nextId; } public function load() { $data = Api::request( array( 'action' => 'query', 'prop' => 'revisions', 'rvprop' => 'ids|content', 'revids' => "{$this->prevId}|{$this->nextId}", ) ); foreach( $data['query']['pages'] as $page ) { if ( $page['title'] != $this->page ) { continue; } foreach ( $page['revisions'] as $rev ) { $revid = $rev['revid']; if ( !isset( $rev['*'] ) ) { echo "Revision $revid not found\n"; return false; } $text = $rev['*']; if ( $revid == $this->prevId ) { $this->prev = $text; } elseif ( $revid == $this->nextId ) { $this->next = $text; } } } return !is_null( $this->prev ) && !is_null( $this->next ); } }mediawiki-php-wikidiff2-1.5.1/DiffTest/Differ.php000066400000000000000000000011461316774221600215550ustar00rootroot00000000000000' . wikidiff2_do_diff( $a, $b, 2 ) . ''; } } class InlineDiffer implements Differ { public function diff( $a, $b ) { return wikidiff2_inline_diff( $a, $b, 2 ); } } class BothDiffer implements Differ { private $table, $inline; public function __construct() { $this->table = new TableDiffer; $this->inline = new InlineDiffer; } public function diff( $a, $b ) { return $this->table->diff( $a, $b ) . $this->inline->diff( $a, $b ); } } mediawiki-php-wikidiff2-1.5.1/DiffTest/test.php000066400000000000000000000042601316774221600213350ustar00rootroot00000000000000 Diff changes HTML; require 'Api.php'; require 'Change.php'; require 'Differ.php'; $differ = new BothDiffer; $site = "http://en.wikipedia.org/w"; $apiUrl = "$site/api.php"; $indexUrl = "$site/index.php"; $recentChanges = Api::request( array( 'action' => 'query', 'list' => 'recentchanges', 'rctype' => 'edit', 'rclimit' => 'max', ) ); $changes = array(); foreach ( $recentChanges['query']['recentchanges'] as $rc ) { $changes[] = new Change( $rc['title'], $rc['old_revid'], $rc['revid'] ); } $count = count( $changes ); echo "

Found $count changes

\n"; $count = 0; $numProcessed = 0; $totalTime = 0; foreach ( $changes as $change ) { $id = sprintf( "%04d", $count ); $page = htmlspecialchars( $change->page ); echo "\n

[$id] {$page}

\n"; if ( !$change->load() ) { echo "Not all content loaded, skipping
\n"; } $time = microtime( true ); $diff = $differ->diff( $change->prev, $change->next ); $time = microtime( true ) - $time; $totalTime += $time; $numProcessed++; echo "Diffed in {$time}s
\n"; $url = htmlspecialchars( "$indexUrl?diff={$change->nextId}&oldid={$change->prevId}" ); echo "$url"; echo $diff; $count++; } $avg = $numProcessed ? $totalTime / $numProcessed : 0; echo << Total processed$numProcessed Average diff time$avg HTML; mediawiki-php-wikidiff2-1.5.1/FuzzTest/000077500000000000000000000000001316774221600177315ustar00rootroot00000000000000mediawiki-php-wikidiff2-1.5.1/FuzzTest/fuzz.php000066400000000000000000000030711316774221600214410ustar00rootroot00000000000000=' ) ) { echo "wikidiff2 version: $wikidiff2Version (with moved-paragraphs patch)\n"; $hasMovedParagraphDetection = true; } else { echo "wikidiff2 version: $wikidiff2Version (without moved-paragraphs patch)\n"; $hasMovedParagraphDetection = false; } // Bail out early in case of any problems error_reporting( E_ALL | E_STRICT ); /*set_error_handler( function( $errno , $errstr ) { echo htmlspecialchars( $errstr ); die ( 1 ); } );//*/ echo "Performing an infinite fuzz test, press Ctrl+C to end...\n"; $count = 0; $totalTime = 0; $chunkTime = 0; while ( true ) { list( $left, $right ) = Random::randomData(); $contextLines = mt_rand( 0, 10 ); $detectionCutoff = mt_rand( 0, 100 ); $time = microtime( true ); if ( $hasMovedParagraphDetection ) { wikidiff2_do_diff( $left, $right, $contextLines, $detectionCutoff ); } else { wikidiff2_do_diff( $left, $right, $contextLines ); } wikidiff2_inline_diff( $left, $right, $contextLines ); $time = microtime( true ) - $time; $totalTime += $time; $chunkTime += $time; if ( ++$count % 100 == 0 ) { $perIteration = round( $totalTime / $count, 3 ); $perIterationInChunk = round( $chunkTime / 100, 3 ); $chunkTime = 0; echo " $count iterations, avg. iteration time $perIteration ($perIterationInChunk last 100 iterations)\n"; } } mediawiki-php-wikidiff2-1.5.1/FuzzTest/random.php000066400000000000000000000074531316774221600217330ustar00rootroot00000000000000 '0123456789.-', // Latin 1 => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTSTUVWXYZ-', // Russian 2 => 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя-', // Thai 3 => 'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู', ]; private static $separators; public static function randomData() { self::init(); switch ( mt_rand( 0, 4 ) ) { // Diff binary garbage with binary garbage case 0: $left = self::randomBinaryString( mt_rand( 0, self::MAX_CONTENT_LENGTH ) ); $right = self::randomBinaryString( mt_rand( 0, self::MAX_CONTENT_LENGTH ) ); break; // Diff binary garbage with text case 1: $left = self::randomBinaryString( mt_rand( 0, self::MAX_CONTENT_LENGTH ) ); $right = self::randomText(); break; case 2: $left = self::randomText(); $right = self::randomBinaryString( mt_rand( 0, self::MAX_CONTENT_LENGTH ) ); break; // Diff text against text case 3: $left = self::randomText(); $right = self::randomText(); break; // Diff text against shuffled text case 4: $left = self::randomText(); $right = self::randomShuffledText( $left ); break; default: throw new Exception( 'This should not happen' ); } return [ $left, $right ]; } private static function init() { static $initd = false; if ( $initd ) { return; } self::$separators = self::split( '.,?!:;。.!?。\'' ); foreach ( self::$tables as $index => $table ) { self::$tables[$index] = self::split( $table ); } $initd = true; } private static function split( $str ) { $result = preg_split( '//u', $str ); array_shift( $result ); array_pop( $result ); return $result; } private static function randomText( $length = 0 ) { if ( !$length ) { $length = mt_rand( 0, self::MAX_CONTENT_LENGTH ); } $str = ''; do { $str .= self::randomLine(); $str .= str_repeat( "\n", mt_rand( 1, 4 ) ); } while ( mb_strlen( $str ) < $length ); return $str; } private static function randomShuffledText($source) { $sourceLines = explode( "\n", $source ); $sourceLineCount = count( $sourceLines ); $outputLineCount = $sourceLineCount * 2; $ret = ""; for ( $i = 0; $i < $outputLineCount; $i++ ) { $ret .= $sourceLines[ mt_rand( 0, $sourceLineCount - 1 ) ]; $ret .= str_repeat( "\n", mt_rand( 1, 4 ) ); } return $ret; } private static function randomLine( $length = 0 ) { if ( !$length ) { $length = mt_rand( 1, self::MAX_LINE_LENGTH ); } $line = ''; do { $line .= self::randomWord(); $line .= self::randomSeparator( mt_rand( 0, 3 ) ); $line .= str_repeat( ' ', mt_rand( 1, 10 ) ); } while ( strlen( $line ) < $length ); return trim( $line ); } private static function randomWord( $length = 0 ) { if ( !$length ) { $length = mt_rand( 1, self::MAX_WORD_LENGTH ); } $charset = self::$tables[mt_rand( 0, count( self::$tables ) - 1 )]; $str = ''; $chars = count( $charset ); for ( $i = 0; $i < $length; $i++ ) { $str .= $charset[mt_rand( 0, $chars - 1 )]; } return $str; } private static function randomSeparator( $count = 1 ) { $separatorCount = count( self::$separators ); $str = ''; for ( $i = 0; $i < $count; $i++ ) { $str .= self::$separators[mt_rand( 0, $separatorCount - 1 )]; } return $str; } private static function randomBinaryString( $length ) { $str = ''; for ( $i = 0; $i < $length; $i++ ) { $str .= chr( mt_rand( 0, 255 ) ); } return $str; } }mediawiki-php-wikidiff2-1.5.1/InlineDiff.cpp000066400000000000000000000045211316774221600206500ustar00rootroot00000000000000#include "InlineDiff.h" void InlineDiff::printAdd(const String& line) { printWrappedLine("
", line, "
\n"); } void InlineDiff::printDelete(const String& line) { printWrappedLine("
", line, "
\n"); } void InlineDiff::printWordDiff(const String& text1, const String& text2, bool printLeft, bool printRight, const String & srcAnchor, const String & dstAnchor) { WordVector words1, words2; TextUtil::explodeWords(text1, words1); TextUtil::explodeWords(text2, words2); WordDiff worddiff(words1, words2, MAX_WORD_LEVEL_DIFF_COMPLEXITY); String word; // XXXX todo: omit left side & do strike-through according to printLeft/printRight result += "
"; for (unsigned i = 0; i < worddiff.size(); ++i) { DiffOp & op = worddiff[i]; int n, j; if (op.op == DiffOp::copy) { n = op.from.size(); for (j=0; jget_whole(word); printText(word); } } else if (op.op == DiffOp::del) { n = op.from.size(); result += ""; for (j=0; jget_whole(word); printText(word); } result += ""; } else if (op.op == DiffOp::add) { n = op.to.size(); result += ""; for (j=0; jget_whole(word); printText(word); } result += ""; } else if (op.op == DiffOp::change) { n = op.from.size(); result += ""; for (j=0; jget_whole(word); printText(word); } result += ""; n = op.to.size(); result += ""; for (j=0; jget_whole(word); printText(word); } result += ""; } } result += "
\n"; } void InlineDiff::printBlockHeader(int leftLine, int rightLine) { char buf[256]; // should be plenty snprintf(buf, sizeof(buf), "
\n", leftLine, rightLine); result += buf; } void InlineDiff::printContext(const String & input) { printWrappedLine("
", input, "
\n"); } void InlineDiff::printWrappedLine(const char* pre, const String& line, const char* post) { result += pre; if (line.empty()) { result += " "; } else { printText(line); } result += post; } mediawiki-php-wikidiff2-1.5.1/InlineDiff.h000066400000000000000000000010631316774221600203130ustar00rootroot00000000000000#ifndef INLINEDIFF_H #define INLINEDIFF_H #include "Wikidiff2.h" class InlineDiff: public Wikidiff2 { public: protected: void printAdd(const String& line); void printDelete(const String& line); void printWordDiff(const String& text1, const String& text2, bool printLeft = true, bool printRight = true, const String & srcAnchor = "", const String & dstAnchor = ""); void printBlockHeader(int leftLine, int rightLine); void printContext(const String& input); void printWrappedLine(const char* pre, const String& line, const char* post); }; #endif mediawiki-php-wikidiff2-1.5.1/JudyHS.h000066400000000000000000000123441316774221600174560ustar00rootroot00000000000000#ifndef _JUDYHS_CPP_WRAPPER_H #define _JUDYHS_CPP_WRAPPER_H /** * JudyHS wrapper by Tim Starling. May be reused, modified and redistributed without restriction. */ #include #include #include /** * value_type must be the size of a pointer */ template class JudyHSWord { public: JudyHSWord() : handle(NULL) {} ~JudyHSWord() { FreeArray(); } /** * Set the given index to a given value. If it already exists, overwrite it. */ value_type & Set(const char *index, Word_t length, const value_type & value) { value_type *p = (value_type*)JudyHSIns(&handle, (void*)index, length, NULL); *p = value; return *p; } value_type & Set(const std::string & s, const value_type & value) { return Set(s.data(), s.length(), value); } /** * Add the given array element. If it already exists, leave it unchanged. If not, * initialise it with the given value. */ value_type & Add(const char *index, Word_t length, const value_type & value) { value_type *p = (value_type*)JudyHSIns(&handle, (void*)index, length, NULL); if (!*p) { *p = value; } return *p; } value_type & Add(const char *index, Word_t length) { return Add(index, length, value_type()); } value_type & Add(const std::string & s, const value_type & value) { return Add(s.data(), s.size(), value); } value_type & Add(const std::string & s) { return Add(s.data(), s.size()); } value_type & operator[](const std::string & s) { return Add(s); } int Delete(const char *index, Word_t length) { return JudyHSDel(&handle, (void*)index, length, NULL); } int Delete(const std::string & s) { return Delete(s.data(), s.size()); } value_type * Get(const char *index, Word_t length) { return (value_type*)JudyHSGet(handle, (void*)index, length); } value_type * Get(const std::string & s) { return (value_type*)Get(s.data(), s.size()); } Word_t FreeArray() { return JudyHSFreeArray(&handle, NULL); } protected: Pvoid_t handle; }; /** * set class that's kind of compatible with set, if you use your imagination */ class JudySet : public JudyHSWord { public: void insert(const std::string & s) { Add(s, 1); } bool find(const std::string & s) { if (Get(s)) { return true; } else { return false; } } bool end() { return false; } }; /* * General value storage */ template class JudyHS { protected: struct List { List() : prev(NULL), next(NULL) {} List(const value_type & v) : value(v), prev(NULL), next(NULL) {} value_type value; List * prev; List * next; }; public: JudyHS() : handle(NULL), storage(NULL) {} ~JudyHS() { FreeArray(); } /** * Set the given index to a given value. If it already exists, overwrite it. */ value_type & Set(const char *index, Word_t length, const value_type & value) { // Add to the list List * node = new List(value); AddNode(node); // Insert into the judy array List ** pNode = (List**)JudyHSIns(&handle, (void*)index, length, NULL); if (*pNode) { DeleteNode(*pNode); } *pNode = node; return node->value; } value_type & Set(const std::string & s, const value_type & value) { return Set(s.data(), s.size(), value); } /** * Add the given array element. If it already exists, leave it unchanged. If not, * initialise it with the given value. */ value_type & Add(const char *index, Word_t length, const value_type & value) { List ** pNode = (List**)JudyHSIns(&handle, (void*)index, length, NULL); if (!*pNode) { // Add to the list List * node = new List(value); AddNode(node); // Register the list in the array *pNode = node; } return (*pNode)->value; } value_type & Add(const char *index, Word_t length) { return Add(index, length, value_type()); } value_type & Add(const std::string & s, const value_type & value) { return Add(s.data(), s.size(), value); } value_type & Add(const std::string & s) { return Add(s.data(), s.size()); } value_type & operator[](const std::string & s) { return Add(s); } value_type * Get(const char *index, Word_t length) { List ** pNode = (List**)JudyHSGet(handle, (void*)index, length); if (!pNode) { return NULL; } else { return &((*pNode)->value); } } value_type * Get(const std::string & s) { return Get(s.data(), s.size()); } int Delete(const char *index, Word_t length) { List ** pNode = (List**)JudyHSGet(handle, (void*)index, length); if (pNode) { // Unlink and delete node DeleteNode(*pNode); // Remove from array return JudyHSDel(&handle, (void*)index, length, NULL); } else { return 0; } } int Delete(const std::string & s) { return Delete(s.data(), s.size()); } Word_t FreeArray() { // Free all list storage List * node = storage; List * next; while (node) { next = node->next; delete node; node = next; } // Destroy the judy array return JudyHSFreeArray(&handle, NULL); } protected: Pvoid_t handle; List * storage; void AddNode(List * node) { List * oldHead = storage; storage = node; storage->next = oldHead; if (oldHead) oldHead->prev = node; } void DeleteNode(List * node) { if (node->prev) node->prev->next = node->next; if (node->next) node->next->prev = node->prev; if (node == storage) { storage = NULL; } delete node; } }; #endif mediawiki-php-wikidiff2-1.5.1/README000066400000000000000000000053151316774221600170170ustar00rootroot00000000000000Wikidiff2 is partly based on the original wikidiff, partly on DifferenceEngine.php, and partly Tim Starling's own work. It performs word-level (space-delimited) diffs on general text, and character-level diffs on text composed of characters from the Japanese and Thai alphabets and the unified han. Japanese, Chinese and Thai do not use spaces to separate words. The input is assumed to be UTF-8 encoded. Invalid UTF-8 may cause undesirable operation, such as truncation of the output, so the input should be validated by the application. The input text should have unix-style line endings. The output is an HTML fragment -- a number of HTML table rows with the rest of the document structure omitted. The characters "<", ">" and "&" will be HTML-escaped in the output. A number of test files are provided: * test-a1 and test-a2, expected output test-a.diff * test-b1 and test-b2, expected output test-b.diff These pairs together give 85.9% coverage of DiffEngine.h. The remaining untested part is mostly in _DiffEngine::_shift_boundaries(). * chinese-reverse-1.txt and chinese-reverse-2.txt (in chinese-reverse.zip) These files are 2.3MB each, and give a worst-case performance test. Performance in the worst case is sensitive to the performance of the associative array class used to cross-reference the strings. I tried using an STL map and a Judy array. The Judy array gave an 11% improvement in execution time over the map, which could probably be increased to 15% with further optimisation work. I don't consider that to be a sufficient improvement to warrant adding a library dependency, but the code has been left in for the benefit of Judy fans and performance perfectionists. It can be enabled by compiling with -DUSE_JUDY. The C++ wrapper for JudyHS might be of use to someone. Wikidiff2 is a PHP extension. == Dependencies == It requires the following library: * libthai, a Thai language support library http://linux.thai.net/plone/TLWG/libthai/ On Debian-based systems, you need libthai0 and libthai-dev packages * To build wikidiff2 as a HHVM extension on Debian systems, you need the following packages: hhvm-dev libtbb-dev libtbb2 libboost-all-dev libdouble-conversion-dev \ libdouble-conversion1 libgoogle-glog-dev libgoogle-glog-doc libgoogle-glog0 \ libjemalloc-dev libjemalloc1 libjemalloc1-dbg * To build wikidiff2 as a PHP extension, you need the following packages: ** On Jessie and previous versions: php5-dev pkg-config ** On Stretch and later versions: php-dev pkg-config == Compilation and installation with Zend PHP == $ phpize $ ./configure $ make $ sudo make install == Compilation and installation with HHVM == $ hphpize $ cmake . $ make $ sudo make install vim: wrap mediawiki-php-wikidiff2-1.5.1/TableDiff.cpp000066400000000000000000000076461316774221600204740ustar00rootroot00000000000000#include #include "Wikidiff2.h" #include "TableDiff.h" void TableDiff::printAdd(const String & line) { result += "\n" "  \n" " +\n" " "; printTextWithDiv(line); result += "\n\n"; } void TableDiff::printDelete(const String & line) { result += "\n" " −\n" " "; printTextWithDiv(line); result += "\n" "  \n" "\n"; } void TableDiff::printWordDiff(const String & text1, const String & text2, bool printLeft, bool printRight, const String & srcAnchor, const String & dstAnchor) { WordVector words1, words2; TextUtil::explodeWords(text1, words1); TextUtil::explodeWords(text2, words2); WordDiff worddiff(words1, words2, MAX_WORD_LEVEL_DIFF_COMPLEXITY); //debugPrintWordDiff(worddiff); result += "\n"; // print left side or blank placeholder. if (printLeft) { result += " "; if(dstAnchor != "") result += ""; else result += "−"; result += "\n"; result += "
"; if(srcAnchor != "") result += ""; printWordDiffSide(worddiff, false); result += "
\n"; } else { result += "  \n"; } // print right side or blank placeholder. if (printRight) { result += " "; if(dstAnchor != "") result += ""; else result += "+"; result += "\n"; result += "
"; if(srcAnchor != "") result += ""; printWordDiffSide(worddiff, true); result += "
\n" "\n"; } else { result += "  \n" "\n"; } } void TableDiff::printWordDiffSide(WordDiff &worddiff, bool added) { String word; for (unsigned i = 0; i < worddiff.size(); ++i) { DiffOp & op = worddiff[i]; int n, j; if (op.op == DiffOp::copy) { n = op.from.size(); if (added) { for (j=0; jget_whole(word); printText(word); } } else { for (j=0; jget_whole(word); printText(word); } } } else if (!added && (op.op == DiffOp::del || op.op == DiffOp::change)) { n = op.from.size(); result += ""; for (j=0; jget_whole(word); printText(word); } result += ""; } else if (added && (op.op == DiffOp::add || op.op == DiffOp::change)) { n = op.to.size(); result += ""; for (j=0; jget_whole(word); printText(word); } result += ""; } } } void TableDiff::printTextWithDiv(const String & input) { // Wrap string in a
if it's not empty if (input.size() > 0) { result.append("
"); printText(input); result.append("
"); } } void TableDiff::printBlockHeader(int leftLine, int rightLine) { char buf[256]; // should be plenty snprintf(buf, sizeof(buf), "\n" " \n" " \n" "\n", leftLine, rightLine); result += buf; } void TableDiff::printContext(const String & input) { result += "\n" "  \n" " "; printTextWithDiv(input); result += "\n" "  \n" " "; printTextWithDiv(input); result += "\n\n"; } mediawiki-php-wikidiff2-1.5.1/TableDiff.h000066400000000000000000000011111316774221600201160ustar00rootroot00000000000000#ifndef TABLEDIFF_H #define TABLEDIFF_H #include "Wikidiff2.h" class TableDiff: public Wikidiff2 { public: protected: void printAdd(const String& line); void printDelete(const String& line); void printWordDiff(const String& text1, const String & text2, bool printLeft = true, bool printRight = true, const String & srcAnchor = "", const String & dstAnchor = ""); void printTextWithDiv(const String& input); void printBlockHeader(int leftLine, int rightLine); void printContext(const String& input); void printWordDiffSide(WordDiff& worddiff, bool added); }; #endif mediawiki-php-wikidiff2-1.5.1/Wikidiff2.cpp000066400000000000000000000252731316774221600204660ustar00rootroot00000000000000/** * Diff formatter, based on code by Steinar H. Gunderson, converted to work with the * Dairiki diff engine by Tim Starling * * GPL. */ #include #include #include //#define DIFFENGINE__EVERY_CHANGE_IS_AN_ADD_AND_DELETE #include "Wikidiff2.h" //#define DEBUG_MOVED_LINES void Wikidiff2::diffLines(const StringVector & lines1, const StringVector & lines2, int numContextLines, int maxMovedLines) { // first do line-level diff StringDiff linediff(lines1, lines2); int from_index = 1, to_index = 1; // Should a line number be printed before the next context line? // Set to true initially so we get a line number on line 1 bool showLineNumber = true; for (int i = 0; i < linediff.size(); ++i) { int n, j, n1, n2; // Line 1 changed, show heading with no leading context if (linediff[i].op != DiffOp::copy && i == 0) { printBlockHeader(1, 1); } switch (linediff[i].op) { case DiffOp::add: // inserted lines n = linediff[i].to.size(); for (j=0; j::del: // deleted lines n = linediff[i].from.size(); for (j=0; j::copy: // copy/context n = linediff[i].from.size(); for (j=0; j= n - numContextLines)) /*leading*/ { if (showLineNumber) { printBlockHeader(from_index, to_index); showLineNumber = false; } printContext(*linediff[i].from[j]); } else { showLineNumber = true; } from_index++; to_index++; } break; case DiffOp::change: // replace, i.e. we do a word diff between the two sets of lines n1 = linediff[i].from.size(); n2 = linediff[i].to.size(); n = std::min(n1, n2); for (j=0; j n2) { for (j=n2; j"; result += ch; result += ""; }; #else auto debugPrintf = [](...) { }; #endif if(!allowPrintMovedLineDiff(linediff, maxMovedLines)) { debugPrintf("printMovedLineDiff: diff too large (maxMovedLines=%ld), not detecting moved lines", maxMovedLines); return false; } debugPrintf("printMovedLineDiff (...), %d, %d\n", opIndex, opLine); bool printLeft = linediff[opIndex].op == DiffOp::del ? true : false; bool printRight = !printLeft; // check whether this op actually refers to the diff map entry auto cmpDiffMapEntries = [&](int otherIndex, int otherLine) -> bool { uint64_t otherKey = makeKey(otherIndex, otherLine); auto it = diffMap.find(otherKey); if (it != diffMap.end()) { auto other = it->second; bool cmp = (printLeft ? other->opIndexFrom == opIndex && other->opLineFrom == opLine : other->opIndexTo == opIndex && other->opLineTo == opLine); if(!cmp) { debugPrintf("printMovedLineDiff(..., %d, %d): not printing diff again. op=%s", opIndex, opLine, linediff[opIndex].op == DiffOp::add ? "add": linediff[opIndex].op == DiffOp::del ? "del": "???"); return false; } } return true; }; // look for corresponding moved line for the opposite case in moved-line-map // if moved line exists: // print diff to the moved line, omitting the left/right side for added/deleted line uint64_t key = makeKey(opIndex, opLine); auto it = diffMap.find(key); if (it != diffMap.end()) { auto best = it->second; int otherIndex = linediff[opIndex].op == DiffOp::add ? best->opIndexFrom : best->opIndexTo; int otherLine = linediff[opIndex].op == DiffOp::add ? best->opLineFrom : best->opLineTo; if(!cmpDiffMapEntries(otherIndex, otherLine)) return false; // XXXX todo: we already have the diff, don't have to do it again, just have to print it printWordDiff(*linediff[best->opIndexFrom].from[best->opLineFrom], *linediff[best->opIndexTo].to[best->opLineTo], printLeft, printRight, makeAnchorName(opIndex, opLine, printLeft), makeAnchorName(otherIndex, otherLine, !printLeft)); if(printLeft) best->lhsDisplayed = true; else best->rhsDisplayed = true; debugPrintf("found in diffmap. copy: %d, del: %d, add: %d, change: %d, similarity: %.4f\n" "from: (%d,%d) to: (%d,%d)\n", best->opCharCount[DiffOp::copy], best->opCharCount[DiffOp::del], best->opCharCount[DiffOp::add], best->opCharCount[DiffOp::change], best->similarity, best->opIndexFrom, best->opLineFrom, best->opIndexTo, best->opLineTo); return true; } debugPrintf("nothing found in moved-line-map"); // else: // try to find a corresponding moved line in deleted/added lines int otherOp = (linediff[opIndex].op == DiffOp::add ? DiffOp::del : DiffOp::add); std::shared_ptr found = nullptr; for (int i = 0; i < linediff.size(); ++i) { if (linediff[i].op == otherOp) { auto& lines = (linediff[opIndex].op == DiffOp::add ? linediff[i].from : linediff[i].to); for (int k = 0; k < lines.size(); ++k) { WordVector words1, words2; std::shared_ptr tmp; TextUtil::explodeWords(*lines[k], words1); if (otherOp == DiffOp::del) { TextUtil::explodeWords(*linediff[opIndex].to[opLine], words2); tmp = std::make_shared(words1, words2, i, k, opIndex, opLine); } else { TextUtil::explodeWords(*linediff[opIndex].from[opLine], words2); tmp = std::make_shared(words1, words2, opIndex, opLine, i, k); } if (!found || tmp->similarity > found->similarity) { found= tmp; } } } } if(found) debugPrintf("candidate found with similarity %.2f", found->similarity); // if candidate exists: // add candidate to moved-line-map twice, for add/del case // print diff to the moved line, omitting the left/right side for added/deleted line if (found && found->similarity > 0.4) { // if we displayed a diff to the found block before, don't display this one as moved. int otherIndex = linediff[opIndex].op == DiffOp::add ? found->opIndexFrom : found->opIndexTo; int otherLine = linediff[opIndex].op == DiffOp::add ? found->opLineFrom : found->opLineTo; if(!cmpDiffMapEntries(otherIndex, otherLine)) return false; if(printLeft) found->lhsDisplayed = true; else found->rhsDisplayed = true; diffMap[key] = found; diffMap[makeKey(otherIndex, otherLine)] = found; debugPrintf("inserting (%d,%d) + (%d,%d)", opIndex, opLine, otherIndex, otherLine); // XXXX todo: we already have the diff, don't have to do it again, just have to print it printWordDiff(*linediff[found->opIndexFrom].from[found->opLineFrom], *linediff[found->opIndexTo].to[found->opLineTo], printLeft, printRight, makeAnchorName(opIndex, opLine, printLeft), makeAnchorName(otherIndex, otherLine, !printLeft)); debugPrintf("copy: %d, del: %d, add: %d, change: %d, similarity: %.4f\n" "from: (%d,%d) to: (%d,%d)\n", found->opCharCount[DiffOp::copy], found->opCharCount[DiffOp::del], found->opCharCount[DiffOp::add], found->opCharCount[DiffOp::change], found->similarity, found->opIndexFrom, found->opLineFrom, found->opIndexTo, found->opLineTo); return true; } return false; } void Wikidiff2::debugPrintWordDiff(WordDiff & worddiff) { for (unsigned i = 0; i < worddiff.size(); ++i) { DiffOp & op = worddiff[i]; switch (op.op) { case DiffOp::copy: result += "Copy\n"; break; case DiffOp::del: result += "Delete\n"; break; case DiffOp::add: result += "Add\n"; break; case DiffOp::change: result += "Change\n"; break; } result += "From: "; bool first = true; for (int j=0; jwhole() + ")"; } result += "\n"; result += "To: "; first = true; for (int j=0; jwhole() + ")"; } result += "\n\n"; } } void Wikidiff2::printText(const String & input) { size_t start = 0; size_t end = input.find_first_of("<>&"); while (end != String::npos) { if (end > start) { result.append(input, start, end - start); } switch (input[end]) { case '<': result.append("<"); break; case '>': result.append(">"); break; default /*case '&'*/: result.append("&"); } start = end + 1; end = input.find_first_of("<>&", start); } // Append the rest of the string after the last special character if (start < input.size()) { result.append(input, start, input.size() - start); } } void Wikidiff2::explodeLines(const String & text, StringVector &lines) { String::const_iterator ptr = text.begin(); while (ptr != text.end()) { String::const_iterator ptr2 = std::find(ptr, text.end(), '\n'); lines.push_back(String(ptr, ptr2)); ptr = ptr2; if (ptr != text.end()) { ++ptr; } } } const Wikidiff2::String & Wikidiff2::execute(const String & text1, const String & text2, int numContextLines, int maxMovedLines) { // Allocate some result space to avoid excessive copying result.clear(); result.reserve(text1.size() + text2.size() + 10000); // Split input strings into lines StringVector lines1; StringVector lines2; explodeLines(text1, lines1); explodeLines(text2, lines2); // Do the diff diffLines(lines1, lines2, numContextLines, maxMovedLines); // Return a reference to the result buffer return result; } mediawiki-php-wikidiff2-1.5.1/Wikidiff2.h000066400000000000000000000075541316774221600201350ustar00rootroot00000000000000#ifndef WIKIDIFF2_H #define WIKIDIFF2_H /** Set WD2_USE_STD_ALLOCATOR depending on whether we're compiling as a PHP module or not */ #if defined(HAVE_CONFIG_H) #define WD2_ALLOCATOR PhpAllocator #include "php_cpp_allocator.h" #else #define WD2_ALLOCATOR std::allocator #endif #include "DiffEngine.h" #include "Word.h" #include #include #include #include #define WIKIDIFF2_VERSION_STRING "1.5.1" class Wikidiff2 { public: typedef std::basic_string, WD2_ALLOCATOR > String; typedef std::vector > StringVector; typedef std::vector > WordVector; typedef std::vector > IntVector; typedef std::set, WD2_ALLOCATOR > IntSet; typedef Diff StringDiff; typedef Diff WordDiff; const String & execute(const String & text1, const String & text2, int numContextLines, int maxMovedLines); inline const String & getResult() const; protected: enum { MAX_WORD_LEVEL_DIFF_COMPLEXITY = 40000000 }; String result; struct DiffMapEntry { double similarity; int opCharCount[4] = { 0 }; int opIndexFrom, opLineFrom, opIndexTo, opLineTo; bool lhsDisplayed = false, rhsDisplayed = false; DiffMapEntry(WordVector& words1, WordVector& words2, int opIndexFrom_, int opLineFrom_, int opIndexTo_, int opLineTo_); }; // PhpAllocator can't be specialized for std::pair, so we're using the standard allocator. typedef std::map > DiffMap; DiffMap diffMap; class AllowPrintMovedLineDiff { bool detectMovedLines = true; // will be set to false when too many 'add' or 'delete' ops appear in diff. bool detectMovedLinesValid = false; // whether detectMovedLines is valid. public: bool operator() (StringDiff & linediff, int maxMovedLines); // calculates & caches comparison count } allowPrintMovedLineDiff; virtual void diffLines(const StringVector & lines1, const StringVector & lines2, int numContextLines, int maxMovedLines); virtual void printAdd(const String & line) = 0; virtual void printDelete(const String & line) = 0; virtual void printWordDiff(const String & text1, const String & text2, bool printLeft = true, bool printRight = true, const String & srcAnchor = "", const String & dstAnchor = "") = 0; virtual void printBlockHeader(int leftLine, int rightLine) = 0; virtual void printContext(const String & input) = 0; void printText(const String & input); void debugPrintWordDiff(WordDiff & worddiff); void explodeLines(const String & text, StringVector &lines); bool printMovedLineDiff(StringDiff & linediff, int opIndex, int opLine, int maxMovedLines); }; inline const Wikidiff2::String & Wikidiff2::getResult() const { return result; } inline Wikidiff2::DiffMapEntry::DiffMapEntry(Wikidiff2::WordVector& words1, Wikidiff2::WordVector& words2, int opIndexFrom_, int opLineFrom_, int opIndexTo_, int opLineTo_): opIndexFrom(opIndexFrom_), opLineFrom(opLineFrom_), opIndexTo(opIndexTo_), opLineTo(opLineTo_) { similarity = calculateSimilarity(words1, words2, MAX_WORD_LEVEL_DIFF_COMPLEXITY, opCharCount); } inline bool Wikidiff2::AllowPrintMovedLineDiff::operator () (StringDiff & linediff, int maxMovedLines) { if(!detectMovedLinesValid) { // count the number of added or removed lines which could have been moved. int adds = 0, deletes = 0; for(int i = 0; i < linediff.size(); ++i) { if(linediff[i].op == DiffOp::add) ++adds; if(linediff[i].op == DiffOp::del) ++deletes; // number of comparisons is (number of additions) x (number of deletions). // if count is too large, don't try detecting moved lines. if(adds+deletes > maxMovedLines) { detectMovedLines = false; break; } } detectMovedLinesValid = true; } return detectMovedLines; } #endif mediawiki-php-wikidiff2-1.5.1/Word.h000066400000000000000000000031551316774221600172230ustar00rootroot00000000000000#ifndef WORD_H #define WORD_H #include #include #include "Wikidiff2.h" // a small class to accomodate word-level diffs; basically, a body and an // optional suffix (the latter consisting of a single whitespace), where // only the bodies are compared on operator==. // // This class stores iterators pointing to the line string, this is to avoid // excessive allocation calls. To avoid invalidation, the source string should // not be changed or destroyed. class Word { public: typedef std::basic_string, WD2_ALLOCATOR > String; typedef String::const_iterator Iterator; Iterator bodyStart; Iterator bodyEnd; Iterator suffixEnd; /** * The body is the character sequence [bs, be) * The whitespace suffix is the character sequence [be, se) */ Word(Iterator bs, Iterator be, Iterator se) : bodyStart(bs), bodyEnd(be), suffixEnd(se) {} bool operator== (const Word &w) const { return (bodyEnd - bodyStart == w.bodyEnd - w.bodyStart) && std::equal(bodyStart, bodyEnd, w.bodyStart); } bool operator!=(const Word &w) const { return !operator==(w); } bool operator<(const Word &w) const { return std::lexicographical_compare(bodyStart, bodyEnd, w.bodyStart, w.bodyEnd); } // Get the whole word as a string String whole() const { String w; get_whole(w); return w; } // Assign the whole word to a string void get_whole(String & w) const { // Do it with swap() to avoid a second copy String temp(bodyStart, suffixEnd); temp.swap(w); } // Get the body as a string operator String() const { return String(bodyStart, bodyEnd); } }; #endif mediawiki-php-wikidiff2-1.5.1/config.cmake000066400000000000000000000002601316774221600204000ustar00rootroot00000000000000HHVM_EXTENSION(wikidiff2 hhvm_wikidiff2.cpp Wikidiff2.cpp InlineDiff.cpp TableDiff.cpp) HHVM_SYSTEMLIB(wikidiff2 ext_wikidiff2.php) target_link_libraries(wikidiff2 libthai.so) mediawiki-php-wikidiff2-1.5.1/config.m4000066400000000000000000000023241316774221600176430ustar00rootroot00000000000000dnl $Id$ dnl if test -z "$CXX"; then dnl AC_MSG_ERROR([PHP is bugged. Set \$CXX to a C++ compiler.]) dnl fi PHP_ARG_ENABLE(wikidiff2, whether to enable wikidiff2 support, [ --enable-wikidiff2 Enable wikidiff2 support]) if test "$PHP_WIKIDIFF2" != "no"; then PHP_REQUIRE_CXX AC_LANG_CPLUSPLUS PHP_ADD_LIBRARY(stdc++,,WIKIDIFF2_SHARED_LIBADD) if test -z "$PKG_CONFIG" then AC_PATH_PROG(PKG_CONFIG, pkg-config, no) fi if test "$PKG_CONFIG" = "no" then AC_MSG_ERROR([required utility 'pkg-config' not found]) fi if ! $PKG_CONFIG --exists libthai then AC_MSG_ERROR(['libthai' not known to pkg-config]) fi PHP_EVAL_INCLINE(`$PKG_CONFIG --cflags-only-I libthai`) PHP_EVAL_LIBLINE(`$PKG_CONFIG --libs libthai`, WIKIDIFF2_SHARED_LIBADD) export OLD_CPPFLAGS="$CPPFLAGS" export CPPFLAGS="$CPPFLAGS $INCLUDES -DHAVE_WIKIDIFF2" AC_CHECK_HEADER([thai/thailib.h], [], AC_MSG_ERROR('thai/thailib.h' header not found')) export CPPFLAGS="$OLD_CPPFLAGS" PHP_SUBST(WIKIDIFF2_SHARED_LIBADD) AC_DEFINE(HAVE_WIKIDIFF2, 1, [ ]) export CXXFLAGS="-Wno-write-strings -std=c++11 $CXXFLAGS" PHP_NEW_EXTENSION(wikidiff2, php_wikidiff2.cpp Wikidiff2.cpp TableDiff.cpp InlineDiff.cpp, $ext_shared) fi mediawiki-php-wikidiff2-1.5.1/ext_wikidiff2.php000066400000000000000000000004721316774221600214050ustar00rootroot00000000000000> function wikidiff2_do_diff(string $text1, string $text2, int $numContextLines, int $maxMovedLines = 25): string; <<__Native>> function wikidiff2_inline_diff(string $text1, string $text2, int $numContextLines, int $maxMovedLines = 25): string; <<__Native>> function wikidiff2_version(): string; mediawiki-php-wikidiff2-1.5.1/hhvm_wikidiff2.cpp000066400000000000000000000044741316774221600215500ustar00rootroot00000000000000/* $Id$ */ #include "hphp/util/lock.h" #include "hphp/runtime/ext/extension.h" #include "hphp/util/compatibility.h" #include "hphp/util/alloc.h" #include "Wikidiff2.h" #include "TableDiff.h" #include "InlineDiff.h" #include namespace HPHP { /* {{{ proto string wikidiff2_do_diff(string text1, string text2, int numContextLines, int maxMovedLines = 25) * * Warning: the input text must be valid UTF-8! Do not pass user input directly * to this function. */ static String HHVM_FUNCTION(wikidiff2_do_diff, const String& text1, const String& text2, int64_t numContextLines, int64_t maxMovedLines) { String result; try { TableDiff wikidiff2; Wikidiff2::String text1String(text1.c_str()); Wikidiff2::String text2String(text2.c_str()); result = wikidiff2.execute(text1String, text2String, numContextLines, maxMovedLines); } catch (OutOfMemoryException &e) { raise_error("Out of memory in wikidiff2_do_diff()."); } catch (...) { raise_error("Unknown exception in wikidiff2_do_diff()."); } return result; } /* {{{ proto string wikidiff2_inline_diff(string text1, string text2, int numContextLines, int maxMovedLines) * * Warning: the input text must be valid UTF-8! Do not pass user input directly * to this function. */ static String HHVM_FUNCTION(wikidiff2_inline_diff, const String& text1, const String& text2, int64_t numContextLines, int64_t maxMovedLines) { String result; try { InlineDiff wikidiff2; Wikidiff2::String text1String(text1.c_str()); Wikidiff2::String text2String(text2.c_str()); result = wikidiff2.execute(text1String, text2String, numContextLines, 0 /*inlinediff todo*/); } catch (OutOfMemoryException &e) { raise_error("Out of memory in wikidiff2_do_diff()."); } catch (...) { raise_error("Unknown exception in wikidiff2_do_diff()."); } return result; } /* {{{ proto string wikidiff2_version() */ static String HHVM_FUNCTION(wikidiff2_version) { String version = WIKIDIFF2_VERSION_STRING; return version; } static class Wikidiff2Extension : public Extension { public: Wikidiff2Extension() : Extension("wikidiff2", WIKIDIFF2_VERSION_STRING) {} virtual void moduleInit() { HHVM_FE(wikidiff2_do_diff); HHVM_FE(wikidiff2_inline_diff); HHVM_FE(wikidiff2_version); loadSystemlib(); } } s_wikidiff2_extension; HHVM_GET_MODULE(wikidiff2) } // namespace HPHP mediawiki-php-wikidiff2-1.5.1/judy_test.cpp000066400000000000000000000011751316774221600206550ustar00rootroot00000000000000#include #include "JudyHS.h" using namespace std; int main(int argc, char** argv) { JudyHS a; a["one"] = "1"; a["two"] = "2"; a["three"] = "3"; cout << a["one"] << " " << a["two"] << " " << a["three"] << endl; cout << "Memleak test: add/delete" << endl; for (int i=0; i<1000000; i++) { a["test"] = "test"; a.Delete("test"); } cout << "Memleak test: add/add" << endl; for (int i=0; i<1000000; i++) { a["test"] = "test"; } cout << "Memleak test: FreeArray" << endl; for (int i=0; i<1000000; i++) { JudyHS b; b["Hello"] = "test"; } cout << "Done, exiting" << endl; return 0; } mediawiki-php-wikidiff2-1.5.1/php_cpp_allocator.h000066400000000000000000000022271316774221600220000ustar00rootroot00000000000000#ifndef PHP_CPP_ALLOCATOR_H #define PHP_CPP_ALLOCATOR_H #include #include "php.h" /** * Allocation class which allows various C++ standard library functions * to allocate and free memory using PHP's emalloc/efree facilities. */ template class PhpAllocator : public std::allocator { public: // Make some typedefs to avoid having to use "typename" everywhere typedef typename std::allocator::pointer pointer; typedef typename std::allocator::size_type size_type; // The rebind member allows callers to get allocators for other types, // given a specialised allocator template struct rebind { typedef PhpAllocator other; }; // Various constructors that do nothing PhpAllocator() throw() {} PhpAllocator(const PhpAllocator& other) throw() {} template PhpAllocator(const PhpAllocator&) throw() {} // Allocate some memory from the PHP request pool pointer allocate(size_type size, typename std::allocator::const_pointer hint = 0) { return (pointer)safe_emalloc(size, sizeof(T), 0); } // Free memory void deallocate(pointer p, size_type n) { return efree(p); } }; #endif mediawiki-php-wikidiff2-1.5.1/php_wikidiff2.cpp000066400000000000000000000077241316774221600213760ustar00rootroot00000000000000/* $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_wikidiff2.h" #include "Wikidiff2.h" #include "TableDiff.h" #include "InlineDiff.h" #if PHP_MAJOR_VERSION >= 7 #define COMPAT_RETURN_STRINGL(s, l) { RETURN_STRINGL(s, l); return; } #else #define COMPAT_RETURN_STRINGL(s, l) { RETURN_STRINGL(s, l, 1); return; } #endif static int le_wikidiff2; zend_function_entry wikidiff2_functions[] = { PHP_FE(wikidiff2_do_diff, NULL) PHP_FE(wikidiff2_inline_diff, NULL) PHP_FE(wikidiff2_version, NULL) {NULL, NULL, NULL} }; zend_module_entry wikidiff2_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "wikidiff2", wikidiff2_functions, PHP_MINIT(wikidiff2), PHP_MSHUTDOWN(wikidiff2), PHP_RINIT(wikidiff2), PHP_RSHUTDOWN(wikidiff2), PHP_MINFO(wikidiff2), #if ZEND_MODULE_API_NO >= 20010901 WIKIDIFF2_VERSION_STRING, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_WIKIDIFF2 ZEND_GET_MODULE(wikidiff2) #endif PHP_MINIT_FUNCTION(wikidiff2) { return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(wikidiff2) { return SUCCESS; } PHP_RINIT_FUNCTION(wikidiff2) { return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(wikidiff2) { return SUCCESS; } PHP_MINFO_FUNCTION(wikidiff2) { php_info_print_table_start(); php_info_print_table_header(2, "wikidiff2 support", "enabled"); php_info_print_table_end(); } /* {{{ proto string wikidiff2_do_diff(string text1, string text2, int numContextLines, int maxMovedLines = 25) * * Warning: the input text must be valid UTF-8! Do not pass user input directly * to this function. */ PHP_FUNCTION(wikidiff2_do_diff) { char *text1 = NULL; char *text2 = NULL; int argc = ZEND_NUM_ARGS(); #if PHP_MAJOR_VERSION >= 7 size_t text1_len; size_t text2_len; zend_long numContextLines; zend_long maxMovedLines = 25; #else int text1_len; int text2_len; long numContextLines; long maxMovedLines = 25; #endif if (zend_parse_parameters(argc TSRMLS_CC, "ssl|l", &text1, &text1_len, &text2, &text2_len, &numContextLines, &maxMovedLines) == FAILURE) { return; } try { TableDiff wikidiff2; Wikidiff2::String text1String(text1, text1_len); Wikidiff2::String text2String(text2, text2_len); const Wikidiff2::String & ret = wikidiff2.execute(text1String, text2String, (int)numContextLines, (int)maxMovedLines); COMPAT_RETURN_STRINGL( const_cast(ret.data()), ret.size()); } catch (std::bad_alloc &e) { zend_error(E_WARNING, "Out of memory in wikidiff2_do_diff()."); } catch (...) { zend_error(E_WARNING, "Unknown exception in wikidiff2_do_diff()."); } } /* {{{ proto string wikidiff2_inline_diff(string text1, string text2, int numContextLines, int maxMovedLines = 25) * * Warning: the input text must be valid UTF-8! Do not pass user input directly * to this function. */ PHP_FUNCTION(wikidiff2_inline_diff) { char *text1 = NULL; char *text2 = NULL; int argc = ZEND_NUM_ARGS(); #if PHP_MAJOR_VERSION >= 7 size_t text1_len; size_t text2_len; zend_long numContextLines; zend_long maxMovedLines = 25; #else int text1_len; int text2_len; long numContextLines; long maxMovedLines = 25; #endif if (zend_parse_parameters(argc TSRMLS_CC, "ssl", &text1, &text1_len, &text2, &text2_len, &numContextLines) == FAILURE) { return; } try { InlineDiff wikidiff2; Wikidiff2::String text1String(text1, text1_len); Wikidiff2::String text2String(text2, text2_len); const Wikidiff2::String& ret = wikidiff2.execute(text1String, text2String, (int)numContextLines, 0 /*inlinediff todo*/); COMPAT_RETURN_STRINGL( const_cast(ret.data()), ret.size()); } catch (std::bad_alloc &e) { zend_error(E_WARNING, "Out of memory in wikidiff2_inline_diff()."); } catch (...) { zend_error(E_WARNING, "Unknown exception in wikidiff2_inline_diff()."); } } /* {{{ proto string wikidiff2_version() */ PHP_FUNCTION(wikidiff2_version) { COMPAT_RETURN_STRINGL( const_cast(WIKIDIFF2_VERSION_STRING), strlen(WIKIDIFF2_VERSION_STRING)); } /* }}} */ mediawiki-php-wikidiff2-1.5.1/php_wikidiff2.h000066400000000000000000000041731316774221600210360ustar00rootroot00000000000000/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2008 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: | +----------------------------------------------------------------------+ */ /* $Id: header,v 1.16.2.1.2.1.2.1 2008/02/07 19:39:50 iliaa Exp $ */ #ifndef PHP_WIKIDIFF2_H #define PHP_WIKIDIFF2_H extern zend_module_entry wikidiff2_module_entry; #define phpext_wikidiff2_ptr &wikidiff2_module_entry #ifdef PHP_WIN32 # define PHP_WIKIDIFF2_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_WIKIDIFF2_API __attribute__ ((visibility("default"))) #else # define PHP_WIKIDIFF2_API #endif #ifdef ZTS #include "TSRM.h" #endif PHP_MINIT_FUNCTION(wikidiff2); PHP_MSHUTDOWN_FUNCTION(wikidiff2); PHP_RINIT_FUNCTION(wikidiff2); PHP_RSHUTDOWN_FUNCTION(wikidiff2); PHP_MINFO_FUNCTION(wikidiff2); PHP_FUNCTION(wikidiff2_do_diff); PHP_FUNCTION(wikidiff2_inline_diff); PHP_FUNCTION(wikidiff2_version); #ifdef ZTS #define WIKIDIFF2_G(v) TSRMG(wikidiff2_globals_id, zend_wikidiff2_globals *, v) #else #define WIKIDIFF2_G(v) (wikidiff2_globals.v) #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ mediawiki-php-wikidiff2-1.5.1/tests/000077500000000000000000000000001316774221600172755ustar00rootroot00000000000000mediawiki-php-wikidiff2-1.5.1/tests/001.phpt000066400000000000000000000234171316774221600205010ustar00rootroot00000000000000--TEST-- Diff test A --SKIPIF-- --FILE-- --EXPECT--  
== Added line ==
 
== Added line ==
      +
sjgfkdjfgb
 
== Removed line ==
 
== Removed line ==
    −
kjahegwnygw
   
== Moved text ==
 
== Moved text ==
 
a
 
a
---line---
   
a
 
a
 
a
 
a
 
a
 
a
 
a
 
a
 
---line---
 
a
 
a
 
a
 
a
 
a
 
a
 
a
 
a
--line1--
 
--line2--
   
a
 
a
 
a
 
a
 
a
 
a
 
a
 
a
 
--line1--
 
--line2--
 
a
 
a
 
a
 
a
 
a
 
a
 
== Shortest sequence in Y ==
 
== Shortest sequence in Y ==
x1
   
x2
 
x2
 
x1
 
x1
 
x2
 
x2
 
x1
 
x1
x2
  −
x1
  −
x2
   
context
 
context
 
context
 
context
 
context
 
context
 
== Changed line ==
 
== Changed line ==
blah blah blah 1
+
blah blah blah 2
    mediawiki-php-wikidiff2-1.5.1/tests/002.phpt000066400000000000000000000047001316774221600204740ustar00rootroot00000000000000--TEST-- Diff test B --SKIPIF-- --FILE-- --EXPECT--  
== Shortest sequence in X ==
 
== Shortest sequence in X ==
  +
x1
 
x2
 
x2
 
x1
 
x1
 
x2
 
x2
 
x1
 
x1
  +
x2
  +
x1
  +
x2
 
context
 
context
 
context
 
context
mediawiki-php-wikidiff2-1.5.1/tests/003.phpt000066400000000000000000000013361316774221600204770ustar00rootroot00000000000000--TEST-- Diff test C: https://phabricator.wikimedia.org/T29993 --SKIPIF-- --FILE-- --EXPECT--
!!FUZZY!!Rajaa
+
Rajaa
mediawiki-php-wikidiff2-1.5.1/tests/004.phpt000066400000000000000000000014761316774221600205050ustar00rootroot00000000000000--TEST-- Diff test D: inline diffs --SKIPIF-- --FILE-- --EXPECT--
foo bartest
 
baz
quux
test
 
bang
mediawiki-php-wikidiff2-1.5.1/tests/005.phpt000066400000000000000000000503721316774221600205050ustar00rootroot00000000000000--TEST-- Diff test E: small change in a big paragraph --SKIPIF-- --FILE-- --EXPECT--
test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test
+
test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test bloody test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test
mediawiki-php-wikidiff2-1.5.1/tests/006.phpt000066400000000000000000000636521316774221600205130ustar00rootroot00000000000000--TEST-- Diff test F: don't diff reeeal long paragraph-level changes --SKIPIF-- --FILE-- --EXPECT--
a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
mediawiki-php-wikidiff2-1.5.1/tests/007.phpt000066400000000000000000000320201316774221600204750ustar00rootroot00000000000000--TEST-- Diff test G: moved paragraphs --SKIPIF-- --FILE-- --EXPECT--
Substance, in the truest and primary and most definite sense of the word, is that which is neither predicable of a subject nor present in a subject; for instance, the individual man or horse. But in a secondary sense those things are called substances within which, as species, the primary substances are included; also those which, as genera, include the species. For instance, the individual man is included in the species 'man', and the genus to which the species belongs is 'animal'; these, therefore—that is to say, the species 'man' and the genus 'animal,-are termed secondary substances.
  −    
It is plain from what has been said that both the name and the definition of the predicate must be predicable of the subject. For instance, 'man' is predicated of the individual man. Now in this case the name of the species 'man' is applied to the individual, for we use the term 'man' in describing the individual; and the definition of 'man' will also be predicated of the individual man, for the individual man is both man and animal. Thus, both the name and the definition of the species are predicable of the individual.
 
It is plain from what has been said that both the name and the definition of the predicate must be predicable of the subject. For instance, 'man' is predicated of the individual man. Now in this case the name of the species 'man' is applied to the individual, for we use the term 'man' in describing the individual; and the definition of 'man' will also be predicated of the individual man, for the individual man is both man and animal. Thus, both the name and the definition of the species are predicable of the individual.
  +  
Everything except primary substances is either predicable of a primary substance or present in a primary substance. This becomes evident by reference to particular instances which occur. 'Animal' is predicated of the species 'man', therefore of the individual man, for if there were no individual man of whom it could be predicated, it could not be predicated of the species 'man' at all. Again, colour is present in body, therefore in individual bodies, for if there were no individual body in which it was present, it could not be present in body at all. Thus everything except primary substances is either predicated of primary substances, or is present in them, and if these last did not exist, it would be impossible for anything else to exist. Never underestimate lawns.
     
With regard, on the other hand, to those things which are present in a subject, it is generally the case that neither their name nor their definition is predicable of that in which they are present. Though, however, the definition is never predicable, there is nothing in certain cases to prevent the name being used. For instance, 'white' being present in a body is predicated of that in which it is present, for a body is called white: the definition, however, of the colour 'white' is never predicable of the body.
 
With regard, on the other hand, to those things which are present in a subject, it is generally the case that neither their name nor their definition is predicable of that in which they are present. Though, however, the definition is never predicable, there is nothing in certain cases to prevent the name being used. For instance, 'white' being present in a body is predicated of that in which it is present, for a body is called white: the definition, however, of the colour 'white' is never predicable of the body.
−  
Everything except primary substances is either predicable of a primary substance or present in a primary substance. This becomes evident by reference to particular instances which occur. 'Animal' is predicated of the species 'man', therefore of the individual man, for if there were no individual man of whom it could be predicated, it could not be predicated of the species 'man' at all. Again, colour is present in body, therefore in individual bodies, for if there were no individual body in which it was present, it could not be present in body at all. Thus everything except primary substances is either predicated of primary substances, or is present in them, and if these last did not exist, it would be impossible for anything else to exist.
       
Lawns are very important. Never underestimate lawns. Never underestimate the power of hot rollers for your hair and eyelash curlers for your eyelashes. You can never underestimate the stupidity of the general public.
 
Lawns are very important. Never underestimate lawns. Never underestimate the power of hot rollers for your hair and eyelash curlers for your eyelashes. You can never underestimate the stupidity of the general public.
  +  
Substance, in the truest and most definite sense of the word, is that which is neither predicable of a subject nor present in a subject; for instance, the individual man or horse. But in a secondary sense those things are called substances within which, as species, the primary substances are included; also those which, as genera, include the species. For instance, the individual man is included in the species 'man', and the genus to which the species belongs is 'animal'; these, therefore—that is to say, the species 'man' and the genus 'animal,-are termed secondary substances.
mediawiki-php-wikidiff2-1.5.1/tests/008.phpt000066400000000000000000000044101316774221600205000ustar00rootroot00000000000000--TEST-- Test detection of dissimilar paragraphs --SKIPIF-- --FILE-- --EXPECT--
AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA
+
AAAAA AAAAA BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB
    −
AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA
    +
AAAAA BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB BBBBB
mediawiki-php-wikidiff2-1.5.1/tests/chinese-reverse.zip000066400000000000000000001520021316774221600231100ustar00rootroot00000000000000PKXsT4]W(KҦ$chinese-reverse-1.txtu =gsF33õM `@ AJAIP AKC`B0% K`C%   NN  ..  nn    ^^  >>  !0" ”0# ’" –# #1pJ8#.+5pK#^^^^>>>>~~~~#!%c0 D b A gP0(T j AǠg0d0b0f0a0e0c0g`dbfaecgpc' N18gpk7 n1gg/ ^1xgo0eGD(&JR('*J&jZ'D)ьhN ZD-юhOt@tHtDtLtBtJtFtNtAtItEtMtCtKtGtO@HDLBJFNAIEM8 qLqN\qMqO<$'SxA$^7[/I@ H"$!II2 )I*!iI:dH2"LH$39ɂdI"YlH$;=!1 )9%5 -=#3 +;'7?_?Ҁ4$F1iBf9iAZV5iCڒv=tD:&NIgstE&ݐnIw{C#cS3s K+k[;{G'gW7wO/o?dYH6 b,%r$j%z!وlL6!d %يlM!ےdddGdd'ddgddddWdd7ddwddddOdd/ddodddd_dd~~|@ yJyI^ yKޑC|B>%K|C%ߑɏȏOO//ɯȯooɟȟ__??ɿȿQ!ŀ")") ))#1ńbJ1S,(+5ņbKSPRQSPRQS\P\R\Q\SPRQSc|%+׌o2c|#'ό_2~c'/ߌ1aI$d2`1$LR&IdR14LZ&ɐɈɘɄɔɌɜɂɒɊɚɆɖɎɞC&GL09erK&WL0erG&OL0yeO&_LcӀit4b3ML39ӂiɴbZ3mL;=!1 )9%5 -=L3=az9 L^3az=L>3}a;L~3/?fـY,f0KerfYŬf0kuzfCf#fcffSf3fsf fKf+fkff[f;f{f1;fvsf.]1fv{f=1{fwf>}1f_f!yc}%+׬oX߲c}#'Ϭ_X~c'/߬aM&d3`$lR6MdS4lZ6͈͔͚͖͎͐̈́͌͂͒͊͆͘͜͞C6Glٜ9esK6WlܰesG6OlټyeO6_lcۀmv6bMئl39ۂmɶb[mضl;=!1 )9%5 -=l=a{9 l^a{=l>}a;l~/?v݀].fKerv]ŮfװkuzvCv#vcvvSv3vsv vKv+vkvv[v;v{v;fwsv.]fw{v={fwv>}f_v!}>a %};a߲nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_;vLw]{8t]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]Kw.ݥt]{3PKisT4e VKw$chinese-reverse-2.txtu =gsF33õM ;-};b_/3)}>b?`eov_>}{g gvO=gw kvW.];gw cvG۳۱۲۰[[[[uZv ]ŮdWeRv ]n.dc?l~`+l>}`{-l^`{)l=`gceafbd`;g;c;e;a;f;b;d۳ضl5ۊmɶ`ئl1ۈm6`l|dW6/lb}uϺcݲnX׬+%u:cNXǬ#!_V?fwVo^Yzf{VwnYݰfusVgNY:fu=- 5%9) 1!UǪeհYUJVU*eYEBV?,Xc',X|a#,X޲ay% ,X`21eof_>}0{g gfO=0gv kfW.]0;gv cfG03120[3[1[2[03120312uZf YŬdV0˙eRf Yl,d0c?L~2`+L>2}`z-L^2`z)L2=`gceafbd`:g:c:e:a:f:b:d3혶L5ӊiɴ`3͘L1ӈi4`L|1dW&/L<1yd[&7L\1drS&'L19drdddddddddddddddȤg1i4Lj&I$g1I$Lb&I/3b;7Ư_?3~b=;Ʒo_3b|93ƧO3>b|qϸc2n׌+%q8c2Nnj#!_F?1fwFo^0zf{Fwn0ftsFgN0:ft=- 5%9) 1!QǨe0UJFQ(e0EBF? c' 2|a# 2ax% 2Oc~@ttt?t>>^^nn..NNt;-݆nM[-t3)݄nL7t]Kt]IWt]Jt݀. hhih~~~~оӾѾҾ>>>>^^^^ОӞўҞiw[ vE]igS vD;i;ږi+ڒi3ڔ6i#mHyyyyyyyy99999999h45͊fIh41͈fHt4-MCST4%MAd4)MBD4&GMEIANFJBLDH@}O}G}K}C}M}E}I}A}N}F}J}B}L}D}H}@Qo7kzA=QO'c[ꆺK:ΨS:!u@GKCjORmT+%ՂjN5RMT#!UOQT UMUQTUNQT ULQ B7';+ 3#=- 5%9) 1!rGP)WKrF9P)GCʞl)ʚ,) ʜ2L)ʘ2P/?o/Ow7Wg'G{;[k+K s3Sc#C=ŎbKXS( 9ŌbJ1S(=EGR45EEQR9EFR$1ED1)?__o/Ow7Wg'G{|C&_/s|B>&{%ok$/s<%Oc|@ddd?dȾɾ>>^^ȞɞnnȮɮ..NNȎɎd;-نlM"[-d3)لlL6"dYK֐dYIVdYJdـ,$ HHIH~~~~>>>>ޓޑޒސ^^^^Iw[ tE$]IgS tD:$I;Җ!I+Ғ I3Ҕ4!I#iH#&"$ y'y#y%y!y&y"y$y '#%!&"$ 9'9#9%9!9&9"9$9 ٓH$5ɊdI H$1ɈdHғt$-ICRT$%IAd$)IBD$$ #%!GMEIANFJBLDH@|O|G|K|C|M|E|I|A|N|F|J|B|L|D|H|@'o7kxA<'O'c'[↸&K8'ΈS8&!q@GKChO#mD+%тhN4#MD#!QOD QMTDQND QL B_? 1fwo ^0xf{w n0fpsg N08fp=- 5%9) 1!AǠe0T JA e0D  B/?o/Ow7Wg'G{;[k+K s3Sc#C=pK!\ 9pJ8!=aG65aEX9aF&1aD8 ?__o/Ow7Wg'G{`C&X, s`B0& z%hj$(r %Hb`@nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_vP/\o5Ơ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;t@wݱ;vcwݱ;vcwݱ;vCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tcwݱ;vcwݱ;vcwݱ;vwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݡ;tCwݛ=PKrS4+;jchinese-reverse.diffnh}CAkjE И4 )%(eYeYeYeY#/$3bvYzS(T%y~??_?_?o׿?_?w?O/_?g_~~_ǿ?׿폿_|ǿ00L p0\cma Fat1rF(1a4c cq1ǸX`a,11VkG cx8`a11NgO ibZ6b0=L3lc3L0S c0 >f905cN00ט39-sy|\c>bn00Ϙ;=+ ybc?؟ıplix8>N q:8N8N'8}gS qjN3ƙ\Lqqf878s[gyAI0 5!L39-`IpO"x X<l;=+HNp" 8|\hMmCۥݢi۴CvB;ihK!vC{L{B5sڷh/i^~H{C3{گhi>}IBhM-B' ۄ!a0" ”0#=‚OX+!aM8"lDŽ+)5pNxK #\ׄ'-3pOJx |#<?τ:EǦqxt|:6NND'Idttr:=:>΀NEgH3әй3sMgFΜ-;:K:tVt|ҹD&Ed9D.Q#6QH!b(%ʈD9Q DhHT1фhJtM4#!-DD+5#цhKL#z!ވDD'3'х 6-b!v[OCqD')qF%Ή{q$WCxD'WSk xA|G$'^?7O[g @F|$~'>?/$Ib$K"H|MtH"$!II2.IN#)H$%ɀ"$#dL2!"\HnH$$ ;%=ɊdMH!y"ْYI6 Ȇd5و!MȮȦdd39-قlIvO"{ [=mȞȶdd;=+فHNv" ;}]tM]CץۢttCݘnB7ttK!ݚnCwLwB5stt.]}HwC3{tt={IBnM-r'!y<"<#=O^+!yM>"o+)5|N~K #_ߓ'-3|OJ~ #??z=EϦsy|z6^^D/Kerz=z>ހ^EoH7ӛл7wMoFޜ-;zKzV={LoGޞ+7zGzN>}һP&EaS8.E£)6EHѡ(b"(9ESbHQS(1ńbJqM1SR,((+5#ņbKLxSR(('3'ŅAߤoѷ;]-}~@M?ߡя'S.~~AO?_ү7'O_ӟѿ?KA=k7o?J@;g/IiQڔK٢(}ʀMRv(#ʘ2L)3.eN٣,(%倲R֔#ʆrL9R^S(o(男 ;%=rMH|R>S(_(7#;LIya`00X lAg0h3tD b AƠ gcP03( T j# 1 +S f n2X0cdp`# '[ v ^280xcpd' AeRYT6CR<**jST*JRKS >UI5T5ՈSMTT39-ՂjIuOzZS=RmTT;=+ՁHNu:S}R] MCeb1 CØa0e12 K!Úapp5s  .3\1|`fp3{  3<1`xfBmPMP-jڧ!u::R=ꂺO]R+!uM=n+)5zN}K^RSԏ'-3zOJ}~>RS?ԟF#f0ry|F6QQ(f0JerF=F>рQhȨf4b030b4ethќ-;FKFV=20zbehў+7FGFN>}24&Ec84.Mƣi6MHӡhb&h49MӔ4fHSӌh1̈́fJsM3,hh44+5#͆fKLyӼhh44'3'ͅdl1;]-cq8da1'S.qqϸd<`\127nj'O_31awTJ}g\e5wz<=[ϊxzŭˍѵוݥㅞ鹞ށFCw{R)z2WޱH[w/{t~zWͯ>ntlu.ltFu^tv,u,tutLuLt5:jMΩRgV+Y\KtE:B}AOgYi~?Nϯ3s3wwxsy3zz{s|3}}~s;}PntO3 LJ;&} ty\O*q{}agg'mGsy{;݅[݋ݑkݗ+ݝKݣ ݩsݯ3ݵSݻZws{ԝ]ugPw9Lj>5+_sÏk8k8i8j8hkij.hFYk^YivYjYhki֙jhj4՚*IfBSY*\hƊ4oaf2WY~Lo_3YIQsA3^NVsF3ZJRsB3\LTsD3hylZiN-5_sͲD3ny7h4mczϚOwŷ7ךWݗg'vJ{BkȴW$1"v@{~bkW1s>snsԞsγ.^ю־N5~5Ӯ55hUJl\\.юi =턮C[7vȳɓvˣ̃vνϝvѭҍvԵՕvץ؅vڹۙvݩމvFpݸҞ\jg.?ڥ3ՉvHv;i'wͯßϟl l,#,)̕/̔5L;LA4#jerRE"W)HqD;BerO|VVb~&EYyIQ9A^NYVFZyJR9B\LYTDPn{{.|^||||}N}~}}}Q_ӗ L~?R<W>0@p!8d rNa+QX+dr |La*0h!jوJN('rYL"-Bً@Óp3lY mƖ1܌w9Ӝdkr6Ng+Ydwr< |Lg*3jj٠JN*rYL(1B٣@ɓIrlY%-.2LgylQ Bm62RkyRj!S5ZM&2X2{,V.y#W^./2s晬Ty"Cײѕt)3]Oԙ\u"c[ׁ'g۲6.2gylQ ɂo72kyR|!S>/ɚO'2p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>p>W89^ 1䷕=PKXsT4]W(KҦ$ chinese-reverse-1.txtPKisT4e VKw$ Kchinese-reverse-2.txtPKrS4+;j Ychinese-reverse.diffPK$mediawiki-php-wikidiff2-1.5.1/textutil.h000066400000000000000000000117331316774221600201730ustar00rootroot00000000000000#ifndef TEXTUTIL_H #define TEXTUTIL_H #include #include #include namespace TextUtil { typedef std::basic_string, WD2_ALLOCATOR > String; typedef std::vector > WordVector; typedef std::set, WD2_ALLOCATOR > IntSet; typedef std::vector > IntVector; // helper functions used in both DiffEngine and Wikidiff2 inline bool isLetter(int ch) { // Standard alphanumeric if ((ch >= '0' && ch <= '9') || (ch == '_') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { return true; } // Punctuation and control characters if (ch < 0xc0) return false; // Chinese, Japanese: split up character by character if (ch >= 0x3000 && ch <= 0x9fff) return false; if (ch >= 0x20000 && ch <= 0x2a000) return false; // Otherwise assume it's from a language that uses spaces return true; } inline bool isSpace(int ch) { return ch == ' ' || ch == '\t'; } // Weak UTF-8 decoder // Will return garbage on invalid input (overshort sequences, overlong sequences, etc.) inline int nextUtf8Char(String::const_iterator & p, String::const_iterator & charStart, String::const_iterator end) { int c = 0; unsigned char byte; int seqLength = 0; charStart = p; if (p == end) { return 0; } do { byte = (unsigned char)*p; if (byte < 0x80) { c = byte; seqLength = 0; } else if (byte >= 0xc0) { // Start of UTF-8 character // If this is unexpected, due to an overshort sequence, we ignore the invalid // sequence and resynchronise here if (byte < 0xe0) { seqLength = 1; c = byte & 0x1f; } else if (byte < 0xf0) { seqLength = 2; c = byte & 0x0f; } else { seqLength = 3; c = byte & 7; } } else if (seqLength) { c <<= 6; c |= byte & 0x3f; --seqLength; } else { // Unexpected continuation, ignore } ++p; } while (seqLength && p != end); return c; } // Split a string into words // // TODO: I think the best way to do this would be to use ICU BreakIterator // instead of libthai + DIY. Basically you'd run BreakIterators from several // different locales (en, th, ja) and merge the results, i.e. if a break occurs // in any locale at a given position, split the string. I don't know if the // quality of the Thai dictionary in ICU matches the one in libthai, we would // have to check this somehow. inline void explodeWords(const String & text, WordVector &words) { // Decode the UTF-8 in the string. // * Save the character sizes (in bytes) // * Convert the string to TIS-620, which is the internal character set of libthai. // * Save the character offsets of any break positions (same format as libthai). String tisText, charSizes; String::const_iterator suffixEnd, charStart, p; IntSet breaks; tisText.reserve(text.size()); charSizes.reserve(text.size()); wchar_t ch, lastChar; thchar_t thaiChar; bool hasThaiChars = false; p = text.begin(); ch = nextUtf8Char(p, charStart, text.end()); lastChar = 0; int charIndex = 0; while (ch) { thaiChar = th_uni2tis(ch); if (thaiChar >= 0x80 && thaiChar != THCHAR_ERR) { hasThaiChars = true; } tisText += (char)thaiChar; charSizes += (char)(p - charStart); if (isLetter(ch)) { if (lastChar && !isLetter(lastChar)) { breaks.insert(charIndex); } } else { breaks.insert(charIndex); } charIndex++; lastChar = ch; ch = nextUtf8Char(p, charStart, text.end()); } // If there were any Thai characters in the string, run th_brk on it and add // the resulting break positions if (hasThaiChars) { IntVector thaiBreakPositions; tisText += '\0'; thaiBreakPositions.resize(tisText.size()); int numBreaks = th_brk((const thchar_t*)(tisText.data()), &thaiBreakPositions[0], thaiBreakPositions.size()); thaiBreakPositions.resize(numBreaks); breaks.insert(thaiBreakPositions.begin(), thaiBreakPositions.end()); } // Add a fake end-of-string character and have a break on it, so that the // last word gets added without special handling breaks.insert(charSizes.size()); charSizes += (char)0; // Now make the word array by traversing the breaks set p = text.begin(); IntSet::iterator pBrk = breaks.begin(); String::const_iterator wordStart = text.begin(); String::const_iterator suffixStart = text.end(); // If there's a break at the start of the string, skip it if (pBrk != breaks.end() && *pBrk == 0) { pBrk++; } for (charIndex = 0; charIndex < charSizes.size(); p += charSizes[charIndex++]) { // Assume all spaces are ASCII if (isSpace(*p)) { suffixStart = p; } if (pBrk != breaks.end() && charIndex == *pBrk) { if (suffixStart == text.end()) { words.push_back(Word(wordStart, p, p)); } else { words.push_back(Word(wordStart, suffixStart, p)); } pBrk++; suffixStart = text.end(); wordStart = p; } } } } #endif // TEXTUTIL_H mediawiki-php-wikidiff2-1.5.1/wikidiff2.ini000066400000000000000000000000271316774221600205110ustar00rootroot00000000000000extension=wikidiff2.so