more color!
This commit is contained in:
parent
5667dacda6
commit
b259b624e4
@ -1,5 +1,4 @@
|
||||
import _winapi
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
os.system('')
|
||||
@ -15,16 +14,16 @@ def rgb(r, g, b):
|
||||
return 2, r, g, b
|
||||
|
||||
|
||||
# i_list = list(range(30, 39, 1))
|
||||
# # i_list = [39]
|
||||
# j_list = list(range(40, 49, 1))
|
||||
# # j_list = [49]
|
||||
#
|
||||
# for i in i_list:
|
||||
# for j in j_list:
|
||||
# print(f'\033[{i};{j}m{i}|{j} {reset}', end='|')
|
||||
# print()
|
||||
# print()
|
||||
i_list = list(range(30, 39, 1))
|
||||
# i_list = [39]
|
||||
j_list = list(range(40, 49, 1))
|
||||
# j_list = [49]
|
||||
|
||||
for i in i_list:
|
||||
for j in j_list:
|
||||
print(f'\033[{i};{j}m{i}|{j} {reset}', end='|')
|
||||
print()
|
||||
print()
|
||||
|
||||
|
||||
def color_print(*args):
|
||||
@ -51,6 +50,8 @@ if os.name == "nt":
|
||||
else:
|
||||
pass
|
||||
|
||||
reset_color = '\033[0m'
|
||||
|
||||
# exit(0)
|
||||
|
||||
color_print(94)
|
||||
@ -62,5 +63,35 @@ color_print(48, *rgb(255, 161, 72))
|
||||
color_print(48, *rgb(255, 161, 72), 38, *rgb(1, 50, 255))
|
||||
color_print(48, *rgb(178, 112, 50), 38, *rgb(98, 96, 167))
|
||||
print()
|
||||
color_print(48, *rgb(100, 10, 10), )
|
||||
exit(0)
|
||||
color_print(48, *rgb(120, 10, 10), 38, *rgb(50, 100, 110))
|
||||
|
||||
color_print(34, 40)
|
||||
color_print(32, 40)
|
||||
print('trace: ', end='')
|
||||
color_print(48, *rgb(40, 40, 40))
|
||||
print('some trace', reset_color)
|
||||
|
||||
print('fine: ', end='')
|
||||
color_print(35)
|
||||
print('some fine', reset_color)
|
||||
|
||||
print('debug: ', end='')
|
||||
color_print(38, *rgb(133, 138, 149))
|
||||
print('some debug', reset_color)
|
||||
|
||||
print('info: ', end='')
|
||||
color_print(0)
|
||||
print('some info', reset_color)
|
||||
|
||||
print('warn: ', end='')
|
||||
# color_print(31, 48, *rgb(56, 28, 0))
|
||||
color_print(33)
|
||||
print('some warn', reset_color)
|
||||
|
||||
print('error: ', end='')
|
||||
color_print(31)
|
||||
print('some error', reset_color)
|
||||
|
||||
print('fatal: ', end='')
|
||||
color_print(37, 41)
|
||||
print('some fatal', reset_color)
|
||||
|
@ -16,10 +16,10 @@ int *print_PyUcs4(PyObject *pyObject){
|
||||
}
|
||||
#if defined(__linux__)
|
||||
const char *out_char = PyUnicode_AsUTF8(pyObject);
|
||||
printf("%s\n", out_char);
|
||||
printf("%s", out_char);
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
Py_UCS4 *ucs4 = PyUnicode_4BYTE_DATA(pyObject);
|
||||
printf("%ws\n", ucs4); // win
|
||||
printf("%ws", ucs4); // win
|
||||
#endif
|
||||
return (int *) 1;
|
||||
};
|
||||
@ -58,6 +58,7 @@ static PyObject *pycpint_printf(PyObject *self, PyObject *args, PyObject *kwargs
|
||||
for (Py_ssize_t i = 0; i < text_len; i++){ // for 遍历
|
||||
cache_obj = PyTuple_GetItem(args, i); // 获取一个字符串
|
||||
if (cache_obj == NULL){ return NULL; }; // 出毛病了就报错
|
||||
|
||||
if (PyUnicode_Check(cache_obj) == 1) {
|
||||
print_PyUcs4(cache_obj);
|
||||
} else if (PyList_Check(cache_obj) == 1) {
|
||||
@ -69,9 +70,9 @@ static PyObject *pycpint_printf(PyObject *self, PyObject *args, PyObject *kwargs
|
||||
if(kwargs != NULL){ // 传入了 end 或者 sep
|
||||
Py_ssize_t kwargs_len = PyDict_Size(kwargs);
|
||||
printf("kwargs_len = %lld\n", (Py_size) kwargs_len);;
|
||||
if(PyDict_Contains(kwargs, PyUnicode_FromString("end"))){ // 如果包含 end 的参数
|
||||
PyObject *end_unicode; // 整个缓存
|
||||
end_unicode = PyDict_GetItemString(kwargs, "end"); // 先获取出来 Pyobj
|
||||
if(PyDict_Contains(kwargs, PyUnicode_FromString("end"))){ // 如果包含 end 的参数
|
||||
|
||||
PyObject *end_unicode = PyDict_GetItemString(kwargs, "end"); // 先获取出来 Pyobj
|
||||
|
||||
end = PyUnicode_AsUTF8(end_unicode);
|
||||
};
|
||||
@ -97,4 +98,4 @@ static struct PyModuleDef pycprintmodule = {
|
||||
|
||||
PyMODINIT_FUNC PyInit_pycprint(void){
|
||||
return PyModule_Create(&pycprintmodule);
|
||||
}
|
||||
};
|
||||
|
@ -3,26 +3,15 @@
|
||||
# Copyright © 2021-2022 by shenjackyuanjie 3695888@qq.com
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
import timeit
|
||||
import time
|
||||
from build import pycprint
|
||||
|
||||
pycprint.print("来个测试\n")
|
||||
|
||||
time.sleep(1)
|
||||
cpyprint = timeit.timeit('pycprint.print("啊啊")', number=100000, globals=globals())
|
||||
pyprint = timeit.timeit('print("啊啊")', number=100000, globals=globals())
|
||||
pycprint.print("再来个测试\n")
|
||||
|
||||
print(cpyprint, pyprint, pyprint - cpyprint)
|
||||
time.sleep(10)
|
||||
pycprint.print("abcdefg\n")
|
||||
|
||||
pycprint.print("a啊 a\n")
|
||||
pycprint.print("a啊采购好难过 a\n")
|
||||
print()
|
||||
#
|
||||
pycprint.printf("a啊a\n", "aaa", "aaa", end='')
|
||||
pycprint.printf('aaaa')
|
||||
|
||||
print()
|
||||
pycprint.printf("啊啊啊abc啊,怎么了")
|
||||
|
||||
pycprint.printf()
|
||||
|
||||
pycprint.printf("aaa\n", "aaa", "aaa")
|
||||
|
@ -18,6 +18,7 @@ import math
|
||||
import logging
|
||||
import configparser
|
||||
|
||||
from typing import Union
|
||||
from xml.dom.minidom import parse
|
||||
|
||||
from libs import toml
|
||||
@ -30,12 +31,14 @@ tools_logger = logging.getLogger('part-tools')
|
||||
file configs
|
||||
"""
|
||||
|
||||
file_error = {'FileNotFoundError': 'no {filetype} file was founded!:\n file name: {filename}\n file_type: {filetype}\n stack: {stack}',
|
||||
'KeyError': 'no stack in {filetype} file {filename} was found! \n file type: {} \n file name: {} \n stack: {stack}',
|
||||
'Error': 'get some unknown error when read {filetype} file {filename}! \n file type: {} \n file name: {} \n stack: {stack}'}
|
||||
file_error = {FileNotFoundError: 'no {filetype} file was founded!:\n file name: {filename}\n file_type: {filetype}\n stack: {stack}',
|
||||
KeyError: 'no stack in {filetype} file {filename} was found! \n file type: {} \n file name: {} \n stack: {stack}',
|
||||
Exception: 'get some {error_type} error when read {filetype} file {filename}! \n file type: {} \n file name: {} \n stack: {stack}'}
|
||||
|
||||
|
||||
def load_file(file_name: str, stack=None):
|
||||
|
||||
|
||||
def load_file(file_name: str, stack:Union[str, list, dict] = None, raise_error: bool = True) -> Union[dict, list]:
|
||||
f_type = file_name[file_name.rfind('.') + 1:] # 从最后一个.到末尾 (截取文件格式)
|
||||
try:
|
||||
get_file = NotImplementedError('解析失败,请检查文件类型/文件内容/文件是否存在!')
|
||||
@ -53,12 +56,13 @@ def load_file(file_name: str, stack=None):
|
||||
elif f_type == 'json5':
|
||||
raise NoMoreJson5("我说什么也不用json5了!喵的")
|
||||
except Exception as exp:
|
||||
error_type = type(exp).__name__
|
||||
error_type = type(exp)
|
||||
if error_type in file_error:
|
||||
tools_logger.error(file_error[error_type].format(filetype=f_type, filename=file_name, stack=stack))
|
||||
else:
|
||||
tools_logger.error(file_error['Error'].format(filetype=f_type, filename=file_name, stack=stack))
|
||||
raise
|
||||
tools_logger.error(file_error[Exception].format(error_type=error_type, filetype=f_type, filename=file_name, stack=stack))
|
||||
if raise_error:
|
||||
raise
|
||||
return get_file
|
||||
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
theme: jekyll-theme-slate
|
@ -6,7 +6,7 @@ import atexit
|
||||
import threading
|
||||
|
||||
from time import strftime
|
||||
from typing import Optional, Union, List, Iterable
|
||||
from typing import Optional, Union, Dict, Iterable, Tuple, List
|
||||
from logging import NOTSET, DEBUG, INFO, WARNING, ERROR, FATAL
|
||||
|
||||
from Difficult_Rocket.utils.thread import ThreadLock
|
||||
@ -24,8 +24,10 @@ from Difficult_Rocket.utils.thread import ThreadLock
|
||||
#
|
||||
|
||||
color_reset_suffix = "\033[0m"
|
||||
""" 只是用来重置颜色的后缀 """
|
||||
|
||||
"""
|
||||
OFF > FATAL > ERROR > WARN > INFO > FINE > FINER > DEBUG > TRACE > ALL
|
||||
logging.py
|
||||
CRITICAL = 50
|
||||
FATAL = CRITICAL
|
||||
@ -36,8 +38,8 @@ INFO = 20
|
||||
DEBUG = 10
|
||||
NOTSET = 0
|
||||
"""
|
||||
|
||||
DETAIL = 5
|
||||
ALL = NOTSET
|
||||
TRACE = 5
|
||||
|
||||
|
||||
class LogFileCache:
|
||||
@ -148,7 +150,7 @@ class Logger:
|
||||
if level < self.level:
|
||||
return None
|
||||
print(level, values, sep, end, flush, sep='|')
|
||||
write_text = sep.join(*values)
|
||||
write_text = sep.join(values)
|
||||
print(write_text)
|
||||
...
|
||||
|
||||
@ -194,10 +196,26 @@ class Logger:
|
||||
self.make_log(*values, level=FATAL, sep=sep, end=end, flush=flush)
|
||||
|
||||
|
||||
def color_in_033(*args) -> str:
|
||||
color_text = ';'.join(args)
|
||||
color_text = f'\033[{color_text}m'
|
||||
return color_text
|
||||
|
||||
|
||||
def rgb(r: int, g: int, b: int) -> Tuple[int, int, int]:
|
||||
return r, g, b
|
||||
|
||||
|
||||
def logging_color() -> Dict:
|
||||
...
|
||||
return {'info': ..., 'message': ...}
|
||||
|
||||
|
||||
|
||||
logger_configs = {
|
||||
'Logger': {
|
||||
'root': {
|
||||
'level': DETAIL,
|
||||
'level': TRACE,
|
||||
'color': {
|
||||
DEBUG: '\033[0m'
|
||||
},
|
||||
@ -205,17 +223,23 @@ logger_configs = {
|
||||
},
|
||||
},
|
||||
'Color': {
|
||||
'detail'
|
||||
TRACE: {'info': '', 'message': '\033[48;2;40;40;40m'},
|
||||
DEBUG: {'info': '', 'message': '\033[32;40m'},
|
||||
INFO: {'info': '', 'message': '\033[33;40m'},
|
||||
WARNING: {'info': '', 'message': ''},
|
||||
ERROR: {'info': '', 'message': ''},
|
||||
FATAL: {'info': '', 'message': ''}
|
||||
},
|
||||
'File': {
|
||||
'main_log_file': {
|
||||
'mode': 'a',
|
||||
'encoding': 'utf-8',
|
||||
'level': DEBUG,
|
||||
'file_name': '{main_time}_logs.md'
|
||||
'file_name': '{file_time}_logs.md'
|
||||
},
|
||||
},
|
||||
'Formatter': {
|
||||
'file_time': {'strftime': '%Y-%m-%d %H-%M'},
|
||||
'main_time': {'strftime': '%Y-%m-%d %H-%M-%S'},
|
||||
'version': 'game.version',
|
||||
'level': 'level',
|
||||
|
@ -34,13 +34,15 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
import math
|
||||
import time
|
||||
import weakref
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import pyglet
|
||||
from pyglet.util import with_metaclass
|
||||
|
||||
|
||||
class AbstractAudioPlayer(with_metaclass(ABCMeta, object)):
|
||||
class AbstractAudioPlayer(with_metaclass(ABCMeta)):
|
||||
"""Base class for driver audio players.
|
||||
"""
|
||||
|
||||
@ -206,7 +208,7 @@ class AbstractAudioPlayer(with_metaclass(ABCMeta, object)):
|
||||
self._source = weakref.proxy(value)
|
||||
|
||||
|
||||
class AbstractAudioDriver(with_metaclass(ABCMeta, object)):
|
||||
class AbstractAudioDriver(with_metaclass(ABCMeta)):
|
||||
@abstractmethod
|
||||
def create_audio_player(self, source, player):
|
||||
pass
|
||||
@ -218,3 +220,36 @@ class AbstractAudioDriver(with_metaclass(ABCMeta, object)):
|
||||
@abstractmethod
|
||||
def delete(self):
|
||||
pass
|
||||
|
||||
|
||||
class MediaEvent:
|
||||
"""Representation of a media event.
|
||||
|
||||
These events are used internally by some audio driver implementation to
|
||||
communicate events to the :class:`~pyglet.media.player.Player`.
|
||||
One example is the ``on_eos`` event.
|
||||
|
||||
Args:
|
||||
event (str): Event description.
|
||||
timestamp (float): The time when this event happens.
|
||||
*args: Any required positional argument to go along with this event.
|
||||
"""
|
||||
|
||||
__slots__ = 'event', 'timestamp', 'args'
|
||||
|
||||
def __init__(self, event, timestamp=0, *args):
|
||||
# Meaning of timestamp is dependent on context; and not seen by application.
|
||||
self.event = event
|
||||
self.timestamp = timestamp
|
||||
self.args = args
|
||||
|
||||
def sync_dispatch_to_player(self, player):
|
||||
pyglet.app.platform_event_loop.post_event(player, self.event, *self.args)
|
||||
time.sleep(0)
|
||||
# TODO sync with media.dispatch_events
|
||||
|
||||
def __repr__(self):
|
||||
return f"MediaEvent({self.event}, {self.timestamp}, {self.args})"
|
||||
|
||||
def __lt__(self, other):
|
||||
return hash(self) < hash(other)
|
||||
|
@ -38,9 +38,8 @@ import ctypes
|
||||
|
||||
from . import interface
|
||||
from pyglet.util import debug_print
|
||||
from pyglet.media.events import MediaEvent
|
||||
from pyglet.media.mediathreads import PlayerWorkerThread
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
|
||||
_debug = debug_print('debug_media')
|
||||
@ -194,7 +193,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
||||
and self._play_cursor > self._eos_cursor)
|
||||
|
||||
def _dispatch_new_event(self, event_name):
|
||||
MediaEvent(0, event_name)._sync_dispatch_to_player(self.player)
|
||||
MediaEvent(event_name).sync_dispatch_to_player(self.player)
|
||||
|
||||
def _get_audiodata(self):
|
||||
if self._audiodata_buffer is None or self._audiodata_buffer.length == 0:
|
||||
|
@ -37,8 +37,7 @@ import weakref
|
||||
|
||||
from . import interface
|
||||
from pyglet.util import debug_print
|
||||
from pyglet.media.events import MediaEvent
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.mediathreads import PlayerWorkerThread
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
|
||||
@ -316,7 +315,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
|
||||
assert _debug('No audio data left')
|
||||
if self._has_underrun():
|
||||
assert _debug('Underrun')
|
||||
MediaEvent(0, 'on_eos')._sync_dispatch_to_player(self.player)
|
||||
MediaEvent('on_eos').sync_dispatch_to_player(self.player)
|
||||
|
||||
def _queue_audio_data(self, audio_data, length):
|
||||
buf = self.alsource.get_buffer()
|
||||
|
@ -35,8 +35,7 @@
|
||||
|
||||
import weakref
|
||||
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.events import MediaEvent
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
from pyglet.util import debug_print
|
||||
|
||||
@ -277,7 +276,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
||||
|
||||
def _add_event_at_write_index(self, event_name):
|
||||
assert _debug('PulseAudioPlayer: Add event at index {}'.format(self._write_index))
|
||||
self._events.append((self._write_index, MediaEvent(0., event_name)))
|
||||
self._events.append((self._write_index, MediaEvent(event_name)))
|
||||
|
||||
def delete(self):
|
||||
assert _debug('Delete PulseAudioPlayer')
|
||||
|
@ -36,9 +36,8 @@
|
||||
import math
|
||||
|
||||
import pyglet
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
from pyglet.media.events import MediaEvent
|
||||
from pyglet.util import debug_print
|
||||
from . import interface
|
||||
|
||||
@ -204,7 +203,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
||||
if self.buffer_end_submitted:
|
||||
if buffers_queued == 0:
|
||||
self._xa2_source_voice.stop()
|
||||
MediaEvent(0, "on_eos")._sync_dispatch_to_player(self.player)
|
||||
MediaEvent("on_eos").sync_dispatch_to_player(self.player)
|
||||
else:
|
||||
current_buffers = []
|
||||
while buffers_queued < self.max_buffer_count:
|
||||
@ -243,12 +242,11 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
||||
self._dispatch_pending_events()
|
||||
|
||||
def _dispatch_new_event(self, event_name):
|
||||
MediaEvent(0, event_name)._sync_dispatch_to_player(self.player)
|
||||
MediaEvent(event_name).sync_dispatch_to_player(self.player)
|
||||
|
||||
def _add_audiodata_events(self, audio_data):
|
||||
for event in audio_data.events:
|
||||
event_cursor = self._write_cursor + event.timestamp * \
|
||||
self.source.audio_format.bytes_per_second
|
||||
event_cursor = self._write_cursor + event.timestamp * self.source.audio_format.bytes_per_second
|
||||
assert _debug('Adding event', event, 'at', event_cursor)
|
||||
self._events.append((event_cursor, event))
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
# pyglet
|
||||
# Copyright (c) 2006-2008 Alex Holkner
|
||||
# Copyright (c) 2008-2022 pyglet contributors
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of pyglet nor the names of its
|
||||
# contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written
|
||||
# permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
import time
|
||||
|
||||
import pyglet
|
||||
|
||||
|
||||
class MediaEvent:
|
||||
"""Representation of a media event.
|
||||
|
||||
These events are used internally by some audio driver implementation to
|
||||
communicate events to the :class:`~pyglet.media.player.Player`.
|
||||
One example is the ``on_eos`` event.
|
||||
|
||||
Args:
|
||||
timestamp (float): The time where this event happens.
|
||||
event (str): Event description.
|
||||
*args: Any required positional argument to go along with this event.
|
||||
"""
|
||||
def __init__(self, timestamp, event, *args):
|
||||
# Meaning of timestamp is dependent on context; and not seen by
|
||||
# application.
|
||||
self.timestamp = timestamp
|
||||
self.event = event
|
||||
self.args = args
|
||||
|
||||
def _sync_dispatch_to_player(self, player):
|
||||
pyglet.app.platform_event_loop.post_event(player, self.event, *self.args)
|
||||
time.sleep(0)
|
||||
# TODO sync with media.dispatch_events
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r, %r)' % (self.__class__.__name__,
|
||||
self.timestamp, self.event, self.args)
|
||||
|
||||
def __lt__(self, other):
|
||||
return hash(self) < hash(other)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user