public static function parseIds(array $ids)
 {
     $info = array();
     foreach ($ids as $id) {
         list($shard, $sequence) = Util::parseId($id);
         if (!$shard || !$sequence) {
             continue;
         }
         if (!isset($info[$shard])) {
             $info[$shard] = array();
         }
         $info[$shard][] = $sequence;
     }
     return $info;
 }
 /**
  * iterate through every record
  * and pass the results to a closure.
  * if the closure returns FALSE, it breaks out of the loop.
  */
 public function filter(array $params)
 {
     Util::filter($this, $params);
 }
$skein->filter(array('sort' => 'descending', 'process' => $cb, 'start_after' => $ids[5]));
$expected_sum = 0;
foreach (array_slice(array_reverse($batch, TRUE), 5) as $data) {
    $expected_sum = bcadd($expected_sum, $data['foo']);
}
Tap::is($ct, 6, 'filter descending with start_after iterated the correct number of rows');
Tap::is($sum, $expected_sum, 'sum from filter with start_after arrived at the correct amount');
$generated_ids = $post_processed_ids = array();
$generate = function (array $params) use($skein, &$generated_ids, &$post_processed_ids) {
    $return = array();
    $ids = $skein->ids($params);
    foreach ($ids as $id) {
        $generated_ids[] = $id;
        if ($id % 2 == 0) {
            $post_processed_ids[] = $return[] = $id;
        }
    }
    return $return;
};
$processed_ids = array();
$process = function ($id, $data) use(&$processed_ids) {
    $processed_ids[] = $id;
};
$skein->filter(array('process' => $process, 'generate' => $generate));
Tap::is($generated_ids, $ids, 'generate filter gets all the ids');
Tap::is($processed_ids, $post_processed_ids, 'process filter gets only the ids returned by generate');
$shard = mt_rand(1, 100);
$id = $skein->add($data = array('foo' => mt_rand(1, 1000000000)), $shard);
$parts = Skein\Util::parseId($id);
Tap::is($parts[0], $shard, 'created a new entry, using a custom shard');
Tap::is($skein->get($id), $data, 'read back the entry with custom shard');