function o_catalog( $id, $action, $options = '' )
    {
        if ( $action != 'new' )
        {
            $o =& $this->objects[$id];
        }
        switch ( $action )
        {
        case 'new':
            $this->objects[$id] = array( 't' => 'catalog', 'info' => array() );
            $this->catalogId = $id;
            break;
        case 'outlines':
        case 'pages':
        case 'openHere':
            $o['info'][$action] = $options;
            break;
        case 'viewerPreferences':
            if ( !isset( $o['info']['viewerPreferences'] ) )
            {
                $this->numObj++;
                $this->o_viewerPreferences( $this->numObj, 'new' );
                $o['info']['viewerPreferences'] = $this->numObj;
            }
            $vp = $o['info']['viewerPreferences'];
            $this->o_viewerPreferences( $vp, 'add', $options );
            break;
        case 'out':
            $res= "\n" . $id . " 0 obj\n" . '<< /Type /Catalog';
            foreach ( $o['info'] as $k => $v )
            {
                switch ( $k )
                {
                case 'outlines':
                    $res .= "\n" . '/Outlines ' . $v . ' 0 R';
                    break;
                case 'pages':
                    $res .= "\n" . '/Pages ' . $v . ' 0 R';
                    break;
                case 'viewerPreferences':
                    $res .= "\n" . '/ViewerPreferences ' . $o['info']['viewerPreferences'] . ' 0 R';
                    break;
                case 'openHere':
                    $res .= "\n" . '/OpenAction ' . $o['info']['openHere'] . ' 0 R';
                    break;
                }
            }
            $res .= " >>\nendobj";
            return $res;
            break;
        }
    }