mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-09-01 13:08:14 +00:00
optimization and cleanup
This commit is contained in:
+3
-2
@@ -41,8 +41,9 @@ class BitBuffer{
|
||||
*/
|
||||
public function put($num, $length){
|
||||
|
||||
for($i = 0; $i < $length; $i++){
|
||||
$this->putBit(($num >> ($length - $i - 1))&1 === 1);
|
||||
$i = 0;
|
||||
while($i < $length){
|
||||
$this->putBit(($num >> ($length - $i - 1))&1 === 1); $i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-1
@@ -34,8 +34,10 @@ class Byte extends QRDataBase implements QRDataInterface{
|
||||
* @param \chillerlan\QRCode\BitBuffer $buffer
|
||||
*/
|
||||
public function write(BitBuffer &$buffer){
|
||||
for($i = 0; $i < $this->dataLength; $i++){
|
||||
$i = 0;
|
||||
while($i < $this->dataLength){
|
||||
$buffer->put(ord($this->data[$i]), 8);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCode\Data;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -47,7 +48,8 @@ class QRDataBase{
|
||||
*
|
||||
* @return int
|
||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||
* @codeCoverageIgnore not used in the code but may be useful to others
|
||||
* @see QRCode::createData()
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function getLengthInBits($type){
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class QRImage extends QROutputBase implements QROutputInterface{
|
||||
$this->options->pixelSize = max(1, min(25, (int)$this->options->pixelSize));
|
||||
$this->options->marginSize = max(0, min(25, (int)$this->options->marginSize));
|
||||
|
||||
foreach(['fgRed', 'fgGreen', 'fgBlue', 'bgRed', 'bgGreen', 'bgBlue',] as $val){
|
||||
foreach(['fgRed', 'fgGreen', 'fgBlue', 'bgRed', 'bgGreen', 'bgBlue'] as $val){
|
||||
$this->options->{$val} = max(0, min(255, (int)$this->options->{$val}));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ class QRImage extends QROutputBase implements QROutputInterface{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
|
||||
*/
|
||||
public function dump(){
|
||||
$length = $this->pixelCount * $this->options->pixelSize + $this->options->marginSize * 2;
|
||||
@@ -74,9 +73,9 @@ class QRImage extends QROutputBase implements QROutputInterface{
|
||||
|
||||
imagefilledrectangle($image, 0, 0, $length, $length, $background);
|
||||
|
||||
for($r = 0; $r < $this->pixelCount; $r++){
|
||||
for($c = 0; $c < $this->pixelCount; $c++){
|
||||
if($this->matrix[$r][$c]){
|
||||
foreach($this->matrix as $r => $row){
|
||||
foreach($row as $c => $pixel){
|
||||
if($pixel){
|
||||
imagefilledrectangle($image,
|
||||
$this->options->marginSize + $c * $this->options->pixelSize,
|
||||
$this->options->marginSize + $r * $this->options->pixelSize,
|
||||
|
||||
@@ -19,7 +19,6 @@ interface QROutputInterface{
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
|
||||
*/
|
||||
public function dump();
|
||||
|
||||
|
||||
+34
-47
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCode\Output;
|
||||
use chillerlan\QRCode\Data\QRCodeDataException;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
|
||||
/**
|
||||
@@ -42,67 +43,53 @@ class QRString extends QROutputBase implements QROutputInterface{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
|
||||
*/
|
||||
public function dump(){
|
||||
return call_user_func([$this, [
|
||||
QRCode::OUTPUT_STRING_TEXT => 'toText',
|
||||
QRCode::OUTPUT_STRING_JSON => 'toJSON',
|
||||
QRCode::OUTPUT_STRING_HTML => 'toHTML',
|
||||
][$this->options->type]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toText(){
|
||||
$text = '';
|
||||
|
||||
foreach($this->matrix as &$row){
|
||||
foreach($row as &$col){
|
||||
$text .= $col
|
||||
? $this->options->textDark
|
||||
: $this->options->textLight;
|
||||
}
|
||||
|
||||
$text .= $this->options->textNewline;
|
||||
if($this->options->type === QRCode::OUTPUT_STRING_JSON){
|
||||
return json_encode($this->matrix);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
else if($this->options->type === QRCode::OUTPUT_STRING_TEXT){
|
||||
$text = '';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toJSON(){
|
||||
return json_encode($this->matrix);
|
||||
}
|
||||
foreach($this->matrix as $row){
|
||||
foreach($row as $col){
|
||||
$text .= $col
|
||||
? $this->options->textDark
|
||||
: $this->options->textLight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toHTML(){
|
||||
$html = '';
|
||||
$text .= $this->options->textNewline;
|
||||
}
|
||||
|
||||
foreach($this->matrix as &$row){
|
||||
// in order to not bloat the output too much, we use the shortest possible valid HTML tags
|
||||
$html .= '<'.$this->options->htmlRowTag.'>';
|
||||
foreach($row as &$col){
|
||||
$tag = $col
|
||||
? 'b' // dark
|
||||
: 'i'; // light
|
||||
return $text;
|
||||
}
|
||||
|
||||
else if($this->options->type === QRCode::OUTPUT_STRING_HTML){
|
||||
$html = '';
|
||||
|
||||
foreach($this->matrix as $row){
|
||||
// in order to not bloat the output too much, we use the shortest possible valid HTML tags
|
||||
$html .= '<'.$this->options->htmlRowTag.'>';
|
||||
foreach($row as $col){
|
||||
$tag = $col
|
||||
? 'b' // dark
|
||||
: 'i'; // light
|
||||
|
||||
$html .= '<'.$tag.'></'.$tag.'>';
|
||||
}
|
||||
|
||||
if(!(bool)$this->options->htmlOmitEndTag){
|
||||
$html .= '</'.$this->options->htmlRowTag.'>';
|
||||
}
|
||||
|
||||
$html .= PHP_EOL;
|
||||
}
|
||||
|
||||
if(!(bool)$this->options->htmlOmitEndTag){
|
||||
$html .= '</'.$this->options->htmlRowTag.'>';
|
||||
}
|
||||
|
||||
$html .= PHP_EOL;
|
||||
return $html;
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-4
@@ -58,8 +58,10 @@ class Polynomial{
|
||||
|
||||
$this->num = array_fill(0, $numCount - $offset + $shift, 0);
|
||||
|
||||
for($i = 0; $i < $numCount - $offset; $i++){
|
||||
$i = 0;
|
||||
while($i < $numCount - $offset){
|
||||
$this->num[$i] = $num[$i + $offset];
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -71,16 +73,22 @@ class Polynomial{
|
||||
protected function setTables(){
|
||||
$this->EXP_TABLE = $this->LOG_TABLE = array_fill(0, 256, 0);
|
||||
|
||||
for($i = 0; $i < 8; $i++){
|
||||
$i = 0;
|
||||
while($i < 8){
|
||||
$this->EXP_TABLE[$i] = 1 << $i;
|
||||
$i++;
|
||||
}
|
||||
|
||||
for($i = 8; $i < 256; $i++){
|
||||
$i = 8;
|
||||
while($i < 256){
|
||||
$this->EXP_TABLE[$i] = $this->EXP_TABLE[$i - 4] ^ $this->EXP_TABLE[$i - 5] ^ $this->EXP_TABLE[$i - 6] ^ $this->EXP_TABLE[$i - 8];
|
||||
$i++;
|
||||
}
|
||||
|
||||
for($i = 0; $i < 255; $i++){
|
||||
$i = 0;
|
||||
while($i < 255){
|
||||
$this->LOG_TABLE[$this->EXP_TABLE[$i]] = $i;
|
||||
$i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
-29
@@ -144,7 +144,6 @@ class QRCode{
|
||||
][$mode];
|
||||
|
||||
$this->qrDataInterface = new $qrDataInterface($data);
|
||||
|
||||
$this->typeNumber = intval($options->typeNumber);
|
||||
|
||||
if($this->typeNumber < 1 || $this->typeNumber > 10){
|
||||
@@ -191,7 +190,7 @@ class QRCode{
|
||||
$minLostPoint = 0;
|
||||
$maskPattern = 0;
|
||||
|
||||
for($pattern = 0; $pattern <= 7; $pattern++){
|
||||
foreach(range(0, 7) as $pattern){
|
||||
$this->getMatrix(true, $pattern);
|
||||
$lostPoint = 0;
|
||||
$darkCount = 0;
|
||||
@@ -199,19 +198,18 @@ class QRCode{
|
||||
$range1 = range(0, $this->pixelCount-1);
|
||||
$range2 = range(0, $this->pixelCount-2);
|
||||
$range3 = range(0, $this->pixelCount-7);
|
||||
$range4 = range(-1, 1);
|
||||
|
||||
// LEVEL1
|
||||
foreach($range1 as $row){
|
||||
foreach($range1 as $col){
|
||||
$sameCount = 0;
|
||||
|
||||
foreach($range4 as $rr){
|
||||
foreach([-1, 0, 1] as $rr){
|
||||
if($row + $rr < 0 || $this->pixelCount <= $row + $rr){
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($range4 as $cr){
|
||||
foreach([-1, 0, 1] as $cr){
|
||||
|
||||
if(($rr === 0 && $cr === 0) || ($col + $cr < 0 || $this->pixelCount <= $col + $cr)){
|
||||
continue;
|
||||
@@ -311,7 +309,7 @@ class QRCode{
|
||||
protected function setTypeNumber($test){
|
||||
$bits = Util::getBCHTypeNumber($this->typeNumber);
|
||||
|
||||
for($i = 0; $i < 18; $i++){
|
||||
foreach(range(0, 17) as $i){
|
||||
$a = (int)floor($i / 3);
|
||||
$b = $i % 3 + $this->pixelCount - 8 - 3;
|
||||
|
||||
@@ -328,7 +326,7 @@ class QRCode{
|
||||
$this->setPattern();
|
||||
$bits = Util::getBCHTypeInfo(($this->errorCorrectLevel << 3) | $pattern);
|
||||
|
||||
for($i = 0; $i < 15; $i++){
|
||||
foreach(range(0, 14) as $i){
|
||||
$mod = !$test && (($bits >> $i) & 1) === 1;
|
||||
|
||||
switch(true){
|
||||
@@ -355,20 +353,18 @@ class QRCode{
|
||||
*/
|
||||
protected function createData(){
|
||||
$this->bitBuffer->clear();
|
||||
|
||||
$MAX_BITS = QRConst::MAX_BITS; // php5 compat
|
||||
$MAX_BITS = $MAX_BITS[$this->typeNumber][$this->errorCorrectLevel];
|
||||
|
||||
/** @noinspection PhpUndefinedFieldInspection */
|
||||
$this->bitBuffer->put($this->qrDataInterface->mode, 4);
|
||||
/** @noinspection PhpUndefinedFieldInspection */
|
||||
$this->bitBuffer->put(
|
||||
$this->qrDataInterface->mode === QRConst::MODE_KANJI ? floor($this->qrDataInterface->dataLength / 2) : $this->qrDataInterface->dataLength,
|
||||
$this->qrDataInterface->mode === QRConst::MODE_KANJI
|
||||
? floor($this->qrDataInterface->dataLength / 2)
|
||||
: $this->qrDataInterface->dataLength,
|
||||
$this->qrDataInterface->getLengthInBits($this->typeNumber)
|
||||
);
|
||||
|
||||
$this->qrDataInterface->write($this->bitBuffer);
|
||||
|
||||
$MAX_BITS = QRConst::MAX_BITS[$this->typeNumber][$this->errorCorrectLevel];
|
||||
|
||||
if($this->bitBuffer->length > $MAX_BITS){
|
||||
throw new QRCodeException('code length overflow. ('.$this->bitBuffer->length.' > '.$MAX_BITS.'bit)');
|
||||
}
|
||||
@@ -430,9 +426,11 @@ class QRCode{
|
||||
$rsPoly = new Polynomial;
|
||||
$modPoly = new Polynomial;
|
||||
|
||||
foreach(range(0, $rsBlockTotal - $rsBlockDataCount - 1) as $i){
|
||||
$i = 0;
|
||||
while($i < $rsBlockTotal - $rsBlockDataCount){
|
||||
$modPoly->setNum([1, $modPoly->gexp($i)]);
|
||||
$rsPoly->multiply($modPoly->num);
|
||||
$i++;
|
||||
}
|
||||
|
||||
$rsPolyCount = count($rsPoly->num);
|
||||
@@ -451,20 +449,24 @@ class QRCode{
|
||||
$data = array_fill(0, $totalCodeCount, null);
|
||||
$rsrange = range(0, $rsBlockCount - 1);
|
||||
|
||||
foreach(range(0, $maxDcCount - 1) as $i){
|
||||
$i = 0;
|
||||
while($i < $maxDcCount){
|
||||
foreach($rsrange as $key){
|
||||
if($i < count($dcdata[$key])){
|
||||
$data[$index++] = $dcdata[$key][$i];
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
foreach(range(0, $maxEcCount - 1) as $i){
|
||||
$i = 0;
|
||||
while($i < $maxEcCount){
|
||||
foreach($rsrange as $key){
|
||||
if($i < count($ecdata[$key])){
|
||||
$data[$index++] = $ecdata[$key][$i];
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -490,7 +492,8 @@ class QRCode{
|
||||
}
|
||||
|
||||
while(true){
|
||||
foreach([0, 1] as $c){
|
||||
$c = 0;
|
||||
while($c < 2){
|
||||
$_col = $col - $c;
|
||||
|
||||
if($this->matrix[$row][$_col] === null){
|
||||
@@ -525,6 +528,7 @@ class QRCode{
|
||||
$bitIndex = 7;
|
||||
}
|
||||
}
|
||||
$c++;
|
||||
}
|
||||
|
||||
$row += $inc;
|
||||
@@ -542,15 +546,18 @@ class QRCode{
|
||||
* @throws \chillerlan\QRCode\QRCodeException
|
||||
*/
|
||||
protected function setPattern(){
|
||||
$range1 = range(-1, 7);
|
||||
$range2 = QRConst::PATTERN_POSITION[$this->typeNumber - 1];
|
||||
$range3 = range(8, $this->pixelCount - 8);
|
||||
|
||||
// setupPositionProbePattern
|
||||
$range = range(-1, 7);
|
||||
foreach([[0, 0], [$this->pixelCount - 7, 0], [0, $this->pixelCount - 7]] as $grid){
|
||||
$row = $grid[0];
|
||||
$col = $grid[1];
|
||||
|
||||
foreach($range as $r){
|
||||
foreach($range as $c){
|
||||
$r = -1;
|
||||
while($r < 8){
|
||||
foreach($range1 as $c){
|
||||
|
||||
if($row + $r <= -1 || $this->pixelCount <= $row + $r || $col + $c <= -1 || $this->pixelCount <= $col + $c){
|
||||
continue;
|
||||
@@ -561,32 +568,33 @@ class QRCode{
|
||||
|| (0 <= $c && $c <= 6 && ($r === 0 || $r === 6))
|
||||
|| (2 <= $c && $c <= 4 && 2 <= $r && $r <= 4);
|
||||
}
|
||||
$r++;
|
||||
}
|
||||
}
|
||||
|
||||
// setupPositionAdjustPattern
|
||||
$PATTERN_POSITION = QRConst::PATTERN_POSITION; // PHP5 compat
|
||||
$pos = $PATTERN_POSITION[$this->typeNumber - 1];
|
||||
$range = range(-2, 2);
|
||||
foreach($pos as $i => $posI){
|
||||
foreach($pos as $j => $posJ){
|
||||
foreach($range2 as $i => $posI){
|
||||
foreach($range2 as $j => $posJ){
|
||||
if($this->matrix[$posI][$posJ] !== null){
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($range as $row){
|
||||
foreach($range as $col){
|
||||
$row = $col = -2;
|
||||
while($row < 2){
|
||||
while($col < 2){
|
||||
$this->matrix[$posI + $row][$posJ + $col] =
|
||||
$row === -2 || $row === 2
|
||||
|| $col === -2 || $col === 2
|
||||
||($row === 0 && $col === 0);
|
||||
$col++;
|
||||
}
|
||||
$row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setupTimingPattern
|
||||
foreach(range(8, $this->pixelCount - 8) as $i){
|
||||
foreach($range3 as $i){
|
||||
if($this->matrix[$i][6] !== null){
|
||||
continue; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
+37
-29
@@ -23,14 +23,17 @@ class Util{
|
||||
* @return bool
|
||||
*/
|
||||
public static function isNumber($s){
|
||||
|
||||
$len = strlen($s);
|
||||
for($i = 0; $i < $len; $i++){
|
||||
$i = 0;
|
||||
|
||||
while($i < $len){
|
||||
$c = ord($s[$i]);
|
||||
|
||||
if(!(ord('0') <= $c && $c <= ord('9'))){
|
||||
return false;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -42,14 +45,17 @@ class Util{
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAlphaNum($s){
|
||||
|
||||
$len = strlen($s);
|
||||
for($i = 0; $i < $len; $i++){
|
||||
$i = 0;
|
||||
|
||||
while($i < $len){
|
||||
$c = ord($s[$i]);
|
||||
|
||||
if(!(ord('0') <= $c && $c <= ord('9')) && !(ord('A') <= $c && $c <= ord('Z')) && strpos(' $%*+-./:', $s[$i]) === false){
|
||||
return false;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -87,13 +93,7 @@ class Util{
|
||||
* @return int
|
||||
*/
|
||||
public static function getBCHTypeInfo($data){
|
||||
$d = $data << 10;
|
||||
|
||||
while(self::getBCHDigit($d) - self::getBCHDigit(QRConst::G15) >= 0){
|
||||
$d ^= (QRConst::G15 << (self::getBCHDigit($d) - self::getBCHDigit(QRConst::G15)));
|
||||
}
|
||||
|
||||
return (($data << 10)|$d)^QRConst::G15_MASK;
|
||||
return (($data << 10)|self::getBCHT($data, 10, QRConst::G15))^QRConst::G15_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,13 +102,24 @@ class Util{
|
||||
* @return int
|
||||
*/
|
||||
public static function getBCHTypeNumber($data){
|
||||
$d = $data << 12;
|
||||
return ($data << 12)|self::getBCHT($data, 12, QRConst::G18);
|
||||
}
|
||||
|
||||
while(self::getBCHDigit($d) - self::getBCHDigit(QRConst::G18) >= 0){
|
||||
$d ^= (QRConst::G18 << (self::getBCHDigit($d) - self::getBCHDigit(QRConst::G18)));
|
||||
/**
|
||||
* @param int $data
|
||||
* @param int $bits
|
||||
* @param int $mask
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected static function getBCHT($data, $bits, $mask){
|
||||
$d = $data << $bits;
|
||||
|
||||
while(self::getBCHDigit($d) - self::getBCHDigit($mask) >= 0){
|
||||
$d ^= ($mask << (self::getBCHDigit($d) - self::getBCHDigit($mask)));
|
||||
}
|
||||
|
||||
return ($data << 12)|$d;
|
||||
return $d;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,22 +146,22 @@ class Util{
|
||||
* @throws \chillerlan\QRCode\QRCodeException
|
||||
*/
|
||||
public static function getRSBlocks($typeNumber, $errorCorrectLevel){
|
||||
// PHP5 compat
|
||||
$RSBLOCK = QRConst::RSBLOCK;
|
||||
$BLOCK_TABLE = QRConst::BLOCK_TABLE;
|
||||
|
||||
if(!isset($RSBLOCK[$errorCorrectLevel])){
|
||||
if(!array_key_exists($errorCorrectLevel, QRConst::RSBLOCK)){
|
||||
throw new QRCodeException('$typeNumber: '.$typeNumber.' / $errorCorrectLevel: '.$errorCorrectLevel);
|
||||
}
|
||||
|
||||
$rsBlock = $BLOCK_TABLE[($typeNumber - 1) * 4 + $RSBLOCK[$errorCorrectLevel]];
|
||||
|
||||
$rsBlock = QRConst::BLOCK_TABLE[($typeNumber - 1) * 4 + QRConst::RSBLOCK[$errorCorrectLevel]];
|
||||
$list = [];
|
||||
$length = count($rsBlock) / 3;
|
||||
for($i = 0; $i < $length; $i++){
|
||||
for($j = 0; $j < $rsBlock[$i * 3 + 0]; $j++){
|
||||
$i = $j = 0;
|
||||
|
||||
while($i < $length){
|
||||
while($j < $rsBlock[$i * 3 + 0]){
|
||||
$list[] = [$rsBlock[$i * 3 + 1], $rsBlock[$i * 3 + 2]];
|
||||
$j++;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $list;
|
||||
@@ -165,19 +176,16 @@ class Util{
|
||||
* @throws \chillerlan\QRCode\QRCodeException
|
||||
*/
|
||||
public static function getMaxLength($typeNumber, $mode, $ecLevel){
|
||||
$RSBLOCK = QRConst::RSBLOCK;
|
||||
$MAX_LENGTH = QRConst::MAX_LENGTH;
|
||||
$MODE = QRConst::MODE;
|
||||
|
||||
if(!isset($RSBLOCK[$ecLevel])){
|
||||
if(!array_key_exists($ecLevel, QRConst::RSBLOCK)){
|
||||
throw new QRCodeException('Invalid error correct level: '.$ecLevel);
|
||||
}
|
||||
|
||||
if(!isset($MODE[$mode])){
|
||||
if(!array_key_exists($mode, QRConst::MODE)){
|
||||
throw new QRCodeException('Invalid mode: '.$mode);
|
||||
}
|
||||
|
||||
return $MAX_LENGTH[$typeNumber - 1][$RSBLOCK[$ecLevel]][$MODE[$mode]];
|
||||
return QRConst::MAX_LENGTH[$typeNumber - 1][QRConst::RSBLOCK[$ecLevel]][QRConst::MODE[$mode]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user