Commit ef44d9eea5e4f884f15fa26315a2f62d2c39b8f5
Exists in
master
and in
4 other branches
Update deploy pattterns
Showing
12 changed files
with
353 additions
and
38 deletions
Show diff stats
CHANGELOG.md
... | ... | @@ -24,6 +24,12 @@ or major refactoring improvments. |
24 | 24 | |
25 | 25 | ## Unreleased |
26 | 26 | |
27 | +## [0.2.pre-5] - 2021-03-19 - More Deploy facilities | |
28 | +### Changed | |
29 | +More documentation | |
30 | +Configuration pattern changed | |
31 | + | |
32 | + | |
27 | 33 | ## [0.2.pre-4] - 2021-03-15 - First Graphs |
28 | 34 | ### New |
29 | 35 | D3js imports | ... | ... |
INSTALL.md
... | ... | @@ -3,6 +3,9 @@ |
3 | 3 | ## Prérequis |
4 | 4 | |
5 | 5 | - python3 |
6 | +- sqlite ( pour le développement et les tests unitaires ) | |
7 | +- chrome-driver et chromium ( pour les tests unitaires) | |
8 | +- postgresql ou mariadb (pour la production) | |
6 | 9 | |
7 | 10 | ## Obtenir un répertoire fonctionnel |
8 | 11 | |
... | ... | @@ -13,14 +16,36 @@ |
13 | 16 | |
14 | 17 | python3 -m venv venv |
15 | 18 | source venv/bin/activate |
19 | + pip install --upgrade pip | |
16 | 20 | pip install -r requirements.txt |
17 | 21 | |
18 | 22 | ### Configurer l'application |
19 | 23 | |
20 | - cp resources/pdc_config.py . | |
21 | - $(EDITOR) pdc_config.py | |
24 | + # D'abord les accés base de donnée | |
25 | + cp resources/db_config.py . | |
26 | + $(EDITOR) db_config.py | |
22 | 27 | |
28 | + # Ensuite l'appli elle même (ce fichier est utilisable tel quel) | |
23 | 29 | cp resources/flaskenv .flaskenv |
30 | + $(EDITOR) .flaskenv | |
31 | + | |
32 | +### Créer la base de données | |
33 | + | |
34 | +Utiliser l'outil de ligne de commande fourni avec l'application. | |
35 | + | |
36 | + flask pdc_db --help | |
37 | + | |
38 | + # créer la structure de la base | |
39 | + flask pdc_db create_db | |
40 | + | |
41 | + # renseigner des agent depuis une base type lesia | |
42 | + flask pdc_db feed_from_lesia | |
43 | + | |
44 | + # entrer des périodes | |
45 | + flask pdc_db feed_periods | |
46 | + | |
47 | + # entrer des charges aléatoires (une centaine) | |
48 | + flask pdc_db feed_random_charges | |
24 | 49 | |
25 | 50 | |
26 | 51 | ### Jouer les tests et exécuter un serveur local |
... | ... | @@ -34,19 +59,34 @@ |
34 | 59 | # ouvrir un serveur sur localhost:5000 |
35 | 60 | flask run |
36 | 61 | |
37 | -## Configurer apache | |
62 | +## Configurer l'appli web avec apache | |
38 | 63 | |
39 | 64 | Les fichiers concernés: |
40 | 65 | |
41 | 66 | - pdc_web.wsgi |
42 | -- pdc_config.py | |
67 | +- db_config.py | |
43 | 68 | |
44 | 69 | La procédure: |
45 | 70 | |
46 | - mkdir /var/www/html/pdc-web | |
71 | + # créer le répertoire pour le web | |
72 | + export WEB_DIR=/var/www/html/pdc-web | |
73 | + mkdir $WEB_DIR | |
74 | + | |
75 | + # le peupler avec le code | |
76 | + export GIT_DIR=/path/to/pdc_web/.git | |
77 | + export GIT_BRANCH=master | |
78 | + git --work-tree=$WEB_DIR --git-dir=$GIT_DIR checkout -f $GIT_BRANCH | |
47 | 79 | |
80 | + # le configurer : cf plus haut "Obtenir un répertoire fonctionnel" | |
81 | + cd $WEB_DIR | |
82 | + python -m venv venv | |
83 | + source venv/bin/activate | |
84 | + pip install -r requirements.txt | |
85 | + $(EDITOR) db_config.py .flaskenv | |
86 | + | |
87 | + # configurer le serveur web | |
48 | 88 | cp ./resources/apache2-virtual-host.conf /etc/apache2/sites-available/pdc-web.conf |
49 | - $(EDITOR) /etc/apache2/sites-available/pdc-web.conf # éditer les paramètres | |
89 | + $(EDITOR) /etc/apache2/sites-available/pdc-web.conf | |
50 | 90 | a2ensite pdc-web |
51 | 91 | apachectl restart |
52 | 92 | ... | ... |
VERSION.txt
app/__init__.py
... | ... | @@ -18,12 +18,12 @@ def load_user(user_id): |
18 | 18 | |
19 | 19 | |
20 | 20 | # Please, set a config file on top project dir |
21 | -# find example in ressources/pdc_config.py | |
21 | +# see in ../pdc_config.py | |
22 | 22 | try: |
23 | 23 | from pdc_config import Config, ProdConfig, DevConfig, TestConfig |
24 | 24 | except ImportError: |
25 | 25 | # TODO: use logging system |
26 | - print("Please set an pdc_config.py file in you PYTHON_PATH") | |
26 | + print("Please set a pdc_config.py file in you PYTHON_PATH") | |
27 | 27 | print("See INSTALL.md for more info") |
28 | 28 | sys.exit(-1) |
29 | 29 | ... | ... |
app/commands/__init__.py
app/commands/commands.py
... | ... | @@ -2,6 +2,7 @@ import sys |
2 | 2 | import click |
3 | 3 | import random |
4 | 4 | |
5 | +from sqlalchemy.exc import OperationalError | |
5 | 6 | from sqlalchemy.sql import func |
6 | 7 | from sqlalchemy.ext.automap import automap_base |
7 | 8 | from sqlalchemy.orm import Session |
... | ... | @@ -9,19 +10,29 @@ from sqlalchemy import create_engine |
9 | 10 | |
10 | 11 | from app.models import db, User, Agent, Service, Project, Capacity, Period, Charge |
11 | 12 | |
12 | -from db_config import mysql_uri | |
13 | +from db_config import mysql_lesia_uri | |
13 | 14 | |
14 | 15 | from . import bp |
15 | 16 | |
16 | 17 | |
17 | 18 | @bp.cli.command("feed_from_lesia") |
18 | 19 | def feed_from_lesia(): |
20 | + """ Feed db with agents from a lesia like mysql database. | |
21 | + | |
22 | + configure that database uri in the db_config.py file. | |
23 | + """ | |
19 | 24 | Base = automap_base() |
20 | 25 | |
21 | - engine = create_engine(mysql_uri) | |
26 | + engine = create_engine(mysql_lesia_uri) | |
22 | 27 | |
23 | 28 | # reflect the tables |
24 | - Base.prepare(engine, reflect=True) | |
29 | + try: | |
30 | + Base.prepare(engine, reflect=True) | |
31 | + except OperationalError: | |
32 | + # TODO: use logging facility instead | |
33 | + print("Please, configure the mysql database (see db_config.py)") | |
34 | + sys.exit(-1) | |
35 | + | |
25 | 36 | |
26 | 37 | # mapped classes are now created with names by default |
27 | 38 | # matching that of the table name. |
... | ... | @@ -58,6 +69,7 @@ def feed_from_lesia(): |
58 | 69 | |
59 | 70 | @bp.cli.command("feed_periods") |
60 | 71 | def feed_periods(): |
72 | + """ Fill in the periods name in the database. """ | |
61 | 73 | for y in range(2014, 2023): |
62 | 74 | for s in ['S1', 'S2']: |
63 | 75 | period_name = "{}_{}".format(y, s) |
... | ... | @@ -66,9 +78,10 @@ def feed_periods(): |
66 | 78 | db.session.commit() |
67 | 79 | |
68 | 80 | |
69 | -@bp.cli.command("random_charges") | |
70 | -@click.option('--agent', '-a', 'agent', default=None) | |
71 | -def random_charges(agent): | |
81 | +@bp.cli.command("feed_random_charges") | |
82 | +@click.option('--agent', '-a', 'agent', default=None, help="the agent id you want to charge") | |
83 | +def feed_random_charges(agent): | |
84 | + """ Randomly fill in the agents charges. """ | |
72 | 85 | for i in range(0, 100): |
73 | 86 | if agent is None: |
74 | 87 | agent_id = random.choice([i for (i,) in db.session.query(Agent.id).all()]) |
... | ... | @@ -98,9 +111,10 @@ def random_charges(agent): |
98 | 111 | db.session.commit() |
99 | 112 | |
100 | 113 | |
101 | -@bp.cli.command('delete_user') | |
114 | +@bp.cli.command('user_delete') | |
102 | 115 | @click.argument('user_id') |
103 | -def delete_user(user_id): | |
116 | +def user_delete(user_id): | |
117 | + """Delete the user by given id (see user_show_all").""" | |
104 | 118 | user = User.query.get(user_id) |
105 | 119 | db.session.delete(user) |
106 | 120 | db.session.commit() |
... | ... | @@ -108,26 +122,29 @@ def delete_user(user_id): |
108 | 122 | |
109 | 123 | @bp.cli.command('create_db') |
110 | 124 | def create_db(): |
125 | + """ Create the database structure.""" | |
111 | 126 | db.create_all() |
112 | 127 | admin = User(email='admin@nowhere.org', name='admin', login='admin', password='admin') |
113 | 128 | db.session.add(admin) |
114 | 129 | db.session.commit() |
115 | 130 | |
116 | 131 | |
117 | -@bp.cli.command('add_user') | |
132 | +@bp.cli.command('user_add') | |
118 | 133 | @click.argument('email') |
119 | 134 | @click.argument('name') |
120 | 135 | @click.argument('login') |
121 | 136 | @click.argument('password') |
122 | -def add_user(email, name, login, password): | |
137 | +def user_add(email, name, login, password): | |
138 | + """ Add a new user in db.""" | |
123 | 139 | user = User(email=email, name=name, login=login, password=password) |
124 | 140 | db.session.add(user) |
125 | 141 | db.session.commit() |
126 | 142 | print("added ", name) |
127 | 143 | |
128 | 144 | |
129 | -@bp.cli.command('show_all') | |
130 | -def show_all(): | |
145 | +@bp.cli.command('user_show_all') | |
146 | +def user_show_all(): | |
147 | + """ Show all users in db.""" | |
131 | 148 | print("{:<5} {:<15} {:<15} {:<15} {:<15}".format('id', 'name', 'login', 'passwd', 'email')) |
132 | 149 | print("{:<5} {:<15} {:<15} {:<15} {:<15}".format('-' * 5, '-' * 15, '-' * 15, '-' * 15, '-' * 15)) |
133 | 150 | for user in User.query.all(): | ... | ... |
app/main/templates/agent.html
... | ... | @@ -74,7 +74,7 @@ |
74 | 74 | // Pour l'axe X, c'est la liste des pays |
75 | 75 | // Pour l'axe Y, c'est le max des charge |
76 | 76 | x.domain(data.map(d => d.periode)); |
77 | - y.domain([0, d3.max(data, d => d.charge)-1]); | |
77 | + y.domain([0, 100]); | |
78 | 78 | |
79 | 79 | // Ajout de l'axe X au SVG |
80 | 80 | // Déplacement de l'axe horizontal et du futur texte (via la fonction translate) au bas du SVG | ... | ... |
resources/pdc_config.py renamed to pdc_config.py
1 | 1 | import os |
2 | +from db_config import * | |
2 | 3 | |
3 | 4 | root_dir = os.path.abspath(os.path.dirname(__file__)) |
4 | 5 | |
5 | 6 | |
7 | +# | |
8 | +# SQLALCHEMY_DATABASE_URI will default to 'sqlite:///:memory:' if not set | |
9 | +# | |
10 | + | |
6 | 11 | class Config(object): |
7 | 12 | SECRET_KEY = 'dev' |
8 | 13 | SQLALCHEMY_TRACK_MODIFICATIONS = False |
9 | - SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ | |
10 | - 'sqlite:///' + os.path.join(root_dir, 'pdc_app.db') | |
14 | + | |
15 | + # Trying to set specific db uri from ./db_config.py | |
16 | + try: | |
17 | + SQLALCHEMY_DATABASE_URI = sqlalchemy_database_uri | |
18 | + except NameError: | |
19 | + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ | |
20 | + 'sqlite:///' + os.path.join(root_dir, 'pdc_app.db') | |
11 | 21 | |
12 | 22 | with open(os.path.join(root_dir, 'VERSION.txt')) as version_file: |
13 | 23 | VERSION = version_file.read().strip() |
... | ... | @@ -20,11 +30,23 @@ class ProdConfig(Config): |
20 | 30 | |
21 | 31 | class DevConfig(Config): |
22 | 32 | DEBUG = True |
33 | + # Trying to set specific db uri from ./db_config.py | |
34 | + try: | |
35 | + SQLALCHEMY_DATABASE_URI = sqlalchemy_devdb_uri | |
36 | + except NameError: | |
37 | + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ | |
38 | + 'sqlite:///' + os.path.join(root_dir, 'pdc_app_dev.db') | |
23 | 39 | |
24 | 40 | |
25 | 41 | class TestConfig(Config): |
26 | 42 | TESTING = True |
27 | 43 | DEBUG = True |
44 | + # Trying to set specific db uri from ./db_config.py | |
45 | + try: | |
46 | + SQLALCHEMY_DATABASE_URI = sqlalchemy_testdb_uri | |
47 | + except NameError: | |
48 | + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ | |
49 | + 'sqlite:///' + os.path.join(root_dir, 'pdc_app_test.db') | |
28 | 50 | # ignores @login_required decorator |
29 | 51 | # LOGIN_DISABLED = True |
30 | 52 | ... | ... |
resources/db_config.py
1 | +SQLITE = { | |
2 | + 'file': '/home/user/tmp/pdc.db' | |
3 | +} | |
4 | +sqlite_uri = 'sqlite:///%(file)s' % SQLITE | |
5 | + | |
6 | +MYSQL = { | |
7 | + 'user': 'mysql', | |
8 | + 'pw': 'mysql', | |
9 | + 'db': 'pdc_dev', | |
10 | + 'host': '127.0.0.1', | |
11 | + 'port': '3306', | |
12 | +} | |
13 | +mysql_uri = 'mysql+pymysql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % MYSQL | |
14 | + | |
1 | 15 | POSTGRES = { |
2 | - 'user': 'postgres', | |
3 | - 'pw': 'postgres', | |
4 | - 'db': 'climso', | |
16 | + 'user': 'aroma-user', | |
17 | + 'pw': 'aroma-pwd', | |
18 | + 'db': 'aroma-db', | |
5 | 19 | 'host': '127.0.0.1', |
6 | - 'port': '5434', | |
20 | + 'port': '5432', | |
7 | 21 | } |
8 | 22 | postgres_uri = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRES |
9 | 23 | |
10 | -SQLITE = { | |
11 | - 'file': '/home/richard/tmp/climso.db' | |
24 | +POSTGRESDEV = { | |
25 | + 'user': 'aroma-user', | |
26 | + 'pw': 'aroma-pwd', | |
27 | + 'db': 'aroma-dev-db', | |
28 | + 'host': '127.0.0.1', | |
29 | + 'port': '5433', | |
12 | 30 | } |
13 | -sqlite_uri = 'sqlite:///%(file)s' % SQLITE | |
14 | - | |
15 | -database_uri = sqlite_uri | |
16 | -database_uri = postgres_uri | |
31 | +postgres_dev_uri = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRESDEV | |
17 | 32 | |
18 | -data_basedir = '/data/CLIMSO' | |
33 | +POSTGRESTEST = { | |
34 | + 'user': 'aroma-user', | |
35 | + 'pw': 'aroma-pwd', | |
36 | + 'db': 'aroma-test-db', | |
37 | + 'host': '127.0.0.1', | |
38 | + 'port': '5434', | |
39 | +} | |
40 | +postgres_test_uri = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRESTEST | |
19 | 41 | |
20 | -MYSQL = { | |
42 | +MYSQL_LESIA = { | |
21 | 43 | 'user': 'mysql', |
22 | 44 | 'pw': 'mysql', |
23 | 45 | 'db': 'pdc_dev', |
24 | 46 | 'host': '127.0.0.1', |
25 | 47 | 'port': '3306', |
26 | 48 | } |
27 | -mysql_uri = 'mysql+pymysql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % MYSQL | |
49 | +mysql_lesia_uri = 'mysql+pymysql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % MYSQL | |
50 | + | |
51 | +# Here, set you database uri | |
52 | +# will be imported in ./pdc_config.py | |
53 | +# | |
54 | +# sqlalchemy_database_uri = 'sqlite:///:memory:' | |
55 | +# sqlalchemy_database_uri = 'sqlite:///another-app.db' | |
56 | +# sqlalchemy_database_uri = postgres_uri | |
57 | +# sqlalchemy_testdb_uri = postgres_test_uri | |
58 | +# sqlalchemy_devdb_uri = postgres_dev_uri | |
59 | +sqlalchemy_devdb_uri = 'sqlite:///another-app.db' | ... | ... |
... | ... | @@ -0,0 +1,95 @@ |
1 | +<!doctype html> | |
2 | +<html lang="fr"> | |
3 | +<head> | |
4 | + <meta charset="utf-8"> | |
5 | + <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"> | |
6 | + <link href="pdc-ico.svg" rel="icon"/> | |
7 | + <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" | |
8 | + integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" rel="stylesheet"> | |
9 | + <title> PDC Farm </title> | |
10 | + <style> | |
11 | + | |
12 | + /* | |
13 | + * Globals | |
14 | + */ | |
15 | + | |
16 | + html, | |
17 | + body { | |
18 | + height: 100%; | |
19 | + /*background-color: #333;*/ | |
20 | + } | |
21 | + | |
22 | + body { | |
23 | + | |
24 | + display: flex; | |
25 | + align-items: center; | |
26 | + background-color: #f5f5f5; | |
27 | + } | |
28 | + | |
29 | + .cover-container { | |
30 | + width: 100%; | |
31 | + max-width: 330px; | |
32 | + padding: 15px; | |
33 | + margin-top: 10em; | |
34 | + } | |
35 | + | |
36 | + | |
37 | + /*.cover {*/ | |
38 | + /* padding: 0 1.5rem;*/ | |
39 | + /*}*/ | |
40 | + | |
41 | + | |
42 | + .cover .btn-lg { | |
43 | + padding: .75rem 1.25rem; | |
44 | + font-weight: 700; | |
45 | + } | |
46 | + | |
47 | + .btn-lg { | |
48 | + display: block; | |
49 | + width: 100%; | |
50 | + margin: 10px; | |
51 | + color: #fff; | |
52 | + background-color: #343a40; | |
53 | + border-color: #343a40; | |
54 | + | |
55 | + padding: .5rem 1rem; | |
56 | + font-size: 1.25rem; | |
57 | + line-height: 1.5; | |
58 | + border-radius: .3rem; | |
59 | + } | |
60 | + | |
61 | + /* | |
62 | + * Footer | |
63 | + */ | |
64 | + /*.mastfoot {*/ | |
65 | + /* color: rgba(255, 255, 255, .5);*/ | |
66 | + /*}*/ | |
67 | + </style> | |
68 | +</head> | |
69 | +<body class="text-center"> | |
70 | + | |
71 | + <div class="cover-container d-flex h-100 p-3 mx-auto flex-column"> | |
72 | + | |
73 | + <main class="inner cover" role="main"> | |
74 | + <img class="mb-4" height="72" src="pdc-farm.svg" width="72"> | |
75 | + <h1 class="h3 font-weight-normal my-5">Plan de Charge</h1> | |
76 | + | |
77 | + <p class="lead"> | |
78 | + Place centrale de redirection vers les différents sites de la ferme d'applications sur le site de l'Irap. | |
79 | + </p> | |
80 | + <p class="lead"> | |
81 | + <a class="btn btn-lg btn-secondary" href="https://plan-de-charges.irap.omp.eu/public/">Pour tous</a> | |
82 | + <a class="btn btn-lg btn-secondary" href="https://plan-de-charges.irap.omp.eu/irap/">Irap</a> | |
83 | + </p> | |
84 | + </main> | |
85 | + | |
86 | + <footer class="mt-5 mb-3 text-muted"> | |
87 | + <p class="text-muted text-center"> | |
88 | + Plan de Charge<br/> | |
89 | + © 2021 IRAP | |
90 | + </p> | |
91 | + </footer> | |
92 | + | |
93 | + </div> | |
94 | +</body> | |
95 | +</html> | |
0 | 96 | \ No newline at end of file | ... | ... |
resources/flaskenv
... | ... | @@ -0,0 +1,101 @@ |
1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
2 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> | |
3 | + | |
4 | +<svg | |
5 | + xmlns:dc="http://purl.org/dc/elements/1.1/" | |
6 | + xmlns:cc="http://creativecommons.org/ns#" | |
7 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
8 | + xmlns:svg="http://www.w3.org/2000/svg" | |
9 | + xmlns="http://www.w3.org/2000/svg" | |
10 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
11 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
12 | + width="620" | |
13 | + height="620" | |
14 | + viewBox="0 0 164.04166 164.04166" | |
15 | + version="1.1" | |
16 | + id="svg8" | |
17 | + inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" | |
18 | + sodipodi:docname="pdc-farm.svg" | |
19 | + inkscape:export-filename="/home/rhitier/00DEV/pdc-web/app/static/img/pdc.png" | |
20 | + inkscape:export-xdpi="96" | |
21 | + inkscape:export-ydpi="96"> | |
22 | + <defs | |
23 | + id="defs2" /> | |
24 | + <sodipodi:namedview | |
25 | + id="base" | |
26 | + pagecolor="#ffffff" | |
27 | + bordercolor="#666666" | |
28 | + borderopacity="1.0" | |
29 | + inkscape:pageopacity="0.0" | |
30 | + inkscape:pageshadow="2" | |
31 | + inkscape:zoom="0.7" | |
32 | + inkscape:cx="266.06923" | |
33 | + inkscape:cy="292.4403" | |
34 | + inkscape:document-units="mm" | |
35 | + inkscape:current-layer="layer1" | |
36 | + showgrid="false" | |
37 | + inkscape:window-width="1595" | |
38 | + inkscape:window-height="893" | |
39 | + inkscape:window-x="192" | |
40 | + inkscape:window-y="103" | |
41 | + inkscape:window-maximized="0" | |
42 | + units="px" | |
43 | + fit-margin-top="0" | |
44 | + fit-margin-left="0" | |
45 | + fit-margin-right="0" | |
46 | + fit-margin-bottom="0" /> | |
47 | + <metadata | |
48 | + id="metadata5"> | |
49 | + <rdf:RDF> | |
50 | + <cc:Work | |
51 | + rdf:about=""> | |
52 | + <dc:format>image/svg+xml</dc:format> | |
53 | + <dc:type | |
54 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
55 | + <dc:title /> | |
56 | + </cc:Work> | |
57 | + </rdf:RDF> | |
58 | + </metadata> | |
59 | + <g | |
60 | + inkscape:label="Layer 1" | |
61 | + inkscape:groupmode="layer" | |
62 | + id="layer1" | |
63 | + transform="translate(-35.439223,-79.805708)"> | |
64 | + <g | |
65 | + id="g820" | |
66 | + transform="matrix(1.0412558,0,0,0.99961298,-6.221947,0.06279446)"> | |
67 | + <rect | |
68 | + style="fill:#7f7f9f;fill-opacity:1;stroke:#ffffff;stroke-width:2.66268826;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |
69 | + id="rect836" | |
70 | + width="151.87685" | |
71 | + height="156.32327" | |
72 | + x="43.024651" | |
73 | + y="83.286613" | |
74 | + ry="42.783207" /> | |
75 | + </g> | |
76 | + <text | |
77 | + xml:space="preserve" | |
78 | + style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:65.38256836px;line-height:24.25;font-family:aakar;-inkscape-font-specification:'aakar Medium';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.62687314;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |
79 | + x="45.287548" | |
80 | + y="165.87547" | |
81 | + id="text3721" | |
82 | + transform="scale(1.025263,0.97535948)"><tspan | |
83 | + sodipodi:role="line" | |
84 | + id="tspan3719" | |
85 | + x="45.287548" | |
86 | + y="165.87547" | |
87 | + style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:65.38256836px;line-height:24.25;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold';text-align:start;text-anchor:start;fill:#ffffff;stroke:#000000;stroke-width:0.62687314;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">PDC</tspan></text> | |
88 | + <text | |
89 | + xml:space="preserve" | |
90 | + style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:65.38256836px;line-height:24.25;font-family:aakar;-inkscape-font-specification:'aakar Medium';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.62687314;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |
91 | + x="45.876003" | |
92 | + y="214.90958" | |
93 | + id="text3721-3" | |
94 | + transform="scale(1.025263,0.97535947)"><tspan | |
95 | + sodipodi:role="line" | |
96 | + id="tspan3719-6" | |
97 | + x="45.876003" | |
98 | + y="214.90958" | |
99 | + style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:65.38256836px;line-height:24.25;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold';text-align:start;text-anchor:start;fill:#ffffff;stroke:#000000;stroke-width:0.62687314;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">farm</tspan></text> | |
100 | + </g> | |
101 | +</svg> | ... | ... |