Generate overview markdown tree
@param string $pad
@param string $relativePath
@return string
770412
public function generateTree( $pad = '', $relativePath = '') {
        $generatedMd = '';

        /// SubPages
        if( ! empty( $this->subPages)){
            foreach( $this->subPages as $subPageName => $subPage){
                $subPageFile  = './' . $relativePath . $subPageName . DIRECTORY_SEPARATOR . $subPage->getPageBfe();
                $generatedMd .=  "$pad- [$subPageName]($subPageFile)". PHP_EOL;
                $generatedMd .= $subPage->generateTree( $pad . '    ', $relativePath . $subPageName . DIRECTORY_SEPARATOR);
            }
        }

        /// Chapters
        if( ! empty( $this->classMds)){
            foreach($this->classMds as $chapter){
                $chapterName   = $chapter->getReflexion()->getShortName();
                $chapterFile   = $relativePath . $this->getPageBfe();
                $chapterAnchor = $chapterFile .'#'. $chapter->getReflexion()->getShortName();
                $generatedMd  .= "$pad- [$chapterName]($chapterAnchor)" . PHP_EOL;
            }
        }

        return $generatedMd;
    }
1052126
public function getEtcDir($relativePathToAppend = '')
    {
        return $this->realpath(
            $this->makePathAbsolute(
                $this->getSystemConfiguration()->getParam(DirectoryKeys::ETC) . $this->makePathAbsolute($relativePathToAppend)
            )
        );
    }
315209
private String getServletPath(final String relativePath) {

		if (relativePath == null) {
			LOG.error("relativePath must not be null");
		}

		String context = getHostFreeBaseUrl();

		if (!Util.empty(context)) {
			return context + relativePath;
		}

		return relativePath;
	}
