doc, pitime.h decomposition
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Timer
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,79 +18,18 @@
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "pitime.h"
|
||||
#ifdef QNX
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifndef MICRO_PIP
|
||||
# include "pisystemtests.h"
|
||||
#elif defined(ARDUINO)
|
||||
# include <Arduino.h>
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
extern FILETIME __pi_ftjan1970;
|
||||
long long __PIQueryPerformanceCounter() {LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart;}
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
//# include <mach/mach_traps.h>
|
||||
//# include <mach/mach.h>
|
||||
# include <mach/clock.h>
|
||||
//# include <crt_externs.h>
|
||||
extern clock_serv_t __pi_mac_clock;
|
||||
#endif
|
||||
#ifdef MICRO_PIP
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
//! \addtogroup Core
|
||||
//! \{
|
||||
//! \class PISystemTime pitime.h
|
||||
//! \brief
|
||||
//! \~english System time with nanosecond precision
|
||||
//! \~russian Системное время с точностью до наносекунд
|
||||
//!
|
||||
//! \~english \section PISystemTime_sec0 Synopsis
|
||||
//! \~russian \section PISystemTime_sec0 Краткий обзор
|
||||
//! \~english
|
||||
//! This class provide arithmetic functions for POSIX system time.
|
||||
//! This time represents as seconds and nanosecons in integer formats.
|
||||
//! You can take current system time with function \a PISystemTime::current(),
|
||||
//! compare times, sum or subtract two times, convert time to/from
|
||||
//! seconds, milliseconds, microseconds or nanoseconds.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Этот класс предоставляет арифметику для системного времени в формате POSIX.
|
||||
//! Это время представлено в виде целочисленных секунд и наносекунд.
|
||||
//! Можно взять текущее время с помощью метода \a PISystemTime::current(),
|
||||
//! сравнивать, суммировать и вычитать времена, преобразовывать в/из
|
||||
//! секунд, миллисекунд, микросекунд и наносекунд.
|
||||
//!
|
||||
//! \~english \section PISystemTime_sec1 Example
|
||||
//! \~russian \section PISystemTime_sec1 Пример
|
||||
//! \~\snippet pitimer.cpp system_time
|
||||
//!
|
||||
//! \}
|
||||
|
||||
|
||||
//! \addtogroup Core
|
||||
//! \{
|
||||
//! \class PITimeMeasurer pitime.h
|
||||
//! \brief
|
||||
//! \~english Time measurements
|
||||
//! \~russian Измерение времени
|
||||
//!
|
||||
//! \~english \section PITimeMeasurer_sec0 Usage
|
||||
//! \~russian \section PITimeMeasurer_sec0 Использование
|
||||
//! \~english
|
||||
//! Function \a reset() set time mark to current
|
||||
//! system time, then functions "double elapsed_*()" returns time elapsed from this mark.
|
||||
//! These functions can returns nano-, micro-, milli- and seconds with suffixes "n", "u", "m"
|
||||
//! and "s"
|
||||
//!
|
||||
//! \~russian
|
||||
//! Метод \a reset() устанавливает текущую метку системного времени. Далее методы
|
||||
//! "double elapsed_*()" возвращают время, прошедшее от установленной метки.
|
||||
//! Эти методы возвращают нано, микро, милли и секунды с приставками
|
||||
//! "n", "u", "m" и "s".
|
||||
//!
|
||||
//! \}
|
||||
|
||||
|
||||
//! \details
|
||||
//! \~english
|
||||
@@ -121,431 +59,3 @@ void piUSleep(int usecs) {
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool operator ==(const PITime & t0, const PITime & t1) {
|
||||
return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PITime & t0, const PITime & t1) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds < t1.seconds;
|
||||
} else return t0.minutes < t1.minutes;
|
||||
} else return t0.hours < t1.hours;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PITime & t0, const PITime & t1) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds > t1.seconds;
|
||||
} else return t0.minutes > t1.minutes;
|
||||
} else return t0.hours > t1.hours;
|
||||
}
|
||||
|
||||
bool operator ==(const PIDate & t0, const PIDate & t1) {
|
||||
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PIDate & t0, const PIDate & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
return t0.day < t1.day;
|
||||
} else return t0.month < t1.month;
|
||||
} else return t0.year < t1.year;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PIDate & t0, const PIDate & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
return t0.day > t1.day;
|
||||
} else return t0.month > t1.month;
|
||||
} else return t0.year > t1.year;
|
||||
}
|
||||
|
||||
bool operator ==(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day &&
|
||||
t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
if (t0.day == t1.day) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds < t1.seconds;
|
||||
} else return t0.minutes < t1.minutes;
|
||||
} else return t0.hours < t1.hours;
|
||||
} else return t0.day < t1.day;
|
||||
} else return t0.month < t1.month;
|
||||
} else return t0.year < t1.year;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
if (t0.day == t1.day) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds > t1.seconds;
|
||||
} else return t0.minutes > t1.minutes;
|
||||
} else return t0.hours > t1.hours;
|
||||
} else return t0.day > t1.day;
|
||||
} else return t0.month > t1.month;
|
||||
} else return t0.year > t1.year;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PITime::toSystemTime() const {
|
||||
return PISystemTime((hours * 60. + minutes) * 60. + seconds, milliseconds * 1000.);
|
||||
}
|
||||
|
||||
|
||||
PITime PITime::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PITime t;
|
||||
t.seconds = pt->tm_sec;
|
||||
t.minutes = pt->tm_min;
|
||||
t.hours = pt->tm_hour;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
PITime PITime::fromSystemTime(const PISystemTime & st) {
|
||||
double s = st.toSeconds();
|
||||
int v = s;
|
||||
PITime ret;
|
||||
ret.milliseconds = (s - v) * 1000;
|
||||
ret.seconds = v % 60; v = (v - ret.seconds) / 60;
|
||||
ret.minutes = v % 60; v = (v - ret.minutes) / 60;
|
||||
ret.hours = v;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIDate PIDate::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PIDate d;
|
||||
d.day = pt->tm_mday;
|
||||
d.month = pt->tm_mon + 1;
|
||||
d.year = pt->tm_year + 1900;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
PIDateTime PIDateTime::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PIDateTime dt;
|
||||
dt.milliseconds = 0;
|
||||
dt.seconds = pt->tm_sec;
|
||||
dt.minutes = pt->tm_min;
|
||||
dt.hours = pt->tm_hour;
|
||||
dt.day = pt->tm_mday;
|
||||
dt.month = pt->tm_mon + 1;
|
||||
dt.year = pt->tm_year + 1900;
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
//! \details
|
||||
//! \warning
|
||||
//! \~english
|
||||
//! Use this function to sleep for difference of system times or constructs system time.
|
||||
//! If you call this function on system time returned with \a PISystemTime::current() thread will be sleep almost forever
|
||||
//! \~russian
|
||||
//! Используйте этот метод для ожидания разниц системных времен или своего времени.
|
||||
//! Если метод будет вызван для системного времени \a PISystemTime::current(), то
|
||||
//! ожидание будет почти бесконечным
|
||||
void PISystemTime::sleep() {
|
||||
piUSleep(piFloord(toMicroseconds()));
|
||||
}
|
||||
|
||||
|
||||
void PISystemTime::toTimespec(void * ts) {
|
||||
#ifndef WINDOWS
|
||||
((timespec*)ts)->tv_sec = seconds;
|
||||
((timespec*)ts)->tv_nsec = nanoseconds;
|
||||
#endif
|
||||
}
|
||||
|
||||
PISystemTime PISystemTime::abs() const {
|
||||
if (seconds < 0)
|
||||
return PISystemTime(piAbsl(seconds) - 1, 1000000000l - piAbsl(nanoseconds));
|
||||
else
|
||||
return PISystemTime(piAbsl(seconds), piAbsl(nanoseconds));
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PISystemTime::current(bool precise_but_not_system) {
|
||||
#ifdef WINDOWS
|
||||
if (precise_but_not_system) {
|
||||
llong qpc(0);
|
||||
if (__pi_perf_freq > 0) {
|
||||
qpc = __PIQueryPerformanceCounter();
|
||||
return PISystemTime::fromSeconds(qpc / double(__pi_perf_freq));
|
||||
}
|
||||
return PISystemTime();
|
||||
} else {
|
||||
FILETIME ft, sft;
|
||||
# if (_WIN32_WINNT >= 0x0602)
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
# else
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
# endif
|
||||
sft.dwHighDateTime = ft.dwHighDateTime - __pi_ftjan1970.dwHighDateTime;
|
||||
if (ft.dwLowDateTime < __pi_ftjan1970.dwLowDateTime) {
|
||||
sft.dwLowDateTime = ft.dwLowDateTime + (0xFFFFFFFF - __pi_ftjan1970.dwLowDateTime);
|
||||
sft.dwHighDateTime--;
|
||||
} else
|
||||
sft.dwLowDateTime = ft.dwLowDateTime - __pi_ftjan1970.dwLowDateTime;
|
||||
ullong lt = ullong(sft.dwHighDateTime) * 0x100000000U + ullong(sft.dwLowDateTime);
|
||||
return PISystemTime(lt / 10000000U, (lt % 10000000U) * 100U);
|
||||
}
|
||||
#elif defined(MAC_OS)
|
||||
mach_timespec_t t_cur;
|
||||
clock_get_time(__pi_mac_clock, &t_cur);
|
||||
#elif defined(MICRO_PIP)
|
||||
timespec t_cur;
|
||||
# ifdef ARDUINO
|
||||
static const uint32_t offSetSinceEpoch_s = 1581897605UL;
|
||||
uint32_t mt = millis();
|
||||
t_cur.tv_sec = offSetSinceEpoch_s + (mt / 1000);
|
||||
t_cur.tv_nsec = (mt - (mt / 1000)) * 1000000UL;
|
||||
# else
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
gettimeofday(&tv, NULL);
|
||||
t_cur.tv_sec = tv.tv_sec;
|
||||
t_cur.tv_nsec = tv.tv_usec * 1000;
|
||||
# endif
|
||||
#else
|
||||
timespec t_cur;
|
||||
clock_gettime(precise_but_not_system ? CLOCK_MONOTONIC : 0, &t_cur);
|
||||
#endif
|
||||
#ifndef WINDOWS
|
||||
return PISystemTime(t_cur.tv_sec, t_cur.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIString PITime::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(hours));
|
||||
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(minutes));
|
||||
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(seconds));
|
||||
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
|
||||
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
|
||||
ts.replace("z", PIString::fromNumber(milliseconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString PIDate::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(month));
|
||||
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString PIDateTime::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(month));
|
||||
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(day));
|
||||
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(hours));
|
||||
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(minutes));
|
||||
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(seconds));
|
||||
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
|
||||
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
|
||||
ts.replace("z", PIString::fromNumber(milliseconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
time_t PIDateTime::toSecondSinceEpoch() const {
|
||||
tm pt;
|
||||
memset(&pt, 0, sizeof(pt));
|
||||
pt.tm_sec = seconds;
|
||||
pt.tm_min = minutes;
|
||||
pt.tm_hour = hours;
|
||||
pt.tm_mday = day;
|
||||
pt.tm_mon = month - 1;
|
||||
#ifdef WINDOWS
|
||||
pt.tm_year = piMaxi(year - 1900, 70);
|
||||
#else
|
||||
pt.tm_year = piMaxi(year - 1900, 0);
|
||||
#endif
|
||||
return mktime(&pt);
|
||||
}
|
||||
|
||||
|
||||
PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) {
|
||||
tm * pt = localtime(&sec);
|
||||
PIDateTime dt;
|
||||
dt.seconds = pt->tm_sec;
|
||||
dt.minutes = pt->tm_min;
|
||||
dt.hours = pt->tm_hour;
|
||||
dt.day = pt->tm_mday;
|
||||
dt.month = pt->tm_mon + 1;
|
||||
dt.year = pt->tm_year + 1900;
|
||||
return dt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIString time2string(const PITime & time, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(time.hours));
|
||||
ts.replace("mm", PIString::fromNumber(time.minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(time.minutes));
|
||||
ts.replace("ss", PIString::fromNumber(time.seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(time.seconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString date2string(const PIDate & date, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(date.year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(date.year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(date.month));
|
||||
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(date.day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString datetime2string(const PIDateTime & date, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(date.hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(date.hours));
|
||||
ts.replace("mm", PIString::fromNumber(date.minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(date.minutes));
|
||||
ts.replace("ss", PIString::fromNumber(date.seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(date.seconds));
|
||||
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(date.year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(date.year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(date.month));
|
||||
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(date.day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PITimeMeasurer::PITimeMeasurer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_n() const {
|
||||
return (PISystemTime::current(true) - t_st).toNanoseconds()
|
||||
#ifndef MICRO_PIP
|
||||
- PISystemTests::time_elapsed_ns
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_u() const {
|
||||
return (PISystemTime::current(true) - t_st).toMicroseconds()
|
||||
#ifndef MICRO_PIP
|
||||
- PISystemTests::time_elapsed_ns / 1.E+3
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_m() const {
|
||||
return (PISystemTime::current(true) - t_st).toMilliseconds()
|
||||
#ifndef MICRO_PIP
|
||||
- PISystemTests::time_elapsed_ns / 1.E+6
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_s() const {
|
||||
return (PISystemTime::current(true) - t_st).toSeconds()
|
||||
#ifndef MICRO_PIP
|
||||
- PISystemTests::time_elapsed_ns / 1.E+9
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PITimeMeasurer::elapsed() const {
|
||||
return (PISystemTime::current(true) - t_st);
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PITime & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "PITime(" << v.hours << ":";
|
||||
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIDate & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "PIDate(" << v.day << "-";
|
||||
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
|
||||
s << v.year << ")";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIDateTime & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "PIDateTime(";
|
||||
s << v.day << "-";
|
||||
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
|
||||
s << v.year << " ";
|
||||
s << v.hours << ":";
|
||||
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user