text:
<?php
namespace TYPO3\CMS\Core\Resource\Driver;

use TYPO3\CMS\Core\Resource\Exception;
use TYPO3\CMS\Core\Resource\FolderInterface;
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Type\File\FileInfo;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;

/**
 * Driver for the local file system
 *
 */
class LocalDriver extends AbstractHierarchicalFilesystemDriver
{
    /**
     * @var string
     */
    const UNSAFE_FILENAME_CHARACTER_EXPRESSION = '\\x00-\\x2C\\/\\x3A-\\x3F\\x5B-\\x60\\x7B-\\xBF';

    /**
     * The absolute base path. It always contains a trailing slash.
     *
     * @var string
     */
    protected $absoluteBasePath;

    /**
     * A list of all supported hash algorithms, written all lower case.
     *
     * @var array
     */
    protected $supportedHashAlgorithms = ['sha1', 'md5'];

    /**
     * The base URL that points to this driver's storage. As long is this
     * is not set, it is assumed that this folder is not publicly available
     *
     * @var string
     */
    protected $baseUri = null;

    /**
     * @var \TYPO3\CMS\Core\Charset\CharsetConverter
     */
    protected $charsetConversion;

    /** @var array */
    protected $mappingFolderNameToRole = [
        '_recycler_' => FolderInterface::ROLE_RECYCLER,
        '_temp_' => FolderInterface::ROLE_TEMPORARY,
        'user_upload' => FolderInterface::ROLE_USERUPLOAD,
    ];

    /**
     * @param array $configuration
     */
    public function __construct(array $configuration = [])
    {
        parent::__construct($configuration);
        // The capabilities default of this driver. See CAPABILITY_* constants for possible values
        $this->capabilities =
            ResourceStorage::CAPABILITY_BROWSABLE
            | ResourceStorage::CAPABILITY_PUBLIC
            | ResourceStorage::CAPABILITY_WRITABLE;
    }

    /**
     * Merges the capabilites merged by the user at the storage
     * configuration into the actual capabilities of the driver
     * and returns the result.
     *
     * @param int $capabilities
     * @return int
     */
    public function mergeConfigurationCapabilities($capabilities)
    {
        $this->capabilities &= $capabilities;
        return $this->capabilities;
    }

    /**
     * Processes the configuration for this driver.
     *
     * @return void
     */
    public function processConfiguration()
    {
        $this->absoluteBasePath = $this->calculateBasePath($this->configuration);
        $this->determineBaseUrl();
        if ($this->baseUri === null) {
            // remove public flag
            $this->capabilities &= ~ResourceStorage::CAPABILITY_PUBLIC;
        }
    }

    /**
     * Initializes this object. This is called by the storage after the driver
     * has been attached.
     *
     * @return void
     */
    public function initialize()
    {
    }

    /**
     * Determines the base URL for this driver, from the configuration or
     * the TypoScript frontend object
     *
     * @return void
     */
    protected function determineBaseUrl()
    {
        // only calculate baseURI if the storage does not enforce jumpUrl Script
        if ($this->hasCapability(ResourceStorage::CAPABILITY_PUBLIC)) {
            if (GeneralUtility::isFirstPartOfStr($this->absoluteBasePath, PATH_site)) {
                // use site-relative URLs
                $temporaryBaseUri = rtrim(PathUtility::stripPathSitePrefix($this->absoluteBasePath), '/');
                if ($temporaryBaseUri !== '') {
                    $uriParts = explode('/', $temporaryBaseUri);
                    $uriParts = array_map('rawurlencode', $uriParts);
                    $temporaryBaseUri = implode('/', $uriParts) . '/';
                }
                $this->baseUri = $temporaryBaseUri;
            } elseif (isset($this->configuration['baseUri']) && GeneralUtility::isValidUrl($this->configuration['baseUri'])) {
                $this->baseUri = rtrim($this->configuration['baseUri'], '/') . '/';
            }
        }
    }

    /**
     * Calculates the absolute path to this drivers storage location.
     *
     * @throws Exception\InvalidConfigurationException
     * @param array $configuration
     * @return string
     */
    protected function calculateBasePath(array $configuration)
    {
        if (!array_key_exists('basePath', $configuration) || empty($configuration['basePath'])) {
            throw new Exception\InvalidConfigurationException(
                'Configuration must contain base path.',
                1346510477
            );
        }

        if ($configuration['pathType'] === 'relative') {
            $relativeBasePath = $configuration['basePath'];
            $absoluteBasePath = PATH_site . $relativeBasePath;
        } else {
            $absoluteBasePath = $configuration['basePath'];
        }
        $absoluteBasePath = $this->canonicalizeAndCheckFilePath($absoluteBasePath);
        $absoluteBasePath = rtrim($absoluteBasePath, '/') . '/';
        if (!is_dir($absoluteBasePath)) {
            throw new Exception\InvalidConfigurationException(
                'Base path "' . $absoluteBasePath . '" does not exist or is no directory.',
                1299233097
            );
        }
        return $absoluteBasePath;
    }

    /**
     * Returns the public URL to a file.
     * For the local driver, this will always return a path relative to PATH_site.
     *
     * @param string $identifier
     * @return string
     * @throws \TYPO3\CMS\Core\Resource\Exception
     */
    public function getPublicUrl($identifier)
    {
        $publicUrl = null;
        if ($this->baseUri !== null) {
            $uriParts = explode('/', ltrim($identifier, '/'));
            $uriParts = array_map('rawurlencode', $uriParts);
            $identifier = implode('/', $uriParts);
            $publicUrl = $this->baseUri . $identifier;
        }
        return $publicUrl;
    }

    /**
     * Returns the Identifier of the root level folder of the storage.
     *
     * @return string
     */
    public function getRootLevelFolder()
    {
        return '/';
    }

    /**
     * Returns identifier of the default folder new files should be put into.
     *
     * @return string
     */
    public function getDefaultFolder()
    {
        $identifier = '/user_upload/';
        $createFolder = !$this->folderExists($identifier);
        if ($createFolder === true) {
            $identifier = $this->createFolder('user_upload');
        }
        return $identifier;
    }

    /**
     * Creates a folder, within a parent folder.
     * If no parent folder is given, a rootlevel folder will be created
     *
     * @param string $newFolderName
     * @param string $parentFolderIdentifier
     * @param bool $recursive
     * @return string the Identifier of the new folder
     */
    public function createFolder($newFolderName, $parentFolderIdentifier = '', $recursive = false)
    {
        $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
        $newFolderName = trim($newFolderName, '/');
        if ($recursive == false) {
            $newFolderName = $this->sanitizeFileName($newFolderName);
            $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
            GeneralUtility::mkdir($this->getAbsolutePath($newIdentifier));
        } else {
            $parts = GeneralUtility::trimExplode('/', $newFolderName);
            $parts = array_map([$this, 'sanitizeFileName'], $parts);
            $newFolderName = implode('/', $parts);
            $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
            GeneralUtility::mkdir_deep($this->getAbsolutePath($parentFolderIdentifier) . '/', $newFolderName);
        }
        return $newIdentifier;
    }

