All scripts in one repository
This commit is contained in:
parent
a0a86492ee
commit
9f9304d6aa
61 changed files with 6668 additions and 681 deletions
44
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php
vendored
Normal file
44
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class BlockquoteConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
// Contents should have already been converted to Markdown by this point,
|
||||
// so we just need to add '>' symbols to each line.
|
||||
|
||||
$markdown = '';
|
||||
|
||||
$quote_content = trim($element->getValue());
|
||||
|
||||
$lines = preg_split('/\r\n|\r|\n/', $quote_content);
|
||||
|
||||
$total_lines = count($lines);
|
||||
|
||||
foreach ($lines as $i => $line) {
|
||||
$markdown .= '> ' . $line . "\n";
|
||||
if ($i + 1 === $total_lines) {
|
||||
$markdown .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('blockquote');
|
||||
}
|
||||
}
|
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/CommentConverter.php
vendored
Normal file
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/CommentConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class CommentConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('#comment');
|
||||
}
|
||||
}
|
20
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ConverterInterface.php
vendored
Normal file
20
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ConverterInterface.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
interface ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element);
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags();
|
||||
}
|
50
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/DefaultConverter.php
vendored
Normal file
50
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/DefaultConverter.php
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\Configuration;
|
||||
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class DefaultConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||
{
|
||||
const DEFAULT_CONVERTER = '_default';
|
||||
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function setConfig(Configuration $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
// If strip_tags is false (the default), preserve tags that don't have Markdown equivalents,
|
||||
// such as <span> nodes on their own. C14N() canonicalizes the node to a string.
|
||||
// See: http://www.php.net/manual/en/domnode.c14n.php
|
||||
if ($this->config->getOption('strip_tags', false)) {
|
||||
return $element->getValue();
|
||||
}
|
||||
|
||||
return html_entity_decode($element->getChildrenAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array(self::DEFAULT_CONVERTER);
|
||||
}
|
||||
}
|
45
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/DivConverter.php
vendored
Normal file
45
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/DivConverter.php
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\Configuration;
|
||||
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class DivConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function setConfig(Configuration $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
if ($this->config->getOption('strip_tags', false)) {
|
||||
return $element->getValue() . "\n\n";
|
||||
}
|
||||
|
||||
return html_entity_decode($element->getChildrenAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('div');
|
||||
}
|
||||
}
|
50
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php
vendored
Normal file
50
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\Configuration;
|
||||
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class EmphasisConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function setConfig(Configuration $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
$tag = $element->getTagName();
|
||||
$value = $element->getValue();
|
||||
|
||||
if ($tag === 'i' || $tag === 'em') {
|
||||
$style = $this->config->getOption('italic_style');
|
||||
} else {
|
||||
$style = $this->config->getOption('bold_style');
|
||||
}
|
||||
|
||||
return $style . $value . $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('em', 'i', 'strong', 'b');
|
||||
}
|
||||
}
|
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php
vendored
Normal file
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class HardBreakConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
return " \n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('br');
|
||||
}
|
||||
}
|
78
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php
vendored
Normal file
78
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\Configuration;
|
||||
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class HeaderConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||
{
|
||||
const STYLE_ATX = 'atx';
|
||||
const STYLE_SETEXT = 'setext';
|
||||
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function setConfig(Configuration $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
$level = (int) substr($element->getTagName(), 1, 1);
|
||||
$style = $this->config->getOption('header_style', self::STYLE_SETEXT);
|
||||
|
||||
if (($level === 1 || $level === 2) && !$element->isDescendantOf('blockquote') && $style === self::STYLE_SETEXT) {
|
||||
return $this->createSetextHeader($level, $element->getValue());
|
||||
} else {
|
||||
return $this->createAtxHeader($level, $element->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
* @param string $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createSetextHeader($level, $content)
|
||||
{
|
||||
$length = (function_exists('mb_strlen')) ? mb_strlen($content, 'utf-8') : strlen($content);
|
||||
$underline = ($level === 1) ? '=' : '-';
|
||||
|
||||
return $content . "\n" . str_repeat($underline, $length) . "\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
* @param string $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createAtxHeader($level, $content)
|
||||
{
|
||||
$prefix = str_repeat('#', $level) . ' ';
|
||||
|
||||
return $prefix . $content . "\n\n";
|
||||
}
|
||||
}
|
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php
vendored
Normal file
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class HorizontalRuleConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
return "- - - - - -\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('hr');
|
||||
}
|
||||
}
|
37
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ImageConverter.php
vendored
Normal file
37
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ImageConverter.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class ImageConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
$src = $element->getAttribute('src');
|
||||
$alt = $element->getAttribute('alt');
|
||||
$title = $element->getAttribute('title');
|
||||
|
||||
if ($title !== '') {
|
||||
// No newlines added. <img> should be in a block-level element.
|
||||
$markdown = '';
|
||||
} else {
|
||||
$markdown = '';
|
||||
}
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('img');
|
||||
}
|
||||
}
|
42
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/LinkConverter.php
vendored
Normal file
42
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/LinkConverter.php
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class LinkConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
$href = $element->getAttribute('href');
|
||||
$title = $element->getAttribute('title');
|
||||
$text = $element->getValue();
|
||||
|
||||
if ($title !== '') {
|
||||
$markdown = '[' . $text . '](' . $href . ' "' . $title . '")';
|
||||
} elseif ($href === $text) {
|
||||
$markdown = '<' . $href . '>';
|
||||
} else {
|
||||
$markdown = '[' . $text . '](' . $href . ')';
|
||||
}
|
||||
|
||||
if (!$href) {
|
||||
$markdown = html_entity_decode($element->getChildrenAsString());
|
||||
}
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('a');
|
||||
}
|
||||
}
|
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php
vendored
Normal file
26
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class ListBlockConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
return $element->getValue() . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('ol', 'ul');
|
||||
}
|
||||
}
|
37
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php
vendored
Normal file
37
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class ListItemConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
// If parent is an ol, use numbers, otherwise, use dashes
|
||||
$list_type = $element->getParent()->getTagName();
|
||||
$value = $element->getValue();
|
||||
|
||||
if ($list_type === 'ul') {
|
||||
$markdown = '- ' . trim($value) . "\n";
|
||||
} else {
|
||||
$number = $element->getSiblingPosition();
|
||||
$markdown = $number . '. ' . trim($value) . "\n";
|
||||
}
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('li');
|
||||
}
|
||||
}
|
28
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php
vendored
Normal file
28
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class ParagraphConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
$value = $element->getValue();
|
||||
|
||||
return (trim($value)) ? rtrim($value) . "\n\n" : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('p');
|
||||
}
|
||||
}
|
73
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php
vendored
Normal file
73
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class PreformattedConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
// Store the content of the code block in an array, one entry for each line
|
||||
|
||||
$markdown = '';
|
||||
|
||||
$code_content = html_entity_decode($element->getChildrenAsString());
|
||||
$code_content = str_replace(array('<code>', '</code>'), '', $code_content);
|
||||
$code_content = str_replace(array('<pre>', '</pre>'), '', $code_content);
|
||||
|
||||
$lines = preg_split('/\r\n|\r|\n/', $code_content);
|
||||
$total = count($lines);
|
||||
|
||||
// If there's more than one line of code, prepend each line with four spaces and no backticks.
|
||||
if ($total > 1 || $element->getTagName() === 'pre') {
|
||||
// Remove the first and last line if they're empty
|
||||
$first_line = trim($lines[0]);
|
||||
$last_line = trim($lines[$total - 1]);
|
||||
$first_line = trim($first_line, '
'); //trim XML style carriage returns too
|
||||
$last_line = trim($last_line, '
');
|
||||
|
||||
if (empty($first_line)) {
|
||||
array_shift($lines);
|
||||
}
|
||||
|
||||
if (empty($last_line)) {
|
||||
array_pop($lines);
|
||||
}
|
||||
|
||||
$count = 1;
|
||||
foreach ($lines as $line) {
|
||||
$line = str_replace('
', '', $line);
|
||||
$markdown .= ' ' . $line;
|
||||
// Add newlines, except final line of the code
|
||||
if ($count !== $total) {
|
||||
$markdown .= "\n";
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
$markdown .= "\n";
|
||||
} else {
|
||||
// There's only one line of code. It's a code span, not a block. Just wrap it with backticks.
|
||||
$markdown .= '`' . $lines[0] . '`';
|
||||
}
|
||||
|
||||
if ($element->getTagName() === 'pre') {
|
||||
$markdown = "\n" . $markdown . "\n";
|
||||
}
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('pre', 'code');
|
||||
}
|
||||
}
|
38
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/TextConverter.php
vendored
Normal file
38
blogger2rangitaki/vendor/league/html-to-markdown/src/Converter/TextConverter.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace League\HTMLToMarkdown\Converter;
|
||||
|
||||
use League\HTMLToMarkdown\ElementInterface;
|
||||
|
||||
class TextConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @param ElementInterface $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert(ElementInterface $element)
|
||||
{
|
||||
$value = $element->getValue();
|
||||
|
||||
$markdown = preg_replace('~\s+~', ' ', $value);
|
||||
$markdown = preg_replace('~^#~', '\\\\#', $markdown);
|
||||
|
||||
if ($markdown === ' ') {
|
||||
$next = $element->getNext();
|
||||
if (!$next || $next->isBlock()) {
|
||||
$markdown = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedTags()
|
||||
{
|
||||
return array('#text');
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue