public static function listTree($root, $prefix = '', $delimiter = '')
    {
        $dir = $root . ((!empty($prefix)) ? $prefix : '');
        $out = [];
        if (is_dir($dir)) {
            $files = array_diff(scandir($dir), ['.', '..']);
            foreach ($files as $file) {
                $key = $dir . $file;
                $local = ((!empty($prefix)) ? $prefix : '') . $file;
                // get file meta
                if (is_dir($key)) {
                    $stat = stat($key);
                    $out[] = [
                        'path'          => str_replace(DIRECTORY_SEPARATOR, '/', $local) . '/',
                        'last_modified' => gmdate('D, d M Y H:i:s \G\M\T', array_get($stat, 'mtime', 0))
                    ];
                    if (empty($delimiter)) {
                        $out = array_merge($out, static::listTree($root, $local . DIRECTORY_SEPARATOR));
                    }
                } elseif (is_file($key)) {
                    $stat = stat($key);
                    $ext = FileUtilities::getFileExtension($key);
                    $out[] = [
                        'path'           => str_replace(DIRECTORY_SEPARATOR, '/', $local),
                        'content_type'   => FileUtilities::determineContentType($ext, '', $key),
                        'last_modified'  => gmdate('D, d M Y H:i:s \G\M\T', array_get($stat, 'mtime', 0)),
                        'content_length' => array_get($stat, 'size', 0)
                    ];
                } else {
                    error_log($key);
                }
            }
        } else {
            throw new NotFoundException("Folder '$prefix' does not exist in storage.");
        }

        return $out;
    }