    /**
     * Returns information about a file.
     *
     * @param string $fileIdentifier In the case of the LocalDriver, this is the (relative) path to the file.
     * @param array $propertiesToExtract Array of properties which should be extracted, if empty all will be extracted
     * @return array
     * @throws \InvalidArgumentException
     */
    public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = [])
    {
        $absoluteFilePath = $this->getAbsolutePath($fileIdentifier);
        // don't use $this->fileExists() because we need the absolute path to the file anyways, so we can directly
        // use PHP's filesystem method.
        if (!file_exists($absoluteFilePath) || !is_file($absoluteFilePath)) {
            throw new \InvalidArgumentException('File ' . $fileIdentifier . ' does not exist.', 1314516809);
        }

        $dirPath = PathUtility::dirname($fileIdentifier);
        $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath);
        return $this->extractFileInformation($absoluteFilePath, $dirPath, $propertiesToExtract);
    }

    /**
     * Returns information about a folder.
     *
     * @param string $folderIdentifier In the case of the LocalDriver, this is the (relative) path to the file.
     * @return array
     * @throws Exception\FolderDoesNotExistException
     */
    public function getFolderInfoByIdentifier($folderIdentifier)
    {
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);

        if (!$this->folderExists($folderIdentifier)) {
            throw new Exception\FolderDoesNotExistException(
                'Folder "' . $folderIdentifier . '" does not exist.',
                1314516810
            );
        }
        return [
            'identifier' => $folderIdentifier,
            'name' => PathUtility::basename($folderIdentifier),
            'storage' => $this->storageUid
        ];
    }

    /**
     * Returns a string where any character not matching [.a-zA-Z0-9_-] is
     * substituted by '_'
     * Trailing dots are removed
     *
     * Previously in \TYPO3\CMS\Core\Utility\File\BasicFileUtility::cleanFileName()
     *
     * @param string $fileName Input string, typically the body of a fileName
     * @param string $charset Charset of the a fileName (defaults to current charset; depending on context)
     * @return string Output string with any characters not matching [.a-zA-Z0-9_-] is substituted by '_' and trailing dots removed
     * @throws Exception\InvalidFileNameException
     */
    public function sanitizeFileName($fileName, $charset = '')
    {
        // Handle UTF-8 characters
        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
            // Allow ".", "-", 0-9, a-z, A-Z and everything beyond U+C0 (latin capital letter a with grave)
            $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . ']/u', '_', trim($fileName));
        } else {
            // Define character set
            if (!$charset) {
                if (TYPO3_MODE === 'FE') {
                    $charset = $GLOBALS['TSFE']->renderCharset;
                } else {
                    // default for Backend
                    $charset = 'utf-8';
                }
            }
            // If a charset was found, convert fileName
            if ($charset) {
                $fileName = $this->getCharsetConversion()->specCharsToASCII($charset, $fileName);
            }
            // Replace unwanted characters by underscores
            $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . '\\xC0-\\xFF]/', '_', trim($fileName));
        }
        // Strip trailing dots and return
        $cleanFileName = rtrim($cleanFileName, '.');
        if ($cleanFileName === '') {
            throw new Exception\InvalidFileNameException(
                'File name ' . $fileName . ' is invalid.',
                1320288991
            );
        }
        return $cleanFileName;
    }

    /**
     * Generic wrapper for extracting a list of items from a path.
     *
     * @param string $folderIdentifier
     * @param int $start The position to start the listing; if not set, start from the beginning
     * @param int $numberOfItems The number of items to list; if set to zero, all items are returned
     * @param array $filterMethods The filter methods used to filter the directory items
     * @param bool $includeFiles
     * @param bool $includeDirs
     * @param bool $recursive
     * @param string $sort Property name used to sort the items.
     *                     Among them may be: '' (empty, no sorting), name,
     *                     fileext, size, tstamp and rw.
     *                     If a driver does not support the given property, it
     *                     should fall back to "name".
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
     * @return array
     * @throws \InvalidArgumentException
     */
    protected function getDirectoryItemList($folderIdentifier, $start = 0, $numberOfItems = 0, array $filterMethods, $includeFiles = true, $includeDirs = true, $recursive = false, $sort = '', $sortRev = false)
    {
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
        $realPath = $this->getAbsolutePath($folderIdentifier);
        if (!is_dir($realPath)) {
            throw new \InvalidArgumentException(
                'Cannot list items in directory ' . $folderIdentifier . ' - does not exist or is no directory',
                1314349666
            );
        }

        $items = $this->retrieveFileAndFoldersInPath($realPath, $recursive, $includeFiles, $includeDirs, $sort, $sortRev);
        $iterator = new \ArrayIterator($items);
        if ($iterator->count() === 0) {
            return [];
        }
        $iterator->seek($start);

        // $c is the counter for how many items we still have to fetch (-1 is unlimited)
        $c = $numberOfItems > 0 ? $numberOfItems : - 1;
        $items = [];
        while ($iterator->valid() && ($numberOfItems === 0 || $c > 0)) {
            // $iteratorItem is the file or folder name
            $iteratorItem = $iterator->current();
            // go on to the next iterator item now as we might skip this one early
            $iterator->next();

            try {
                if (
                    !$this->applyFilterMethodsToDirectoryItem(
                        $filterMethods,
                        $iteratorItem['name'],
                        $iteratorItem['identifier'],
                        $this->getParentFolderIdentifierOfIdentifier($iteratorItem['identifier'])
                    )
                ) {
                    continue;
                }

                $items[$iteratorItem['identifier']] = $iteratorItem['identifier'];
                // Decrement item counter to make sure we only return $numberOfItems
                // we cannot do this earlier in the method (unlike moving the iterator forward) because we only add the
                // item here
                --$c;
            } catch (Exception\InvalidPathException $e) {
            }
        }
        return $items;
    }

    /**
     * Applies a set of filter methods to a file name to find out if it should be used or not. This is e.g. used by
     * directory listings.
     *
     * @param array $filterMethods The filter methods to use
     * @param string $itemName
     * @param string $itemIdentifier
     * @param string $parentIdentifier
     * @throws \RuntimeException
     * @return bool
     */
    protected function applyFilterMethodsToDirectoryItem(array $filterMethods, $itemName, $itemIdentifier, $parentIdentifier)
    {
        foreach ($filterMethods as $filter) {
            if (is_callable($filter)) {
                $result = call_user_func($filter, $itemName, $itemIdentifier, $parentIdentifier, [], $this);
                // We have to use -1 as the "don't include" return value, as call_user_func() will return FALSE
                // If calling the method succeeded and thus we can't use that as a return value.
                if ($result === -1) {
                    return false;
                } elseif ($result === false) {
                    throw new \RuntimeException('Could not apply file/folder name filter ' . $filter[0] . '::' . $filter[1]);
                }
            }
        }
        return true;
    }

    /**
     * Returns a file inside the specified path
     *
     * @param string $fileName
     * @param string $folderIdentifier
     * @return string File Identifier
     */
    public function getFileInFolder($fileName, $folderIdentifier)
    {
        return $this->canonicalizeAndCheckFileIdentifier($folderIdentifier . '/' . $fileName);
    }

    /**
     * Returns a list of files inside the specified path
     *
     * @param string $folderIdentifier
     * @param int $start
     * @param int $numberOfItems
     * @param bool $recursive
     * @param array $filenameFilterCallbacks The method callbacks to use for filtering the items
     * @param string $sort Property name used to sort the items.
     *                     Among them may be: '' (empty, no sorting), name,
     *                     fileext, size, tstamp and rw.
     *                     If a driver does not support the given property, it
     *                     should fall back to "name".
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
     * @return array of FileIdentifiers
     */
    public function getFilesInFolder($folderIdentifier, $start = 0, $numberOfItems = 0, $recursive = false, array $filenameFilterCallbacks = [], $sort = '', $sortRev = false)
    {
        return $this->getDirectoryItemList($folderIdentifier, $start, $numberOfItems, $filenameFilterCallbacks, true, false, $recursive, $sort, $sortRev);
    }

    /**
     * Returns the number of files inside the specified path
     *
     * @param string $folderIdentifier
     * @param bool $recursive
     * @param array $filenameFilterCallbacks callbacks for filtering the items
     * @return int Number of files in folder
     */
    public function countFilesInFolder($folderIdentifier, $recursive = false, array $filenameFilterCallbacks = [])
    {
        return count($this->getFilesInFolder($folderIdentifier, 0, 0, $recursive, $filenameFilterCallbacks));
    }

    /**
     * Returns a list of folders inside the specified path
     *
     * @param string $folderIdentifier
     * @param int $start
     * @param int $numberOfItems
     * @param bool $recursive
     * @param array $folderNameFilterCallbacks The method callbacks to use for filtering the items
     * @param string $sort Property name used to sort the items.
     *                     Among them may be: '' (empty, no sorting), name,
     *                     fileext, size, tstamp and rw.
     *                     If a driver does not support the given property, it
     *                     should fall back to "name".
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
     * @return array of Folder Identifier
     */
    public function getFoldersInFolder($folderIdentifier, $start = 0, $numberOfItems = 0, $recursive = false, array $folderNameFilterCallbacks = [], $sort = '', $sortRev = false)
    {
        return $this->getDirectoryItemList($folderIdentifier, $start, $numberOfItems, $folderNameFilterCallbacks, false, true, $recursive, $sort, $sortRev);
    }

    /**
     * Returns the number of folders inside the specified path
     *
     * @param string  $folderIdentifier
     * @param bool $recursive
     * @param array   $folderNameFilterCallbacks callbacks for filtering the items
     * @return int Number of folders in folder
     */
    public function countFoldersInFolder($folderIdentifier, $recursive = false, array $folderNameFilterCallbacks = [])
    {
        return count($this->getFoldersInFolder($folderIdentifier, 0, 0, $recursive, $folderNameFilterCallbacks));
    }

    /**
     * Returns a list with the names of all files and folders in a path, optionally recursive.
     *
     * @param string $path The absolute path
     * @param bool $recursive If TRUE, recursively fetches files and folders
     * @param bool $includeFiles
     * @param bool $includeDirs
     * @param string $sort Property name used to sort the items.
     *                     Among them may be: '' (empty, no sorting), name,
     *                     fileext, size, tstamp and rw.
     *                     If a driver does not support the given property, it
     *                     should fall back to "name".
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
     * @return array
     */
    protected function retrieveFileAndFoldersInPath($path, $recursive = false, $includeFiles = true, $includeDirs = true, $sort = '', $sortRev = false)
    {
        $pathLength = strlen($this->getAbsoluteBasePath());
        $iteratorMode = \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::FOLLOW_SYMLINKS;
        if ($recursive) {
            $iterator = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($path, $iteratorMode),
                \RecursiveIteratorIterator::SELF_FIRST,
                \RecursiveIteratorIterator::CATCH_GET_CHILD
            );
        } else {
            $iterator = new \RecursiveDirectoryIterator($path, $iteratorMode);
        }

        $directoryEntries = [];
        while ($iterator->valid()) {
            /** @var $entry \SplFileInfo */
            $entry = $iterator->current();
            // skip non-files/non-folders, and empty entries
            if ((!$entry->isFile() && !$entry->isDir()) || $entry->getFilename() == '' ||
                ($entry->isFile() && !$includeFiles) || ($entry->isDir() && !$includeDirs)) {
                $iterator->next();
                continue;
            }
            $entryIdentifier = '/' . substr($entry->getPathname(), $pathLength);
            $entryName = PathUtility::basename($entryIdentifier);
            if ($entry->isDir()) {
                $entryIdentifier .= '/';
            }
            $entryArray = [
                'identifier' => $entryIdentifier,
                'name' => $entryName,
                'type' => $entry->isDir() ? 'dir' : 'file'
            ];
            $directoryEntries[$entryIdentifier] = $entryArray;
            $iterator->next();
        }
        return $this->sortDirectoryEntries($directoryEntries, $sort, $sortRev);
    }

    /**
     * Sort the directory entries by a certain key
     *
     * @param array $directoryEntries Array of directory entry arrays from
     *                                retrieveFileAndFoldersInPath()
     * @param string $sort Property name used to sort the items.
     *                     Among them may be: '' (empty, no sorting), name,
     *                     fileext, size, tstamp and rw.
     *                     If a driver does not support the given property, it
     *                     should fall back to "name".
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
     * @return array Sorted entries. Content of the keys is undefined.
     */
    protected function sortDirectoryEntries($directoryEntries, $sort = '', $sortRev = false)
    {
        $entriesToSort = [];
        foreach ($directoryEntries as $entryArray) {
            $dir      = pathinfo($entryArray['name'], PATHINFO_DIRNAME) . '/';
            $fullPath = $this->getAbsoluteBasePath() . $entryArray['identifier'];
            switch ($sort) {
                case 'size':
                    $sortingKey = '0';
                    if ($entryArray['type'] === 'file') {
                        $sortingKey = $this->getSpecificFileInformation($fullPath, $dir, 'size');
                    }
                    // Add a character for a natural order sorting
                    $sortingKey .= 's';
                    break;
                case 'rw':
                    $perms = $this->getPermissions($entryArray['identifier']);
                    $sortingKey = ($perms['r'] ? 'R' : '')
                        . ($perms['w'] ? 'W' : '');
                    break;
                case 'fileext':
                    $sortingKey = pathinfo($entryArray['name'], PATHINFO_EXTENSION);
                    break;
                case 'tstamp':
                    $sortingKey = '0';
                    if ($entryArray['type'] === 'file') {
                        $sortingKey = $this->getSpecificFileInformation($fullPath, $dir, 'mtime');
                    }
                    // Add a character for a natural order sorting
                    $sortingKey .= 't';
                    break;
                case 'name':
                case 'file':
                default:
                    $sortingKey = $entryArray['name'];
            }
            $i = 0;
            while (isset($entriesToSort[$sortingKey . $i])) {
                $i++;
            }
            $entriesToSort[$sortingKey . $i] = $entryArray;
        }
        uksort($entriesToSort, 'strnatcasecmp');

        if ($sortRev) {
            $entriesToSort = array_reverse($entriesToSort);
        }

        return $entriesToSort;
    }

    /**
     * Extracts information about a file from the filesystem.
     *
     * @param string $filePath The absolute path to the file
     * @param string $containerPath The relative path to the file's container
     * @param array $propertiesToExtract array of properties which should be returned, if empty all will be extracted
     * @return array
     */
    protected function extractFileInformation($filePath, $containerPath, array $propertiesToExtract = [])
    {
        if (empty($propertiesToExtract)) {
            $propertiesToExtract = [
                'size', 'atime', 'atime', 'mtime', 'ctime', 'mimetype', 'name',
                'identifier', 'identifier_hash', 'storage', 'folder_hash'
            ];
        }
        $fileInformation = [];
        foreach ($propertiesToExtract as $property) {
            $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
        }
        return $fileInformation;
    }

    /**
     * Extracts a specific FileInformation from the FileSystems.
     *
     * @param string $fileIdentifier
     * @param string $containerPath
     * @param string $property
     *
     * @return bool|int|string
     * @throws \InvalidArgumentException
     */
    public function getSpecificFileInformation($fileIdentifier, $containerPath, $property)
    {
        $identifier = $this->canonicalizeAndCheckFileIdentifier($containerPath . PathUtility::basename($fileIdentifier));

        /** @var FileInfo $fileInfo */
        $fileInfo = GeneralUtility::makeInstance(FileInfo::class, $fileIdentifier);
        switch ($property) {
            case 'size':
                return $fileInfo->getSize();
            case 'atime':
                return $fileInfo->getATime();
            case 'mtime':
                return $fileInfo->getMTime();
            case 'ctime':
                return $fileInfo->getCTime();
            case 'name':
                return PathUtility::basename($fileIdentifier);
            case 'mimetype':
                return (string)$fileInfo->getMimeType();
            case 'identifier':
                return $identifier;
            case 'storage':
                return $this->storageUid;
            case 'identifier_hash':
                return $this->hashIdentifier($identifier);
            case 'folder_hash':
                return $this->hashIdentifier($this->getParentFolderIdentifierOfIdentifier($identifier));
            default:
                throw new \InvalidArgumentException(sprintf('The information "%s" is not available.', $property));
        }
    }

    /**
     * Returns the absolute path of the folder this driver operates on.
     *
     * @return string
     */
    protected function getAbsoluteBasePath()
    {
        return $this->absoluteBasePath;
    }

    /**
     * Returns the absolute path of a file or folder.
     *
     * @param string $fileIdentifier
     * @return string
     * @throws Exception\InvalidPathException
     */
    protected function getAbsolutePath($fileIdentifier)
    {
        $relativeFilePath = ltrim($this->canonicalizeAndCheckFileIdentifier($fileIdentifier), '/');
        $path = $this->absoluteBasePath . $relativeFilePath;
        return $path;
    }

    /**
     * Creates a (cryptographic) hash for a file.
     *
     * @param string $fileIdentifier
     * @param string $hashAlgorithm The hash algorithm to use
     * @return string
     * @throws \RuntimeException
     * @throws \InvalidArgumentException
     */
    public function hash($fileIdentifier, $hashAlgorithm)
    {
        if (!in_array($hashAlgorithm, $this->supportedHashAlgorithms)) {
            throw new \InvalidArgumentException('Hash algorithm "' . $hashAlgorithm . '" is not supported.', 1304964032);
        }
        switch ($hashAlgorithm) {
            case 'sha1':
                $hash = sha1_file($this->getAbsolutePath($fileIdentifier));
                break;
            case 'md5':
                $hash = md5_file($this->getAbsolutePath($fileIdentifier));
                break;
            default:
                throw new \RuntimeException('Hash algorithm ' . $hashAlgorithm . ' is not implemented.', 1329644451);
        }
        return $hash;
    }

    /**
     * Adds a file from the local server hard disk to a given path in TYPO3s virtual file system.
     * This assumes that the local file exists, so no further check is done here!
     * After a successful the original file must not exist anymore.
     *
     * @param string $localFilePath (within PATH_site)
     * @param string $targetFolderIdentifier
     * @param string $newFileName optional, if not given original name is used
     * @param bool $removeOriginal if set the original file will be removed after successful operation
     * @return string the identifier of the new file
     * @throws \RuntimeException
     * @throws \InvalidArgumentException
     */
    public function addFile($localFilePath, $targetFolderIdentifier, $newFileName = '', $removeOriginal = true)
    {
        $localFilePath = $this->canonicalizeAndCheckFilePath($localFilePath);
        // as for the "virtual storage" for backwards-compatibility, this check always fails, as the file probably lies under PATH_site
        // thus, it is not checked here
        // @todo is check in storage
        if (GeneralUtility::isFirstPartOfStr($localFilePath, $this->absoluteBasePath) && $this->storageUid > 0) {
            throw new \InvalidArgumentException('Cannot add a file that is already part of this storage.', 1314778269);
        }
        $newFileName = $this->sanitizeFileName($newFileName !== '' ? $newFileName : PathUtility::basename($localFilePath));
        $newFileIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier) . $newFileName;
        $targetPath = $this->getAbsolutePath($newFileIdentifier);

        if ($removeOriginal) {
            if (is_uploaded_file($localFilePath)) {
                $result = move_uploaded_file($localFilePath, $targetPath);
            } else {
                $result = rename($localFilePath, $targetPath);
            }
        } else {
            $result = copy($localFilePath, $targetPath);
        }
        if ($result === false || !file_exists($targetPath)) {
            throw new \RuntimeException('Adding file ' . $localFilePath . ' at ' . $newFileIdentifier . ' failed.');
        }
        clearstatcache();
        // Change the permissions of the file
        GeneralUtility::fixPermissions($targetPath);
        return $newFileIdentifier;
    }

    /**
     * Checks if a file exists.
     *
     * @param string $fileIdentifier
     *
     * @return bool
     */
    public function fileExists($fileIdentifier)
    {
        $absoluteFilePath = $this->getAbsolutePath($fileIdentifier);
        return is_file($absoluteFilePath);
    }

    /**
     * Checks if a file inside a folder exists
     *
     * @param string $fileName
     * @param string $folderIdentifier
     * @return bool
     */
    public function fileExistsInFolder($fileName, $folderIdentifier)
    {
        $identifier = $folderIdentifier . '/' . $fileName;
        $identifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
        return $this->fileExists($identifier);
    }

    /**
     * Checks if a folder exists.
     *
     * @param string $folderIdentifier
     *
     * @return bool
     */
    public function folderExists($folderIdentifier)
    {
        $absoluteFilePath = $this->getAbsolutePath($folderIdentifier);
        return is_dir($absoluteFilePath);
    }

    /**
     * Checks if a folder inside a folder exists.
     *
     * @param string $folderName
     * @param string $folderIdentifier
     * @return bool
     */
    public function folderExistsInFolder($folderName, $folderIdentifier)
    {
        $identifier = $folderIdentifier . '/' . $folderName;
        $identifier = $this->canonicalizeAndCheckFolderIdentifier($identifier);
        return $this->folderExists($identifier);
    }

    /**
     * Returns the Identifier for a folder within a given folder.
     *
     * @param string $folderName The name of the target folder
     * @param string $folderIdentifier
     * @return string
     */
    public function getFolderInFolder($folderName, $folderIdentifier)
    {
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier . '/' . $folderName);
        return $folderIdentifier;
    }

    /**
     * Replaces the contents (and file-specific metadata) of a file object with a local file.
     *
     * @param string $fileIdentifier
     * @param string $localFilePath
     * @return bool TRUE if the operation succeeded
     * @throws \RuntimeException
     */
    public function replaceFile($fileIdentifier, $localFilePath)
    {
        $filePath = $this->getAbsolutePath($fileIdentifier);
        if (is_uploaded_file($localFilePath)) {
            $result = move_uploaded_file($localFilePath, $filePath);
        } else {
            $result = rename($localFilePath, $filePath);
        }
        GeneralUtility::fixPermissions($filePath);
        if ($result === false) {
            throw new \RuntimeException('Replacing file ' . $fileIdentifier . ' with ' . $localFilePath . ' failed.', 1315314711);
        }
        return $result;
    }

    /**
     * Copies a file *within* the current storage.
     * Note that this is only about an intra-storage copy action, where a file is just
     * copied to another folder in the same storage.
     *
     * @param string $fileIdentifier
     * @param string $targetFolderIdentifier
     * @param string $fileName
     * @return string the Identifier of the new file
     */
    public function copyFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $fileName)
    {
        $sourcePath = $this->getAbsolutePath($fileIdentifier);
        $newIdentifier = $targetFolderIdentifier . '/' . $fileName;
        $newIdentifier = $this->canonicalizeAndCheckFileIdentifier($newIdentifier);

        $absoluteFilePath = $this->getAbsolutePath($newIdentifier);
        copy($sourcePath, $absoluteFilePath);
        GeneralUtility::fixPermissions($absoluteFilePath);
        return $newIdentifier;
    }

    /**
     * Moves a file *within* the current storage.
     * Note that this is only about an inner-storage move action, where a file is just
     * moved to another folder in the same storage.
     *
     * @param string $fileIdentifier
     * @param string $targetFolderIdentifier
     * @param string $newFileName
     * @return string
     * @throws \RuntimeException
     */
    public function moveFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $newFileName)
    {
        $sourcePath = $this->getAbsolutePath($fileIdentifier);
        $targetIdentifier = $targetFolderIdentifier . '/' . $newFileName;
        $targetIdentifier = $this->canonicalizeAndCheckFileIdentifier($targetIdentifier);
        $result = rename($sourcePath, $this->getAbsolutePath($targetIdentifier));
        if ($result === false) {
            throw new \RuntimeException('Moving file ' . $sourcePath . ' to ' . $targetIdentifier . ' failed.', 1315314712);
        }
        return $targetIdentifier;
    }

    /**
     * Copies a file to a temporary path and returns that path.
     *
     * @param string $fileIdentifier
     * @return string The temporary path
     * @throws \RuntimeException
     */
    protected function copyFileToTemporaryPath($fileIdentifier)
    {
        $sourcePath = $this->getAbsolutePath($fileIdentifier);
        $temporaryPath = $this->getTemporaryPathForFile($fileIdentifier);
        $result = copy($sourcePath, $temporaryPath);
        touch($temporaryPath, filemtime($sourcePath));
        if ($result === false) {
            throw new \RuntimeException(
                'Copying file "' . $fileIdentifier . '" to temporary path "' . $temporaryPath . '" failed.',
                1320577649
            );
        }
        return $temporaryPath;
    }

    /**
     * Moves a file or folder to the given directory, renaming the source in the process if
     * a file or folder of the same name already exists in the target path.
     *
     * @param string $filePath
     * @param string $recycleDirectory
     * @return bool
     */
    protected function recycleFileOrFolder($filePath, $recycleDirectory)
    {
        $destinationFile = $recycleDirectory . '/' . PathUtility::basename($filePath);
        if (file_exists($destinationFile)) {
            $timeStamp = \DateTimeImmutable::createFromFormat('U.u', microtime(true))->format('YmdHisu');
            $destinationFile = $recycleDirectory . '/' . $timeStamp . '_' . PathUtility::basename($filePath);
        }
        $result = rename($filePath, $destinationFile);
        return $result;
    }

    /**
     * Creates a map of old and new file/folder identifiers after renaming or
     * moving a folder. The old identifier is used as the key, the new one as the value.
     *
     * @param array $filesAndFolders
     * @param string $sourceFolderIdentifier
     * @param string $targetFolderIdentifier
     *
     * @return array
     * @throws Exception\FileOperationErrorException
     */
    protected function createIdentifierMap(array $filesAndFolders, $sourceFolderIdentifier, $targetFolderIdentifier)
    {
        $identifierMap = [];
        $identifierMap[$sourceFolderIdentifier] = $targetFolderIdentifier;
        foreach ($filesAndFolders as $oldItem) {
            if ($oldItem['type'] == 'dir') {
                $oldIdentifier = $oldItem['identifier'];
                $newIdentifier = $this->canonicalizeAndCheckFolderIdentifier(
                    str_replace($sourceFolderIdentifier, $targetFolderIdentifier, $oldItem['identifier'])
                );
            } else {
                $oldIdentifier = $oldItem['identifier'];
                $newIdentifier = $this->canonicalizeAndCheckFileIdentifier(
                    str_replace($sourceFolderIdentifier, $targetFolderIdentifier, $oldItem['identifier'])
                );
            }
            if (!file_exists($this->getAbsolutePath($newIdentifier))) {
                throw new Exception\FileOperationErrorException(
                    sprintf('File "%1$s" was not found (should have been copied/moved from "%2$s").', $newIdentifier, $oldIdentifier),
                    1330119453
                );
            }
            $identifierMap[$oldIdentifier] = $newIdentifier;
        }
        return $identifierMap;
    }

    /**
     * Folder equivalent to moveFileWithinStorage().
     *
     * @param string $sourceFolderIdentifier
     * @param string $targetFolderIdentifier
     * @param string $newFolderName
     *
     * @return array A map of old to new file identifiers
     * @throws \RuntimeException
     */
    public function moveFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
    {
        $sourcePath = $this->getAbsolutePath($sourceFolderIdentifier);
        $relativeTargetPath = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier . '/' . $newFolderName);
        $targetPath = $this->getAbsolutePath($relativeTargetPath);
        // get all files and folders we are going to move, to have a map for updating later.
        $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath, true);
        $result = rename($sourcePath, $targetPath);
        if ($result === false) {
            throw new \RuntimeException('Moving folder ' . $sourcePath . ' to ' . $targetPath . ' failed.', 1320711817);
        }
        // Create a mapping from old to new identifiers
        $identifierMap = $this->createIdentifierMap($filesAndFolders, $sourceFolderIdentifier, $relativeTargetPath);
        return $identifierMap;
    }

    /**
     * Folder equivalent to copyFileWithinStorage().
     *
     * @param string $sourceFolderIdentifier
     * @param string $targetFolderIdentifier
     * @param string $newFolderName
     *
     * @return bool
     * @throws Exception\FileOperationErrorException
     */
    public function copyFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
    {
        // This target folder path already includes the topmost level, i.e. the folder this method knows as $folderToCopy.
        // We can thus rely on this folder being present and just create the subfolder we want to copy to.
        $newFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier . '/' . $newFolderName);
        $sourceFolderPath = $this->getAbsolutePath($sourceFolderIdentifier);
        $targetFolderPath = $this->getAbsolutePath($newFolderIdentifier);

        mkdir($targetFolderPath);
        /** @var $iterator \RecursiveDirectoryIterator */
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($sourceFolderPath),
            \RecursiveIteratorIterator::SELF_FIRST,
            \RecursiveIteratorIterator::CATCH_GET_CHILD
        );
        // Rewind the iterator as this is important for some systems e.g. Windows
        $iterator->rewind();
        while ($iterator->valid()) {
            /** @var $current \RecursiveDirectoryIterator */
            $current = $iterator->current();
            $fileName = $current->getFilename();
            $itemSubPath = GeneralUtility::fixWindowsFilePath($iterator->getSubPathname());
            if ($current->isDir() && !($fileName === '..' || $fileName === '.')) {
                GeneralUtility::mkdir($targetFolderPath . '/' . $itemSubPath);
            } elseif ($current->isFile()) {
                $result = copy($sourceFolderPath . '/' . $itemSubPath, $targetFolderPath . '/' . $itemSubPath);
                if ($result === false) {
                    // rollback
                    GeneralUtility::rmdir($targetFolderIdentifier, true);
                    throw new Exception\FileOperationErrorException(
                        'Copying file "' . $sourceFolderPath . $itemSubPath . '" to "' . $targetFolderPath . $itemSubPath . '" failed.',
                        1330119452
                    );
                }
            }
            $iterator->next();
        }
        GeneralUtility::fixPermissions($targetFolderPath, true);
        return true;
    }

    /**
     * Renames a file in this storage.
     *
     * @param string $fileIdentifier
     * @param string $newName The target path (including the file name!)
     * @return string The identifier of the file after renaming
     * @throws Exception\ExistingTargetFileNameException
     * @throws \RuntimeException
     */
    public function renameFile($fileIdentifier, $newName)
    {
        // Makes sure the Path given as parameter is valid
        $newName = $this->sanitizeFileName($newName);
        $newIdentifier = rtrim(GeneralUtility::fixWindowsFilePath(PathUtility::dirname($fileIdentifier)), '/') . '/' . $newName;
        $newIdentifier = $this->canonicalizeAndCheckFileIdentifier($newIdentifier);
        // The target should not exist already
        if ($this->fileExists($newIdentifier)) {
            throw new Exception\ExistingTargetFileNameException(
                'The target file "' . $newIdentifier . '" already exists.',
                1320291063
            );
        }
        $sourcePath = $this->getAbsolutePath($fileIdentifier);
        $targetPath = $this->getAbsolutePath($newIdentifier);
        $result = rename($sourcePath, $targetPath);
        if ($result === false) {
            throw new \RuntimeException('Renaming file ' . $sourcePath . ' to ' . $targetPath . ' failed.', 1320375115);
        }
        return $newIdentifier;
    }

    /**
     * Renames a folder in this storage.
     *
     * @param string $folderIdentifier
     * @param string $newName
     * @return array A map of old to new file identifiers of all affected files and folders
     * @throws \RuntimeException if renaming the folder failed
     */
    public function renameFolder($folderIdentifier, $newName)
    {
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
        $newName = $this->sanitizeFileName($newName);

        $newIdentifier = PathUtility::dirname($folderIdentifier) . '/' . $newName;
        $newIdentifier = $this->canonicalizeAndCheckFolderIdentifier($newIdentifier);

        $sourcePath = $this->getAbsolutePath($folderIdentifier);
        $targetPath = $this->getAbsolutePath($newIdentifier);
        // get all files and folders we are going to move, to have a map for updating later.
        $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath, true);
        $result = rename($sourcePath, $targetPath);
        if ($result === false) {
            throw new \RuntimeException(sprintf('Renaming folder "%1$s" to "%2$s" failed."', $sourcePath, $targetPath), 1320375116);
        }
        try {
            // Create a mapping from old to new identifiers
            $identifierMap = $this->createIdentifierMap($filesAndFolders, $folderIdentifier, $newIdentifier);
        } catch (\Exception $e) {
            rename($targetPath, $sourcePath);
            throw new \RuntimeException(
                sprintf(
                    'Creating filename mapping after renaming "%1$s" to "%2$s" failed. Reverted rename operation.\\n\\nOriginal error: %3$s"',
                    $sourcePath, $targetPath, $e->getMessage()
                ),
                1334160746
            );
        }
        return $identifierMap;
    }

    /**
     * Removes a file from the filesystem. This does not check if the file is
     * still used or if it is a bad idea to delete it for some other reason
     * this has to be taken care of in the upper layers (e.g. the Storage)!
     *
     * @param string $fileIdentifier
     * @return bool TRUE if deleting the file succeeded
     * @throws \RuntimeException
     */
    public function deleteFile($fileIdentifier)
    {
        $filePath = $this->getAbsolutePath($fileIdentifier);
        $recycleDirectory = $this->getRecycleDirectory($filePath);
        if (!empty($recycleDirectory)) {
            $result = $this->recycleFileOrFolder($filePath, $recycleDirectory);
        } else {
            $result = unlink($filePath);
        }
        if ($result === false) {
            throw new \RuntimeException('Deletion of file ' . $fileIdentifier . ' failed.', 1320855304);
        }
        return $result;
    }

    /**
     * Removes a folder from this storage.
     *
     * @param string $folderIdentifier
     * @param bool $deleteRecursively
     * @return bool
     * @throws Exception\FileOperationErrorException
     * @throws Exception\InvalidPathException
     */
    public function deleteFolder($folderIdentifier, $deleteRecursively = false)
    {
        $folderPath = $this->getAbsolutePath($folderIdentifier);
        $recycleDirectory = $this->getRecycleDirectory($folderPath);
        if (!empty($recycleDirectory) && $folderPath !== $recycleDirectory) {
            $result = $this->recycleFileOrFolder($folderPath, $recycleDirectory);
        } else {
            $result = GeneralUtility::rmdir($folderPath, $deleteRecursively);
        }
        if ($result === false) {
            throw new Exception\FileOperationErrorException(
                'Deleting folder "' . $folderIdentifier . '" failed.',
                1330119451
            );
        }
        return $result;
    }

    /**
     * Checks if a folder contains files and (if supported) other folders.
     *
     * @param string $folderIdentifier
     * @return bool TRUE if there are no files and folders within $folder
     */
    public function isFolderEmpty($folderIdentifier)
    {
        $path = $this->getAbsolutePath($folderIdentifier);
        $dirHandle = opendir($path);
        while ($entry = readdir($dirHandle)) {
            if ($entry !== '.' && $entry !== '..') {
                closedir($dirHandle);
                return false;
            }
        }
        closedir($dirHandle);
        return true;
    }

    /**
     * Returns (a local copy of) a file for processing it. This makes a copy
     * first when in writable mode, so if you change the file, you have to update it yourself afterwards.
     *
     * @param string $fileIdentifier
     * @param bool $writable Set this to FALSE if you only need the file for read operations.
     *                          This might speed up things, e.g. by using a cached local version.
     *                          Never modify the file if you have set this flag!
     * @return string The path to the file on the local disk
     */
    public function getFileForLocalProcessing($fileIdentifier, $writable = true)
    {
        if ($writable === false) {
            return $this->getAbsolutePath($fileIdentifier);
        } else {
            return $this->copyFileToTemporaryPath($fileIdentifier);
        }
    }

    /**
     * Returns the permissions of a file/folder as an array (keys r, w) of boolean flags
     *
     * @param string $identifier
     * @return array
     * @throws Exception\ResourcePermissionsUnavailableException
     */
    public function getPermissions($identifier)
    {
        $path = $this->getAbsolutePath($identifier);
        $permissionBits = fileperms($path);
        if ($permissionBits === false) {
            throw new Exception\ResourcePermissionsUnavailableException('Error while fetching permissions for ' . $path, 1319455097);
        }
        return [
            'r' => (bool)is_readable($path),
            'w' => (bool)is_writable($path)
        ];
    }

    /**
     * Checks if a given identifier is within a container, e.g. if
     * a file or folder is within another folder. It will also return
     * TRUE if both canonicalized identifiers are equal.
     *
     * @param string $folderIdentifier
     * @param string $identifier identifier to be checked against $folderIdentifier
     * @return bool TRUE if $content is within or matches $folderIdentifier
     */
    public function isWithin($folderIdentifier, $identifier)
    {
        $folderIdentifier = $this->canonicalizeAndCheckFileIdentifier($folderIdentifier);
        $entryIdentifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
        if ($folderIdentifier === $entryIdentifier) {
            return true;
        }
        // File identifier canonicalization will not modify a single slash so
        // we must not append another slash in that case.
        if ($folderIdentifier !== '/') {
            $folderIdentifier .= '/';
        }
        return GeneralUtility::isFirstPartOfStr($entryIdentifier, $folderIdentifier);
    }

    /**
     * Creates a new (empty) file and returns the identifier.
     *
     * @param string $fileName
     * @param string $parentFolderIdentifier
     * @return string
     * @throws Exception\InvalidFileNameException
     * @throws \RuntimeException
     */
    public function createFile($fileName, $parentFolderIdentifier)
    {
        if (!$this->isValidFilename($fileName)) {
            throw new Exception\InvalidFileNameException(
                'Invalid characters in fileName "' . $fileName . '"',
                1320572272
            );
        }
        $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
        $fileIdentifier =  $this->canonicalizeAndCheckFileIdentifier(
            $parentFolderIdentifier . $this->sanitizeFileName(ltrim($fileName, '/'))
        );
        $absoluteFilePath = $this->getAbsolutePath($fileIdentifier);
        $result = touch($absoluteFilePath);
        GeneralUtility::fixPermissions($absoluteFilePath);
        clearstatcache();
        if ($result !== true) {
            throw new \RuntimeException('Creating file ' . $fileIdentifier . ' failed.', 1320569854);
        }
        return $fileIdentifier;
    }

    /**
     * Returns the contents of a file. Beware that this requires to load the
     * complete file into memory and also may require fetching the file from an
     * external location. So this might be an expensive operation (both in terms of
     * processing resources and money) for large files.
     *
     * @param string $fileIdentifier
     * @return string The file contents
     */
    public function getFileContents($fileIdentifier)
    {
        $filePath = $this->getAbsolutePath($fileIdentifier);
        return file_get_contents($filePath);
    }

    /**
     * Sets the contents of a file to the specified value.
     *
     * @param string $fileIdentifier
     * @param string $contents
     * @return int The number of bytes written to the file
     * @throws \RuntimeException if the operation failed
     */
    public function setFileContents($fileIdentifier, $contents)
    {
        $filePath = $this->getAbsolutePath($fileIdentifier);
        $result = file_put_contents($filePath, $contents);

        // Make sure later calls to filesize() etc. return correct values.
        clearstatcache(true, $filePath);

        if ($result === false) {
            throw new \RuntimeException('Setting contents of file "' . $fileIdentifier . '" failed.', 1325419305);
        }
        return $result;
    }

    /**
     * Gets the charset conversion object.
     *
     * @return \TYPO3\CMS\Core\Charset\CharsetConverter
     */
    protected function getCharsetConversion()
    {
        if (!isset($this->charsetConversion)) {
            if (TYPO3_MODE === 'FE') {
                $this->charsetConversion = $GLOBALS['TSFE']->csConvObj;
            } elseif (is_object($GLOBALS['LANG'])) {
                // BE assumed:
                $this->charsetConversion = $GLOBALS['LANG']->csConvObj;
            } else {
                // The object may not exist yet, so we need to create it now. Happens in the Install Tool for example.
                $this->charsetConversion = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Charset\CharsetConverter::class);
            }
        }
        return $this->charsetConversion;
    }

    /**
     * Returns the role of an item (currently only folders; can later be extended for files as well)
     *
     * @param string $folderIdentifier
     * @return string
     */
    public function getRole($folderIdentifier)
    {
        $name = PathUtility::basename($folderIdentifier);
        $role = $this->mappingFolderNameToRole[$name];
        if (empty($role)) {
            $role = FolderInterface::ROLE_DEFAULT;
        }
        return $role;
    }

    /**
     * Directly output the contents of the file to the output
     * buffer. Should not take care of header files or flushing
     * buffer before. Will be taken care of by the Storage.
     *
     * @param string $identifier
     * @return void
     */
    public function dumpFileContents($identifier)
    {
        readfile($this->getAbsolutePath($this->canonicalizeAndCheckFileIdentifier($identifier)), 0);
    }

    /**
     * Get the path of the nearest recycler folder of a given $path.
     * Return an empty string if there is no recycler folder available.
     *
     * @param string $path
     * @return string
     */
    protected function getRecycleDirectory($path)
    {
        $recyclerSubdirectory = array_search(FolderInterface::ROLE_RECYCLER, $this->mappingFolderNameToRole, true);
        if ($recyclerSubdirectory === false) {
            return '';
        }
        $rootDirectory = rtrim($this->getAbsolutePath($this->getRootLevelFolder()), '/');
        $searchDirectory = PathUtility::dirname($path);
        // Check if file or folder to be deleted is inside a recycler directory
        if ($this->getRole($searchDirectory) === FolderInterface::ROLE_RECYCLER) {
            $searchDirectory = PathUtility::dirname($searchDirectory);
            // Check if file or folder to be deleted is inside the root recycler
            if ($searchDirectory == $rootDirectory) {
                return '';
            }
            $searchDirectory = PathUtility::dirname($searchDirectory);
        }
        // Search for the closest recycler directory
        while ($searchDirectory) {
            $recycleDirectory = $searchDirectory . '/' . $recyclerSubdirectory;
            if (is_dir($recycleDirectory)) {
                return $recycleDirectory;
            } elseif ($searchDirectory === $rootDirectory) {
                return '';
            } else {
                $searchDirectory = PathUtility::dirname($searchDirectory);
            }
        }

        return '';
    }
}

redpajama_set_name: RedPajamaGithub


Vote for me by rating me with more stars. Click on the five yellow stars under ma name until they flash! Share this profile on Facebook and other social media. What do you think about my music? Leave a comment below. Thanks!
I give you much respect on your videos and lyrics of your songs. I enjoy listening to music, keep it up ??, you're doing a great job.


Bring a lawn chair and picnic for the 19th Annual Englewood Jazz Festival! The Englewood Jazz Festival is presented in partnership with Live The Spirit Residency. The Festival is supported by The MacArthur Fund for the Arts and Culture, The Richard H. Driehaus Foundation, the Cohn Family foundation, the Oppenheimer Family Foundation, The Chicago Park District, 6th Ward Alderman Roderick T. Sawyer, the Old Town School of Folk Music, Dawk Publishing, WDCB, Delmark Records, and Chicago Creative Arts Online.


A global crisis such as Ebola requires fast, targeted action, and, as USAID's Administrator Rajiv Shah said last week, "the success of the Ebola response is access to real-time data". GeoPoll's own CEO, James Eberhard, recently penned an Op-Ed which similarly argues that better data is crucial to tracking and stopping the spread of Ebola.
At GeoPoll, we're working with partners worldwide to monitor the spread of the disease and understand the long-term effects of Ebola. Our ongoing work with the World Food Programme has already provided valuable data on food security in Sierra Leone, and the WFP has also just released findings from our surveys in Liberia, and Guinea. All 3 countries are currently affected by food insecurity, and the regions where Ebola is most prevalent have even more fragile food security than surrounding areas.
Last week we asked GeoPoll users in Sierra Leone and Liberia about the most pressing needs in their communities, and their perceptions of the international response to the Ebola crisis. We collected mobile survey responses from over 1,000 individuals in each country (n=1,001 in Sierra Leone and n=4,025 in Liberia) from November 5th-12th. Interestingly, responses were very similar across the two countries. Respondents from both countries are satisfied with the international community's response, with 45% in Sierra Leone and 54% in Liberia reporting they are "very satisfied" with the response. In Montserrado county, which includes Monrovia, one of Liberia's Ebola epicenters, 55% of respondents were "very satisfied", and 78% of respondents were either "somewhat" or "very" satisfied with the international community's response (n=1,261). In total, only 17% in Sierra Leone and 13% in Liberia reported they were either "somewhat" or "very" unsatisfied with the response.
We also asked respondents "What help is most needed in your community?" with food, healthcare facilities, healthcare workers, money, security, shelter, and water/sanitation as answer options. In Liberia, healthcare facilities was by far the most common answer, with 30% of respondents choosing it. 15% of Liberians said water and sanitation help was needed most, 15% said money, and 13% said healthcare workers.
In Montserrado county responses were similar: 29% healthcare facilities, 16% water/sanitation, 12% healthcare workers, 12% money, and 14% food. As we have seen with food security, the effects of Ebola are wide-ranging, which could be why responses are quite spread out, and water/sanitation and food help are requested just as much as healthcare workers.
In Sierra Leone, respondents had similar needs, although more respondents listed water/sanitation as their biggest concern. 27% of respondents listed water/sanitation as their greatest need, and 26% stated healthcare facilities are needed most in their community. In both Sierra Leone and Liberia, the perceived need of healthcare workers was quite low: 8% and 13% respectively.
This survey only included these two simple questions, but over the next months GeoPoll will work with partners to collect valuable information on knowledge of Ebola spread, symptoms, and more. As a note, GeoPoll always takes very seriously the privacy of respondents, and we have put extra precautions in place when asking about sensitive health issues such as Ebola. All responses are completely anonymous, and when asking questions about the disease we are including a message informing the participants that we are asking about Ebola, and that their responses are confidential. We are also including the phone number for the national Ebola hotline for users to call with health concerns, displayed at both the beginning and end of surveys.
For more data from GeoPoll's surveys, sign up for our blog alerts at the top of this page, and click below to contact us about running your own survey with GeoPoll.


