Just making sure all files added for index shard stuff, a=chris

Chris Pollett [2010-10-11 15:Oct:th]
Just making sure all files added for index shard stuff, a=chris
Filename
lib/bst_array.php
tests/bst_array_test.php
tests/index_shard_test.php
tests/string_cat_experiment.php
diff --git a/lib/bst_array.php b/lib/bst_array.php
new file mode 100644
index 000000000..9e41f3c5f
--- /dev/null
+++ b/lib/bst_array.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009, 2010  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage library
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009, 2010
+ * @filesource
+ */
+if(!defined('BASE_DIR')) {echo "BAD REQUEST"; exit();}
+
+/**
+ * Load charCopy
+ */
+require_once "utility.php";
+
+/**
+ *
+ * @author Chris Pollett
+ *
+ * @package seek_quarry
+ * @subpackage library
+ */
+
+class BSTArray
+{
+    var $data;
+    var $data_len;
+    var $key_len;
+    var $value_len;
+    var $entry_len;
+    var $key_compare;
+
+    /**
+     *
+     */
+    function __construct($key_len, $value_len, $key_compare)
+    {
+        $this->data = "";
+        $this->data_len = 0;
+        $this->key_len = $key_len;
+        $this->value_len = $value_len;
+        $this->entry_len = $key_len + $value_len + 8;
+        $this->key_compare = $key_compare;
+    }
+
+    /**
+     *
+     */
+    function insertUpdate($key, $value)
+    {
+        $key_compare = $this->key_compare;
+        if($this->contains($key, $offset, $parent_offset))
+        {
+            list(, , $left_offset, $right_offset) = $this->readEntry($offset);
+            charCopy($key . $value . pack("N",$left_offset) .
+                pack("N", $right_offset),$this->data, $offset,$this->entry_len);
+        } else {
+            if($parent_offset != $offset) { // data already exists
+                list($parent_key, $parent_value, $parent_left_offset,
+                    $parent_right_offset) = $this->readEntry($parent_offset);
+                if($key_compare($parent_key, $key) < 0 ) {
+                    $parent_right_offset = $offset;
+                } else {
+                    $parent_left_offset = $offset;
+                }
+                $new_parent_entry =  $parent_key . $parent_value .
+                    pack("N", $parent_left_offset) .
+                    pack("N", $parent_right_offset);
+                charCopy( $new_parent_entry,
+                    $this->data, $parent_offset, $this->entry_len);
+            }
+            $this->data .= $key . $value . pack("H*", "7FFFFFFF7FFFFFFF");
+            $this->data_len += $this->entry_len;
+        }
+    }
+
+    /**
+     *
+     */
+    function contains($key, &$offset, &$parent_offset)
+    {
+        $offset = 0;
+        $parent_offset = 0;
+        $data_len = $this->data_len;
+        $entry_len = $this->entry_len;
+        $last_entry = $data_len - $entry_len;
+        $key_compare = $this->key_compare;
+        while($offset <= $last_entry ) {
+            list($cur_key, , $left_offset, $right_offset) =
+                $this->readEntry($offset);
+            $comparison = $key_compare($cur_key, $key);
+            if($comparison == 0) {
+                return true;
+            } else if ($comparison < 0) {
+                $parent_offset = $offset;
+                $offset = $right_offset;
+            } else {
+                $parent_offset = $offset;
+                $offset = $left_offset;
+            }
+        }
+
+        $offset = $data_len;
+        return false;
+    }
+
+    /**
+     *
+     */
+    function readEntry($offset)
+    {
+        $key = substr($this->data, $offset, $this->key_len);
+        $offset += $this->key_len;
+        $value = substr($this->data, $offset, $this->value_len);
+        $offset += $this->value_len;
+        $left_string = substr($this->data, $offset, 4);
+        $tmp = unpack("N", $left_string);
+        $left_offset = $tmp[1];
+        $offset += 4;
+        $right_string = substr($this->data, $offset, 4);
+        $tmp = unpack("N", $right_string);
+        $right_offset = $tmp[1];
+        return array($key, $value, $left_offset, $right_offset);
+    }
+}
diff --git a/tests/bst_array_test.php b/tests/bst_array_test.php
new file mode 100644
index 000000000..5c545e4d2
--- /dev/null
+++ b/tests/bst_array_test.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009, 2010  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage test
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009, 2010
+ * @filesource
+ */
+
+if(!defined('BASE_DIR')) {echo "BAD REQUEST"; exit();}
+
+/**
+ *  Load the string_array library we'll be testing
+ */
+require_once BASE_DIR."/lib/bst_array.php";
+
+/**
+ *  Used to test that the BSTArray class properly stores/retrieves values,
+ *
+ *  @author Chris Pollett
+ *  @package seek_quarry
+ *  @subpackage test
+ */
+class BSTArrayTest extends UnitTest
+{
+    /**
+     * We'll use two different tables one more representative of how the table
+     * is going to be used by the web_queue_bundle, the other small enough that
+     * we can manually figure out what the result should be
+     */
+    public function setUp()
+    {
+        $this->test_objects['BST'] = new BSTArray(1, 1, "strcmp");
+    }
+
+    /**
+     */
+    public function tearDown()
+    {
+        unset($this->test_objects['BST']);
+    }
+
+    /**
+     * Check if can put objects into BST array and retrieve them
+     */
+    public function insertTestCase()
+    {
+        $this->test_objects['BST']->insertUpdate(chr(65), chr(66));
+        $flag = $this->test_objects['BST']->contains(chr(65), $offset, $parent);
+        $this->assertTrue($flag, "BST contains what was just inserted");
+        $this->test_objects['BST']->insertUpdate(chr(67), chr(68));
+        $flag = $this->test_objects['BST']->contains(chr(67), $offset, $parent);
+        $this->assertTrue($flag, "BST contains second insert");
+        $this->test_objects['BST']->insertUpdate(chr(66), chr(69));
+        $flag = $this->test_objects['BST']->contains(chr(66), $offset, $parent);
+        $this->assertTrue($flag, "BST contains third insert");
+        $this->test_objects['BST']->insertUpdate(chr(69), chr(69));
+        $flag = $this->test_objects['BST']->contains(chr(69), $offset, $parent);
+        $this->assertTrue($flag, "BST contains fourth insert");
+    }
+
+    /**
+     * Check if can modify objects in BST array
+     */
+    public function updateTestCase()
+    {
+        $this->test_objects['BST']->insertUpdate(chr(65), chr(66));
+        $this->test_objects['BST']->insertUpdate(chr(67), chr(68));
+        $this->test_objects['BST']->insertUpdate(chr(66), chr(69));
+        $this->test_objects['BST']->insertUpdate(chr(69), chr(69));
+        $this->test_objects['BST']->insertUpdate(chr(66), chr(66));
+        $this->test_objects['BST']->contains(chr(66), $offset, $parent);
+        list($key, $value, $left, $right) = $this->test_objects['BST']->
+            readEntry($offset);
+        $this->assertEqual($value, chr(66), "BST contains fourth insert");
+    }
+
+}
+?>
diff --git a/tests/index_shard_test.php b/tests/index_shard_test.php
new file mode 100644
index 000000000..e95ece531
--- /dev/null
+++ b/tests/index_shard_test.php
@@ -0,0 +1,367 @@
+<?php
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009, 2010  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage test
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009, 2010
+ * @filesource
+ */
+
+if(!defined('BASE_DIR')) {echo "BAD REQUEST"; exit();}
+
+/**
+ *  Load the library for crawlHash
+ */
+require_once BASE_DIR."/lib/utility.php";
+
+/**
+ *  Load the library for crawlHash
+ */
+require_once BASE_DIR."/lib/crawl_constants.php";
+
+
+/**
+ *  Load the index_shard library we'll be testing
+ */
+require_once BASE_DIR."/lib/index_shard.php";
+
+
+/**
+ *  Used to test that the StringArray class properly stores/retrieves values,
+ *  and can handle loading and saving
+ *
+ *  @author Chris Pollett
+ *  @package seek_quarry
+ *  @subpackage test
+ */
+class IndexShardTest extends UnitTest
+{
+    /**
+     *
+     */
+    public function setUp()
+    {
+        $this->test_objects['shard'] = new IndexShard("shard.txt", 0);
+        $this->test_objects['shard2'] = new IndexShard("shard2.txt", 0);
+    }
+
+    /**
+     *
+     */
+    public function tearDown()
+    {
+        @unlink("shard.txt");
+        @unlink("shard2.txt");
+    }
+
+    /**
+     * Check if can store documents into an index shard and retrieve them
+     */
+    public function addDocumentsGetWordSliceByIdTestCase()
+    {
+        $docid = "AAAAAAAA";
+        $offset = 5;
+        $word_counts = array(
+            'BBBBBBBB' => 1,
+            'CCCCCCCC' => 2,
+            'DDDDDDDD' => 6,
+        );
+
+        $meta_ids = array(
+            "EEEEEEEE",
+            "FFFFFFFF"
+        );
+
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $this->assertEqual($this->test_objects['shard']->len_all_docs, 9,
+            "Len All Docs Correctly Counts Length of First Doc");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('CCCCCCCC', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Doc lookup by word works");
+        // add a second document and check
+        $docid = "HHHHHHHH";
+        $offset = 7;
+        $word_counts = array(
+            'CCCCCCCC' => 9,
+            'GGGGGGGG' => 6,
+        );
+        $meta_ids = array(
+            "YYYYYYYY"
+        );
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('CCCCCCCC', true), 5);
+
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Work lookup first item of two works");
+        $this->assertTrue(isset($c_data["HHHHHHHH"]),
+            "Work lookup second item of two works");
+        $this->assertEqual(count($c_data), 2,
+            "Exactly two items were found in two item case");
+
+        //add a meta word lookup
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('EEEEEEEE', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Doc lookup by meta word works");
+        $this->assertEqual(count($c_data), 1,
+            "Doc lookup by meta word works has correct count");
+    }
+
+    /**
+     * Check if can store link documents into an index shard and retrieve them
+     */
+    public function addLinkGetWordSliceByIdTestCase()
+    {
+        $docid = "AAAAAAAA:BBBBBBBB:CCCCCCCC"; //set up link doc
+        $offset = 5;
+        $word_counts = array(
+            'MMMMMMMM' => 1,
+            'NNNNNNNN' => 2,
+            'OOOOOOOO' => 6,
+        );
+
+        $meta_ids = array(
+            "PPPPPPPP",
+            "QQQQQQQQ"
+        );
+
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $this->assertEqual($this->test_objects['shard']->len_all_link_docs, 9,
+            "Len All Docs Correctly Counts Length of First Doc");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('MMMMMMMM', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA:BBBBBBBB:CCCCCCCC"]),
+            "Link Doc lookup by word works");
+        $docid = "AAAAAAAA";
+        $offset = 10;
+        $word_counts = array(
+            'BBBBBBBB' => 1,
+            'CCCCCCCC' => 2,
+            'MMMMMMMM' => 6,
+        );
+
+        $meta_ids = array(
+            "EEEEEEEE",
+            "FFFFFFFF"
+        );
+
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('MMMMMMMM', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA:BBBBBBBB:CCCCCCCC"]),
+            "Link Doc lookup by word works 1st of two");
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Link Doc lookup by word works 2nd doc");
+        $this->assertEqual(count($c_data), 2,
+            "Link Doc lookup by word works has correct count");
+    }
+
+    /**
+     * Check that appending two index shards works correctly
+     */
+    public function appendIndexShardTestCase()
+    {
+        $docid = "AAAAAAAA";
+        $offset = 5;
+        $word_counts = array(
+            'BBBBBBBB' => 1,
+            'CCCCCCCC' => 2,
+            'DDDDDDDD' => 6,
+        );
+
+        $meta_ids = array(
+            "EEEEEEEE",
+            "FFFFFFFF"
+        );
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+
+        $docid = "KKKKKKKK:GGGGGGGG:HHHHHHHH";
+        $offset = 20;
+        $word_counts = array(
+            'ZZZZZZZZ' => 9,
+            'DDDDDDDD' => 4,
+        );
+        $meta_ids = array(
+        );
+        $this->test_objects['shard2']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $docid = "GGGGGGGG";
+        $offset = 6;
+        $word_counts = array(
+            'DDDDDDDD' => 3,
+            'IIIIIIII' => 4,
+            'JJJJJJJJ' => 5,
+        );
+
+        $meta_ids = array(
+            "KKKKKKKK"
+        );
+        $this->test_objects['shard2']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $this->test_objects['shard']->appendIndexShard(
+            $this->test_objects['shard2']);
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('BBBBBBBB', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Data from first shard present 1");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('CCCCCCCC', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Data from first shard present 2");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('DDDDDDDD', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Data from first shard present 3");
+        $this->assertTrue(isset($c_data["KKKKKKKK:GGGGGGGG:HHHHHHHH"]),
+            "Data from second shard present 1");
+        $this->assertTrue(isset($c_data["GGGGGGGG"]),
+            "Data from third shard present 1");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('EEEEEEEE', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Data from first shard present 4");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('FFFFFFFF', true), 5);
+        $this->assertTrue(isset($c_data["AAAAAAAA"]),
+            "Data from first shard present 5");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('ZZZZZZZZ', true), 5);
+        $this->assertTrue(isset($c_data["KKKKKKKK:GGGGGGGG:HHHHHHHH"]),
+            "Data from second shard present 2");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('IIIIIIII', true), 5);
+        $this->assertTrue(isset($c_data["GGGGGGGG"]),
+            "Data from third shard present 2");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('JJJJJJJJ', true), 5);
+        $this->assertTrue(isset($c_data["GGGGGGGG"]),
+            "Data from third shard present 3");
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('KKKKKKKK', true), 5);
+        $this->assertTrue(isset($c_data["GGGGGGGG"]),
+            "Data from third shard present 4");
+    }
+
+    /**
+     * Check that changing document offsets works
+     */
+    public function changeDocumentOffsetTestCase()
+    {
+        $docid = "AAAAAAAA";
+        $offset = 0;
+        $word_counts = array(
+            'BBBBBBBB' => 1
+        );
+
+        $meta_ids = array(
+        );
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $docid = "AAAAAAAA:EEEEEEEE:FFFFFFFF";
+        $offset = 0;
+        $word_counts = array(
+            'BBBBBBBB' => 1
+        );
+        $meta_ids = array(
+        );
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $docid = "QQQQQQQQ:EEEEEEEE:FFFFFFFF";
+        $offset = 0;
+        $word_counts = array(
+            'BBBBBBBB' => 1
+        );
+        $meta_ids = array(
+        );
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $docid = "DDDDDDDD";
+        $offset = 0;
+        $word_counts = array(
+            'BBBBBBBB' => 1
+        );
+        $meta_ids = array(
+        );
+        $this->test_objects['shard']->addDocumentWords($docid,
+            $offset, $word_counts, $meta_ids);
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('BBBBBBBB', true), 5);
+        $new_doc_offsets = array(
+            "AAAAAAAA" => 5,
+            "CCCCCCCC" => 6,
+            "QQQQQQQQ:EEEEEEEE:FFFFFFFF" => 9,
+            "DDDDDDDD" => 7,
+        );
+        $this->test_objects['shard']->changeDocumentOffsets($new_doc_offsets);
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('BBBBBBBB', true), 5);
+        $predicted_offsets = array(
+            "AAAAAAAA" => 5,
+            "AAAAAAAA:EEEEEEEE:FFFFFFFF" => 0,
+            "QQQQQQQQ:EEEEEEEE:FFFFFFFF" => 9,
+            "DDDDDDDD" => 7,
+        );
+        $i = 0;
+        foreach($predicted_offsets as $key =>$offset) {
+            $this->assertTrue(isset($c_data[$key]),  "Summary key matches predicted $i");
+            $this->assertEqual($c_data[$key][CrawlConstants::SUMMARY_OFFSET],
+                $offset,  "Summary offset matches predicted $i");
+            $i++;
+        }
+    }
+
+    /**
+     * Check the code for calculating word document relaevance computes
+     * correct values
+     */
+    public function checkRelevanceCalculationTestCase()
+    {
+    }
+
+    /**
+     *
+     */
+    public function markDuplicatesTestCase()
+    {
+        $doc_urls = array("http://somewhere.com/");
+
+        $this->test_objects['shard']->markDuplicateDocs($doc_urls);
+        $c_data = $this->test_objects['shard']->getWordSliceById(
+            crawlHash('info:http://somewhere.com/', true), 5);
+        $this->assertTrue(isset(
+            $c_data[crawlHash($doc_urls[0], true)][CrawlConstants::DUPLICATE]),
+            "Duplicate data shows up as duplicate");
+    }
+}
+?>
diff --git a/tests/string_cat_experiment.php b/tests/string_cat_experiment.php
new file mode 100644
index 000000000..da2f3441e
--- /dev/null
+++ b/tests/string_cat_experiment.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009, 2010  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * Test to see for big strings which how long various string concatenation
+ * operations take.
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage test
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009, 2010
+ * @filesource
+ */
+
+if(isset($_SERVER['DOCUMENT_ROOT']) && strlen($_SERVER['DOCUMENT_ROOT']) > 0) {
+    echo "BAD REQUEST";
+    exit();
+}
+
+ini_set("memory_limit","300M");
+echo "Time to pack null strings of various lengths with pack('xLEN')\n";
+
+for($i = 10; $i< 100000000; $i *= 10) {
+    $start = microtime();
+    $big_string = pack("x$i");
+    echo "Len = $i Time =".changeInMicroTime($start)."secs \n";
+}
+
+echo 'Concatenation $str2 = $str1.$str1 where $str1 of various lengths'."\n";
+for($i = 10; $i< 100000000; $i *= 10) {
+    $big_string = pack("x$i");
+    $start = microtime();
+    $str2 = $big_string.$big_string;
+    echo "Len = $i Time =".changeInMicroTime($start)."secs \n";
+}
+
+unset($str2);
+
+echo 'Concatenation $str1 .= $str1 where $str1 of various lengths'."\n";
+for($i = 10; $i< 100000000; $i *= 10) {
+    $big_string = pack("x$i");
+    $start = microtime();
+    $big_string .= $big_string;
+    echo "Len = $i Time =".changeInMicroTime($start)."secs \n";
+}
+
+echo 'Time to concatenate "hello" on to a string of various lengths'."\n";
+for($i = 10; $i< 100000000; $i *= 10) {
+    $big_string = pack("x$i");
+    $start = microtime();
+    $big_string .= "hello";
+    echo "Len = $i Time =".changeInMicroTime($start)."secs \n";
+}
+
+echo "Concatenate hello various numbers of times to a string of length 10^7\n";
+
+for($i = 10; $i< 10000000; $i *= 10) {
+    $big_string = pack("x100000000");
+    $start = microtime();
+    for($j = 0; $j < $i; $j++) {
+        $big_string .= "hello";
+    }
+    echo "Num Hello Cats = $i Time =".changeInMicroTime($start)."secs \n";
+}
+
+function changeInMicrotime( $start, $end=NULL )
+{
+    if( !$end ) {
+            $end= microtime();
+    }
+    list($start_microseconds, $start_seconds) = explode(" ", $start);
+    list($end_microseconds, $end_seconds) = explode(" ", $end);
+
+    $change_in_seconds = intval($end_seconds) - intval($start_seconds);
+    $change_in_microseconds =
+        floatval($end_microseconds) - floatval($start_microseconds);
+
+    return floatval( $change_in_seconds ) + $change_in_microseconds;
+}
+
+?>
ViewGit