mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-08 06:00:51 -07:00
Update arrow==1.2.1
This commit is contained in:
parent
03012cd2b2
commit
c79c48fcca
4 changed files with 297 additions and 31 deletions
|
@ -1 +1 @@
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.1"
|
||||||
|
|
|
@ -75,6 +75,7 @@ _GRANULARITY = Literal[
|
||||||
"day",
|
"day",
|
||||||
"week",
|
"week",
|
||||||
"month",
|
"month",
|
||||||
|
"quarter",
|
||||||
"year",
|
"year",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@ class Arrow:
|
||||||
_SECS_PER_DAY: Final[int] = 60 * 60 * 24
|
_SECS_PER_DAY: Final[int] = 60 * 60 * 24
|
||||||
_SECS_PER_WEEK: Final[int] = 60 * 60 * 24 * 7
|
_SECS_PER_WEEK: Final[int] = 60 * 60 * 24 * 7
|
||||||
_SECS_PER_MONTH: Final[float] = 60 * 60 * 24 * 30.5
|
_SECS_PER_MONTH: Final[float] = 60 * 60 * 24 * 30.5
|
||||||
|
_SECS_PER_QUARTER: Final[float] = 60 * 60 * 24 * 30.5 * 3
|
||||||
_SECS_PER_YEAR: Final[int] = 60 * 60 * 24 * 365
|
_SECS_PER_YEAR: Final[int] = 60 * 60 * 24 * 365
|
||||||
|
|
||||||
_SECS_MAP: Final[Mapping[TimeFrameLiteral, float]] = {
|
_SECS_MAP: Final[Mapping[TimeFrameLiteral, float]] = {
|
||||||
|
@ -141,6 +143,7 @@ class Arrow:
|
||||||
"day": _SECS_PER_DAY,
|
"day": _SECS_PER_DAY,
|
||||||
"week": _SECS_PER_WEEK,
|
"week": _SECS_PER_WEEK,
|
||||||
"month": _SECS_PER_MONTH,
|
"month": _SECS_PER_MONTH,
|
||||||
|
"quarter": _SECS_PER_QUARTER,
|
||||||
"year": _SECS_PER_YEAR,
|
"year": _SECS_PER_YEAR,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1245,12 +1248,14 @@ class Arrow:
|
||||||
delta = sign * delta_second / self._SECS_PER_WEEK
|
delta = sign * delta_second / self._SECS_PER_WEEK
|
||||||
elif granularity == "month":
|
elif granularity == "month":
|
||||||
delta = sign * delta_second / self._SECS_PER_MONTH
|
delta = sign * delta_second / self._SECS_PER_MONTH
|
||||||
|
elif granularity == "quarter":
|
||||||
|
delta = sign * delta_second / self._SECS_PER_QUARTER
|
||||||
elif granularity == "year":
|
elif granularity == "year":
|
||||||
delta = sign * delta_second / self._SECS_PER_YEAR
|
delta = sign * delta_second / self._SECS_PER_YEAR
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid level of granularity. "
|
"Invalid level of granularity. "
|
||||||
"Please select between 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'."
|
"Please select between 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter' or 'year'."
|
||||||
)
|
)
|
||||||
|
|
||||||
if trunc(abs(delta)) != 1:
|
if trunc(abs(delta)) != 1:
|
||||||
|
@ -1258,6 +1263,13 @@ class Arrow:
|
||||||
return locale.describe(granularity, delta, only_distance=only_distance)
|
return locale.describe(granularity, delta, only_distance=only_distance)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
if not granularity:
|
||||||
|
raise ValueError(
|
||||||
|
"Empty granularity list provided. "
|
||||||
|
"Please select one or more from 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'."
|
||||||
|
)
|
||||||
|
|
||||||
timeframes: List[Tuple[TimeFrameLiteral, float]] = []
|
timeframes: List[Tuple[TimeFrameLiteral, float]] = []
|
||||||
|
|
||||||
def gather_timeframes(_delta: float, _frame: TimeFrameLiteral) -> float:
|
def gather_timeframes(_delta: float, _frame: TimeFrameLiteral) -> float:
|
||||||
|
@ -1275,6 +1287,7 @@ class Arrow:
|
||||||
delta = float(delta_second)
|
delta = float(delta_second)
|
||||||
frames: Tuple[TimeFrameLiteral, ...] = (
|
frames: Tuple[TimeFrameLiteral, ...] = (
|
||||||
"year",
|
"year",
|
||||||
|
"quarter",
|
||||||
"month",
|
"month",
|
||||||
"week",
|
"week",
|
||||||
"day",
|
"day",
|
||||||
|
@ -1288,7 +1301,7 @@ class Arrow:
|
||||||
if len(timeframes) < len(granularity):
|
if len(timeframes) < len(granularity):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid level of granularity. "
|
"Invalid level of granularity. "
|
||||||
"Please select between 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'."
|
"Please select between 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter' or 'year'."
|
||||||
)
|
)
|
||||||
|
|
||||||
return locale.describe_multi(timeframes, only_distance=only_distance)
|
return locale.describe_multi(timeframes, only_distance=only_distance)
|
||||||
|
|
|
@ -143,4 +143,6 @@ DEHUMANIZE_LOCALES = {
|
||||||
"ta",
|
"ta",
|
||||||
"ta-in",
|
"ta-in",
|
||||||
"ta-lk",
|
"ta-lk",
|
||||||
|
"ur",
|
||||||
|
"ur-pk",
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ TimeFrameLiteral = Literal[
|
||||||
"weeks",
|
"weeks",
|
||||||
"month",
|
"month",
|
||||||
"months",
|
"months",
|
||||||
|
"quarter",
|
||||||
|
"quarters",
|
||||||
"year",
|
"year",
|
||||||
"years",
|
"years",
|
||||||
]
|
]
|
||||||
|
@ -98,6 +100,8 @@ class Locale:
|
||||||
"weeks": "",
|
"weeks": "",
|
||||||
"month": "",
|
"month": "",
|
||||||
"months": "",
|
"months": "",
|
||||||
|
"quarter": "",
|
||||||
|
"quarters": "",
|
||||||
"year": "",
|
"year": "",
|
||||||
"years": "",
|
"years": "",
|
||||||
}
|
}
|
||||||
|
@ -314,6 +318,8 @@ class EnglishLocale(Locale):
|
||||||
"weeks": "{0} weeks",
|
"weeks": "{0} weeks",
|
||||||
"month": "a month",
|
"month": "a month",
|
||||||
"months": "{0} months",
|
"months": "{0} months",
|
||||||
|
"quarter": "a quarter",
|
||||||
|
"quarters": "{0} quarters",
|
||||||
"year": "a year",
|
"year": "a year",
|
||||||
"years": "{0} years",
|
"years": "{0} years",
|
||||||
}
|
}
|
||||||
|
@ -2447,7 +2453,7 @@ class AzerbaijaniLocale(Locale):
|
||||||
|
|
||||||
timeframes = {
|
timeframes = {
|
||||||
"now": "indi",
|
"now": "indi",
|
||||||
"second": "saniyə",
|
"second": "bir saniyə",
|
||||||
"seconds": "{0} saniyə",
|
"seconds": "{0} saniyə",
|
||||||
"minute": "bir dəqiqə",
|
"minute": "bir dəqiqə",
|
||||||
"minutes": "{0} dəqiqə",
|
"minutes": "{0} dəqiqə",
|
||||||
|
@ -2455,9 +2461,11 @@ class AzerbaijaniLocale(Locale):
|
||||||
"hours": "{0} saat",
|
"hours": "{0} saat",
|
||||||
"day": "bir gün",
|
"day": "bir gün",
|
||||||
"days": "{0} gün",
|
"days": "{0} gün",
|
||||||
|
"week": "bir həftə",
|
||||||
|
"weeks": "{0} həftə",
|
||||||
"month": "bir ay",
|
"month": "bir ay",
|
||||||
"months": "{0} ay",
|
"months": "{0} ay",
|
||||||
"year": "il",
|
"year": "bir il",
|
||||||
"years": "{0} il",
|
"years": "{0} il",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3370,15 +3378,15 @@ class HebrewLocale(Locale):
|
||||||
"minute": "דקה",
|
"minute": "דקה",
|
||||||
"minutes": "{0} דקות",
|
"minutes": "{0} דקות",
|
||||||
"hour": "שעה",
|
"hour": "שעה",
|
||||||
"hours": {"2": "שעתיים", "general": "{0} שעות"},
|
"hours": {"2": "שעתיים", "ten": "{0} שעות", "higher": "{0} שעות"},
|
||||||
"day": "יום",
|
"day": "יום",
|
||||||
"days": {"2": "יומיים", "general": "{0} ימים"},
|
"days": {"2": "יומיים", "ten": "{0} ימים", "higher": "{0} יום"},
|
||||||
"week": "שבוע",
|
"week": "שבוע",
|
||||||
"weeks": {"2": "שבועיים", "general": "{0} שבועות"},
|
"weeks": {"2": "שבועיים", "ten": "{0} שבועות", "higher": "{0} שבועות"},
|
||||||
"month": "חודש",
|
"month": "חודש",
|
||||||
"months": {"2": "חודשיים", "general": "{0} חודשים"},
|
"months": {"2": "חודשיים", "ten": "{0} חודשים", "higher": "{0} חודשים"},
|
||||||
"year": "שנה",
|
"year": "שנה",
|
||||||
"years": {"2": "שנתיים", "general": "{0} שנים"},
|
"years": {"2": "שנתיים", "ten": "{0} שנים", "higher": "{0} שנה"},
|
||||||
}
|
}
|
||||||
|
|
||||||
meridians = {
|
meridians = {
|
||||||
|
@ -3422,18 +3430,16 @@ class HebrewLocale(Locale):
|
||||||
day_names = ["", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"]
|
day_names = ["", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"]
|
||||||
day_abbreviations = ["", "ב׳", "ג׳", "ד׳", "ה׳", "ו׳", "ש׳", "א׳"]
|
day_abbreviations = ["", "ב׳", "ג׳", "ד׳", "ה׳", "ו׳", "ש׳", "א׳"]
|
||||||
|
|
||||||
def _format_timeframe(
|
def _format_timeframe(self, timeframe: TimeFrameLiteral, delta: int) -> str:
|
||||||
self, timeframe: TimeFrameLiteral, delta: Union[float, int]
|
|
||||||
) -> str:
|
|
||||||
"""Hebrew couple of <timeframe> aware"""
|
|
||||||
form = self.timeframes[timeframe]
|
form = self.timeframes[timeframe]
|
||||||
delta = abs(trunc(delta))
|
delta = abs(delta)
|
||||||
|
|
||||||
if isinstance(form, Mapping):
|
if isinstance(form, Mapping):
|
||||||
if delta == 2:
|
if delta == 2:
|
||||||
form = form["2"]
|
form = form["2"]
|
||||||
|
elif delta == 0 or 2 < delta <= 10:
|
||||||
|
form = form["ten"]
|
||||||
else:
|
else:
|
||||||
form = form["general"]
|
form = form["higher"]
|
||||||
|
|
||||||
return form.format(delta)
|
return form.format(delta)
|
||||||
|
|
||||||
|
@ -5213,13 +5219,13 @@ class SerbianLocale(Locale):
|
||||||
|
|
||||||
month_names = [
|
month_names = [
|
||||||
"",
|
"",
|
||||||
"januar", # Јануар
|
"januar", # јануар
|
||||||
"februar", # фебруар
|
"februar", # фебруар
|
||||||
"mart", # март
|
"mart", # март
|
||||||
"april", # април
|
"april", # април
|
||||||
"maj", # мај
|
"maj", # мај
|
||||||
"juni", # јун
|
"jun", # јун
|
||||||
"juli", # јул
|
"jul", # јул
|
||||||
"avgust", # август
|
"avgust", # август
|
||||||
"septembar", # септембар
|
"septembar", # септембар
|
||||||
"oktobar", # октобар
|
"oktobar", # октобар
|
||||||
|
@ -5229,18 +5235,18 @@ class SerbianLocale(Locale):
|
||||||
|
|
||||||
month_abbreviations = [
|
month_abbreviations = [
|
||||||
"",
|
"",
|
||||||
"jan.",
|
"jan",
|
||||||
"febr.",
|
"feb",
|
||||||
"mart",
|
"mar",
|
||||||
"april",
|
"apr",
|
||||||
"maj",
|
"maj",
|
||||||
"juni",
|
"jun",
|
||||||
"juli",
|
"jul",
|
||||||
"avg.",
|
"avg",
|
||||||
"sept.",
|
"sep",
|
||||||
"okt.",
|
"okt",
|
||||||
"nov.",
|
"nov",
|
||||||
"dec.",
|
"dec",
|
||||||
]
|
]
|
||||||
|
|
||||||
day_names = [
|
day_names = [
|
||||||
|
@ -5644,3 +5650,248 @@ class AlbanianLocale(Locale):
|
||||||
"sht",
|
"sht",
|
||||||
"die",
|
"die",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class SinhalaLocale(Locale):
|
||||||
|
|
||||||
|
names = ["si", "si-lk"]
|
||||||
|
|
||||||
|
past = "{0}ට පෙර"
|
||||||
|
future = "{0}"
|
||||||
|
and_word = "සහ"
|
||||||
|
|
||||||
|
timeframes: ClassVar[Mapping[TimeFrameLiteral, Union[Mapping[str, str], str]]] = {
|
||||||
|
"now": "දැන්",
|
||||||
|
"second": {
|
||||||
|
"past": "තත්පරයක",
|
||||||
|
"future": "තත්පරයකින්",
|
||||||
|
}, # ක් is the article
|
||||||
|
"seconds": {
|
||||||
|
"past": "තත්පර {0} ක",
|
||||||
|
"future": "තත්පර {0} කින්",
|
||||||
|
},
|
||||||
|
"minute": {
|
||||||
|
"past": "විනාඩියක",
|
||||||
|
"future": "විනාඩියකින්",
|
||||||
|
},
|
||||||
|
"minutes": {
|
||||||
|
"past": "විනාඩි {0} ක",
|
||||||
|
"future": "මිනිත්තු {0} කින්",
|
||||||
|
},
|
||||||
|
"hour": {"past": "පැයක", "future": "පැයකින්"},
|
||||||
|
"hours": {
|
||||||
|
"past": "පැය {0} ක",
|
||||||
|
"future": "පැය {0} කින්",
|
||||||
|
},
|
||||||
|
"day": {"past": "දිනක", "future": "දිනකට"},
|
||||||
|
"days": {
|
||||||
|
"past": "දින {0} ක",
|
||||||
|
"future": "දින {0} කින්",
|
||||||
|
},
|
||||||
|
"week": {"past": "සතියක", "future": "සතියකින්"},
|
||||||
|
"weeks": {
|
||||||
|
"past": "සති {0} ක",
|
||||||
|
"future": "සති {0} කින්",
|
||||||
|
},
|
||||||
|
"month": {"past": "මාසයක", "future": "එය මාසය තුළ"},
|
||||||
|
"months": {
|
||||||
|
"past": "මාස {0} ක",
|
||||||
|
"future": "මාස {0} කින්",
|
||||||
|
},
|
||||||
|
"year": {"past": "වසරක", "future": "වසරක් තුළ"},
|
||||||
|
"years": {
|
||||||
|
"past": "අවුරුදු {0} ක",
|
||||||
|
"future": "අවුරුදු {0} තුළ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
# Sinhala: the general format to describe timeframe is different from past and future,
|
||||||
|
# so we do not copy the original timeframes dictionary
|
||||||
|
timeframes_only_distance = dict()
|
||||||
|
timeframes_only_distance["second"] = "තත්පරයක්"
|
||||||
|
timeframes_only_distance["seconds"] = "තත්පර {0}"
|
||||||
|
timeframes_only_distance["minute"] = "මිනිත්තුවක්"
|
||||||
|
timeframes_only_distance["minutes"] = "විනාඩි {0}"
|
||||||
|
timeframes_only_distance["hour"] = "පැයක්"
|
||||||
|
timeframes_only_distance["hours"] = "පැය {0}"
|
||||||
|
timeframes_only_distance["day"] = "දවසක්"
|
||||||
|
timeframes_only_distance["days"] = "දවස් {0}"
|
||||||
|
timeframes_only_distance["week"] = "සතියක්"
|
||||||
|
timeframes_only_distance["weeks"] = "සති {0}"
|
||||||
|
timeframes_only_distance["month"] = "මාසයක්"
|
||||||
|
timeframes_only_distance["months"] = "මාස {0}"
|
||||||
|
timeframes_only_distance["year"] = "අවුරුද්දක්"
|
||||||
|
timeframes_only_distance["years"] = "අවුරුදු {0}"
|
||||||
|
|
||||||
|
def _format_timeframe(self, timeframe: TimeFrameLiteral, delta: int) -> str:
|
||||||
|
"""
|
||||||
|
Sinhala awares time frame format function, takes into account
|
||||||
|
the differences between general, past, and future forms (three different suffixes).
|
||||||
|
"""
|
||||||
|
abs_delta = abs(delta)
|
||||||
|
form = self.timeframes[timeframe]
|
||||||
|
|
||||||
|
if isinstance(form, str):
|
||||||
|
return form.format(abs_delta)
|
||||||
|
|
||||||
|
if delta > 0:
|
||||||
|
key = "future"
|
||||||
|
else:
|
||||||
|
key = "past"
|
||||||
|
form = form[key]
|
||||||
|
|
||||||
|
return form.format(abs_delta)
|
||||||
|
|
||||||
|
def describe(
|
||||||
|
self,
|
||||||
|
timeframe: TimeFrameLiteral,
|
||||||
|
delta: Union[float, int] = 1, # key is always future when only_distance=False
|
||||||
|
only_distance: bool = False,
|
||||||
|
) -> str:
|
||||||
|
"""Describes a delta within a timeframe in plain language.
|
||||||
|
|
||||||
|
:param timeframe: a string representing a timeframe.
|
||||||
|
:param delta: a quantity representing a delta in a timeframe.
|
||||||
|
:param only_distance: return only distance eg: "11 seconds" without "in" or "ago" keywords
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not only_distance:
|
||||||
|
return super().describe(timeframe, delta, only_distance)
|
||||||
|
# Sinhala uses a different case without 'in' or 'ago'
|
||||||
|
humanized = self.timeframes_only_distance[timeframe].format(trunc(abs(delta)))
|
||||||
|
|
||||||
|
return humanized
|
||||||
|
|
||||||
|
month_names = [
|
||||||
|
"",
|
||||||
|
"ජනවාරි",
|
||||||
|
"පෙබරවාරි",
|
||||||
|
"මාර්තු",
|
||||||
|
"අප්රේල්",
|
||||||
|
"මැයි",
|
||||||
|
"ජූනි",
|
||||||
|
"ජූලි",
|
||||||
|
"අගෝස්තු",
|
||||||
|
"සැප්තැම්බර්",
|
||||||
|
"ඔක්තෝබර්",
|
||||||
|
"නොවැම්බර්",
|
||||||
|
"දෙසැම්බර්",
|
||||||
|
]
|
||||||
|
|
||||||
|
month_abbreviations = [
|
||||||
|
"",
|
||||||
|
"ජන",
|
||||||
|
"පෙබ",
|
||||||
|
"මාර්",
|
||||||
|
"අප්රේ",
|
||||||
|
"මැයි",
|
||||||
|
"ජුනි",
|
||||||
|
"ජූලි",
|
||||||
|
"අගෝ",
|
||||||
|
"සැප්",
|
||||||
|
"ඔක්",
|
||||||
|
"නොවැ",
|
||||||
|
"දෙසැ",
|
||||||
|
]
|
||||||
|
|
||||||
|
day_names = [
|
||||||
|
"",
|
||||||
|
"සදුදා",
|
||||||
|
"අඟහරැවදා",
|
||||||
|
"බදාදා",
|
||||||
|
"බ්රහස්පතින්දා",
|
||||||
|
"සිකුරාදා",
|
||||||
|
"සෙනසුරාදා",
|
||||||
|
"ඉරිදා",
|
||||||
|
]
|
||||||
|
|
||||||
|
day_abbreviations = [
|
||||||
|
"",
|
||||||
|
"සදුද",
|
||||||
|
"බදා",
|
||||||
|
"බදා",
|
||||||
|
"සිකු",
|
||||||
|
"සෙන",
|
||||||
|
"අ",
|
||||||
|
"ඉරිදා",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class UrduLocale(Locale):
|
||||||
|
|
||||||
|
names = ["ur", "ur-pk"]
|
||||||
|
|
||||||
|
past = "پہلے {0}"
|
||||||
|
future = "میں {0}"
|
||||||
|
and_word = "اور"
|
||||||
|
|
||||||
|
timeframes = {
|
||||||
|
"now": "ابھی",
|
||||||
|
"second": "ایک سیکنڈ",
|
||||||
|
"seconds": "{0} سیکنڈ",
|
||||||
|
"minute": "ایک منٹ",
|
||||||
|
"minutes": "{0} منٹ",
|
||||||
|
"hour": "ایک گھنٹے",
|
||||||
|
"hours": "{0} گھنٹے",
|
||||||
|
"day": "ایک دن",
|
||||||
|
"days": "{0} دن",
|
||||||
|
"week": "ایک ہفتے",
|
||||||
|
"weeks": "{0} ہفتے",
|
||||||
|
"month": "ایک مہینہ",
|
||||||
|
"months": "{0} ماہ",
|
||||||
|
"year": "ایک سال",
|
||||||
|
"years": "{0} سال",
|
||||||
|
}
|
||||||
|
|
||||||
|
month_names = [
|
||||||
|
"",
|
||||||
|
"جنوری",
|
||||||
|
"فروری",
|
||||||
|
"مارچ",
|
||||||
|
"اپریل",
|
||||||
|
"مئی",
|
||||||
|
"جون",
|
||||||
|
"جولائی",
|
||||||
|
"اگست",
|
||||||
|
"ستمبر",
|
||||||
|
"اکتوبر",
|
||||||
|
"نومبر",
|
||||||
|
"دسمبر",
|
||||||
|
]
|
||||||
|
|
||||||
|
month_abbreviations = [
|
||||||
|
"",
|
||||||
|
"جنوری",
|
||||||
|
"فروری",
|
||||||
|
"مارچ",
|
||||||
|
"اپریل",
|
||||||
|
"مئی",
|
||||||
|
"جون",
|
||||||
|
"جولائی",
|
||||||
|
"اگست",
|
||||||
|
"ستمبر",
|
||||||
|
"اکتوبر",
|
||||||
|
"نومبر",
|
||||||
|
"دسمبر",
|
||||||
|
]
|
||||||
|
|
||||||
|
day_names = [
|
||||||
|
"",
|
||||||
|
"سوموار",
|
||||||
|
"منگل",
|
||||||
|
"بدھ",
|
||||||
|
"جمعرات",
|
||||||
|
"جمعہ",
|
||||||
|
"ہفتہ",
|
||||||
|
"اتوار",
|
||||||
|
]
|
||||||
|
|
||||||
|
day_abbreviations = [
|
||||||
|
"",
|
||||||
|
"سوموار",
|
||||||
|
"منگل",
|
||||||
|
"بدھ",
|
||||||
|
"جمعرات",
|
||||||
|
"جمعہ",
|
||||||
|
"ہفتہ",
|
||||||
|
"اتوار",
|
||||||
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue