public function parse()
    {
        $time   = time();
        $gmdate = gmdate('D, d M Y H:i:s', $time);

        Container::get('response')
            ->setHeader('MDE-Version', \MarkdownExtended\MarkdownExtended::MDE_VERSION)
            ->setHeader('Last-Modified', $gmdate.' GMT')
        ;

        $etag       = '';
        $sources    = $this->getSources();
        $options    = Container::get('request')->getData('options', array());
        $format     = Container::get('request')->getData('format');
        $extract    = Container::get('request')->getData('extract', 'full');
        if (!empty($format)) {
            $options['output_format'] = $format;
        }
        if (!empty($sources)) {
            try {
                foreach ($sources as $index=>$source) {

                    /* @var \MarkdownExtended\Content $mde_content */
                    $mde_content = Helper::parseMdeSource($source, $options);
                    //var_export($mde_content);

                    switch ($extract) {
                        case 'metadata':
                            $parsed_content = $mde_content->getMetadataToString();
                            break;
                        case 'body':
                            $parsed_content = $mde_content->getBody();
                            break;
                        case 'notes':
                            $parsed_content = $mde_content->getNotesToString();
                            break;
                        case 'full':
                        default:
                            $parsed_content =
                                $mde_content->getMetadataToString()
                                .PHP_EOL
                                .$mde_content->getBody()
                                .PHP_EOL
                                .$mde_content->getNotesToString()
                            ;
                            break;
                    }
                    $etag .= $source.'='.$parsed_content.';';

                    $content_index = $this->addContent($parsed_content);
                    if ($this->getSourceType() == 'file' && is_string($index)) {
                        $source = $index;
                    }
                    if ($content_index !== $index) {
                        $this
                            ->unsetSource($index)
                            ->setSource($content_index, $source)
                        ;
                    }
                }
            } catch (\Exception $e) {
                throw $e;
            }
            $etag = md5($etag);
            Container::get('response')->setHeader('ETag', $etag);

        }

        // if not modified, fetch headers and exit
        $if_modified_since  = Container::get('request')->getHeader('If-Modified-Since');
        $if_none_match      = Container::get('request')->getHeader('If-None-Match');
        if (
            (!empty($if_modified_since) && @strtotime($if_modified_since) >= $time) ||
            (!empty($if_none_match) && !empty($etag) && trim($if_none_match) == $etag)
        ) {
            Container::get('response')
                ->setStatus(Response::STATUS_NOT_MODIFIED)
                ->fetchHeaders()
            ;
            exit(PHP_EOL);
        }

        return $this;
    }