Senior Salon Services is looking for Part-Time Hair Stylists to join our senior living community beauty salon in Lancaster, PA. Must have experience and a current PA Cosmetology License. - Provide full salon services, including hair cutting, shampooing, blow drying, roller sets, perms, coloring and styling. - Flexible, part time hours. 1 day per week. No nights or weekends! - Earn commission based on services. - Room for advancement. - Supplies provided except scissors and electrical equipment. If you are self-motivated, energetic, positive, and have a current PA Cosmetology License, call Nicole at (484) 792-1777.


THE PRESIDENT: Bienvenidos. It is such an honor to have you all here to the Casa Blanca, la casa de todos que viven en esta pais. As the Surgeon General mentioned, I'm just a temporary resident -- (laughter) -- but es un gran honor para mi familia de vivir aqui.
I want to thank you all for coming. Hispanic Heritage Month is an important month for our country -- particularly now that we're at a time of war. You see, Hispanic Heritage Month talks to the great diversity of our country and the fact that our country is a strong country because of our diversity.
And this particular month we welcome the influence of the Hispano in our country. We welcome the great values that our Hispanic Americans bring to America, the values of faith y familia. Part of our entrepreneurial spirit is made stronger by the Hispanics who live in America. We're really proud of this heritage; we appreciate the hard work, we appreciate the determination.
I love the stories of our Surgeon General, the success stories of families who have sought a better day and have worked hard and Americans have been able to reap the benefit of the greatest country in the face of the earth. So welcome to the White House. It's an honor for me to welcome you here.
I want to thank Senator Orrin Hatch for coming. He's a great friend of -- (applause) -- he's a good buddy. I'm glad he's here. I'm glad he's in the Senate. (Laughter.) One of my jobs is to put together an administration that is talented; an administration here to serve the country, not themselves; an administration that reflects the diversity of our country. And I'm doing just that. Obviously, you met our new Surgeon General, Rich Carmona. Rich is a -- he's a piece of work. (Laughter.) He'll do a fabulous job in that incredibly important position.
Gaddi Vasquez, who is director of the Peace Corps, is here. Gaddi, thank you for coming. Hans Hertell is an Embajador de -- to the Dominican Republic, is with us today. Hans is from Puerto Rico, a good friend of mine.
Mira, y tambien un otro amigo de mio. He is the gobernador, the governor of Tamulipas, Tomas Yarrington. I appreciate you coming, Gobernador. (Applause.) I don't know if this helps or hurts him, but he is a rising star in Mexican politics. (Laughter.) I've known him, obviously when I was the governor of Texas and now as the President. He's a good fellow and I'm proud to call him friend.
Jose Forquet, who is the United States executive director of the Inter-American Development Bank, Jose thank you for coming. Where are you, Jose? Oh, there he is. (Applause.) These are people I've appointed. These are part of the diversity of our administration. I'm glad they're here so I can herald their -- their accomplishment and their service to the country.
Our military is -- the Hispanic population in our country has served disproportionately in our military. The Hispanic population steps up when the country says, we need service. And they do. They have throughout our history. Today we've got with us Major General Chris Cortez of the United States Marine Corps. (Applause.) I've got great confidence in our military. I've got confidence in our troops. I'll talk a little bit about that in a second, but, General, thanks for coming.
I want to thank Nomar Garciaparra from the Red Sox for coming. Nomar, thanks for being here. (Applause.) Nomar, when we had the first T-ball game at the White House, was there. And one of the things we're trying to do is use our backyard to promote baseball. And we had these kids come, and Nomar was here to help kick that off. I'm so honored you came.
These are the current players. These guys are stars, and potential Hall of Famers. But we're also really fortunate to have some Hall of Famers with us, people who've actually done what these players are doing.
It is such an honor to have four Hall of Famers, starting with Rod Carew -- man, that guy could hit. (Applause.) I appreciate you coming, Rod. (Applause.) Tony Perez. (Applause.) Luis Aparicio. (Applause.) Yes. Y por fin, Juan Marichal. (Applause.) I'm really glad you all are here. You brighten my day. (Laughter.) Thanks for coming.
One of my jobs as well is to make sure our bench is strong. I've named a fantastic Hispanic American to the bench, a young guy named Miguel Estrada. I named him to one of the highest courts possible, to the D.C. Circuit Court of Appeals. It's an incredibly important appointment. He's well qualified. He is very smart. He came to our country from El Salvador, he couldn't speak English. He's now been picked, amongst all the candidates, to take on this highest of high positions in the bench. He's having trouble in the United States Senate.
I talked about our military. The reason we're talking about our military these days is because we're at war, and we're at war for precisely the reason why we're here. We're at war because we love freedom. We love the fact that people are free in America, free to worship an Almighty any way you see fit, free to come to this country with a dream and realize the dream, free to express your opinion, free to -- if you happen to be in the press, to write anything you want to write. That's freedom, and that's what we love.
And it's hard to believe, but there's an enemy which hates freedom, and hates us as a result of our embrace of freedom. And so therefore, we're at war, we're at war, and we're still at war. We're still at risk here in America. We're at risk because there's some enemies still lurking around out there.
This is a different kind of war, as the General would tell you. In the old days, you could destroy the person's tanks, or airplanes, or ships, and be making progress. But these people don't have tanks. They don't have ships. They hide in caves and send youngsters to their suicidal death.
We will win, because of what we love. We will win because we're determined and strong. We will win because we're a nation which holds values dear to our heart. And we refuse to be intimidated by anybody, at any place, at any time. We will win because we want to uphold our duty and obligation to leave America intact and free, so future generations of people, Hispanic or otherwise, can realize dreams, can succeed, can realize their God-given talents. That's what this is all about.
And so I want to thank you for coming to honor this month, but I want to assure you that this great nation will lead the world to be more free.
And we've got some difficult tasks at hand. Not only we must chase down the al Qaeda one by one, which we continue to do to this very day, but we've also got to deal with threats that are real. And I gave a speech to the nation the other day to discuss those threats in sober terms, to talk about the realities of the world in which we live.
It used to be in this great country we had two oceans protecting us, and if somebody had a problem across the sea, we might help them or we might not. Today, these oceans -- the fact that the oceans no longer protect us mean that the battleground is here. So this great country will be deliberate, we will rally other nations, we will give other people a chance to deal with Iraq, for example.
The U.N., the United Nations now has a chance, Mr. Ambassador. As a member of the Security Council, I'm confident your nation will join us to -- to send a clear message that this man must disarm before he hurts America or anybody else. And he has to make a choice. We're a patient nation. He's got a choice to make. His choice is, he must do what he said he was going to do. He said he wasn't going to have weapons of mass destruction, that's what we expect. We take a man for his word.
But if he doesn't disarm and if the United Nations won't act, for the sake of our freedom we will lead other countries that love freedom as much as we do and disarm him. We owe it to our children. We love peace in this country and when we see threats to peace, we will deal with them in a deliberate, calm, logical and, if need be, forceful way.
And as we work to make America a more secure place and a safer place, we've got to make it a better place, too. And that means making sure everybody gets a good education in our country, everybody.
See, when you have low standards, you're liable to get bad results. That's what I have called the soft bigotry of low expectations. We have challenged that soft bigotry. We say in this country every child can learn -- every child -- not just some, not a select few, not those who may live in the nice suburban districts -- but every child can learn.
And then it says that in return for receiving federal money, we want to know. You see, in return for receiving federal money, we expect local districts and states to show us whether or not each child is learning.
I believe this nation is strong in its diversity. We love our freedom. It's an incredibly great nation. And out of the evil done to our country on September the 11th, 2001, will come incredible good. That's what you must know about our nation. Out of the evil done to America can come some great good.
If we stay tough and firm and strong, we can achieve peace. We can achieve peace for people here at home, we can achieve peace in the world. And by being -- by loving your neighbor just like you'd like to be loved yourself, we can achieve a better tomorrow. We can work together to eradicate the pockets of hopelessness, loneliness and despair. People can fight evil by doing some good, by putting your arm around a lost soul and saying, I love you. My fellow American, I love you.
There is no question in my mind, because of our strength, diversity, because of the values we hold, that we will be a stronger and more compassionate and better nation.


text:
Shop Zartonk
DonorBox
ZARTONKMEDIA
EconomyMilitaryPoliticsSocietySports
PM Pashinyan & Netherlands Ambassador Discuss Development Of Bilateral Relations & Opening Of New Embassy In Yerevan.
The Editor - January 19, 2021 0
Today, Prime Minister Nikol Pashinyan met with Nicholas Schermers, the first resident Ambassador of the Netherlands to Armenia In...
High Tech Development Is One Of The Main Priorities Of Armenia's Gov't, Says Minister Hakob Arshakyan.
Minister of High technological industry Hakob Arshakyan has presented the list of Armenian companies who have been declared winners...
Ex-President Robert Kocharyan's Trial Resumes In Yerevan.
The trial of former President Robert Kocharyan and three other former senior Armenian officials facing coup charges resumed on...
AmericasEuropeMiddle East
Armenia's Human Right Defender Arman Tatoyan Thanks Two Armenian Attorneys From The Diaspora For Legal Support.
Today, Armenia's Human Right Defender Arman Tatoyan took to Facebook to thanked two prominent U.S. based Armenian attorneys Garo...
United States & Turkey Sign "Disastrous" Cultural Property Agreement In The Final Hours Of The Trump Administration.
In its final hours, the Trump Administration signed a disastrous bilateral U.S.-Turkey Memorandum of Understanding granting Turkey legal rights...
City Of Paphos In Cyprus Renames Talaat Pasha Street to Justice Street At Request Of Local Armenian & Greek Communities.
On January 18, the Municipal Council of Paphos in Cyprus renamed the Talaat Pasha Street into Tikeosinis (Justice) Street...
AzerbaijanGeorgiaIranRussiaTurkey
Armenian Orphanage In Istanbul Where Journalist Hrant Dink Grew Up Will Be Turned Into An Armenian Youth Center.
The Armenian Orphanage in Istanbul's Tuzla city where the slain Armenian-Turkish journalist Hrant Dink grew up will be turned...
FM Lavrov: Russia Seeks To Ensure Exchange Of POWs According To "All-For-All" Principle.
Russia seeks to ensure exchange of POWs between Armenia and Azerbaijan according to "all-for-all" principle, Russian Foreign Minister Sergey...
Home Homeland
Armenia Sees "Positive Trend" In Coronavirus Situation As Schools Are Set To Reopen On September 15.
by The Editor
The number of active coronavirus cases in Armenia continued to decrease over the weekend as the fatality rate remained relatively high, according to official statistics, per Azatutyun.
The figures reported by the Ministry of Health show that for the first time since early June the number of active coronavirus cases in Armenia has dropped below 7,000. Eleven more patients died from COVID-19 over the weekend, bringing the total number of deaths to 796.
Classes will resume at all public schools, public schools, vocational institutions, music and art schools on September 15, Minister of Education, Science, Culture and sports Arayik Harutyunyan informs, per Public Radio of Armenia.
He said strict sanitary and hygiene rules will be in place. Decision on higher educational establishments will be made in the coming week. The commandant's Office and the Ministry have developed detailed guidelines, which will be made public in the coming days.
According to the ministry, since the start of the epidemic in March 228 other patients infected with the virus died from other pre-existing diseases.
The daily number of officially registered fatalities averaged approximately 15 from July 6 through July 24 after which a downward trend began.
As of August 10, the total number of coronavirus cases identified in Armenia has reached 40,433. In the past weeks and days the number of daily reported cases decreased more than twice as compared to what appears to be the peak of the epidemic in early July when over 700 cases were identified on a daily basis.
Ministry spokesperson Alina Nikoghosian sees a continuing positive trend in the rate of infections. "The numbers themselves show a significant decrease. But, like we did it before, we keep repeating that vigilance must not be weakened, because if we relax, the numbers will start growing again," she said.
The Armenian government ascribes the recent improvement in the coronavirus situation to the wearing of face masks in all public places that was made mandatory in Armenia in early June and other enforced and popularized measures like social distancing and regular washing of hands.
Prime Minister Nikol Pashinian and other officials have urged Armenians to continue to follow the basic anti-epidemic rules, insisting that they can help cope with the epidemic.
Despite the improving trend the Pashinian government intends to extend the coronavirus-related state of emergency that ends on August 12 for another month.
Deputy Prime Minister Tigran Avinian said last week that the government will at the same time fully or partly lift its ban on public gatherings and make it easier for foreign nationals to enter the country. He also reaffirmed plans to reopen all schools and universities in time for the start of the new academic year in September.
Health Minister Arsen Torosian, meanwhile, said at a government session on August 6 that his ministry planned more targeted and "pro-active" testing among people working in government agencies, supermarkets, factories, banks or other businesses as well as patients of various medical and elderly care institutions.
Critics have for months urged authorities to significantly expand COVID-19 testing, saying that it is vital for tackling the epidemic.
H/T Azatutyun & Public Radio of Armenia
Previous articleBREAKING NEWS: Lebanese Government Resigns Amid Outrage Over Beirut Blast.
Next articleAmulsar Gold Mine Will Cause Huge Damage To Lake Sevan, Warns An Armenian Environmentalist.
The Editorhttp://zartonkmedia778541986.wordpress.com
Today, Prime Minister Nikol Pashinyan met with Nicholas Schermers, the first resident Ambassador of the Netherlands to Armenia In Yerevan.
Minister of High technological industry Hakob Arshakyan has presented the list of Armenian companies who have been declared winners in 2020 on...
The trial of former President Robert Kocharyan and three other former senior Armenian officials facing coup charges resumed on Tuesday nearly four...
Today, Armenia's Human Right Defender Arman Tatoyan took to Facebook to thanked two prominent U.S. based Armenian attorneys Garo Ghazarian and Karnig...
In its final hours, the Trump Administration signed a disastrous bilateral U.S.-Turkey Memorandum of Understanding granting Turkey legal rights over the vast...
On January 18, the Municipal Council of Paphos in Cyprus renamed the Talaat Pasha Street into Tikeosinis (Justice) Street after examining requests...
Armenia's Ambassador to the U.S. To Attend Joe Biden's Inauguration On January 20.
Armenia's Ambassador to the United States Varuzhan Nersesyan will attend the inauguration of Joe Biden as the 46th President of the United States...
Australian Broadcaster (ABC) Republishes Serj Tankian Article After Public Outcry, Edited To Appease Foreign Pressure.
A public outcry led by the Armenian National Committee of Australia (ANC-AU) has forced the ABC (Australian Broadcasting Corporation) to republish an...
To be updated with all the latest news and special announcements.

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: Plsql case is not reading properly from case I need to read data row by row and update it based on the matching case.
My code is just reading ORBREFTND and inserting  Refund from case , not reading other cases. What am i doing wrong.
DECLARE
    v_tot_rows   NUMBER (3);

    v_eval       ISG.SWR_CERT_TXN_MSG_TYPE.DESC_TX%TYPE;

    CURSOR pltfm_msg_type_cur
    IS
        SELECT sctmt.PLTFM_MSG_TYPE_CD
          FROM ISG.SWR_CERT_TXN_MSG_TYPE  sctmt
               JOIN ISG.FEATURE_VALUES ft_val
                   ON sctmt.SWR_CERT_FETR_VAL_ID = ft_val.FEATURE_VAL
               JOIN ISG.FEATURE_CATEGORY ft_cat
                   ON ft_val.FEATURE_CAT = ft_cat.FEATURE_CAT
         WHERE     ft_cat.SHORT_DESCRIP = 'PLT'
               AND ft_val.FEATURE_VALUE = 'Orbital';
