mirror of
https://github.com/RaidMax/IW4M-Admin.git
synced 2025-06-27 07:30:08 -05:00
Add server version to master api
Add IsEvadedOffense to EFPenalty Fix remote log reading in not Windows
This commit is contained in:
386
Master/env_master/Lib/site-packages/pygal/util.py
Normal file
386
Master/env_master/Lib/site-packages/pygal/util.py
Normal file
@ -0,0 +1,386 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of pygal
|
||||
#
|
||||
# A python svg graph plotting library
|
||||
# Copyright © 2012-2016 Kozea
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Various utility functions"""
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import re
|
||||
from decimal import Decimal
|
||||
from math import ceil, cos, floor, log10, pi, sin
|
||||
|
||||
from pygal._compat import _ellipsis, to_unicode, u
|
||||
|
||||
|
||||
def float_format(number):
|
||||
"""Format a float to a precision of 3, without zeroes or dots"""
|
||||
return ("%.3f" % number).rstrip('0').rstrip('.')
|
||||
|
||||
|
||||
def majorize(values):
|
||||
"""Filter sequence to return only major considered numbers"""
|
||||
sorted_values = sorted(values)
|
||||
if len(values) <= 3 or (
|
||||
abs(2 * sorted_values[1] - sorted_values[0] - sorted_values[2]) >
|
||||
abs(1.5 * (sorted_values[1] - sorted_values[0]))):
|
||||
return []
|
||||
values_step = sorted_values[1] - sorted_values[0]
|
||||
full_range = sorted_values[-1] - sorted_values[0]
|
||||
step = 10 ** int(log10(full_range))
|
||||
if step == values_step:
|
||||
step *= 10
|
||||
step_factor = 10 ** (int(log10(step)) + 1)
|
||||
if round(step * step_factor) % (round(values_step * step_factor) or 1):
|
||||
# TODO: Find lower common multiple instead
|
||||
step *= values_step
|
||||
if full_range <= 2 * step:
|
||||
step *= .5
|
||||
elif full_range >= 5 * step:
|
||||
step *= 5
|
||||
major_values = [
|
||||
value for value in values if value / step == round(value / step)]
|
||||
return [value for value in sorted_values if value in major_values]
|
||||
|
||||
|
||||
def round_to_int(number, precision):
|
||||
"""Round a number to a precision"""
|
||||
precision = int(precision)
|
||||
rounded = (int(number) + precision / 2) // precision * precision
|
||||
return rounded
|
||||
|
||||
|
||||
def round_to_float(number, precision):
|
||||
"""Round a float to a precision"""
|
||||
rounded = Decimal(
|
||||
str(floor((number + precision / 2) // precision))
|
||||
) * Decimal(str(precision))
|
||||
return float(rounded)
|
||||
|
||||
|
||||
def round_to_scale(number, precision):
|
||||
"""Round a number or a float to a precision"""
|
||||
if precision < 1:
|
||||
return round_to_float(number, precision)
|
||||
return round_to_int(number, precision)
|
||||
|
||||
|
||||
def cut(list_, index=0):
|
||||
"""Cut a list by index or arg"""
|
||||
if isinstance(index, int):
|
||||
cut_ = lambda x: x[index]
|
||||
else:
|
||||
cut_ = lambda x: getattr(x, index)
|
||||
return list(map(cut_, list_))
|
||||
|
||||
|
||||
def rad(degrees):
|
||||
"""Convert degrees in radiants"""
|
||||
return pi * degrees / 180
|
||||
|
||||
|
||||
def deg(radiants):
|
||||
"""Convert radiants in degrees"""
|
||||
return 180 * radiants / pi
|
||||
|
||||
|
||||
def _swap_curly(string):
|
||||
"""Swap single and double curly brackets"""
|
||||
return (string
|
||||
.replace('{{ ', '{{')
|
||||
.replace('{{', '\x00')
|
||||
.replace('{', '{{')
|
||||
.replace('\x00', '{')
|
||||
.replace(' }}', '}}')
|
||||
.replace('}}', '\x00')
|
||||
.replace('}', '}}')
|
||||
.replace('\x00', '}'))
|
||||
|
||||
|
||||
def template(string, **kwargs):
|
||||
"""Format a string using double braces"""
|
||||
return _swap_curly(string).format(**kwargs)
|
||||
|
||||
|
||||
swap = lambda tuple_: tuple(reversed(tuple_))
|
||||
ident = lambda x: x
|
||||
|
||||
|
||||
def compute_logarithmic_scale(min_, max_, min_scale, max_scale):
|
||||
"""Compute an optimal scale for logarithmic"""
|
||||
if max_ <= 0 or min_ <= 0:
|
||||
return []
|
||||
min_order = int(floor(log10(min_)))
|
||||
max_order = int(ceil(log10(max_)))
|
||||
positions = []
|
||||
amplitude = max_order - min_order
|
||||
if amplitude <= 1:
|
||||
return []
|
||||
detail = 10.
|
||||
while amplitude * detail < min_scale * 5:
|
||||
detail *= 2
|
||||
while amplitude * detail > max_scale * 3:
|
||||
detail /= 2
|
||||
for order in range(min_order, max_order + 1):
|
||||
for i in range(int(detail)):
|
||||
tick = (10 * i / detail or 1) * 10 ** order
|
||||
tick = round_to_scale(tick, tick)
|
||||
if min_ <= tick <= max_ and tick not in positions:
|
||||
positions.append(tick)
|
||||
return positions
|
||||
|
||||
|
||||
def compute_scale(
|
||||
min_, max_, logarithmic, order_min,
|
||||
min_scale, max_scale):
|
||||
"""Compute an optimal scale between min and max"""
|
||||
if min_ == 0 and max_ == 0:
|
||||
return [0]
|
||||
if max_ - min_ == 0:
|
||||
return [min_]
|
||||
if logarithmic:
|
||||
log_scale = compute_logarithmic_scale(
|
||||
min_, max_, min_scale, max_scale)
|
||||
if log_scale:
|
||||
return log_scale
|
||||
# else we fallback to normal scalling
|
||||
|
||||
order = round(log10(max(abs(min_), abs(max_)))) - 1
|
||||
if order_min is not None and order < order_min:
|
||||
order = order_min
|
||||
else:
|
||||
while ((max_ - min_) / (10 ** order) < min_scale and
|
||||
(order_min is None or order > order_min)):
|
||||
order -= 1
|
||||
step = float(10 ** order)
|
||||
while (max_ - min_) / step > max_scale:
|
||||
step *= 2.
|
||||
positions = []
|
||||
position = round_to_scale(min_, step)
|
||||
while position < (max_ + step):
|
||||
rounded = round_to_scale(position, step)
|
||||
if min_ <= rounded <= max_:
|
||||
if rounded not in positions:
|
||||
positions.append(rounded)
|
||||
position += step
|
||||
if len(positions) < 2:
|
||||
return [min_, max_]
|
||||
return positions
|
||||
|
||||
|
||||
def text_len(length, fs):
|
||||
"""Approximation of text width"""
|
||||
return length * 0.6 * fs
|
||||
|
||||
|
||||
def reverse_text_len(width, fs):
|
||||
"""Approximation of text length"""
|
||||
return int(width / (0.6 * fs))
|
||||
|
||||
|
||||
def get_text_box(text, fs):
|
||||
"""Approximation of text bounds"""
|
||||
return (fs, text_len(len(text), fs))
|
||||
|
||||
|
||||
def get_texts_box(texts, fs):
|
||||
"""Approximation of multiple texts bounds"""
|
||||
max_len = max(map(len, texts))
|
||||
return (fs, text_len(max_len, fs))
|
||||
|
||||
|
||||
def decorate(svg, node, metadata):
|
||||
"""Add metedata next to a node"""
|
||||
if not metadata:
|
||||
return node
|
||||
xlink = metadata.get('xlink')
|
||||
if xlink:
|
||||
if not isinstance(xlink, dict):
|
||||
xlink = {'href': xlink, 'target': '_blank'}
|
||||
node = svg.node(node, 'a', **xlink)
|
||||
svg.node(node, 'desc', class_='xlink').text = to_unicode(
|
||||
xlink.get('href'))
|
||||
|
||||
if 'tooltip' in metadata:
|
||||
svg.node(node, 'title').text = to_unicode(
|
||||
metadata['tooltip'])
|
||||
|
||||
if 'color' in metadata:
|
||||
color = metadata.pop('color')
|
||||
node.attrib['style'] = 'fill: %s; stroke: %s' % (
|
||||
color, color)
|
||||
|
||||
if 'style' in metadata:
|
||||
node.attrib['style'] = metadata.pop('style')
|
||||
|
||||
if 'label' in metadata:
|
||||
svg.node(node, 'desc', class_='label').text = to_unicode(
|
||||
metadata['label'])
|
||||
return node
|
||||
|
||||
|
||||
def alter(node, metadata):
|
||||
"""Override nodes attributes from metadata node mapping"""
|
||||
if node is not None and metadata and 'node' in metadata:
|
||||
node.attrib.update(
|
||||
dict((k, str(v)) for k, v in metadata['node'].items()))
|
||||
|
||||
|
||||
def truncate(string, index):
|
||||
"""Truncate a string at index and add ..."""
|
||||
if len(string) > index and index > 0:
|
||||
string = string[:index - 1] + u('…')
|
||||
return string
|
||||
|
||||
|
||||
# # Stolen partly from brownie http://packages.python.org/Brownie/
|
||||
class cached_property(object):
|
||||
|
||||
"""Memoize a property"""
|
||||
|
||||
def __init__(self, getter, doc=None):
|
||||
"""Initialize the decorator"""
|
||||
self.getter = getter
|
||||
self.__module__ = getter.__module__
|
||||
self.__name__ = getter.__name__
|
||||
self.__doc__ = doc or getter.__doc__
|
||||
|
||||
def __get__(self, obj, type_=None):
|
||||
"""
|
||||
Get descriptor calling the property function and replacing it with
|
||||
its value or on state if we are in the transient state.
|
||||
"""
|
||||
if obj is None:
|
||||
return self
|
||||
value = self.getter(obj)
|
||||
if hasattr(obj, 'state'):
|
||||
setattr(obj.state, self.__name__, value)
|
||||
else:
|
||||
obj.__dict__[self.__name__] = self.getter(obj)
|
||||
return value
|
||||
|
||||
|
||||
css_comments = re.compile(r'/\*.*?\*/', re.MULTILINE | re.DOTALL)
|
||||
|
||||
|
||||
def minify_css(css):
|
||||
"""Little css minifier"""
|
||||
# Inspired by slimmer by Peter Bengtsson
|
||||
remove_next_comment = 1
|
||||
for css_comment in css_comments.findall(css):
|
||||
if css_comment[-3:] == '\*/':
|
||||
remove_next_comment = 0
|
||||
continue
|
||||
if remove_next_comment:
|
||||
css = css.replace(css_comment, '')
|
||||
else:
|
||||
remove_next_comment = 1
|
||||
|
||||
# >= 2 whitespace becomes one whitespace
|
||||
css = re.sub(r'\s\s+', ' ', css)
|
||||
# no whitespace before end of line
|
||||
css = re.sub(r'\s+\n', '', css)
|
||||
# Remove space before and after certain chars
|
||||
for char in ('{', '}', ':', ';', ','):
|
||||
css = re.sub(char + r'\s', char, css)
|
||||
css = re.sub(r'\s' + char, char, css)
|
||||
css = re.sub(r'}\s(#|\w)', r'}\1', css)
|
||||
# no need for the ; before end of attributes
|
||||
css = re.sub(r';}', r'}', css)
|
||||
css = re.sub(r'}//-->', r'}\n//-->', css)
|
||||
return css.strip()
|
||||
|
||||
|
||||
def compose(f, g):
|
||||
"""Chain functions"""
|
||||
fun = lambda *args, **kwargs: f(g(*args, **kwargs))
|
||||
fun.__name__ = "%s o %s" % (f.__name__, g.__name__)
|
||||
return fun
|
||||
|
||||
|
||||
def safe_enumerate(iterable):
|
||||
"""Enumerate which does not yield None values"""
|
||||
for i, v in enumerate(iterable):
|
||||
if v is not None:
|
||||
yield i, v
|
||||
|
||||
|
||||
def split_title(title, width, title_fs):
|
||||
"""Split a string for a specified width and font size"""
|
||||
titles = []
|
||||
if not title:
|
||||
return titles
|
||||
size = reverse_text_len(width, title_fs * 1.1)
|
||||
title_lines = title.split("\n")
|
||||
for title_line in title_lines:
|
||||
while len(title_line) > size:
|
||||
title_part = title_line[:size]
|
||||
i = title_part.rfind(' ')
|
||||
if i == -1:
|
||||
i = len(title_part)
|
||||
titles.append(title_part[:i])
|
||||
title_line = title_line[i:].strip()
|
||||
titles.append(title_line)
|
||||
return titles
|
||||
|
||||
|
||||
def filter_kwargs(fun, kwargs):
|
||||
if not hasattr(fun, '__code__'):
|
||||
return {}
|
||||
args = fun.__code__.co_varnames[1:]
|
||||
return dict((k, v) for k, v in kwargs.items() if k in args)
|
||||
|
||||
|
||||
def coord_project(rho, alpha):
|
||||
return rho * sin(-alpha), rho * cos(-alpha)
|
||||
|
||||
|
||||
def coord_diff(x, y):
|
||||
return (x[0] - y[0], x[1] - y[1])
|
||||
|
||||
|
||||
def coord_format(x):
|
||||
return '%f %f' % x
|
||||
|
||||
|
||||
def coord_dual(r):
|
||||
return coord_format((r, r))
|
||||
|
||||
|
||||
def coord_abs_project(center, rho, theta):
|
||||
return coord_format(coord_diff(center, coord_project(rho, theta)))
|
||||
|
||||
|
||||
def mergextend(list1, list2):
|
||||
if list1 is None or _ellipsis not in list1:
|
||||
return list1
|
||||
index = list1.index(_ellipsis)
|
||||
return list(list1[:index]) + list(list2) + list(list1[index + 1:])
|
||||
|
||||
|
||||
def merge(dict1, dict2):
|
||||
from pygal.config import CONFIG_ITEMS, Key
|
||||
_list_items = [item.name for item in CONFIG_ITEMS if item.type == list]
|
||||
for key, val in dict2.items():
|
||||
if isinstance(val, Key):
|
||||
val = val.value
|
||||
|
||||
if key in _list_items:
|
||||
dict1[key] = mergextend(val, dict1.get(key, ()))
|
||||
else:
|
||||
dict1[key] = val
|
Reference in New Issue
Block a user