761835
public function setHtmlBody(string $html, string $basePath = null)
    {
        if ($basePath) {
            $cids = [];
            $matches = Strings::matchAll(
                $html,
                '#
					(<img[^<>]*\s src\s*=\s*
					|<body[^<>]*\s background\s*=\s*
					|<[^<>]+\s style\s*=\s* ["\'][^"\'>]+[:\s] url\(
					|<style[^>]*>[^<]+ [:\s] url\()
					(["\']?)(?![a-z]+:|[/\\#])([^"\'>)\s]+)
					|\[\[ ([\w()+./@~-]+) \]\]
				#ix',
                PREG_OFFSET_CAPTURE
            );
            foreach (\array_reverse($matches) as $m) {
                $file = \rtrim($basePath, '/\\') . '/' . (isset($m[4]) ? $m[4][0] : \urldecode($m[3][0]));
                if (!isset($cids[$file])) {
                    $cids[$file] = \substr($this->addEmbeddedFile($file)->getHeader('Content-ID'), 1, -1);
                }
                $html = \substr_replace($html,
                    "{$m[1][0]}{$m[2][0]}cid:{$cids[$file]}",
                    $m[0][1], \strlen($m[0][0])
                );
            }
        }

        if ($this->getSubject() == null) { // intentionally ==
            $html = Strings::replace($html, '#<title>(.+?)</title>#is', function (array $m): void {
                $this->setSubject(\html_entity_decode($m[1], ENT_QUOTES, 'UTF-8'));
            });
        }

        $this->htmlBody = \ltrim(\str_replace("\r", '', $html), "\n");

        if ($html !== '' && $this->getBody() === '') {
            $this->setBody($this->buildText($html));
        }

        return $this;
    }
1047749
public function sanitize_filename($str, $relative_path = FALSE) {
		$bad = array("../", "<!--", "-->", "<", ">", "'", '"', '&', '$', '#', '{', '}', '[', ']', '=', ';', '?', "%20", "%22", "%3c", 		// <
		"%253c", 		// <
		"%3e", 		// >
		"%0e", 		// >
		"%28", 		// (
		"%29", 		// )
		"%2528", 		// (
		"%26", 		// &
		"%24", 		// $
		"%3f", 		// ?
		"%3b", 		// ;
		"%3d")		// =
		;
		
		if (!$relative_path) {
			$bad[] = './';
			$bad[] = '/';
		}
		
		$str = $this->remove_invisible_characters($str, FALSE);
		return stripslashes(str_replace($bad, '', $str));
	}
1095785
public static function get($relativePath)
    {
        $relativePath = substr($relativePath, 0, 1) === '/' ? substr($relativePath, 1) : $relativePath;
        if (isset($_SESSION[LanguageComponent::SESSION_PARAMETER_LANGUAGE_COMPONENT][LanguageComponent::SESSION_PARAMETER_LANGUAGE])) {
            $language = $_SESSION[LanguageComponent::SESSION_PARAMETER_LANGUAGE_COMPONENT][LanguageComponent::SESSION_PARAMETER_LANGUAGE];
            if ($language == LanguageComponent::$DEFAULT_LANGUAGE) {
                return Request::$subfolders . $relativePath;
            } else {
                return Request::$subfolders . $language . '/' . $relativePath;
            }
        } else {
            return Request::$subfolders . $relativePath;
        }
    }
1114560
public function getSystemTmpDir($relativePathToAppend = '')
    {
        return $this->realpath(
            $this->makePathAbsolute(
                $this->getSystemConfiguration()->getParam(DirectoryKeys::TMP) . $this->makePathAbsolute($relativePathToAppend)
            )
        );
    }
802694
public function addPath($relativePath)
    {
        if ($relativePath != '/' &&
            is_string($relativePath) &&
            strlen($relativePath) > 0
        ) {
            // Add a leading slash if needed
            if ($relativePath[0] !== '/' &&
                substr($this->path, -1, 1) !== '/'
            ) {
                $relativePath = '/' . $relativePath;
            }

            $this->setPath($this->path . $relativePath);
        }
    }
415559
protected function getRelativeRoot($relativeTo, $basePath, $baseUrl)
    {
        if ($relativeTo === self::RELATIVE_PATH) {
            return $basePath;
        }
        if ($relativeTo === self::RELATIVE_URL) {
            return $baseUrl;
        }
        return null;
    }
1286580
public function relativize(string $absolutePath): string
    {
        $relativePath = \str_replace($this->workingDirectory, '.', $absolutePath);

        return \is_dir($absolutePath) ? \rtrim($relativePath, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR : $relativePath;
    }
370134
protected function get_file_info($relative_path)
    {
        $fullpath = $this->getFullPath($relative_path);
        $pathInfo = pathinfo($fullpath);
        $filemtime = @filemtime($fullpath);

        if(is_dir($fullpath)) {
            $model = $this->folder_model;
        } else {
            $model = $this->file_model;
            $model['attributes']['size'] = filesize($fullpath);
            $model['attributes']['extension'] = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
        }

        $model['id'] = $relative_path;
        $model['attributes']['name'] = $pathInfo['basename'];
        $model['attributes']['path'] = $this->getDynamicPath($fullpath);
        $model['attributes']['readable'] = 1;
        $model['attributes']['writable'] = 1;
        $model['attributes']['timestamp'] = $filemtime;
        $model['attributes']['modified'] = $this->formatDate($filemtime);
        //$model['attributes']['created'] = $model['attributes']['modified']; // PHP cannot get create timestamp
        return $model;
    }
41781
protected function get_file_info($relative_path) {
        $fullpath = $this->getFullPath($relative_path);
        $pathInfo = pathinfo($fullpath);
        $filemtime = filemtime($fullpath);

        // check if file is readable
        $is_readable = $this->has_system_permission($fullpath, ['r']);
        // check if file is writable
        $is_writable = $this->has_system_permission($fullpath, ['w']);

        if (is_dir($fullpath)) {
            $model = $this->folder_model;
        } else {
            $model = $this->file_model;
            $model['attributes']['extension'] = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';

            if ($is_readable) {
                $model['attributes']['size'] = $this->get_real_filesize($fullpath);

                if ($this->is_image_file($fullpath)) {
                    if ($model['attributes']['size']) {
                        list($width, $height, $type, $attr) = getimagesize($fullpath);
                    } else {
                        list($width, $height) = [0, 0];
                    }

                    $model['attributes']['width'] = $width;
                    $model['attributes']['height'] = $height;
                }
            }
        }

        $model['id'] = $relative_path;
        $model['attributes']['name'] = $pathInfo['basename'];
        $model['attributes']['path'] = $this->getDynamicPath($fullpath);
        $model['attributes']['readable'] = (int) $is_readable;
        $model['attributes']['writable'] = (int) $is_writable;
        $model['attributes']['timestamp'] = $filemtime;
        $model['attributes']['modified'] = $this->formatDate($filemtime);
        //$model['attributes']['created'] = $model['attributes']['modified']; // PHP cannot get create timestamp
        return $model;
    }
948449
function indexWriter(&$doclet) {

        parent::MDWriter($doclet);

        $phpdoctor = & $this->_doclet->phpdoctor();
        $displayTree = $phpdoctor->getOption("tree");

        $rootDoc = & $this->_doclet->rootDoc();

        $classes = & $rootDoc->classes();
        if ($classes == NULL)
            $classes = array();

        $functions = & $rootDoc->functions();
        if ($functions == NULL)
            $functions = array();

        $globals = & $rootDoc->globals();
        if ($globals == NULL)
            $globals = array();

        $elements = array_merge($classes, $functions, $globals);
        uasort($elements, array($this, "compareElements"));

        ob_start();

        echo "#INDEX#";

        if(isset($this->_doclet->phpdoctor()->_options["github_sources_repository"])){
            echo "\n\n[View Source codes]({$this->getSourcesBaseURL()})";
        }
        
        if ($displayTree) {
            echo "\n\n[View class hierarchy]({$this->getDirBaseURL()}/overview-tree.md)";
        }
        
        echo "\n\n[View depreacted list]({$this->getDirBaseURL()}/deprecated-list.md)";

        echo "\n\n[View todo list]({$this->getDirBaseURL()}/todo-list.md)";

        echo "\n\n[View the list of all classes, functions and globals]({$this->getDirBaseURL()}/index-all.md)";

        $this->_output = ob_get_contents();
        ob_end_clean();

        $this->_write("README.md");

        ///------------------------------------------------------

        ob_start();

        $letter = 64;
        foreach ($elements as $name => $element) {
            $firstChar = strtoupper(substr($element->name(), 0, 1));
            if (is_object($element) && $firstChar != chr($letter)) {
                $letter = ord($firstChar);
                echo "<a href=\"#", strtolower(chr($letter)), "\">", chr($letter), "</a>\n";
            }
        }

        echo "- - -\n\n";

        $first = TRUE;
        foreach ($elements as $element) {
            if (is_object($element)) {
                if (strtoupper(substr($element->name(), 0, 1)) != chr($letter)) {
                    $letter = ord(strtoupper(substr($element->name(), 0, 1)));
                    if (!$first) {
                        echo "</dl>\n";
                    }
                    $first = FALSE;
                    echo "<h1 id=\"letter", chr($letter), "\">", chr($letter), "</h1>\n";
                    echo "<dl>\n";
                }
                $parent = & $element->containingClass();
                if ($parent && strtolower(get_class($parent)) != "rootdoc") {
                    $in = "class <a href=\"" . $this->_asURL($parent) . "\">" . $parent->qualifiedName() . "</a>";
                } else {
                    $package = & $element->containingPackage();
                    $in = "namespace <a href=\"" . $this->_asURL($package) . "/README.md\">" . $package->name() . "</a>";
                }
                switch (strtolower(get_class($element))) {
                    case "classdoc":
                        if ($element->isOrdinaryClass()) {
                            echo "<dt><a href=\"", $this->_asURL($element), "\">", $element->name(), "</a> - Class in ", $in, "</dt>\n";
                        } elseif ($element->isInterface()) {
                            echo "<dt><a href=\"", $this->_asURL($element), "\">", $element->name(), "</a> - Interface in ", $in, "</dt>\n";
                        } elseif ($element->isException()) {
                            echo "<dt><a href=\"", $this->_asURL($element), "\">", $element->name(), "</a> - Exception in ", $in, "</dt>\n";
                        }
                        break;
                    case 'methoddoc':
                        if ($element->isFunction()) {
                            echo '<dt><a href="', $this->_asURL($element), '">', $element->name(), '()</a> - Function in ', $in, "</dt>\n";
                        }
                        break;
                    case "fielddoc":
                        if ($element->isGlobal()) {
                            echo "<dt><a href=\"", $this->_asURL($element), "\">", $element->name(), "</a> - Global in ", $in, "</dt>\n";
                        }
                        break;
                }
                if ($textTag = & $element->tags("@text") && $firstSentenceTags = & $textTag->firstSentenceTags($this->_doclet)) {
                    echo "<dd>";
                    foreach ($firstSentenceTags as $firstSentenceTag) {
                        echo $firstSentenceTag->text($this->_doclet);
                    }
                    echo "</dd>\n";
                }
            }
        }
        echo "</dl>\n";

        $this->_output = ob_get_contents();
        ob_end_clean();

        $this->_write("index-all.md");
    }
878685
protected function normalizeRelativePath(RelativePathInterface $path)
    {
        return $this->factory()->createFromAtoms(
            $this->normalizeRelativePathAtoms($path->atoms()),
            false,
            false
        );
    }
140312
public static File getRelativePath(final File relativePath) {
        final String p = getRelativePathForPath(relativePath.getPath(), File.separator);
        return p != null ? new File(p) : null;
    }
1284338
public function browseFilesystem($path = '')
    {
        // helpers
        function getBreadcrumbs($base, $path)
        {
            $paths  = ['/' => $base];
            $path   = trim($path, '/');
            if ($path !== '')
            {
                $segments   = explode('/', $path);
                $current    = '/';
	            foreach($segments as $segment)
	            {
	                $current .= $segment . '/';
	                $paths[$current] = $segment;
	            }
            }
            return $paths;
        }

	    // paths
	    $path       = str_replace('../', '', $path);
	    $path       = '/' . trim(preg_replace('%[\\/]+%', '/', $path), '/');
        $realpath   = realpath(base_path($path));
	    $base       = pathinfo(base_path())['basename'];

        // found
        if($realpath)
        {
            try
            {
                $objects        = array_diff(scandir($realpath), ['.','..']);
                $breadcrumbs    = getBreadcrumbs($base, $path);
                $folders        = array_filter($objects, function($f) use ($realpath) { return is_dir($realpath . '/' . $f); });
                $files          = array_filter($objects, function($f) use ($realpath) { return is_file($realpath . '/' . $f); });
                $path           = rtrim($path, '/') . '/';
                $parent         = $path !== '/' ? preg_replace('%[^/]+/$%', '', $path) : '/';

                return view('sketchpad::help/tools/folder', compact('parent', 'path', 'folders', 'files', 'breadcrumbs'));
            }
            catch(\Exception $e)
            {
                return "Unable to read folder '$path'";
            }
        }

        // not found
        return "Path '$path' not found";
	}
1095234
protected function parseDirectoryDo(\Gettext\Translations $translations, $rootDirectory, $relativePath, $subParsersFilter, $exclude3rdParty)
    {
        $themesPresets = array();
        $prefix = ($relativePath === '') ? '' : "$relativePath/";
        $matches = null;
        foreach (array_merge(array(''), $this->getDirectoryStructure($rootDirectory, $exclude3rdParty)) as $child) {
            $presetsAbsDirectory = ($child === '') ? $rootDirectory : "$rootDirectory/$child";
            if (preg_match('%(?:^|/)themes/\w+/css/presets$%', $presetsAbsDirectory, $matches)) {
                $dirList = @scandir($presetsAbsDirectory);
                if ($dirList === false) {
                    throw new \Exception("Unable to parse directory $presetsAbsDirectory");
                }
                $shownChild = ($child === '') ? rtrim($prefix, '/') : ($prefix.$child);
                foreach ($dirList as $file) {
                    if (($file[0] !== '.') && preg_match('/[^.].*\.less$/i', $file)) {
                        $fileAbs = "$presetsAbsDirectory/$file";
                        if (is_file($fileAbs)) {
                            $content = @file_get_contents($fileAbs);
                            if ($content === false) {
                                throw new \Exception("Error reading file '$fileAbs'");
                            }
                            $content = str_replace("\r", "\n", str_replace("\r\n", "\n", $content));
                            // Strip multiline comments
                            $content = preg_replace_callback(
                                '|/\*.*?\*/|s',
                                function ($matches) {
                                    return str_repeat("\n", substr_count($matches[0], "\n"));
                                },
                                $content
                            );
                            foreach (array("'", '"') as $quote) {
                                if (preg_match('%(?:^|\\n|;)[ \\t]*@preset-name:\\s*'.$quote.'([^'.$quote.']*)'.$quote.'\\s*(?:;|$)%s', $content, $matches)) {
                                    $presetName = $matches[1];
                                    $presetLine = null;
                                    $p = strpos($content, $matches[0]);
                                    if ($p !== false) {
                                        $presetLine = substr_count(substr($content, 0, $p), "\n") + 1;
                                    }
                                    if (!isset($themesPresets[$presetName])) {
                                        $themesPresets[$presetName] = array();
                                    }
                                    $themesPresets[$presetName][] = array($shownChild."/$file", $presetLine);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        foreach ($themesPresets as $themesPreset => $references) {
            $translation = $translations->insert('PresetName', ucwords(str_replace(array('_', '-', '/'), ' ', $themesPreset)));
            foreach ($references as $reference) {
                $translation->addReference($reference[0], $reference[1]);
            }
        }
    }