BEGIN
    FOR msg_code IN pltfm_msg_type_cur
    LOOP
        CASE msg_code.PLTFM_MSG_TYPE_CD
            WHEN 'WAC'
            THEN
                v_eval := 'Authorization and Mark for Capture';
            WHEN 'ORBAUTHCAP'
            THEN
                v_eval := 'Authorization Capture';
            WHEN 'ORBREFTND'
            THEN
                v_eval := 'Refund';
        END CASE;

        UPDATE ISG.SWR_CERT_TXN_MSG_TYPE sctmt
           SET sctmt.DESC_TX = v_eval;
    END LOOP;

    COMMIT;

    v_tot_rows := SQL%ROWCOUNT;
    /* Implicit Attribute %ROWCOUNT is used   to find the number of rows affected     by the update command */
    DBMS_OUTPUT.PUT_LINE ('Total records updated : ' || v_tot_rows);
END;

A: You're missing a where-condition:
    UPDATE ISG.SWR_CERT_TXN_MSG_TYPE sctmt
       SET sctmt.DESC_TX = v_eval
     WHERE sctmt.primarykey = msg_code.primarykey; -- This one is missing. Don't know your primary key..

Without the where you'll always set the value of the last cursor-object to all objects in your table ISG.SWR_CERT_TXN_MSG_TYPE.
You also need to select the key from your table:
    CURSOR pltfm_msg_type_cur
    IS
        SELECT sctmt.PLTFM_MSG_TYPE_CD,
               sctmt.PRIMARYKEY -- select key here
          FROM ISG.SWR_CERT_TXN_MSG_TYPE  sctmt
               JOIN ISG.FEATURE_VALUES ft_val
                   ON sctmt.SWR_CERT_FETR_VAL_ID = ft_val.FEATURE_VAL
               JOIN ISG.FEATURE_CATEGORY ft_cat
                   ON ft_val.FEATURE_CAT = ft_cat.FEATURE_CAT
         WHERE     ft_cat.SHORT_DESCRIP = 'PLT'
               AND ft_val.FEATURE_VALUE = 'Orbital';

