mirror of
https://github.com/php/php-src.git
synced 2025-08-18 15:08:55 +02:00
- Update docu
This commit is contained in:
parent
208a97a221
commit
b67ca452c3
9 changed files with 237 additions and 11 deletions
|
@ -1,8 +1,23 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file cachingiterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class CachingIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
define('CIT_CALL_TOSTRING', 1);
|
define('CIT_CALL_TOSTRING', 1);
|
||||||
define('CIT_CATCH_GET_CHILD', 2);
|
define('CIT_CATCH_GET_CHILD', 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cached Iteration over another Iterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.1
|
||||||
|
*
|
||||||
|
*/
|
||||||
class CachingIterator implements OuterIterator
|
class CachingIterator implements OuterIterator
|
||||||
{
|
{
|
||||||
protected $it;
|
protected $it;
|
||||||
|
@ -11,6 +26,12 @@ class CachingIterator implements OuterIterator
|
||||||
protected $valid;
|
protected $valid;
|
||||||
protected $strValue;
|
protected $strValue;
|
||||||
|
|
||||||
|
/** Construct from another iterator
|
||||||
|
*
|
||||||
|
* @param it Iterator to cache
|
||||||
|
* @param flags Bitmask:
|
||||||
|
* - CIT_CALL_TOSTRING (whether to call __toString() for every element)
|
||||||
|
*/
|
||||||
function __construct(Iterator $it, $flags = CIT_CALL_TOSTRING)
|
function __construct(Iterator $it, $flags = CIT_CALL_TOSTRING)
|
||||||
{
|
{
|
||||||
$this->it = $it;
|
$this->it = $it;
|
||||||
|
@ -18,12 +39,16 @@ class CachingIterator implements OuterIterator
|
||||||
$this->next();
|
$this->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Rewind the Iterator
|
||||||
|
*/
|
||||||
function rewind()
|
function rewind()
|
||||||
{
|
{
|
||||||
$this->it->rewind();
|
$this->it->rewind();
|
||||||
$this->next();
|
$this->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Forward to the next element
|
||||||
|
*/
|
||||||
function next()
|
function next()
|
||||||
{
|
{
|
||||||
if ($this->valid = $this->it->valid()) {
|
if ($this->valid = $this->it->valid()) {
|
||||||
|
@ -44,31 +69,45 @@ class CachingIterator implements OuterIterator
|
||||||
$this->it->next();
|
$this->it->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether teh iterator is valid
|
||||||
|
*/
|
||||||
function valid()
|
function valid()
|
||||||
{
|
{
|
||||||
return $this->valid;
|
return $this->valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether there is one more element
|
||||||
|
*/
|
||||||
function hasNext()
|
function hasNext()
|
||||||
{
|
{
|
||||||
return $this->it->valid();
|
return $this->it->valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the current element
|
||||||
|
*/
|
||||||
function current()
|
function current()
|
||||||
{
|
{
|
||||||
return $this->current;
|
return $this->current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the current key
|
||||||
|
*/
|
||||||
function key()
|
function key()
|
||||||
{
|
{
|
||||||
return $this->key;
|
return $this->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Aggregate the inner iterator
|
||||||
|
*/
|
||||||
function __call($func, $params)
|
function __call($func, $params)
|
||||||
{
|
{
|
||||||
return call_user_func_array(array($this->it, $func), $params);
|
return call_user_func_array(array($this->it, $func), $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the string represenatation that was generated for the current
|
||||||
|
* element
|
||||||
|
* @throw exception when CIT_CALL_TOSTRING was not specified in constructor
|
||||||
|
*/
|
||||||
function __toString()
|
function __toString()
|
||||||
{
|
{
|
||||||
if (!$this->flags & CIT_CALL_TOSTRING) {
|
if (!$this->flags & CIT_CALL_TOSTRING) {
|
||||||
|
@ -77,6 +116,9 @@ class CachingIterator implements OuterIterator
|
||||||
return $this->strValue;
|
return $this->strValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The inner iterator
|
||||||
|
*/
|
||||||
function getInnerIterator()
|
function getInnerIterator()
|
||||||
{
|
{
|
||||||
return $this->it;
|
return $this->it;
|
||||||
|
|
|
@ -1,15 +1,38 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file cachingrecursiveiterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class CachingRecursiveIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.1
|
||||||
|
*/
|
||||||
class CachingRecursiveIterator extends CachingIterator implements RecursiveIterator
|
class CachingRecursiveIterator extends CachingIterator implements RecursiveIterator
|
||||||
{
|
{
|
||||||
protected $hasChildren;
|
protected $hasChildren;
|
||||||
protected $getChildren;
|
protected $getChildren;
|
||||||
|
|
||||||
|
/** Construct from another iterator
|
||||||
|
*
|
||||||
|
* @param it Iterator to cache
|
||||||
|
* @param flags Bitmask:
|
||||||
|
* - CIT_CALL_TOSTRING (whether to call __toString() for every element)
|
||||||
|
* - CIT_CATCH_GET_CHILD (whether to catch exceptions when trying to get childs)
|
||||||
|
*/
|
||||||
function __construct(RecursiveIterator $it, $flags = CIT_CALL_TOSTRING)
|
function __construct(RecursiveIterator $it, $flags = CIT_CALL_TOSTRING)
|
||||||
{
|
{
|
||||||
parent::__construct($it, $flags);
|
parent::__construct($it, $flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Rewind Iterator
|
||||||
|
*/
|
||||||
function rewind();
|
function rewind();
|
||||||
{
|
{
|
||||||
$this->hasChildren = false;
|
$this->hasChildren = false;
|
||||||
|
@ -17,6 +40,9 @@ class CachingRecursiveIterator extends CachingIterator implements RecursiveItera
|
||||||
parent::rewind();
|
parent::rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Forward to next element if necessary then an Iterator for the Children
|
||||||
|
* will be created.
|
||||||
|
*/
|
||||||
function next()
|
function next()
|
||||||
{
|
{
|
||||||
if ($this->hasChildren = $this->it->hasChildren()) {
|
if ($this->hasChildren = $this->it->hasChildren()) {
|
||||||
|
@ -39,11 +65,19 @@ class CachingRecursiveIterator extends CachingIterator implements RecursiveItera
|
||||||
parent::next();
|
parent::next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether the current element has children
|
||||||
|
* @note The check whether the Iterator for the children can be created was
|
||||||
|
* already executed. Hence when flag CIT_CATCH_GET_CHILD was given in
|
||||||
|
* constructor this fucntion returns false so that getChildren does
|
||||||
|
* not try to access those children.
|
||||||
|
*/
|
||||||
function hasChildren()
|
function hasChildren()
|
||||||
{
|
{
|
||||||
return $this->hasChildren;
|
return $this->hasChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return An Iterator for the children
|
||||||
|
*/
|
||||||
function getChildren()
|
function getChildren()
|
||||||
{
|
{
|
||||||
return $this->getChildren;
|
return $this->getChildren;
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file filteriterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class FilterIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Regular expression filter for string iterators
|
* @brief Regular expression filter for string iterators
|
||||||
* @author Marcus Boerger
|
* @author Marcus Boerger
|
||||||
* @version 1.0
|
* @version 1.1
|
||||||
*
|
*
|
||||||
* Instances of this class act as a filter around iterators. In other words
|
* Instances of this class act as a filter around iterators. In other words
|
||||||
* you can put an iterator into the constructor and the instance will only
|
* you can put an iterator into the constructor and the instance will only
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file limititerator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class LimitIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Limited Iteration over another Iterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.1
|
||||||
|
*
|
||||||
|
*/
|
||||||
class LimitIterator implements OuterIterator
|
class LimitIterator implements OuterIterator
|
||||||
{
|
{
|
||||||
protected $it;
|
protected $it;
|
||||||
|
@ -7,7 +22,12 @@ class LimitIterator implements OuterIterator
|
||||||
protected $count;
|
protected $count;
|
||||||
private $pos;
|
private $pos;
|
||||||
|
|
||||||
// count === NULL means all
|
/** Construct
|
||||||
|
*
|
||||||
|
* @param it Iterator to limit
|
||||||
|
* @param offset Offset to first element
|
||||||
|
* @param count Maximum number of elements to show or NULL for all
|
||||||
|
*/
|
||||||
function __construct(Iterator $it, $offset = 0, $count = -1)
|
function __construct(Iterator $it, $offset = 0, $count = -1)
|
||||||
{
|
{
|
||||||
if ($offset < 0) {
|
if ($offset < 0) {
|
||||||
|
@ -22,6 +42,11 @@ class LimitIterator implements OuterIterator
|
||||||
$this->pos = 0;
|
$this->pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Seek to specified position
|
||||||
|
* @param position offset to seek to (relative to beginning not offset
|
||||||
|
* specified in constructor).
|
||||||
|
* @throw exception when position is invalid
|
||||||
|
*/
|
||||||
function seek($position) {
|
function seek($position) {
|
||||||
if ($position < $this->offset) {
|
if ($position < $this->offset) {
|
||||||
throw new exception('Cannot seek to '.$position.' which is below offset '.$this->offset);
|
throw new exception('Cannot seek to '.$position.' which is below offset '.$this->offset);
|
||||||
|
@ -39,6 +64,8 @@ class LimitIterator implements OuterIterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Rewind to offset specified in constructor
|
||||||
|
*/
|
||||||
function rewind()
|
function rewind()
|
||||||
{
|
{
|
||||||
$this->it->rewind();
|
$this->it->rewind();
|
||||||
|
@ -46,24 +73,35 @@ class LimitIterator implements OuterIterator
|
||||||
$this->seek($this->offset);
|
$this->seek($this->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether iterator is valid
|
||||||
|
*/
|
||||||
function valid() {
|
function valid() {
|
||||||
return ($this->count == -1 || $this->pos < $this->offset + $this->count)
|
return ($this->count == -1 || $this->pos < $this->offset + $this->count)
|
||||||
&& $this->it->valid();
|
&& $this->it->valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return current key
|
||||||
|
*/
|
||||||
function key() {
|
function key() {
|
||||||
return $this->it->key();
|
return $this->it->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return current element
|
||||||
|
*/
|
||||||
function current() {
|
function current() {
|
||||||
return $this->it->current();
|
return $this->it->current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Forward to nect element
|
||||||
|
*/
|
||||||
function next() {
|
function next() {
|
||||||
$this->it->next();
|
$this->it->next();
|
||||||
$this->pos++;
|
$this->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return current position relative to zero (not to offset specified in
|
||||||
|
* constructor).
|
||||||
|
*/
|
||||||
function getPosition() {
|
function getPosition() {
|
||||||
return $this->pos;
|
return $this->pos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/** \ingroup SPL
|
/** @file outeriterator.inc
|
||||||
* \brief Interface to access inner iterator of iterator wrappers
|
* @ingroup Internal
|
||||||
|
* @brief class OuterIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interface to access the current inner iteraor of iterator wrappers
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
interface OuterIterator extends Iterator
|
interface OuterIterator extends Iterator
|
||||||
{
|
{
|
||||||
/** \return inner iterator
|
/** @return inner iterator
|
||||||
*/
|
*/
|
||||||
function getInnerIterator();
|
function getInnerIterator();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,48 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file parentiterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class FilterIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iterator to filter parents
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.1
|
||||||
|
*
|
||||||
|
* This extended FilterIterator allows a recursive iteration using
|
||||||
|
* RecursiveIteratorIterator that only shows those elements which have
|
||||||
|
* children.
|
||||||
|
*/
|
||||||
class ParentIterator extends FilterIterator implements RecursiveIterator
|
class ParentIterator extends FilterIterator implements RecursiveIterator
|
||||||
{
|
{
|
||||||
|
/** @param $it the RecursiveIterator to filter
|
||||||
|
*/
|
||||||
function __construct(RecursiveIterator $it)
|
function __construct(RecursiveIterator $it)
|
||||||
{
|
{
|
||||||
parent::__construct($it);
|
parent::__construct($it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whetehr the current element has children
|
||||||
|
*/
|
||||||
function accept()
|
function accept()
|
||||||
{
|
{
|
||||||
return $this->it->hasChildren();
|
return $this->it->hasChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether the current element has children
|
||||||
|
*/
|
||||||
function hasChildren()
|
function hasChildren()
|
||||||
{
|
{
|
||||||
return $this->it->hasChildren();
|
return $this->it->hasChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the ParentIterator for the current elements children
|
||||||
|
*/
|
||||||
function getChildren()
|
function getChildren()
|
||||||
{
|
{
|
||||||
return new ParentIterator($this->it->getChildren());
|
return new ParentIterator($this->it->getChildren());
|
||||||
|
|
|
@ -1,8 +1,27 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file recursiveiterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class RecursiveIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interface for recursive iteration with RecursiveIteratorIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
interface RecursiveIterator implements Iterator
|
interface RecursiveIterator implements Iterator
|
||||||
{
|
{
|
||||||
|
/** @return whether the current element has children
|
||||||
|
*/
|
||||||
function hasChildren();
|
function hasChildren();
|
||||||
|
|
||||||
|
/** @return the sub iterator for the current element
|
||||||
|
*/
|
||||||
function getChildren();
|
function getChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @file recursiveiteratoriterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class RecursiveIteratorIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('RIT_LEAVES_ONLY', 0);
|
||||||
|
define('RIT_SELF_FIRST', 1);
|
||||||
|
define('RIT_CHILD_FIRST', 2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Iterates through recursive iterators
|
* @brief Iterates through recursive iterators
|
||||||
* @author Marcus Boerger
|
* @author Marcus Boerger
|
||||||
* @version 1.0
|
* @version 1.1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class RecursiveIteratorIterator implements OuterIterator
|
class RecursiveIteratorIterator implements OuterIterator
|
||||||
|
@ -11,12 +24,21 @@ class RecursiveIteratorIterator implements OuterIterator
|
||||||
protected $ait = array();
|
protected $ait = array();
|
||||||
protected $count = 0;
|
protected $count = 0;
|
||||||
|
|
||||||
function __construct(RecursiveIterator $it)
|
/** Construct from RecursiveIterator
|
||||||
|
*
|
||||||
|
* @param it RecursiveIterator to iterate
|
||||||
|
* @param flags Operation mode:
|
||||||
|
* - RIT_LEAVES_ONLY only show leaves
|
||||||
|
* - RIT_SELF_FIRST show parents prior to their childs
|
||||||
|
* - RIT_CHILD_FIRST show all childs prior to their parent
|
||||||
|
*/
|
||||||
|
function __construct(RecursiveIterator $it, $flags)
|
||||||
{
|
{
|
||||||
$this->ait[0] = $it;
|
$this->ait[0] = $it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Rewind to top iterator as set in constructor
|
||||||
|
*/
|
||||||
function rewind()
|
function rewind()
|
||||||
{
|
{
|
||||||
while ($this->count) {
|
while ($this->count) {
|
||||||
|
@ -26,6 +48,8 @@ class RecursiveIteratorIterator implements OuterIterator
|
||||||
$this->ait[0]->recursed = false;
|
$this->ait[0]->recursed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether iterator is valid
|
||||||
|
*/
|
||||||
function valid()
|
function valid()
|
||||||
{
|
{
|
||||||
$count = $this->count;
|
$count = $this->count;
|
||||||
|
@ -39,18 +63,24 @@ class RecursiveIteratorIterator implements OuterIterator
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @reutrn current key
|
||||||
|
*/
|
||||||
function key()
|
function key()
|
||||||
{
|
{
|
||||||
$it = $this->ait[$this->count];
|
$it = $this->ait[$this->count];
|
||||||
return $it->key();
|
return $it->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return current element
|
||||||
|
*/
|
||||||
function current()
|
function current()
|
||||||
{
|
{
|
||||||
$it = $this->ait[$this->count];
|
$it = $this->ait[$this->count];
|
||||||
return $it->current();
|
return $it->current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Forward to next element
|
||||||
|
*/
|
||||||
function next()
|
function next()
|
||||||
{
|
{
|
||||||
while ($this->count) {
|
while ($this->count) {
|
||||||
|
@ -83,7 +113,10 @@ class RecursiveIteratorIterator implements OuterIterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Sub Iterator at given level or if unspecified the current sub
|
||||||
|
* Iterator
|
||||||
|
*/
|
||||||
function getSubIterator($level = NULL)
|
function getSubIterator($level = NULL)
|
||||||
{
|
{
|
||||||
if (is_null($level)) {
|
if (is_null($level)) {
|
||||||
|
@ -100,6 +133,8 @@ class RecursiveIteratorIterator implements OuterIterator
|
||||||
return $this->it;
|
return $this->it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Current Depth (Number of parents)
|
||||||
|
*/
|
||||||
function getDepth()
|
function getDepth()
|
||||||
{
|
{
|
||||||
return $this->level;
|
return $this->level;
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/** \brief seekable iterator
|
/** @file seekableiterator.inc
|
||||||
|
* @ingroup Internal
|
||||||
|
* @brief class SeekableIterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @date 2003 - 2004
|
||||||
|
*
|
||||||
|
* SPL - Standard PHP Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief seekable iterator
|
||||||
|
* @author Marcus Boerger
|
||||||
|
* @version 1.0
|
||||||
*
|
*
|
||||||
* Turns a normal iterator ino a seekable iterator. When there is a way
|
* Turns a normal iterator ino a seekable iterator. When there is a way
|
||||||
* to seek on an iterator LimitIterator can use this to efficiently rewind
|
* to seek on an iterator LimitIterator can use this to efficiently rewind
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue