forked from rc/aircox
logo; RelatedPost sync with related object
This commit is contained in:
parent
a4f1b03bde
commit
4a9263cdd8
|
@ -1,5 +1,6 @@
|
||||||
# Aircox
|

|
||||||
Platform to manage a radio. We use the power of Django
|
|
||||||
|
Platform to manage a radio, schedules, website, and so on. We use the power of Django and Liquidsoap.
|
||||||
|
|
||||||
## Current features
|
## Current features
|
||||||
* **streams**: multiple random music streams when no program is played. We also can specify a time range and frequency;
|
* **streams**: multiple random music streams when no program is played. We also can specify a time range and frequency;
|
||||||
|
|
|
@ -92,15 +92,15 @@ class RelatedPostBase (models.base.ModelBase):
|
||||||
registry = {}
|
registry = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register (cl, key, model):
|
def register (cl, key, post_model):
|
||||||
"""
|
"""
|
||||||
Register a model and return the key under which it is registered.
|
Register a model and return the key under which it is registered.
|
||||||
Raise a ValueError if another model is yet associated under this key.
|
Raise a ValueError if another model is yet associated under this key.
|
||||||
"""
|
"""
|
||||||
if key in cl.registry and cl.registry[key] is not model:
|
if key in cl.registry and cl.registry[key] is not post_model:
|
||||||
raise ValueError('A model has yet been registered with "{}"'
|
raise ValueError('A model has yet been registered with "{}"'
|
||||||
.format(key))
|
.format(key))
|
||||||
cl.registry[key] = model
|
cl.registry[key] = post_model
|
||||||
return key
|
return key
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -137,13 +137,15 @@ class RelatedPostBase (models.base.ModelBase):
|
||||||
return rel
|
return rel
|
||||||
|
|
||||||
def __new__ (cl, name, bases, attrs):
|
def __new__ (cl, name, bases, attrs):
|
||||||
|
# TODO: allow proxy models and better inheritance
|
||||||
if name == 'RelatedPost':
|
if name == 'RelatedPost':
|
||||||
return super().__new__(cl, name, bases, attrs)
|
return super().__new__(cl, name, bases, attrs)
|
||||||
|
|
||||||
rel = cl.make_relation(name, attrs)
|
rel = cl.make_relation(name, attrs)
|
||||||
|
field_args = rel.field_args or {}
|
||||||
attrs['_relation'] = rel
|
attrs['_relation'] = rel
|
||||||
attrs.update({ x:y for x,y in {
|
attrs.update({ x:y for x,y in {
|
||||||
'related': models.ForeignKey(rel.model),
|
'related': models.ForeignKey(rel.model, **field_args),
|
||||||
'__str__': lambda self: str(self.related)
|
'__str__': lambda self: str(self.related)
|
||||||
}.items() if not attrs.get(x) })
|
}.items() if not attrs.get(x) })
|
||||||
|
|
||||||
|
@ -207,6 +209,8 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
* rel_to_post: auto update the post when related object is updated
|
* rel_to_post: auto update the post when related object is updated
|
||||||
* thread_model: generated by the metaclass, points to the RelatedPost
|
* thread_model: generated by the metaclass, points to the RelatedPost
|
||||||
model generated for the bindings.thread object.
|
model generated for the bindings.thread object.
|
||||||
|
* field_args: dict of arguments to pass to the ForeignKey constructor,
|
||||||
|
such as: ForeignKey(related_model, **field_args)
|
||||||
|
|
||||||
Be careful with post_to_rel!
|
Be careful with post_to_rel!
|
||||||
* There is no check of permissions when related object is synchronised
|
* There is no check of permissions when related object is synchronised
|
||||||
|
@ -217,14 +221,15 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
model = None
|
model = None
|
||||||
bindings = None # values to map { post_attr: rel_attr }
|
bindings = None # values to map { post_attr: rel_attr }
|
||||||
post_to_rel = False
|
post_to_rel = False
|
||||||
rel_to_post = True
|
rel_to_post = False
|
||||||
thread_model = None
|
thread_model = None
|
||||||
|
field_args = None
|
||||||
|
|
||||||
def get_rel_attr(self, attr):
|
def get_rel_attr(self, attr):
|
||||||
attr = self._relation.bindings.get(attr)
|
attr = self._relation.bindings.get(attr)
|
||||||
return getattr(self.related, attr) if attr else None
|
return getattr(self.related, attr) if attr else None
|
||||||
|
|
||||||
def set_rel_attr(self, attr, value)
|
def set_rel_attr(self, attr, value):
|
||||||
if attr not in self._relation.bindings:
|
if attr not in self._relation.bindings:
|
||||||
raise AttributeError('attribute {} is not bound'.format(attr))
|
raise AttributeError('attribute {} is not bound'.format(attr))
|
||||||
attr = self._relation.bindings.get(attr)
|
attr = self._relation.bindings.get(attr)
|
||||||
|
@ -240,13 +245,13 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
if not rel.bindings:
|
if not rel.bindings:
|
||||||
return
|
return
|
||||||
|
|
||||||
for attr, rel_attr in rel.bindings.items()
|
for attr, rel_attr in rel.bindings.items():
|
||||||
if attr == 'thread':
|
if attr == 'thread':
|
||||||
continue
|
continue
|
||||||
value = getattr(self, attr) if hasattr(self, attr) else None
|
value = getattr(self, attr) if hasattr(self, attr) else None
|
||||||
setattr(self.related, rel_attr, value)
|
setattr(self.related, rel_attr, value)
|
||||||
|
|
||||||
if self.thread_model:
|
if rel.thread_model:
|
||||||
thread = self.thread if not issubclass(thread, rel.thread_model) \
|
thread = self.thread if not issubclass(thread, rel.thread_model) \
|
||||||
else None
|
else None
|
||||||
self.set_rel_attr('thread', thread.related)
|
self.set_rel_attr('thread', thread.related)
|
||||||
|
@ -254,6 +259,19 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
if save:
|
if save:
|
||||||
self.related.save()
|
self.related.save()
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sync_from_rel(cl, rel, save = True):
|
||||||
|
"""
|
||||||
|
Update a rel_to_post from a given rel object. Return -1 if there is no
|
||||||
|
related post to update
|
||||||
|
"""
|
||||||
|
self = cl.objects.filter(related = rel)
|
||||||
|
if not self or not self.count():
|
||||||
|
return -1
|
||||||
|
self[0].rel_to_post(save)
|
||||||
|
|
||||||
|
|
||||||
def rel_to_post(self, save = True):
|
def rel_to_post(self, save = True):
|
||||||
"""
|
"""
|
||||||
Change the post using the related object bound values. Save the
|
Change the post using the related object bound values. Save the
|
||||||
|
@ -264,7 +282,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
if rel.bindings:
|
if rel.bindings:
|
||||||
return
|
return
|
||||||
|
|
||||||
for attr, rel_attr in rel.bindings.items()
|
for attr, rel_attr in rel.bindings.items():
|
||||||
if attr == 'thread':
|
if attr == 'thread':
|
||||||
continue
|
continue
|
||||||
self.set_rel_attr
|
self.set_rel_attr
|
||||||
|
@ -272,7 +290,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
if hasattr(self.related, attr) else None
|
if hasattr(self.related, attr) else None
|
||||||
setattr(self, attr, value)
|
setattr(self, attr, value)
|
||||||
|
|
||||||
if self.thread_model:
|
if rel.thread_model:
|
||||||
thread = self.get_rel_attr('thread')
|
thread = self.get_rel_attr('thread')
|
||||||
thread = rel.thread_model.objects.filter(related = thread) \
|
thread = rel.thread_model.objects.filter(related = thread) \
|
||||||
if thread else None
|
if thread else None
|
||||||
|
@ -282,11 +300,19 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
if save:
|
if save:
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def __init__ (self, *kargs, **kwargs):
|
||||||
|
super().__init__(*kargs, **kwargs)
|
||||||
|
# we use this method for sync, in order to avoid intrusive code on other
|
||||||
|
# applications, e.g. using signals.
|
||||||
|
if self._relation.rel_to_post:
|
||||||
|
self.rel_to_post(save = False)
|
||||||
|
|
||||||
def save (self, *args, **kwargs):
|
def save (self, *args, **kwargs):
|
||||||
|
# TODO handle when related change
|
||||||
if not self.title and self.related:
|
if not self.title and self.related:
|
||||||
self.title = self.get_rel_attr('title')
|
self.title = self.get_rel_attr('title')
|
||||||
if self._relation.post_to_rel:
|
if self._relation.post_to_rel:
|
||||||
self.post_to_rel(False)
|
self.post_to_rel(save = True)
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<meta name="description" content="{{ website.description }}">
|
<meta name="description" content="{{ website.description }}">
|
||||||
<meta name="keywords" content="{{ website.tags }}">
|
<meta name="keywords" content="{{ website.tags }}">
|
||||||
|
|
||||||
<link rel="stylesheet" href="{% static "aircox_cms/styles.css" %}" type="text/css">
|
<link rel="stylesheet" href="{% static "aircox/cms/styles.css" %}" type="text/css">
|
||||||
{% if website.styles %}
|
{% if website.styles %}
|
||||||
<link rel="stylesheet" href="{% static website.styles %}" type="text/css">
|
<link rel="stylesheet" href="{% static website.styles %}" type="text/css">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends embed|yesno:"aircox_cms/base_content.html,aircox_cms/base_site.html" %}
|
{% extends embed|yesno:"aircox/cms/base_content.html,aircox/cms/base_site.html" %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{ object.title }}
|
{{ object.title }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends embed|yesno:"aircox_cms/base_content.html,aircox_cms/base_site.html" %}
|
{% extends embed|yesno:"aircox/cms/base_content.html,aircox/cms/base_site.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load thumbnail %}
|
{% load thumbnail %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "aircox_cms/base_section.html" %}
|
{% extends "aircox/cms/base_section.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if title %}
|
{% if title %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "aircox_cms/section.html" %}
|
{% extends "aircox/cms/section.html" %}
|
||||||
|
|
||||||
{% load thumbnail %}
|
{% load thumbnail %}
|
||||||
|
|
||||||
|
|
|
@ -307,6 +307,8 @@ class Sections:
|
||||||
"""
|
"""
|
||||||
@property
|
@property
|
||||||
def content (self):
|
def content (self):
|
||||||
|
if not self.object.image:
|
||||||
|
return ''
|
||||||
return '<img src="{}" class="post_image">'.format(
|
return '<img src="{}" class="post_image">'.format(
|
||||||
self.object.image.url
|
self.object.image.url
|
||||||
)
|
)
|
||||||
|
|
BIN
data/logo.png
Normal file
BIN
data/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
165
data/logo.svg
Normal file
165
data/logo.svg
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 744.09448819 1052.3622047"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="logo.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath4570">
|
||||||
|
<path
|
||||||
|
d="M 124.61621,447.85033 A 128.45006,128.45006 0 0 1 26.456632,334.05117 128.45006,128.45006 0 0 1 103.46536,204.99611 l 50.95693,117.91017 z"
|
||||||
|
sodipodi:end="4.3044632"
|
||||||
|
sodipodi:start="1.8049749"
|
||||||
|
sodipodi:ry="128.45006"
|
||||||
|
sodipodi:rx="128.45006"
|
||||||
|
sodipodi:cy="322.90628"
|
||||||
|
sodipodi:cx="154.42229"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="opacity:1;fill:#9f9f9f;fill-opacity:0.38967136;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="path4572" />
|
||||||
|
</clipPath>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath4589">
|
||||||
|
<path
|
||||||
|
d="m -417.18553,459.80156 a 128.45006,128.45006 0 0 1 -98.15958,-113.79916 128.45006,128.45006 0 0 1 77.00872,-129.05506 l 50.95693,117.91017 z"
|
||||||
|
sodipodi:end="4.3044632"
|
||||||
|
sodipodi:start="1.8049749"
|
||||||
|
sodipodi:ry="128.45006"
|
||||||
|
sodipodi:rx="128.45006"
|
||||||
|
sodipodi:cy="334.85751"
|
||||||
|
sodipodi:cx="-387.37946"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="opacity:1;fill:#9f9f9f;fill-opacity:0.38967136;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="path4591"
|
||||||
|
transform="matrix(-0.99924777,0.03878018,0.03878018,0.99924777,0,0)" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.81249936"
|
||||||
|
inkscape:cx="87.39633"
|
||||||
|
inkscape:cy="611.94509"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
showguides="false"
|
||||||
|
inkscape:window-width="1364"
|
||||||
|
inkscape:window-height="736"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="1454"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<g
|
||||||
|
id="g4202"
|
||||||
|
style="fill:#ffffff;fill-opacity:1"
|
||||||
|
transform="matrix(0.89378493,0,0,0.89378493,41.184024,25.814665)" />
|
||||||
|
<g
|
||||||
|
id="g4376"
|
||||||
|
transform="matrix(0.97221505,-0.23408952,0.23408952,0.97221505,-73.655087,41.382345)"
|
||||||
|
clip-path="url(#clipPath4570)">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4155-6"
|
||||||
|
d="m 110.80568,266.04718 c -3.29167,-19.8207 -11.124776,-15.37046 -12.352066,-24.27303 -0.14135,-3.58896 4.663986,-8.38983 8.867286,-4.51659 7.90435,9.32416 0.41767,10.96241 14.73478,22.36105 -2.96184,1.98522 -7.49488,4.28469 -11.25,6.42857 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4155-7-80"
|
||||||
|
d="m 97.267374,355.00848 c -19.8207,3.29167 -15.37045,11.12478 -24.27302,12.35207 -3.58896,0.14135 -8.38984,-4.66399 -4.51659,-8.86729 9.32415,-7.90435 10.96241,-0.41767 22.36104,-14.73478 1.98522,2.96184 4.28469,7.49488 6.42857,11.25 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4155-7-8-6"
|
||||||
|
d="m 85.476584,307.73621 c -16.34291,-11.68779 -18.73496,-3.00215 -25.89785,-8.42939 -2.63773,-2.43783 -2.63457,-9.23045 3.07641,-9.46383 12.18239,1.00395 8.04693,7.45626 26.23071,5.39258 -0.69058,3.4981 -2.26995,8.32941 -3.40927,12.50064 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4155-7-0-0"
|
||||||
|
d="m 139.41029,379.1225 c -11.68779,16.34292 -3.00214,18.73496 -8.42939,25.89785 -2.43783,2.63773 -9.23045,2.63458 -9.46383,-3.07641 1.00394,-12.18239 7.45626,-8.04693 5.39257,-26.23071 3.4981,0.69058 8.32942,2.26995 12.50065,3.40927 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<circle
|
||||||
|
id="path4136-5-5"
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
cx="148.58382"
|
||||||
|
cy="316.89429"
|
||||||
|
r="61.081726" />
|
||||||
|
<circle
|
||||||
|
r="50.376423"
|
||||||
|
cy="317.04373"
|
||||||
|
cx="148.79494"
|
||||||
|
id="path4136-5-6-5"
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.40858507;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
<flowRoot
|
||||||
|
xml:space="preserve"
|
||||||
|
id="flowRoot4439"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:Adler;-inkscape-font-specification:Adler;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
transform="matrix(0.96092081,0,0,0.96092081,-26.716999,5.7888348)"><flowRegion
|
||||||
|
id="flowRegion4441"><rect
|
||||||
|
id="rect4443"
|
||||||
|
width="416.00034"
|
||||||
|
height="148.9232"
|
||||||
|
x="141.53857"
|
||||||
|
y="278.20776"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;font-family:Adler;-inkscape-font-specification:Adler" /></flowRegion><flowPara
|
||||||
|
id="flowPara4445"><flowSpan
|
||||||
|
style="fill:#ff0000"
|
||||||
|
id="flowSpan4447">Air</flowSpan>cox</flowPara></flowRoot> <g
|
||||||
|
id="g4492"
|
||||||
|
clip-path="url(#clipPath4589)"
|
||||||
|
transform="matrix(0.962985,-0.26955499,0.26955499,0.962985,-82.471435,120.78786)">
|
||||||
|
<circle
|
||||||
|
r="61.731167"
|
||||||
|
cy="313.76675"
|
||||||
|
cx="403.01682"
|
||||||
|
id="path4136-5-6"
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:7.99999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<circle
|
||||||
|
r="43.736217"
|
||||||
|
cy="313.76675"
|
||||||
|
cx="403.01682"
|
||||||
|
id="path4136-5-6-4"
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4.99999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.9 KiB |
Loading…
Reference in New Issue
Block a user