redpajama_set_name: RedPajamaStackExchange


text:
Now Offering Self-Guided & In-Person Tours! Contact Our Leasing Office Today!!
Bell Pasadena
Explore Pasadena
Surround yourself with opportunity at Bell Pasadena. With convenient access to shopping, dining and entertainment options in Pasadena, there's always something great to do nearby.
Historic, cosmopolitan and distinct, Pasadena is a vibrant city nestled at the base of the San Gabriel Mountains, 10 miles northeast of Los Angeles. The "Crown of the Valley" is known for decades-long traditions, yet remains one of Los Angeles's most forward thinking cities. History buffs, culture vultures, design aficionados and leisure travelers alike find plenty to do, whether exploring the famous grand mansions and museums, world-class shopping and dining or attending iconic year round events and festivals.
Pasadena has a Mediterranean climate, with typically hotter summers and slightly cooler winters than nearby coastal areas. No matter what you want to do, chances are you'll find it in beautiful Pasadena.
Explore our apartment features and community amenities or take a look at more photos of our community in the gallery.
3330 East Foothill Boulevard
Pasadena, CA, 91107
Bell Partners, Inc. CA DRE # 02014166


Lord Peter Wimsey: Mystery and Suspense on Television.
The Lord Peter Wimsey mysteries, produced in the UK, were based on the books by Dorothy L. Sayers.
Between 1972 and 1975, 5 mini-series were aired starring Ian Carmichael as the title character and Glyn Houston as Bunter, his manservant and partner in crime.
In 1987, three additional books were filmed as miniseries, this time starring Edward Petherbridge as Wimsey and Richard Morant as Bunter.


text:
Rose-Marie Pierre est une joueuse de kayak-polo internationale française née le .

Inscrite au club de Saint Maur de 2002 à 2004, elle participe en 2008 au championnat de France N1F dans l'équipe de Tarbes Auch Midi-Pyrénées.

Sélections

 Sélections en équipe de France espoir
 Championnats d'Europe 2001 : Médaille d'or

 Sélections en équipe de France senior
 Championnats du monde 2002 : Médaille d'argent
 Championnats d'Europe 2003 : Médaille d'argent
 Championnats du monde 2004 : Médaille de bronze

Références

Voir aussi

 Équipe de France de kayak-polo féminin

Liens externes

Joueuse française de kayak-polo
Naissance en octobre 1980

redpajama_set_name: RedPajamaWikipedia


text:
We The Youth Vote holds fundraising concert for the Samahan ng Nagkakaisang Pantawid ng Pamilya
On November 27, 2020 By pelikulamaniaIn Advocacy, Concert
Let 'Bayanihan' reign on Bonifacio Day with Tayô Táyo: A We The Youth Vote Online Fundraising Concert
Admit it or not, 2020 has been a hard year for everyone in the world. In the Philippines, it started with the eruption of Taal Volcano in January, followed by the still on-going COVID-19 outbreak which has been resulting to not just a health crisis but an economic damage, and just recently, a series of typhoons that hit several areas in the country.
It is not an easy task but who else will help and inspire each of the most affected ones to rise up and move forward? Us, Filipinos through our very own custom 'bayanihan.' This is what We The Youth Vote (WTYV) wants us to be reminded of as the non-partisan group holds an online fundraising concert for the benefit of the Samahan ng Nagkakaisang Pantawid ng Pamilya (SNPP), an organizational community that champions the continued implementation of expansion of the government's Pantawid Pamilyang Pilipino Program.
Dubbed as 'Tayô Táyo: A WTYV Online Fundraising Concert,' the digital event is happening on November 30, 2020, in light of the commemoration of the birth of Filipino hero Andres Bonifacio. The phrase "Tayô Táyo" stands for "let's rise up."
Streaming live on WTYV's official Facebook page and Kumu channel, the two-hour concert–from 8:00 p.m. to 10:00 p.m. PST–is headlined by today's most sought after acts such as Kean Cipriano, Unique, theater gems Phi Palmos and Gab Pangilinan, bird., Rice Lucido, Glaiza de Castro, Adrian Lindayag, Chai Fonacier, Earl Generao and Pappel, Biahana and a whole lot more.
We The Youth Vote
We The Youth Vote was officially launched in September, shorty after the voter's registration period began.
"Since its launch, we have attracted the attention and participation of youth leaders nationwide, school organizations, and local celebrities and content creators, helping the movement gain traction, especially on social media," says the group. "Some of those who have openly expressed support in our advocacy are Macoy Dubs, Ria Atayde, Direk Tonette Jadaone, Kean Cipriano; vloggers Laureen Uy, Kerwin King, and Benny Cua; theater artists Gabby Pangilinan and Phil Palmos, among others."
Using the introductory hashtags #MasMaramiTayo and #40MStrong, the group taps the young Filipinos or the so-called GenZs and Millennials (18-39 years old) as they comprise the biggest voting population by next election season, according to the Philippine Statistics Authority (PSA).
Follow We The Youth Vote on social media: facebook.com/WeTheYouthVote, twitter.com/WeTheYouthVote, Instagram.com/wetheyouthvote and @wetheyouthvote on Kumu.
AdvocacyConcertPhilippinesTayo TayoWe The Youth Vote
GoDaddy and AXN's Project GO Unveils the Top 4 Contestants Competing for Php 1 Million Grand Prize
World Vision continues to bring joy this Christmas to the most vulnerable children and their families


On 3 December, International Day of People with Disabilities, we launched The Lord Holmes Review: opening up public appointments to disabled people in the Churchill Room in 100 Parliament street.
Given that disability was at the heart of this project, the Review team was conscious from the very beginning that it was paramount that all public-facing aspects of the Review were as accessible and disability-friendly as possible.
Below I share some lessons I have taken away from the Review, in part from the Review's 16 recommendations and in part from the process of making the Review happen. Whilst these reflections are about disability, the workplace and engaging with the public in the context of public appointments, I believe they can be applied across the Cabinet Office's remit.
First a bit of background. The Review was semi-independent but resourced by members of the Public Appointments Policy Team, based within Private Office Group.
There are almost 6000 public appointees across 550 public bodies, which account for £200bn of annual expenditure across all areas of public services. Public appointees provide leadership, specialist expertise, strategic direction, and hold public bodies to account. Read more information about public appointments.
The Review was commissioned by Minister for Implementation Oliver Dowden MP CBE to fulfil a commitment made in the Public Appointments Diversity Action Plan. It is a government priority to ensure that public appointees reflect the society they serve, and yet disabled people are badly underrepresented. We only know the disability status of 65% of our public appointees, of whom just 5% are disabled (as compared to the working aged population of the UK, where 18.3% are disabled).
This is a quote from an attendee at a public workshop, relating to an experience they had when the adjustments they had been offered at an interview fell short of their expectations.
Be proactive: if adjustments have been requested, contact the interviewee in advance to plan ahead.
Be guided by the individual: do not make assumptions about what adjustments they need.
Consider that access is more than physical: is the room or alternative facility appropriate and giving the candidate the same opportunity as everyone else?
How does one deliver this in practice? The Review team found that accessibility cannot be an afterthought or nice-to-have part of the process. As we worked towards every public-facing element of the review, we learned accessibility needs to be embedded and plotted into your project plan, with time and resource allocated to it.
Engaging early with the DaTT team to work out which of the survey platforms that had passed the GDS' accessibility tests would best suit the project.
Tendering for external suppliers to provide British Sign Language and EasyRead* versions, which took 2 weeks from start to finished publishable products.
Testing the final online call for evidence with a specialist Disability Access testing lab, which took a week.
Securing support and resource in advance from comms and digital to subtitle and edit the supporting short videos of Lord Holmes.
The Cabinet Office is a Disability Confident Leader. This is a DWP administered scheme that measures and acknowledges employers who go the extra mile to ensure disabled people get a fair chance in their organisation. Our "Leader" status means we go still further than this that Cabinet Office is a champion of Disability Confident, and its ethos is embedded in everything we do.
Becoming disability confident online training, this is a great place to start for civil servants of any grade who want to learn more. And that's not just me saying that, Cabinet Office ExCo want to encourage as many people as possible to take the course.
The autism and neurodiversity toolkit for managers provides practical guidance on supporting people who have neurodiverse conditions into employment.
*The EasyRead version of the Lord Holmes Review (PDF) was created to help people with learning disabilities understand information easily. It is often also preferred by some readers without learning disabilities, as it gives essential information on a topic without a lot of background information.


text:
Visas & Border Control
Bushtracks Africa
The Lookout Cafe, Victoria Falls, suffers unfortunate fire incident
We are very sad to report that the Lookout Cafe, a popular spot in Victoria Falls, Zimbabwe, has experienced severe fire damage during the festive season.
The Lookout Cafe was an extremely popular destination for both locals and tourists, as it offered spectacular views of the Zambezi River and the gorge below.
The cafe will be closed until further notice.
Our deepest sympathies to all those affected by this tragic event. We hope to see this beautiful establishment restored to it's former glory in the future.
Devil's Pool at Livingstone Island closed for the season - but Angel's Pool still welcomes guests!
Airlines that are currently flying into our region
Bushtracks Africa launches a Virtual Tour of the Falls