Commit 07a6a779854eb2c66930082f3fa2469b8cf58390
Exists in
master
and in
4 other branches
Status history pie chart
Showing
33 changed files
with
848 additions
and
357 deletions
Show diff stats
CHANGELOG.md
... | ... | @@ -24,6 +24,14 @@ or major refactoring improvments. |
24 | 24 | |
25 | 25 | ## Unreleased |
26 | 26 | |
27 | +## [0.4.pre-3] - 2021-06-23 - Status Pie Chart | |
28 | +### New | |
29 | +Status Pie Chart | |
30 | +Status History table and ingest | |
31 | + | |
32 | +### Changed | |
33 | +D3js drawing scripts refactoring | |
34 | + | |
27 | 35 | ## [0.4.pre-2] - 2021-05-31 - Edit/Delete Links |
28 | 36 | ### New |
29 | 37 | Excell export | ... | ... |
VERSION.txt
app/commands/commands.py
1 | 1 | import csv |
2 | 2 | import os |
3 | 3 | import sys |
4 | +from datetime import datetime | |
4 | 5 | |
5 | 6 | import click |
6 | 7 | import random |
... | ... | @@ -10,7 +11,7 @@ from sqlalchemy.exc import IntegrityError |
10 | 11 | from sqlalchemy.sql import func |
11 | 12 | |
12 | 13 | from app.models import db, Agent, Service, Project, Capacity, Period, Charge, AgentStatus, Company, AgentBap, \ |
13 | - AgentGrade, Category, Label, ProjectLabel, CategoryLabel | |
14 | + AgentGrade, Category, Label, ProjectLabel, CategoryLabel, AgentHistory | |
14 | 15 | # TODO: rename to methods and add get_roles() |
15 | 16 | from app.auth.models import User, _nameToRole, _roleToName |
16 | 17 | |
... | ... | @@ -244,7 +245,7 @@ def feed_from_irap(csv_file_name): |
244 | 245 | # Feed categories and labels |
245 | 246 | # |
246 | 247 | for category, labels in categorie_labels.items(): |
247 | - print(category) | |
248 | + print(f"Category: {category}") | |
248 | 249 | n_c = Category.query.filter_by(name=category).one() |
249 | 250 | for label in labels: |
250 | 251 | print(label) |
... | ... | @@ -293,10 +294,17 @@ def feed_from_irap(csv_file_name): |
293 | 294 | db.session.add(n_a) |
294 | 295 | db.session.commit() |
295 | 296 | |
296 | - # Feed agents from agents list previously filled | |
297 | + # Feed status history | |
298 | + # This is done for the current period only | |
299 | + # as this csv format doesnt hold any history information | |
297 | 300 | # |
301 | + for a in Agent.query.all(): | |
302 | + _p = Period.query.filter(Period.name == datetime.today().year).one() | |
303 | + n_ap = AgentHistory(period_id=_p.id, agent_id=a.id, status_id=a.status_id) | |
304 | + db.session.add(n_ap) | |
305 | + db.session.commit() | |
298 | 306 | |
299 | - # Now feed the charges. | |
307 | + # Now feed both charges and status history | |
300 | 308 | # |
301 | 309 | # At least one for each csv row |
302 | 310 | # At most one for each year |
... | ... | @@ -309,22 +317,30 @@ def feed_from_irap(csv_file_name): |
309 | 317 | # TODO: period names should come from db request |
310 | 318 | for period_name in range(2011, 2030): |
311 | 319 | t = Period.query.filter(Period.name == period_name).one() |
312 | - charge = r[f"{period_name}"] | |
320 | + charge_value = r[f"{period_name}"] | |
313 | 321 | # Charge are stored as percent in db, but as fraction of ETP in irap csv |
314 | 322 | # we make the conversion here. |
315 | 323 | try: |
316 | - charge = int(100 * float(charge)) | |
324 | + charge_value = int(100 * float(charge_value)) | |
317 | 325 | except ValueError: |
318 | - charge = 0 | |
319 | - if charge == 0: | |
326 | + charge_value = 0 | |
327 | + if charge_value == 0: | |
320 | 328 | continue |
321 | 329 | n_c = Charge(agent_id=a.id, |
322 | 330 | project_id=p.id, |
323 | 331 | service_id=s.id, |
324 | 332 | capacity_id=c.id, |
325 | 333 | period_id=t.id, |
326 | - charge_rate=charge) | |
327 | - db.session.add(n_c) | |
334 | + charge_rate=charge_value) | |
335 | + status_value = r[status_key].strip().upper() | |
336 | + if not status_value: | |
337 | + continue | |
338 | + st = AgentStatus.query.filter(AgentStatus.name == status_value).one_or_none() | |
339 | + if st is None: | |
340 | + continue | |
341 | + print(f"Adding history p: {t.name}, a: {a.firstname}, s: {st.name}") | |
342 | + n_ap = AgentHistory(period_id=t.id, agent_id=a.id, status_id=st.id) | |
343 | + db.session.add_all([n_c, n_ap]) | |
328 | 344 | db.session.commit() |
329 | 345 | |
330 | 346 | |
... | ... | @@ -337,7 +353,7 @@ def feed_from_lesia(): |
337 | 353 | """ |
338 | 354 | from .lesia_db import lesia_agent, lesia_session, lesia_service, lesia_project, \ |
339 | 355 | lesia_fonction, lesia_periods, lesia_affectation, lesia_domains, lesia_poles, \ |
340 | - lesia_domainprojects | |
356 | + lesia_domainprojects, lesia_agentsemestres, lesia_statutagent | |
341 | 357 | |
342 | 358 | # Feed all lesia 'domaine' names and link to new category "Domaine" |
343 | 359 | # |
... | ... | @@ -432,6 +448,18 @@ def feed_from_lesia(): |
432 | 448 | db.session.add(n_c) |
433 | 449 | db.session.commit() |
434 | 450 | |
451 | + for sa in lesia_session.query(lesia_statutagent): | |
452 | + n_as = AgentStatus(id=sa.IDstatut, name=sa.nomstatut) | |
453 | + print(f"Adding Status {sa.nomstatut}") | |
454 | + db.session.add(n_as) | |
455 | + db.session.commit() | |
456 | + | |
457 | + for las in lesia_session.query(lesia_agentsemestres): | |
458 | + _p = Period.query.filter(Period.name == las.semestre_id).one() | |
459 | + n_ap = AgentHistory(period_id=_p.id, agent_id=las.agent_id, status_id=las.statut_id) | |
460 | + db.session.add(n_ap) | |
461 | + db.session.commit() | |
462 | + | |
435 | 463 | |
436 | 464 | @bp.cli.command("fake_lesia_names") |
437 | 465 | def fake_lesia_names(): | ... | ... |
app/commands/lesia_db.py
... | ... | @@ -31,3 +31,5 @@ lesia_periods = lesia_base.classes.gestit_semestres |
31 | 31 | lesia_domains = lesia_base.classes.gestit_domaines |
32 | 32 | lesia_poles = lesia_base.classes.poles |
33 | 33 | lesia_domainprojects = lesia_base.classes.gestit_domaine_projets |
34 | +lesia_agentsemestres = lesia_base.classes.gestit_agent_semestres | |
35 | +lesia_statutagent = lesia_base.classes.statutagent | ... | ... |
app/db_mgr.py
... | ... | @@ -166,11 +166,11 @@ def charges_by_project(project_id): |
166 | 166 | return nocomma_results |
167 | 167 | |
168 | 168 | |
169 | -def charges_by_project_stacked(project_id, category="service"): | |
169 | +def charges_by_project_stacked(project_id, sort_key="service"): | |
170 | 170 | """ |
171 | 171 | Build the list of charges for one project, period by period |
172 | 172 | :param project_id: the project's id we want to return data for |
173 | - :param category: what dict to build for each period, 'service' or 'capacity' ? | |
173 | + :param sort_key: what dict to build for each period, 'service' or 'capacity' ? | |
174 | 174 | :return: a 2 dim table with header as first line and datas next, of the form |
175 | 175 | period, category_0, category_1, ....., category_n, |
176 | 176 | per_0, value_00, value_01, ....., value_0n, |
... | ... | @@ -181,7 +181,7 @@ def charges_by_project_stacked(project_id, category="service"): |
181 | 181 | |
182 | 182 | TODO: common with charges_by_agent_stacked(agent_id): code to extrat |
183 | 183 | """ |
184 | - if category == 'capacity': | |
184 | + if sort_key == 'capacity': | |
185 | 185 | category_table = 'capacity' |
186 | 186 | sql_req = """ |
187 | 187 | select sum(c.charge_rate) |
... | ... | @@ -190,7 +190,7 @@ def charges_by_project_stacked(project_id, category="service"): |
190 | 190 | group by c1.id |
191 | 191 | order by c1.id |
192 | 192 | """ |
193 | - elif category == 'service': | |
193 | + elif sort_key == 'service': | |
194 | 194 | category_table = 'service' |
195 | 195 | sql_req = """ |
196 | 196 | select sum(c.charge_rate) |
... | ... | @@ -284,7 +284,8 @@ def charges_for_projects_stacked(): |
284 | 284 | select p.name, IFNULL(s.tot_charge, 0) tot_charge |
285 | 285 | from project p |
286 | 286 | left join |
287 | - (select c.project_id, sum(c.charge_rate) as tot_charge from charge c where c.period_id = {} group by c.project_id) s | |
287 | + (select c.project_id, sum(c.charge_rate) as tot_charge | |
288 | + from charge c where c.period_id = {} group by c.project_id) s | |
288 | 289 | on s.project_id = p.id |
289 | 290 | group by p.id |
290 | 291 | order by p.id; |
... | ... | @@ -359,7 +360,7 @@ def charges_by_agent_tabled(agent_id): |
359 | 360 | for line in results: |
360 | 361 | nocomma_line = [str(cell) for cell in line] |
361 | 362 | nocomma_results.append(nocomma_line) |
362 | - headers = ["Periode", "Projet", "Service", "Fonction", "Charge"] | |
363 | + headers = ["Période", "Projet", "Service", "Fonction", "Charge"] | |
363 | 364 | nocomma_results.insert(0, headers) |
364 | 365 | return nocomma_results |
365 | 366 | |
... | ... | @@ -379,3 +380,18 @@ def charges_by_agent(agent_id): |
379 | 380 | else: |
380 | 381 | all_charges.append([p, 0]) |
381 | 382 | return all_charges |
383 | + | |
384 | + | |
385 | +def count_agents_by_status(period_id): | |
386 | + sql_txt = f""" | |
387 | + select s.name, IFNULL(h.status_count, 0) as status_count | |
388 | + from agent_status s | |
389 | + left join | |
390 | + (select status_id, count(*) as status_count | |
391 | + from agent_history where period_id = {period_id} group by status_id) as h | |
392 | + on s.id = h.status_id | |
393 | + order by s.id; | |
394 | + """ | |
395 | + request = db.session.execute(sql_txt) | |
396 | + all_counts = [["Statut", "Effectif"]] + [[f'{s_n}', f'{a_c}'] for (s_n, a_c) in request.fetchall()] | |
397 | + return all_counts | ... | ... |
app/main/routes.py
... | ... | @@ -75,6 +75,15 @@ def agents(): |
75 | 75 | agents=all_agents) |
76 | 76 | |
77 | 77 | |
78 | +@bp.route('/agents/stats') | |
79 | +@role_required('project') | |
80 | +def agents_stats(): | |
81 | + num_agents = len(Agent.query.all()) | |
82 | + all_periods = Period.query.order_by(Period.name).all() | |
83 | + return render_template('agents_stats.html', subtitle="Statistiques des agents ({})".format(num_agents), | |
84 | + periods=all_periods) | |
85 | + | |
86 | + | |
78 | 87 | @bp.route('/capacities') |
79 | 88 | @login_required |
80 | 89 | def capacities(): |
... | ... | @@ -225,11 +234,11 @@ def label_edit(label_id=None): |
225 | 234 | if label_id: |
226 | 235 | # then update existing |
227 | 236 | this_label = Label.query.get(int(label_id)) |
228 | - done_string = updated_message+"." | |
237 | + done_string = updated_message + "." | |
229 | 238 | else: |
230 | 239 | # or create from scratch |
231 | 240 | this_label = Label() |
232 | - done_string = added_message+"." | |
241 | + done_string = added_message + "." | |
233 | 242 | # fill orm with form and write to db |
234 | 243 | this_label.from_request(request) |
235 | 244 | db.session.add(this_label) |
... | ... | @@ -259,7 +268,7 @@ def category_edit(category_id=None): |
259 | 268 | if category_id: |
260 | 269 | # then update existing |
261 | 270 | this_category = Category.query.get(int(category_id)) |
262 | - done_string = updated_message+"." | |
271 | + done_string = updated_message + "." | |
263 | 272 | else: |
264 | 273 | # or create from scratch |
265 | 274 | this_category = Category() |
... | ... | @@ -294,7 +303,7 @@ def project_edit(project_id=None): |
294 | 303 | if project_id: |
295 | 304 | # then update existing |
296 | 305 | this_project = Project.query.get(int(project_id)) |
297 | - done_string = updated_message+"." | |
306 | + done_string = updated_message + "." | |
298 | 307 | else: |
299 | 308 | # check name doesnt exist yet |
300 | 309 | existing_project = Project.query.filter(Project.name == request.form.get('name')).one_or_none() |
... | ... | @@ -303,7 +312,7 @@ def project_edit(project_id=None): |
303 | 312 | return redirect(url_for('main.project_edit')) |
304 | 313 | # or create from scratch |
305 | 314 | this_project = Project() |
306 | - done_string = added_message+"." | |
315 | + done_string = added_message + "." | |
307 | 316 | # fill orm with form and write to db |
308 | 317 | this_project.from_request(request) |
309 | 318 | db.session.add(this_project) |
... | ... | @@ -345,11 +354,11 @@ def agent_edit(agent_id=None): |
345 | 354 | if agent_id: |
346 | 355 | # then update existing |
347 | 356 | this_agent = Agent.query.get(int(agent_id)) |
348 | - done_string = updated_message+"." | |
357 | + done_string = updated_message + "." | |
349 | 358 | else: |
350 | 359 | # or create from scratch |
351 | 360 | this_agent = Agent() |
352 | - done_string = added_message+"." | |
361 | + done_string = added_message + "." | |
353 | 362 | # fill orm with form and write to db |
354 | 363 | this_agent.from_request(request) |
355 | 364 | db.session.add(this_agent) |
... | ... | @@ -446,11 +455,11 @@ def array_to_csv(array, sep=','): |
446 | 455 | return resp |
447 | 456 | |
448 | 457 | |
449 | -@bp.route('/charge/project/<project_id>/<category>/<any_format>') | |
450 | -@bp.route('/charge/project/<project_id>/<category>') | |
458 | +@bp.route('/charge/project/<project_id>/<sort_key>/<any_format>') | |
459 | +@bp.route('/charge/project/<project_id>/<sort_key>') | |
451 | 460 | @role_required('project') |
452 | -def rest_charge_project(project_id, category, any_format='csv'): | |
453 | - return array_to_any(db_mgr.charges_by_project_stacked(project_id, category), any_format) | |
461 | +def rest_charge_project(project_id, sort_key, any_format='csv'): | |
462 | + return array_to_any(db_mgr.charges_by_project_stacked(project_id, sort_key), any_format) | |
454 | 463 | |
455 | 464 | |
456 | 465 | @bp.route('/charge/agent/<agent_id>/<any_format>') |
... | ... | @@ -472,3 +481,10 @@ def rest_labels_stats(category_id, any_format='csv'): |
472 | 481 | @role_required('project') |
473 | 482 | def rest_projects_stats(any_format='csv'): |
474 | 483 | return array_to_any(db_mgr.charges_for_projects_stacked(), any_format) |
484 | + | |
485 | + | |
486 | +@bp.route('/count/agents/by_status/<period_id>/<any_format>') | |
487 | +@bp.route('/count/agents/by_status/<period_id>') | |
488 | +@role_required('project') | |
489 | +def rest_agents_status_count(period_id, any_format='csv'): | |
490 | + return array_to_any(db_mgr.count_agents_by_status(period_id), any_format) | ... | ... |
app/main/static/css/charges.css
... | ... | @@ -4,14 +4,17 @@ |
4 | 4 | stroke-width: 2px; |
5 | 5 | z-index: -1; |
6 | 6 | } |
7 | + | |
7 | 8 | .total-circle { |
8 | - fill: orangered; | |
9 | + fill: orangered; | |
9 | 10 | } |
11 | + | |
10 | 12 | .total-circle:hover { |
11 | 13 | -webkit-filter: brightness(2.0); |
12 | 14 | -moz-filter: brightness(2.0); |
13 | 15 | filter: brightness(2.0); |
14 | 16 | } |
17 | + | |
15 | 18 | .total-tooltip { |
16 | 19 | border: orangered; |
17 | 20 | } |
... | ... | @@ -28,8 +31,9 @@ |
28 | 31 | stroke-width: 0px; |
29 | 32 | } |
30 | 33 | |
31 | -#charge_table, .charge_chart{ | |
32 | - width: 100%; | |
34 | +#charge_table, .charge_chart { | |
35 | + /*width: 100%;*/ | |
36 | + /*height: 100%;*/ | |
33 | 37 | } |
34 | 38 | |
35 | 39 | #charge_table, |
... | ... | @@ -46,11 +50,23 @@ |
46 | 50 | } |
47 | 51 | |
48 | 52 | .svg_chart { |
49 | - margin-bottom: 50px; | |
53 | + /*margin-bottom: 50px;*/ | |
50 | 54 | background-color: #fAfAfA; |
51 | 55 | border: 1pt solid black; |
52 | 56 | display: inline-block; |
53 | 57 | width: 100%; |
58 | + /*height: 100%;*/ | |
59 | +} | |
60 | + | |
61 | +.pie_border { | |
62 | + stroke: black; | |
63 | + stroke-width: 0.8pt; | |
64 | + fill: none; | |
65 | +} | |
66 | + | |
67 | +path.pie { | |
68 | + stroke: #fafafa; | |
69 | + stroke-width: 1pt; | |
54 | 70 | } |
55 | 71 | |
56 | 72 | text.legend { |
... | ... | @@ -94,7 +110,7 @@ rect.bar { |
94 | 110 | i.export { |
95 | 111 | padding: 7px; |
96 | 112 | position: absolute; |
97 | - margin-top:8px; | |
113 | + margin-top: 8px; | |
98 | 114 | right: 3%; |
99 | 115 | } |
100 | 116 | |
... | ... | @@ -109,7 +125,7 @@ i.export:hover { |
109 | 125 | right: 2%; |
110 | 126 | pointer-events: auto; |
111 | 127 | width: 150px; |
112 | - margin-top:15px; | |
128 | + margin-top: 15px; | |
113 | 129 | padding: 0; |
114 | 130 | } |
115 | 131 | |
... | ... | @@ -137,7 +153,7 @@ i.export:hover { |
137 | 153 | height: 150px; |
138 | 154 | position: absolute; |
139 | 155 | padding: 10px; |
140 | - top:0; | |
156 | + top: 0; | |
141 | 157 | right: 0; |
142 | 158 | /*background-color: #0b2e13;*/ |
143 | 159 | } |
144 | 160 | \ No newline at end of file | ... | ... |
app/main/static/js/charges.js
... | ... | @@ -3,89 +3,151 @@ function roundToTwo(num) { |
3 | 3 | return +(Math.round(num + "e+2") + "e-2"); |
4 | 4 | } |
5 | 5 | |
6 | -function build_chart(div_selector, data_url, entity_name, category_type) { | |
6 | +function make_svg(div_selector, data_url, width, height, | |
7 | + margin = {top: 10, right: 50, bottom: 10, left: 10}) { | |
7 | 8 | |
8 | - const main_elt = document.getElementById("main") | |
9 | 9 | |
10 | - var margin = {top: 60, right: 100, bottom: 200, left: 90}, | |
11 | - width = main_elt.offsetWidth * 0.95 - margin.left - margin.right, | |
12 | - height = 600 - margin.top - margin.bottom; | |
10 | + d3.select(div_selector).selectAll("*").remove(); | |
11 | + | |
12 | + let svg_height = height + margin.top + margin.bottom; | |
13 | + let svg_width = width + margin.left + margin.right; | |
14 | + | |
15 | + const svg = d3.select(div_selector).append("svg") | |
16 | + .attr("viewBox", [0, 0, svg_width, svg_height]) | |
17 | + .attr("preserveAspectRatio", 'xMinYMin meet') | |
18 | + .attr("class", "svg_chart") | |
19 | + .attr("width", svg_width) | |
20 | + .attr("height", svg_height) | |
21 | + .append("g") | |
22 | + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
23 | + | |
24 | + d3.select(div_selector).node().appendChild(make_hamburger(data_url).node()); | |
25 | + | |
26 | + // Show svg.g start and border | |
27 | + // | |
28 | + // svg.append('circle') | |
29 | + // .attr('r', 5) | |
30 | + // .attr('stroke', 'red'); | |
31 | + // svg.append('rect') | |
32 | + // .attr('width', width) | |
33 | + // .attr('height', height) | |
34 | + // .attr('stroke', 'red') | |
35 | + // .attr('fill', 'none'); | |
36 | + | |
37 | + return svg; | |
38 | +} | |
13 | 39 | |
14 | - const height_ratio = 1.2; // how murch room to give above chart for lisibility | |
15 | 40 | |
16 | - const tooltip_offset = {dx: 0, dy: 100} | |
17 | - const tooltip_offset_dot = {dx: 20, dy: 60} | |
41 | +function make_title(svg, parent_width, titles, offset = {'x': 0, 'y': 0}) { | |
42 | + let l1_h = 20; | |
43 | + let l2_h = 20; | |
44 | + // move to center of containing element | |
45 | + let title_g = svg.append('g') | |
46 | + .attr("transform", "translate(" + (offset.x + parent_width / 2) + "," + offset.y + ")"); | |
47 | + // display part 1 | |
48 | + title_g.append("text") | |
49 | + .attr("text-anchor", "middle") | |
50 | + .style("font-size", "16px") | |
51 | + .style("font-weight", "bold") | |
52 | + .attr("y", l1_h) | |
53 | + .text(titles[0]); | |
54 | + // part 2 | |
55 | + title_g.append("text") | |
56 | + .attr("y", l1_h + l2_h) | |
57 | + .attr("text-anchor", "middle") | |
58 | + .style("font-size", "12px") | |
59 | + .text(titles[1]); | |
60 | + return l1_h + l2_h; | |
61 | +} | |
18 | 62 | |
19 | - const y_ticks_num = 5 // dont show to many y ticks for lisibility | |
63 | +function make_legend(svg, offset, parent_width, color_scale, mouseleave_callback, mouseover_callback) { | |
20 | 64 | |
21 | 65 | const legend_rect_size = 15; // size of rectangle in legend |
22 | 66 | const legend_height = 20; |
23 | 67 | const legend_max_length = 20; |
24 | 68 | const legend_spacing = 5; |
69 | + const text_margin_left = legend_rect_size + legend_spacing * 1.5; | |
25 | 70 | |
26 | - const dot_radius = 6; // size of total line dot | |
27 | - | |
28 | - | |
29 | - var colorScale = d3.scaleOrdinal([]); // Will be really set later by category type | |
30 | - | |
31 | - // | |
32 | - // Configure chart by the category given as arg | |
33 | - // | |
34 | - var chart_title = "" | |
35 | - var category_title = "" | |
36 | - var draw_areas = () => void 0; | |
37 | - var draw_total_line = () => void 0; | |
38 | - var draw_categories_bars = () => void 0; | |
71 | + // Get list of elements to display | |
72 | + let legend_keys = color_scale.domain(); | |
39 | 73 | |
40 | - var mouseoverlegend = category_mouseoverlegend; | |
41 | - var mouseleavelegend = category_mouseleavelegend; | |
74 | + if (legend_keys.length === 0) { | |
75 | + return 0; | |
76 | + } | |
42 | 77 | |
78 | + // Truncate legend keys when too long | |
79 | + let short_legend_keys = legend_keys.map(function (l) { | |
80 | + const n = legend_max_length; | |
81 | + return (l.length > n) ? l.substr(0, n - 1) : l; | |
82 | + }); | |
83 | + | |
84 | + | |
85 | + let legend_wrap = svg.append('g') | |
86 | + .attr('width', parent_width) | |
87 | + .attr('class', 'legendwrap') | |
88 | + .attr("transform", "translate(" + offset.x + "," + offset.y + ")") | |
89 | + ; | |
90 | + | |
91 | + let legend = legend_wrap.selectAll('.legend') | |
92 | + .data(legend_keys) | |
93 | + .enter() | |
94 | + .append('g') | |
95 | + .attr('class', (d,i) => short_legend_keys[i]) | |
96 | + .on("mouseover", mouseover_callback) | |
97 | + .on("mouseleave", mouseleave_callback); | |
98 | + | |
99 | + legend.append('rect') | |
100 | + .attr('width', legend_rect_size) | |
101 | + .attr('height', legend_rect_size) | |
102 | + .attr('fill', function (d) { | |
103 | + return color_scale(d); | |
104 | + }) | |
105 | + .attr('class', 'legend'); | |
43 | 106 | |
44 | - if (category_type == 'capacity') { | |
45 | - chart_title = "Charge par fonction" | |
46 | - category_title = "Fonction" | |
47 | - //draw_total_line | |
48 | - draw_categories_bars = draw_categories_grouped | |
49 | - colorScale = d3.scaleOrdinal(d3.schemeSet3); | |
50 | - } else if (category_type == 'service') { | |
51 | - chart_title = "Charge par service" | |
52 | - category_title = "Service" | |
53 | - draw_total_line = draw_totalcharge_line | |
54 | - draw_categories_bars = draw_categories_stacked | |
55 | - colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
56 | - } else if (category_type == 'project') { | |
57 | - chart_title = "Charge par projet" | |
58 | - category_title = "Projet" | |
59 | - draw_categories_bars = draw_categories_stacked | |
60 | - colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
61 | - } else if (category_type == 'area') { | |
62 | - margin.bottom = 400 | |
63 | - height = 1200 - margin.top - margin.bottom; | |
64 | - chart_title = "Tous agents confondus" | |
65 | - category_title = "Projet" | |
66 | - draw_areas = draw_projects_areas | |
67 | - colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
68 | - mouseoverlegend = () => void 0; | |
69 | - mouseleavelegend = () => void 0; | |
70 | - } else { | |
71 | - alert("ALERT ! Every body shall quit the boat, we are sinking ! ALERT !") | |
72 | - } | |
107 | + legend.append('text') | |
108 | + .attr('class', 'legend') | |
109 | + .attr('x', text_margin_left) | |
110 | + .attr('y', 13) | |
111 | + .text( (d,i) => short_legend_keys[i]); | |
73 | 112 | |
113 | + // Make legend column length for later display | |
114 | + // | |
115 | + // - first make an array of the length of each legend element | |
116 | + const row_height = legend.selectAll('text.legend')._groups[0][0].getBBox().height + legend_spacing; | |
117 | + const text_length_list = legend.selectAll('text.legend')._groups.map(el => el[0].getComputedTextLength()); | |
118 | + // - then extract the maximum of those lengths plus a margin including the colored rect length | |
119 | + const column_length = Math.max(...text_length_list) + text_margin_left + 20; | |
120 | + | |
121 | + const nb_cols = Math.floor(parent_width / column_length); | |
122 | + const nb_rows = Math.floor(legend_keys.length / nb_cols) + 1; | |
123 | + let ypos = 0, | |
124 | + xpos = 0; | |
125 | + | |
126 | + | |
127 | + // Now move each legend element to its position | |
128 | + legend.attr("transform", function (d, i) { | |
129 | + if (i > 0 && i % nb_rows == 0) { | |
130 | + xpos += column_length; | |
131 | + ypos = 0; | |
132 | + } | |
133 | + let translation = 'translate(' + xpos + ',' + ypos + ')'; | |
134 | + ypos += row_height; | |
135 | + return translation; | |
136 | + }); | |
74 | 137 | |
75 | - const xScale = d3.scaleBand() | |
76 | - .range([0, width]) | |
77 | - .padding(0.4); | |
138 | + // TODO: should be able to return the height | |
78 | 139 | |
79 | - const yScale = d3.scaleLinear() | |
80 | - .range([height, 0]); | |
140 | + return row_height * nb_rows; | |
141 | +} | |
81 | 142 | |
143 | +function make_hamburger(data_url) { | |
82 | 144 | |
83 | 145 | // Configure the tooltip to export svg to png or csv |
84 | - var update_export_menu = function (e, d) { | |
146 | + let update_export_menu = function (e, d) { | |
85 | 147 | |
86 | 148 | const tooltip_test = document.getElementsByClassName('tooltip_hamburger'); |
87 | 149 | |
88 | - if (tooltip_test.length == 0) { | |
150 | + if (tooltip_test.length === 0) { | |
89 | 151 | d3.select(".tooltip_hamburger").remove(); |
90 | 152 | |
91 | 153 | const tooltip_hamburger = hamburger.append("div") |
... | ... | @@ -93,75 +155,142 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
93 | 155 | .attr("class", "tooltip tooltip_hamburger"); |
94 | 156 | |
95 | 157 | d3.select(this).transition() |
96 | - .duration(1) | |
158 | + .duration(1); | |
97 | 159 | tooltip_hamburger |
98 | 160 | .transition() |
99 | 161 | .duration(200) |
100 | - .style("opacity", 1) | |
162 | + .style("opacity", 1); | |
101 | 163 | tooltip_hamburger |
102 | 164 | .html("<span>Export </span>" + |
103 | 165 | "<li id='to_csv'>To CSV</li>" + |
104 | 166 | "<li id='to_xls'>To XLS</li>" + |
105 | - "<li id='to_png'>To PNG</li>") | |
167 | + "<li id='to_png'>To PNG</li>"); | |
106 | 168 | d3.select("#to_png").on("click", download_png); |
107 | 169 | d3.select("#to_csv").on("click", function () { |
108 | - download_any(this, data_url, format='csv'); | |
170 | + download_any(this, data_url, format = 'csv'); | |
109 | 171 | }); |
110 | 172 | d3.select("#to_xls").on("click", function () { |
111 | - download_any(this, data_url, format='xls'); | |
173 | + download_any(this, data_url, format = 'xls'); | |
112 | 174 | }); |
113 | 175 | } else { |
114 | 176 | d3.select(".tooltip_hamburger").remove(); |
115 | 177 | } |
116 | 178 | |
117 | - } | |
179 | + }; | |
118 | 180 | // Create a download button inside the div contaning svg chart |
119 | - const hamburger = d3.select(div_selector).append('i') | |
181 | + const hamburger = d3.create('i') | |
120 | 182 | .attr('class', 'fas fa-bars fa-lg export') |
121 | 183 | .on("click", update_export_menu); |
122 | 184 | |
123 | - const real_width = width + margin.left + margin.right; | |
124 | - const real_height = height + margin.top + margin.bottom; | |
185 | + return hamburger; | |
186 | +} | |
125 | 187 | |
126 | - const svg = d3.select(div_selector).append("svg") | |
127 | - .attr("viewBox", [0, 0, real_width, real_height]) | |
128 | - .attr("class", "svg_chart") | |
129 | - .attr("width", real_width) | |
130 | - .attr("height", real_height) | |
131 | - .append("g") | |
132 | - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
188 | +function build_chart(div_selector, data_url, entity_name, category_type) { | |
189 | + // TODO: split build_bar and build_area | |
190 | + | |
191 | + | |
192 | + // TODO: common code, find a way to factorize | |
193 | + let main_elt = document.querySelector(div_selector); | |
194 | + let width = main_elt.offsetWidth, | |
195 | + height = 400; | |
196 | + | |
197 | + const height_ratio = 1.2; // how murch room to give above chart for lisibility | |
198 | + | |
199 | + const tooltip_offset = {dx: 0, dy: 100}; | |
200 | + const tooltip_offset_dot = {dx: 20, dy: 60}; | |
201 | + | |
202 | + const y_ticks_num = 5; // dont show to many y ticks for lisibility | |
203 | + | |
204 | + const dot_radius = 6; // size of total line dot | |
205 | + | |
206 | + | |
207 | + let colorScale = d3.scaleOrdinal([]); // Will be really set later by category type | |
208 | + | |
209 | + // | |
210 | + // Configure chart by the category given as arg | |
211 | + // | |
212 | + let chart_title = ""; | |
213 | + let category_title = ""; | |
214 | + let draw_areas = () => void 0; | |
215 | + let draw_total_line = () => void 0; | |
216 | + let draw_categories_bars = () => void 0; | |
217 | + | |
218 | + let mouseoverlegend = category_mouseoverlegend; | |
219 | + let mouseleavelegend = category_mouseleavelegend; | |
220 | + | |
221 | + let margin = {top: 100, right: 100, bottom: 100, left: 100}; | |
222 | + | |
223 | + | |
224 | + if (category_type === 'capacity') { | |
225 | + chart_title = "Charge par fonction"; | |
226 | + category_title = "Fonction"; | |
227 | + //draw_total_line | |
228 | + draw_categories_bars = draw_categories_grouped; | |
229 | + colorScale = d3.scaleOrdinal(d3.schemeSet3); | |
230 | + } else if (category_type === 'service') { | |
231 | + chart_title = "Charge par service"; | |
232 | + category_title = "Service"; | |
233 | + draw_total_line = draw_totalcharge_line; | |
234 | + draw_categories_bars = draw_categories_stacked; | |
235 | + colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
236 | + } else if (category_type === 'project') { | |
237 | + chart_title = "Charge par projet"; | |
238 | + category_title = "Projet"; | |
239 | + draw_categories_bars = draw_categories_stacked; | |
240 | + colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
241 | + } else if (category_type === 'area') { | |
242 | + // margin.bottom = 400; | |
243 | + // height = 1200 ;//- margin.top - margin.bottom; | |
244 | + chart_title = "Tous agents confondus"; | |
245 | + category_title = "Projet"; | |
246 | + draw_areas = draw_projects_areas; | |
247 | + colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
248 | + mouseoverlegend = () => void 0; | |
249 | + mouseleavelegend = () => void 0; | |
250 | + } else { | |
251 | + alert("ALERT ! Every body shall quit the boat, we are sinking ! ALERT !"); | |
252 | + } | |
253 | + | |
254 | + | |
255 | + const xScale = d3.scaleBand() | |
256 | + .range([0, width]) | |
257 | + .padding(0.4); | |
258 | + | |
259 | + const yScale = d3.scaleLinear() | |
260 | + .range([height, 0]); | |
261 | + | |
262 | + const svg = make_svg(div_selector, data_url, width, height, margin); | |
133 | 263 | |
134 | 264 | const tooltip = d3.select('html') |
135 | 265 | .append("div") |
136 | 266 | .style("opacity", 0) |
137 | - .attr("class", "tooltip") | |
267 | + .attr("class", "tooltip"); | |
138 | 268 | |
139 | - var mousemove = function (e, d) { | |
269 | + let mousemove = function (e, d) { | |
140 | 270 | tooltip |
141 | 271 | .style("left", (e.pageX - tooltip_offset.dx) + "px") |
142 | - .style("top", (e.pageY - tooltip_offset.dy) + "px") | |
143 | - } | |
272 | + .style("top", (e.pageY - tooltip_offset.dy) + "px"); | |
273 | + }; | |
144 | 274 | |
145 | - var mouseleave = function (d) { | |
275 | + let mouseleave = function (d) { | |
146 | 276 | tooltip |
147 | 277 | .transition() |
148 | 278 | .duration(900) |
149 | - .style("opacity", 0) | |
150 | - } | |
151 | - | |
152 | - var mouseover = function (e, d) { | |
153 | - var category_name = d3.select(this.parentNode).datum().key | |
154 | - var category_charge = d.data[category_name] | |
155 | - show_tooltip(e, category_name, category_charge) | |
156 | - console.log("HELLO") | |
157 | - } | |
158 | - | |
159 | - var mouseovergrouped = function (e, d) { | |
160 | - var category_name = d.key | |
161 | - var category_charge = d.value | |
162 | - show_tooltip(e, category_name, category_charge) | |
163 | - } | |
164 | - var show_tooltip = function (e, category_name, category_charge) { | |
279 | + .style("opacity", 0); | |
280 | + }; | |
281 | + | |
282 | + let mouseover = function (e, d) { | |
283 | + let category_name = d3.select(this.parentNode).datum().key; | |
284 | + let category_charge = d.data[category_name]; | |
285 | + show_tooltip(e, category_name, category_charge); | |
286 | + }; | |
287 | + | |
288 | + let mouseovergrouped = function (e, d) { | |
289 | + let category_name = d.key; | |
290 | + let category_charge = d.value; | |
291 | + show_tooltip(e, category_name, category_charge); | |
292 | + }; | |
293 | + let show_tooltip = function (e, category_name, category_charge) { | |
165 | 294 | tooltip |
166 | 295 | .transition() |
167 | 296 | .duration(200) |
... | ... | @@ -169,155 +298,90 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
169 | 298 | tooltip |
170 | 299 | .html("<b>" + category_title + ":</b> " + category_name + "<br>" + "<b>Charge:</b> " + category_charge + " ETP") |
171 | 300 | .style("left", (e.pageX - tooltip_offset.dx) + "px") |
172 | - .style("top", (e.pageY - tooltip_offset.dy) + "px") | |
173 | - } | |
301 | + .style("top", (e.pageY - tooltip_offset.dy) + "px"); | |
302 | + }; | |
174 | 303 | |
175 | - var mouseleavedot = function (e, d) { | |
304 | + let mouseleavedot = function (e, d) { | |
176 | 305 | d3.select(this).transition() |
177 | 306 | .duration(1) |
178 | 307 | .attr("r", dot_radius); |
179 | 308 | mouseleave(d); |
180 | - } | |
309 | + }; | |
181 | 310 | |
182 | - var mouseoverdot = function (e, d) { | |
311 | + let mouseoverdot = function (e, d) { | |
183 | 312 | d3.select(this).transition() |
184 | 313 | .duration(1) |
185 | 314 | .attr("r", dot_radius * 1.5); |
186 | 315 | tooltip |
187 | 316 | .transition() |
188 | 317 | .duration(200) |
189 | - .style("opacity", 1) | |
318 | + .style("opacity", 1); | |
190 | 319 | tooltip |
191 | 320 | .html("<b>" + d.period + ": </b>" + d.total + " ETP") |
192 | 321 | .style("left", (e.pageX - tooltip_offset_dot.dx) + "px") |
193 | - .style("top", (e.pageY - tooltip_offset_dot.dy) + "px") | |
194 | - } | |
322 | + .style("top", (e.pageY - tooltip_offset_dot.dy) + "px"); | |
323 | + }; | |
195 | 324 | |
196 | 325 | function category_mouseoverlegend() { |
197 | - var legend_category = $(this).attr("class"); | |
198 | - var bar_category = document.getElementsByClassName(legend_category); | |
326 | + let legend_category = $(this).attr("class"); | |
327 | + let bar_category = document.getElementsByClassName(legend_category); | |
199 | 328 | if (bar_category[0].tagName === "g") { |
200 | - var rect_to_hover = bar_category[0].children; | |
329 | + let rect_to_hover = bar_category[0].children; | |
201 | 330 | (bar_category[1].children[0]).classList.add("brillance"); |
202 | - for (var i = 0; i < rect_to_hover.length; i++) { | |
331 | + for (let i = 0; i < rect_to_hover.length; i++) { | |
203 | 332 | rect_to_hover[i].classList.add("brillance"); |
204 | 333 | } |
205 | 334 | } else { |
206 | - for (var i = 0; i < bar_category.length; i++) { | |
335 | + for (let i = 0; i < bar_category.length; i++) { | |
207 | 336 | bar_category[i].classList.add("brillance"); |
208 | 337 | } |
209 | 338 | } |
210 | 339 | } |
211 | 340 | |
212 | 341 | function category_mouseleavelegend() { |
213 | - var legend_category = $(this).attr("class"); | |
214 | - var bar_category = document.getElementsByClassName(legend_category); | |
342 | + let legend_category = $(this).attr("class"); | |
343 | + let bar_category = document.getElementsByClassName(legend_category); | |
215 | 344 | if (bar_category[0].tagName === "g") { |
216 | - var rect_to_hover = bar_category[0].children; | |
345 | + let rect_to_hover = bar_category[0].children; | |
217 | 346 | (bar_category[1].children[0]).classList.remove("brillance"); |
218 | - for (var i = 0; i < rect_to_hover.length; i++) { | |
347 | + for (let i = 0; i < rect_to_hover.length; i++) { | |
219 | 348 | rect_to_hover[i].classList.remove("brillance"); |
220 | 349 | } |
221 | 350 | } else { |
222 | - var lenght_i = bar_category.length - 1; | |
223 | - for (var i = lenght_i; i >= 0; i--) { | |
351 | + let lenght_i = bar_category.length - 1; | |
352 | + for (let i = lenght_i; i >= 0; i--) { | |
224 | 353 | bar_category[i].classList.remove("brillance"); |
225 | 354 | } |
226 | 355 | } |
227 | 356 | } |
228 | 357 | |
229 | - var addlegend = function (color_scale) { | |
230 | - | |
231 | - // add horizontal legend | |
232 | - let legend_keys = color_scale.domain(); | |
233 | - | |
234 | - // Truncate legend keys when too long | |
235 | - legend_keys = legend_keys.map(function (l) { | |
236 | - const n = legend_max_length; | |
237 | - return (l.length > n) ? l.substr(0, n - 1) : l; | |
238 | - }); | |
239 | - | |
240 | - | |
241 | - var legendWrap = svg.append('g') | |
242 | - .attr('width', '100%') | |
243 | - .attr('class', 'legendwrap'); | |
244 | - | |
245 | - var legend = svg.select('.legendwrap').selectAll('.legend') | |
246 | - .data(legend_keys) | |
247 | - .enter() | |
248 | - .append('g') | |
249 | - .attr('class', d => d) | |
250 | - .on("mouseover", mouseoverlegend) | |
251 | - .on("mouseleave", mouseleavelegend); | |
252 | - | |
253 | - legend.append('rect') | |
254 | - .attr('width', legend_rect_size) | |
255 | - .attr('height', legend_rect_size) | |
256 | - .style('fill', color_scale) | |
257 | - .attr('class', 'legend'); | |
258 | - | |
259 | - legend.append('text') | |
260 | - .attr('class', 'legend') | |
261 | - .attr('x', legend_rect_size + legend_spacing * 1.5) | |
262 | - .attr('y', 13) | |
263 | - .text(d => d); | |
264 | - | |
265 | - var ypos = 0, | |
266 | - newxpos = 0, | |
267 | - maxwidth = 0, | |
268 | - xpos; | |
269 | - | |
270 | - // Get Max legend key length for later display | |
271 | - const text_length_list = legend.selectAll('text.legend')._groups.map(el => el[0].getComputedTextLength()) | |
272 | - const keycol_length = Math.max(...text_length_list) + 40 | |
273 | - | |
274 | - legend | |
275 | - .attr("transform", function (d, i) { | |
276 | - xpos = newxpos; | |
277 | - if (width < xpos + keycol_length) { | |
278 | - newxpos = xpos = 0; | |
279 | - ypos += legend_height; | |
280 | - | |
281 | - } | |
282 | - newxpos += keycol_length; | |
283 | - if (newxpos > maxwidth) maxwidth = newxpos; | |
284 | - | |
285 | - return 'translate(' + xpos + ',' + ypos + ')'; | |
286 | - | |
287 | - }); | |
288 | - | |
289 | - | |
290 | - legendWrap | |
291 | - .attr("transform", function (d, i) { | |
292 | - return "translate(0 ," + (height + 100) + ")"; | |
293 | - }); | |
294 | - } | |
295 | 358 | |
296 | 359 | function draw_categories_grouped(data, categories) { |
297 | 360 | |
298 | 361 | // TODO: use ymax_from_stacked |
299 | 362 | // Get the max y to plot |
300 | 363 | // If no data at all, force to 0 |
301 | - if (categories.length == 0) { | |
302 | - y_max = 0 | |
364 | + let y_max; | |
365 | + if (categories.length === 0) { | |
366 | + y_max = 0; | |
303 | 367 | } else { |
304 | - var y_max = d3.max(data, function (d) { | |
368 | + y_max = d3.max(data, function (d) { | |
305 | 369 | return d3.max(categories, function (c) { |
306 | - return +d[c] | |
307 | - }) | |
370 | + return +d[c]; | |
371 | + }); | |
308 | 372 | }); |
309 | 373 | } |
310 | 374 | // Force maximum in any cases |
311 | - if (y_max == 0) { | |
312 | - y_max = 100 | |
375 | + if (y_max === 0) { | |
376 | + y_max = 100; | |
313 | 377 | } |
314 | - y_max = y_max * height_ratio | |
315 | - yScale.domain([0, y_max]) | |
378 | + y_max = y_max * height_ratio; | |
379 | + yScale.domain([0, y_max]); | |
316 | 380 | // Another scale for subgroup position |
317 | - var xCategories = d3.scaleBand() | |
381 | + let xCategories = d3.scaleBand() | |
318 | 382 | .domain(categories) |
319 | 383 | .range([0, xScale.bandwidth()]) |
320 | - .padding([0.2]) | |
384 | + .padding([0.2]); | |
321 | 385 | |
322 | 386 | svg.append("g") |
323 | 387 | .selectAll("g") |
... | ... | @@ -336,9 +400,7 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
336 | 400 | .attr("x", d => xCategories(d.key)) |
337 | 401 | .attr("width", xCategories.bandwidth()) |
338 | 402 | /* Transition part */ |
339 | - .attr("y", d => { | |
340 | - return height; | |
341 | - }) | |
403 | + .attr("y", height) | |
342 | 404 | .attr("height", 0) |
343 | 405 | .transition() |
344 | 406 | .duration(750) |
... | ... | @@ -362,30 +424,31 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
362 | 424 | |
363 | 425 | // Get the max y to plot |
364 | 426 | // If no data at all, force to 0 |
365 | - if (stacked_data.length == 0) { | |
366 | - y_max = 0 | |
427 | + let y_max; | |
428 | + if (stacked_data.length === 0) { | |
429 | + y_max = 0; | |
367 | 430 | } else { |
368 | - var y_max = d3.max(stacked_data[stacked_data.length - 1], d => d[1]); | |
431 | + y_max = d3.max(stacked_data[stacked_data.length - 1], d => d[1]); | |
369 | 432 | } |
370 | 433 | // Force maximum in any cases |
371 | - if (y_max == 0) { | |
372 | - y_max = 100 | |
434 | + if (y_max === 0) { | |
435 | + y_max = 100; | |
373 | 436 | } |
374 | 437 | // Enhance it by %ratio to leave room on the top of the graph |
375 | - y_max = y_max * height_ratio | |
438 | + y_max = y_max * height_ratio; | |
376 | 439 | |
377 | - return y_max | |
440 | + return y_max; | |
378 | 441 | } |
379 | 442 | |
380 | 443 | function draw_projects_areas(data, projects) { |
381 | 444 | |
382 | 445 | // Now build the stacked data for stacked bars |
383 | 446 | // |
384 | - var stack = d3.stack() | |
385 | - .keys(projects) | |
447 | + let stack = d3.stack() | |
448 | + .keys(projects); | |
386 | 449 | // .order(d3.stackOrderNone) |
387 | 450 | // .offset(d3.stackOffsetNone); |
388 | - var stacked_data = stack(data) | |
451 | + let stacked_data = stack(data); | |
389 | 452 | |
390 | 453 | const y_max = ymax_from_stacked(stacked_data); |
391 | 454 | yScale.domain([0, y_max]); |
... | ... | @@ -393,9 +456,9 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
393 | 456 | const area = d3.area() |
394 | 457 | .x(d => xScale(d.data.period)) |
395 | 458 | .y0(d => yScale(d[0])) |
396 | - .y1(d => yScale(d[1])) | |
459 | + .y1(d => yScale(d[1])); | |
397 | 460 | |
398 | - let paths = svg.append("g") | |
461 | + svg.append("g") | |
399 | 462 | .selectAll("path") |
400 | 463 | .data(stacked_data) |
401 | 464 | .join("path") |
... | ... | @@ -410,14 +473,13 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
410 | 473 | |
411 | 474 | |
412 | 475 | function draw_categories_stacked(data, categories) { |
413 | - | |
414 | 476 | // Now build the stacked data for stacked bars |
415 | 477 | // |
416 | - var stack = d3.stack() | |
417 | - .keys(categories) | |
478 | + let stack = d3.stack() | |
479 | + .keys(categories); | |
418 | 480 | // .order(d3.stackOrderNone) |
419 | 481 | // .offset(d3.stackOffsetNone); |
420 | - var stacked_data = stack(data) | |
482 | + let stacked_data = stack(data); | |
421 | 483 | |
422 | 484 | const y_max = ymax_from_stacked(stacked_data); |
423 | 485 | yScale.domain([0, y_max]); |
... | ... | @@ -431,7 +493,7 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
431 | 493 | .style("fill", (d) => colorScale(d.key)); |
432 | 494 | |
433 | 495 | // then draw each period/category bar |
434 | - let rect = groups.selectAll("rect") | |
496 | + groups.selectAll("rect") | |
435 | 497 | .data(d => d) |
436 | 498 | .enter() |
437 | 499 | .append("rect") |
... | ... | @@ -439,9 +501,7 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
439 | 501 | .attr("x", d => xScale(d.data.period)) |
440 | 502 | .attr("width", xScale.bandwidth()) |
441 | 503 | /* transition part */ |
442 | - .attr("y", d => { | |
443 | - return height; | |
444 | - }) | |
504 | + .attr("y", height) | |
445 | 505 | .attr("height", 0) |
446 | 506 | .transition() |
447 | 507 | .duration(750) |
... | ... | @@ -449,7 +509,7 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
449 | 509 | return i * 150; |
450 | 510 | }) |
451 | 511 | .attr("y", d => yScale(d[1])) |
452 | - .attr("height", d => height - yScale(d[1] - d[0])) | |
512 | + .attr("height", d => height - yScale(d[1] - d[0])); | |
453 | 513 | |
454 | 514 | groups.selectAll("rect") |
455 | 515 | .on("mouseover", mouseover) |
... | ... | @@ -462,15 +522,15 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
462 | 522 | // Build the total charge by period; |
463 | 523 | // it will be used for the line drawing above bars. |
464 | 524 | // |
465 | - var periods_total_charge = [] | |
525 | + let periods_total_charge = []; | |
466 | 526 | |
467 | 527 | data.forEach(function (d) { |
468 | 528 | // get the list of values for all columns except the first one which is the period name |
469 | - var period_values = Object.values(d).slice(1) | |
470 | - var row = {} | |
471 | - row['period'] = d.period | |
472 | - row['total'] = roundToTwo(d3.sum(period_values)) | |
473 | - periods_total_charge.push(row) | |
529 | + let period_values = Object.values(d).slice(1); | |
530 | + let row = {}; | |
531 | + row['period'] = d.period; | |
532 | + row['total'] = roundToTwo(d3.sum(period_values)); | |
533 | + periods_total_charge.push(row); | |
474 | 534 | }); |
475 | 535 | |
476 | 536 | // the line itselet |
... | ... | @@ -494,7 +554,7 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
494 | 554 | .attr("class", "total-circle") |
495 | 555 | .attr("r", dot_radius) |
496 | 556 | .attr("cx", function (d) { |
497 | - return (xScale.bandwidth() / 2) + xScale(d.period) | |
557 | + return (xScale.bandwidth() / 2) + xScale(d.period); | |
498 | 558 | }) |
499 | 559 | .attr("cy", function (d) { |
500 | 560 | return yScale(d.total); |
... | ... | @@ -507,11 +567,11 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
507 | 567 | |
508 | 568 | d3.csv(data_url).then(data => { |
509 | 569 | // we could get categories that way, |
510 | - // var categories = data.columns.slice(1) | |
570 | + // let categories = data.columns.slice(1) | |
511 | 571 | // but instead we want to filter by non zero, see later |
512 | 572 | |
513 | - var periods = d3.map(data, d => d.period) | |
514 | - xScale.domain(periods) | |
573 | + let periods = d3.map(data, d => d.period); | |
574 | + xScale.domain(periods); | |
515 | 575 | |
516 | 576 | // Filter datas to only keep non zero categories |
517 | 577 | // TODO: should be done on server (python/flask) side |
... | ... | @@ -520,57 +580,57 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
520 | 580 | // That will leave '0' to categories with no charge at all |
521 | 581 | // TODO: to be done with Object.keys, Object.values and d3 filtering methods |
522 | 582 | // |
523 | - var categories_total_charge = {} | |
583 | + let categories_total_charge = {}; | |
524 | 584 | data.forEach(function (d) { |
525 | 585 | Object.keys(d).forEach(function (k) { |
526 | 586 | if (k === 'period') { |
527 | 587 | return; |
528 | 588 | } |
529 | 589 | if (categories_total_charge.hasOwnProperty(k)) { |
530 | - categories_total_charge[k] += +d[k] | |
590 | + categories_total_charge[k] += +d[k]; | |
531 | 591 | } else { |
532 | - categories_total_charge[k] = +d[k] | |
592 | + categories_total_charge[k] = +d[k]; | |
533 | 593 | } |
534 | - categories_total_charge[k] = roundToTwo(categories_total_charge[k]) | |
594 | + categories_total_charge[k] = roundToTwo(categories_total_charge[k]); | |
535 | 595 | } |
536 | - ) | |
537 | - }) | |
596 | + ); | |
597 | + }); | |
538 | 598 | |
539 | 599 | // 2- Now, filter only categories that have a non-zero charge |
540 | 600 | // TODO: to be done with Object.keys, Object.values and d3 filtering methods |
541 | 601 | // |
542 | - var categories = [] | |
543 | - for (var key in categories_total_charge) { | |
602 | + let categories = []; | |
603 | + for (let key in categories_total_charge) { | |
544 | 604 | if (categories_total_charge[key] > 0) { |
545 | - categories.push(key) | |
605 | + categories.push(key); | |
546 | 606 | } |
547 | 607 | } |
548 | 608 | |
549 | 609 | // |
550 | - // Draw the areas, stacked. | |
610 | + // This former list we use as color_scale domain. | |
611 | + // And that allows us to build the legend | |
551 | 612 | // |
552 | - draw_areas(data, categories) | |
613 | + colorScale.domain(categories); | |
614 | + make_legend(svg, {'x': 0, 'y': height + 90}, width, colorScale, mouseleavelegend, mouseoverlegend); | |
553 | 615 | |
554 | 616 | // |
555 | - // Draw the bars, stacked or grouped | |
617 | + // Draw the areas, stacked. | |
556 | 618 | // |
557 | - draw_categories_bars(data, categories) | |
619 | + draw_areas(data, categories); | |
558 | 620 | |
559 | 621 | // |
560 | - // Draw the total charge line ( may be) | |
622 | + // Draw the bars, stacked or grouped | |
561 | 623 | // |
562 | - draw_total_line(data, categories) | |
624 | + draw_categories_bars(data, categories); | |
563 | 625 | |
564 | 626 | // |
565 | - // This former list we use as color_scale domain. | |
566 | - // And that allows us to build the legend | |
627 | + // Draw the total charge line ( may be) | |
567 | 628 | // |
568 | - colorScale.domain(categories) | |
569 | - addlegend(colorScale) | |
629 | + draw_total_line(data, categories); | |
570 | 630 | |
571 | 631 | // Xaxis |
572 | 632 | // |
573 | - const xAxis = d3.axisBottom(xScale) | |
633 | + const xAxis = d3.axisBottom(xScale); | |
574 | 634 | |
575 | 635 | // Draw Xaxis |
576 | 636 | svg.append("g") |
... | ... | @@ -586,19 +646,19 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
586 | 646 | // Yaxis |
587 | 647 | // |
588 | 648 | const yAxis = d3.axisLeft(yScale) |
589 | - .ticks(y_ticks_num) | |
649 | + .ticks(y_ticks_num); | |
590 | 650 | |
591 | 651 | // Draw Yaxis |
592 | 652 | svg.append("g") |
593 | 653 | .attr("class", "y_axis") |
594 | - .call(yAxis) | |
654 | + .call(yAxis); | |
595 | 655 | |
596 | 656 | // Draw horizontal lines |
597 | 657 | svg.selectAll("y axis") |
598 | 658 | .data(yScale.ticks(y_ticks_num)) |
599 | 659 | .enter() |
600 | 660 | .append("line") |
601 | - .attr("class", d => (d == 0 ? "horizontalY0" : "horizontalY")) | |
661 | + .attr("class", d => (d === 0 ? "horizontalY0" : "horizontalY")) | |
602 | 662 | .attr("x1", 0) |
603 | 663 | .attr("x2", width) |
604 | 664 | .attr("y1", d => yScale(d)) |
... | ... | @@ -607,32 +667,97 @@ function build_chart(div_selector, data_url, entity_name, category_type) { |
607 | 667 | |
608 | 668 | // Write Y axis title |
609 | 669 | svg.append("text") |
610 | - .attr("text-anchor", "end") | |
670 | + .attr("text-anchor", "middle") | |
611 | 671 | .attr("transform", "rotate(-90)") |
612 | - .attr("y", -margin.left + 40) | |
613 | - .attr("x", -margin.top - 70) | |
672 | + .attr("y", -margin.left / 2) | |
673 | + .attr("x", -height / 2) | |
614 | 674 | .text("Charge en ETP"); |
615 | 675 | |
616 | 676 | // |
617 | 677 | // Write chart Title |
618 | 678 | // |
679 | + make_title(svg, width, [entity_name, chart_title], {'x': 0, 'y': -50}); | |
619 | 680 | |
620 | - // part 1 | |
621 | - svg.append("text") | |
622 | - .attr("x", (width / 2)) | |
623 | - .attr("y", 0 - (margin.top / 2) - 10) | |
624 | - .attr("text-anchor", "middle") | |
625 | - .style("font-size", "16px") | |
626 | - .text(entity_name); | |
627 | - // part 2 | |
628 | - svg.append("text") | |
629 | - .attr("x", (width / 2)) | |
630 | - .attr("y", 0 - (margin.top / 2) + 10) | |
631 | - .attr("text-anchor", "middle") | |
632 | - .style("font-size", "12px") | |
633 | - .text(chart_title); | |
681 | + }); // end of d3.csv().then({}) | |
634 | 682 | |
683 | +} | |
635 | 684 | |
636 | - }); // end of d3.csv().then({}) | |
685 | +function build_pie_chart(div_selector, _height, data_url, entity_name) { | |
686 | + // TODO: common code, find a way to factorize | |
687 | + let main_elt = document.querySelector(div_selector); | |
688 | + let width = main_elt.offsetWidth, | |
689 | + height = _height; | |
690 | + | |
691 | + let svg = make_svg(div_selector, data_url, width, height); | |
692 | + | |
693 | + let colorScale = d3.scaleOrdinal(d3.schemeTableau10); | |
694 | + | |
695 | + let pie = d3.pie().value( | |
696 | + function (d) { | |
697 | + // TODO: rename to d[1] | |
698 | + return d['Effectif']; | |
699 | + }) | |
700 | + .sort(null); | |
701 | + | |
702 | + d3.csv(data_url).then(data => { | |
703 | + let pie_margin = {'top': 30, 'right': 0, 'bottom': 0, 'left': 0}; | |
704 | + | |
705 | + // Append Title on top of chart | |
706 | + // | |
707 | + let title_height = make_title(svg, width, ["Répartion des agents par statut", "Période: " + entity_name]); | |
708 | + | |
709 | + // Get pie positions | |
710 | + // | |
711 | + let pie_height = height - title_height - (pie_margin.top + pie_margin.bottom); | |
712 | + let pie_radius = pie_height / 2; | |
713 | + let pie_offset = {'x': pie_radius, 'y': title_height + pie_margin.top + pie_radius}; | |
714 | + | |
715 | + let inner_radius = Math.floor(pie_radius * 0.6); | |
716 | + | |
717 | + // TODO: rename to a[0] | |
718 | + let statuses = data.map(a => a['Statut']); | |
719 | + colorScale.domain(statuses); | |
720 | + | |
721 | + let arc = d3.arc() | |
722 | + .innerRadius(inner_radius) | |
723 | + .outerRadius(pie_radius); | |
724 | + | |
725 | + let arcs = svg | |
726 | + .append('g') | |
727 | + .attr('transform', 'translate(' + pie_offset.x + ',' + pie_offset.y + ')'); | |
728 | + | |
729 | + arcs.selectAll('arc') | |
730 | + .data(pie(data)) | |
731 | + .enter() | |
732 | + .append('g') | |
733 | + .attr('class', 'arc') | |
734 | + .append('path') | |
735 | + .attr('class', 'pie') | |
736 | + .attr('fill', d => colorScale(d.data.Statut)) | |
737 | + .attr('d', arc); | |
738 | + | |
739 | + // Draw borders to pie | |
740 | + // | |
741 | + arcs.append("circle") | |
742 | + .attr('class', 'pie_border') | |
743 | + .attr('r', pie_radius); | |
744 | + arcs.append("circle") | |
745 | + .attr('class', 'pie_border') | |
746 | + .attr('r', inner_radius); | |
747 | + | |
748 | + // Add Legend | |
749 | + let legend_offset = {'x': 2 * pie_radius + 50, 'y': title_height + pie_margin.top}; | |
750 | + let legend_height = make_legend(svg, legend_offset, 2 * pie_radius, colorScale, | |
751 | + () => void 0, () => void 0); | |
752 | + }); | |
637 | 753 | |
638 | 754 | } |
755 | + | |
756 | +function build_line_chart(div_selector, _height, data_url, entity_name) { | |
757 | + // TODO: common code, find a way to factorize | |
758 | + let main_elt = document.querySelector(div_selector); | |
759 | + let width = main_elt.offsetWidth, | |
760 | + height = _height; | |
761 | + let svg = make_svg(div_selector, data_url, width, height); | |
762 | + let title_height = make_title(svg, width, ["Default Line Chart", "default subtitle"]); | |
763 | +} | |
639 | 764 | \ No newline at end of file | ... | ... |
app/main/static/js/svg_to_any.js
1 | -let download_any = function (node, base_rest_url, format='csv') { | |
1 | +let download_any = function (node, base_rest_url, format = 'csv') { | |
2 | 2 | let chart_div = node.parentNode.parentNode.parentNode; |
3 | 3 | let chart_title = chart_div.id; |
4 | 4 | let content_type; |
5 | 5 | let extension; |
6 | 6 | let rest_url; |
7 | - if (format === 'csv'){ | |
7 | + if (format === 'csv') { | |
8 | 8 | content_type = 'text/csv'; |
9 | 9 | extension = '.csv'; |
10 | - rest_url = base_rest_url+'/csv' | |
10 | + rest_url = base_rest_url + '/csv'; | |
11 | 11 | } else if (format == 'xls') { |
12 | 12 | content_type = 'application/vnd.ms-excel'; |
13 | 13 | extension = '.xslx'; |
14 | - rest_url = base_rest_url+'/xls' | |
14 | + rest_url = base_rest_url + '/xls'; | |
15 | 15 | } |
16 | 16 | fetch(rest_url) |
17 | 17 | .then(function (r) { |
18 | - r.headers.set('content-type', content_type ) | |
19 | - return r.blob() | |
18 | + r.headers.set('content-type', content_type); | |
19 | + return r.blob(); | |
20 | 20 | }) |
21 | 21 | .then((blob) => { |
22 | 22 | saveAs(blob, chart_title + extension); // FileSaver.js function |
23 | - }) | |
24 | -} | |
23 | + }); | |
24 | +}; | |
25 | 25 | |
26 | 26 | var download_png = function () { |
27 | 27 | // This callback is supposed to be called on the click event of a button child of the div containing the svg. |
28 | 28 | // We then get the parent of this btn to guess the chart's title, width and heigth |
29 | - var chart_div = this.parentNode.parentNode.parentNode; | |
30 | - var chart_title = chart_div.id; | |
31 | - width = chart_div.offsetWidth; | |
32 | - height = chart_div.offsetHeight; | |
29 | + let chart_div = this.parentNode.parentNode.parentNode; | |
30 | + let chart_title = chart_div.id; | |
31 | + let width = chart_div.offsetWidth; | |
32 | + let height = chart_div.offsetHeight; | |
33 | 33 | |
34 | 34 | // Then we can access the svg contained in that parent |
35 | - svg = chart_div.getElementsByTagName('svg')[0] | |
35 | + svg = chart_div.getElementsByTagName('svg')[0]; | |
36 | 36 | |
37 | 37 | // Export to string and save |
38 | 38 | var svgString = getSVGString(svg); |
39 | 39 | svgString2Image(svgString, 2 * width, 2 * height, 'png', save); // passes Blob and filesize String to the callback |
40 | 40 | |
41 | 41 | function save(dataBlob, filesize) { |
42 | - console.log(dataBlob) | |
42 | + console.log(dataBlob); | |
43 | 43 | saveAs(dataBlob, chart_title); // FileSaver.js function |
44 | 44 | } |
45 | -} | |
45 | +}; | |
46 | 46 | |
47 | 47 | |
48 | 48 | // Below are the functions that handle actual exporting: |
... | ... | @@ -98,11 +98,11 @@ function getSVGString(svgNode) { |
98 | 98 | |
99 | 99 | var cssRules = s.cssRules; |
100 | 100 | for (var r = 0; r < cssRules.length; r++) { |
101 | - var cssRule = cssRules[r] | |
101 | + var cssRule = cssRules[r]; | |
102 | 102 | if (typeof cssRule.selectorText === 'undefined') { |
103 | 103 | continue; |
104 | 104 | } |
105 | - var classFromSelector = '.' + cssRule.selectorText.split('.')[1] | |
105 | + var classFromSelector = '.' + cssRule.selectorText.split('.')[1]; | |
106 | 106 | if (contains(classFromSelector, selectorTextArr)) |
107 | 107 | extractedCSSText += cssRule.cssText; |
108 | 108 | } | ... | ... |
app/main/templates/agent.html
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | {% block content %} |
9 | 9 | |
10 | 10 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
11 | - <span id="nav_actived" style="display: none">agent,liste_agents</span> | |
11 | + <span id="nav_actived" style="display: none">agent,agents_list</span> | |
12 | 12 | |
13 | 13 | <div class="card"> |
14 | 14 | <div class="card-header"> |
... | ... | @@ -71,6 +71,7 @@ |
71 | 71 | </div> |
72 | 72 | |
73 | 73 | <div class="charge_chart" id="projects_chart"></div> |
74 | + | |
74 | 75 | <table class="table_datatables table table-hover"> |
75 | 76 | <thead> |
76 | 77 | <tr> | ... | ... |
app/main/templates/agent_form.html
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 | {% block content %} |
11 | 11 | |
12 | 12 | <!-- Invisible span to define wich ul and a in the navbar are actived --> |
13 | - <span id="nav_actived" style="display: none">cds,edit_agent</span> | |
13 | + <span id="nav_actived" style="display: none">cds,agent_edit</span> | |
14 | 14 | |
15 | 15 | <form id="agent_form" class="pdc-form" action="{{ url_for('main.agent_edit') }}" method="post"> |
16 | 16 | {% if agent and agent['id'] not in ['', None] %} | ... | ... |
app/main/templates/agents.html
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | {% block content %} |
4 | 4 | |
5 | 5 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
6 | - <span id="nav_actived" style="display: none">agent,liste_agents</span> | |
6 | + <span id="nav_actived" style="display: none">agent,agents_list</span> | |
7 | 7 | |
8 | 8 | <table class="table_datatables table table-hover"> |
9 | 9 | <thead> | ... | ... |
... | ... | @@ -0,0 +1,99 @@ |
1 | +{% extends "base_page.html" %} | |
2 | +{% block more_heads %} | |
3 | + <link href="{{ url_for('main.static', filename='css/charges.css', version=config.VERSION) }}" rel="stylesheet" | |
4 | + type="text/css"/> | |
5 | +{% endblock %} | |
6 | + | |
7 | +{% block content %} | |
8 | + | |
9 | + <!-- Invisible span to definte wich ul and a in the navbar are actived --> | |
10 | + <span id="nav_actived" style="display: none">agent,agents_stats</span> | |
11 | + | |
12 | + <div class="pdc-controls"> | |
13 | + <select title="Choisir la période" id="period_id_select" name="period_id_select"> | |
14 | + {% for p in periods %} | |
15 | + <option value="{{ p.id }}" {{ "selected" if p.id == 1 }}>{{ p.name }}</option> | |
16 | + {% endfor %} | |
17 | + </select> | |
18 | + <button id='prev_period' title="Période précédente"><span data-feather="chevron-left"></span></button> | |
19 | + <button id='next_period' title="Période suivante"><span data-feather="chevron-right"></span></button> | |
20 | + </div> | |
21 | + | |
22 | + <h3 class="sub-header">Tout le laboratoire</h3> | |
23 | + | |
24 | + <div class="row"> | |
25 | + <div class="col-4"> | |
26 | + <div class="charge_chart" id="agents_by_status_chart"></div> | |
27 | + </div> | |
28 | + <div class="col-8"> | |
29 | + <div class="charge_chart" id="charge_by_status_chart"></div> | |
30 | + </div> | |
31 | + </div> | |
32 | + | |
33 | + {# {% for c in categories %}#} | |
34 | + {# <h3 class="sub-header">Charge pour la catégorie {{ c.name }}</h3>#} | |
35 | + {# <div class="charge_chart" id="labels_stats_chart_{{ c.id }}"></div>#} | |
36 | + {# {% endfor %}#} | |
37 | + | |
38 | +{% endblock %} | |
39 | + | |
40 | +{% block more_scripts %} | |
41 | + {% include 'd3js-includes.html' %} | |
42 | + {% include 'charges-includes.html' %} | |
43 | + | |
44 | + <script> | |
45 | + $('#period_id_select').on('change', function () { | |
46 | + let period_id = $(this).find(':selected').val(); | |
47 | + let period_name = $(this).find(':selected').text(); | |
48 | + build_all(period_id, period_name); | |
49 | + }); | |
50 | + document.getElementById('next_period').onclick = function () { | |
51 | + period_select_update(1); | |
52 | + }; | |
53 | + document.getElementById('prev_period').onclick = function () { | |
54 | + period_select_update(-1); | |
55 | + }; | |
56 | + | |
57 | + let period_select_update = function (step) { | |
58 | + let select_elemnt = $('#period_id_select'); | |
59 | + let selectoptions_length = $('#period_id_select option').length; | |
60 | + let next_step = +select_elemnt.val() + step; | |
61 | + if (next_step <= 0 || next_step > selectoptions_length) { | |
62 | + return; | |
63 | + } | |
64 | + select_elemnt.val(next_step); | |
65 | + select_elemnt.trigger('change'); | |
66 | + }; | |
67 | + | |
68 | + let build_all = function (period_id, period_name) { | |
69 | + let agent_status_url = "{{url_for('main.rest_agents_status_count', period_id='PERIOD_ID')}}" | |
70 | + .replace("PERIOD_ID", period_id); | |
71 | + let height = 300; | |
72 | + | |
73 | + build_pie_chart("#agents_by_status_chart", | |
74 | + height, | |
75 | + agent_status_url, | |
76 | + period_name); | |
77 | + | |
78 | + build_line_chart("#charge_by_status_chart", | |
79 | + height, | |
80 | + agent_status_url, | |
81 | + "Charge des agents par statut"); | |
82 | + | |
83 | + }; | |
84 | + | |
85 | + {#TODO: get current period id from session#} | |
86 | + | |
87 | + let curr_p_id = $('#period_id_select').val(); | |
88 | + let curr_p_name = $('#period_id_select').find(":selected").text(); | |
89 | + | |
90 | + build_all(curr_p_id, curr_p_name); | |
91 | + | |
92 | + {# {% for c in categories %}#} | |
93 | + {# build_chart("#labels_stats_chart_{{ c.id }}",#} | |
94 | + {# "{{url_for('main.rest_labels_stats', category_id=c.id)}}",#} | |
95 | + {# "Charge pour la catégorie {{c.name}}",#} | |
96 | + {# "area");#} | |
97 | + {# {% endfor %}#} | |
98 | + </script> | |
99 | +{% endblock %} | ... | ... |
app/main/templates/categories.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">project,categories</span> | |
5 | + <span id="nav_actived" style="display: none">project,categories_list</span> | |
6 | 6 | |
7 | 7 | <table class="table_datatables table table-hover"> |
8 | 8 | <thead> | ... | ... |
app/main/templates/category.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">project,categories</span> | |
5 | + <span id="nav_actived" style="display: none">project,categories_list</span> | |
6 | 6 | |
7 | 7 | <div class="card"> |
8 | 8 | <div class="card-header"> | ... | ... |
app/main/templates/charge_form.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">cds,add_charge</span> | |
5 | + <span id="nav_actived" style="display: none">cds,charge_add</span> | |
6 | 6 | |
7 | 7 | <form id="charge_form" class="pdc-form" action="{{ url_for('main.charge_add') }}" method="post"> |
8 | 8 | <div class="form-group"> | ... | ... |
app/main/templates/label.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">project,labels</span> | |
5 | + <span id="nav_actived" style="display: none">project,labels_list</span> | |
6 | 6 | |
7 | 7 | <div class="card"> |
8 | 8 | <div class="card-header"> | ... | ... |
app/main/templates/labels.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">project,labels</span> | |
5 | + <span id="nav_actived" style="display: none">project,labels_list</span> | |
6 | 6 | |
7 | 7 | <table class="table_datatables table table-hover"> |
8 | 8 | <thead> | ... | ... |
app/main/templates/periods.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">admin,liste_periodes</span> | |
5 | + <span id="nav_actived" style="display: none">admin,periods_list</span> | |
6 | 6 | |
7 | 7 | <table class="table_datatables table table-hover"> |
8 | 8 | <thead> | ... | ... |
app/main/templates/project.html
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | |
8 | 8 | {% block content %} |
9 | 9 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
10 | - <span id="nav_actived" style="display: none">projet,liste_projets</span> | |
10 | + <span id="nav_actived" style="display: none">projet,projects_list</span> | |
11 | 11 | |
12 | 12 | <div class="card"> |
13 | 13 | <div class="card-header"> |
... | ... | @@ -68,11 +68,11 @@ |
68 | 68 | |
69 | 69 | <script> |
70 | 70 | build_chart("#project_services_chart", |
71 | - "{{url_for('main.rest_charge_project', project_id=project.id, category='service')}}", | |
71 | + "{{url_for('main.rest_charge_project', project_id=project.id, sort_key='service')}}", | |
72 | 72 | "{{project.name}}", |
73 | 73 | "service"); |
74 | 74 | build_chart("#project_capacities_chart", |
75 | - "{{url_for('main.rest_charge_project', project_id=project.id, category='capacity')}}", | |
75 | + "{{url_for('main.rest_charge_project', project_id=project.id, sort_key='capacity')}}", | |
76 | 76 | "{{project.name}}", |
77 | 77 | "capacity"); |
78 | 78 | </script> | ... | ... |
app/main/templates/projects.html
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | {% block content %} |
4 | 4 | |
5 | 5 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
6 | - <span id="nav_actived" style="display: none">project,projects</span> | |
6 | + <span id="nav_actived" style="display: none">project,projects_list</span> | |
7 | 7 | |
8 | 8 | <table class="table_datatables table table-hover"> |
9 | 9 | <thead> | ... | ... |
app/main/templates/services.html
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | {% block content %} |
3 | 3 | |
4 | 4 | <!-- Invisible span to definte wich ul and a in the navbar are actived --> |
5 | - <span id="nav_actived" style="display: none">service,liste_services</span> | |
5 | + <span id="nav_actived" style="display: none">service,services_list</span> | |
6 | 6 | |
7 | 7 | <table class="table_datatables table table-hover"> |
8 | 8 | <thead> | ... | ... |
app/models.py
... | ... | @@ -207,6 +207,17 @@ class Category(db.Model, Formable): |
207 | 207 | |
208 | 208 | |
209 | 209 | # |
210 | +# History | |
211 | +# | |
212 | + | |
213 | +class AgentHistory(db.Model): | |
214 | + id = db.Column(db.Integer, primary_key=True) | |
215 | + period_id = db.Column(db.Integer, db.ForeignKey('period.id')) | |
216 | + agent_id = db.Column(db.Integer, db.ForeignKey('agent.id')) | |
217 | + status_id = db.Column(db.Integer, db.ForeignKey('agent_status.id')) | |
218 | + | |
219 | + | |
220 | +# | |
210 | 221 | # Agents |
211 | 222 | # |
212 | 223 | ... | ... |
app/static/css/style.css
No preview for this file type
... | ... | @@ -0,0 +1,13 @@ |
1 | +!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.feather=n():e.feather=n()}("undefined"!=typeof self?self:this,function(){return function(e){var n={};function i(t){if(n[t])return n[t].exports;var l=n[t]={i:t,l:!1,exports:{}};return e[t].call(l.exports,l,l.exports,i),l.l=!0,l.exports}return i.m=e,i.c=n,i.d=function(e,n,t){i.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:t})},i.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},i.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(n,"a",n),n},i.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},i.p="",i(i.s=80)}([function(e,n,i){(function(n){var i="object",t=function(e){return e&&e.Math==Math&&e};e.exports=t(typeof globalThis==i&&globalThis)||t(typeof window==i&&window)||t(typeof self==i&&self)||t(typeof n==i&&n)||Function("return this")()}).call(this,i(75))},function(e,n){var i={}.hasOwnProperty;e.exports=function(e,n){return i.call(e,n)}},function(e,n,i){var t=i(0),l=i(11),r=i(33),o=i(62),a=t.Symbol,c=l("wks");e.exports=function(e){return c[e]||(c[e]=o&&a[e]||(o?a:r)("Symbol."+e))}},function(e,n,i){var t=i(6);e.exports=function(e){if(!t(e))throw TypeError(String(e)+" is not an object");return e}},function(e,n){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,n,i){var t=i(8),l=i(7),r=i(10);e.exports=t?function(e,n,i){return l.f(e,n,r(1,i))}:function(e,n,i){return e[n]=i,e}},function(e,n){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,n,i){var t=i(8),l=i(35),r=i(3),o=i(18),a=Object.defineProperty;n.f=t?a:function(e,n,i){if(r(e),n=o(n,!0),r(i),l)try{return a(e,n,i)}catch(e){}if("get"in i||"set"in i)throw TypeError("Accessors not supported");return"value"in i&&(e[n]=i.value),e}},function(e,n,i){var t=i(4);e.exports=!t(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,n){e.exports={}},function(e,n){e.exports=function(e,n){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:n}}},function(e,n,i){var t=i(0),l=i(19),r=i(17),o=t["__core-js_shared__"]||l("__core-js_shared__",{});(e.exports=function(e,n){return o[e]||(o[e]=void 0!==n?n:{})})("versions",[]).push({version:"3.1.3",mode:r?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var t=o(i(43)),l=o(i(41)),r=o(i(40));function o(e){return e&&e.__esModule?e:{default:e}}n.default=Object.keys(l.default).map(function(e){return new t.default(e,l.default[e],r.default[e])}).reduce(function(e,n){return e[n.name]=n,e},{})},function(e,n){e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(e,n,i){var t=i(72),l=i(20);e.exports=function(e){return t(l(e))}},function(e,n){e.exports={}},function(e,n,i){var t=i(11),l=i(33),r=t("keys");e.exports=function(e){return r[e]||(r[e]=l(e))}},function(e,n){e.exports=!1},function(e,n,i){var t=i(6);e.exports=function(e,n){if(!t(e))return e;var i,l;if(n&&"function"==typeof(i=e.toString)&&!t(l=i.call(e)))return l;if("function"==typeof(i=e.valueOf)&&!t(l=i.call(e)))return l;if(!n&&"function"==typeof(i=e.toString)&&!t(l=i.call(e)))return l;throw TypeError("Can't convert object to primitive value")}},function(e,n,i){var t=i(0),l=i(5);e.exports=function(e,n){try{l(t,e,n)}catch(i){t[e]=n}return n}},function(e,n){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,n){var i=Math.ceil,t=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?t:i)(e)}},function(e,n,i){var t; | |
2 | +/*! | |
3 | + Copyright (c) 2016 Jed Watson. | |
4 | + Licensed under the MIT License (MIT), see | |
5 | + http://jedwatson.github.io/classnames | |
6 | +*/ | |
7 | +/*! | |
8 | + Copyright (c) 2016 Jed Watson. | |
9 | + Licensed under the MIT License (MIT), see | |
10 | + http://jedwatson.github.io/classnames | |
11 | +*/ | |
12 | +!function(){"use strict";var i=function(){function e(){}function n(e,n){for(var i=n.length,t=0;t<i;++t)l(e,n[t])}e.prototype=Object.create(null);var i={}.hasOwnProperty;var t=/\s+/;function l(e,l){if(l){var r=typeof l;"string"===r?function(e,n){for(var i=n.split(t),l=i.length,r=0;r<l;++r)e[i[r]]=!0}(e,l):Array.isArray(l)?n(e,l):"object"===r?function(e,n){for(var t in n)i.call(n,t)&&(e[t]=!!n[t])}(e,l):"number"===r&&function(e,n){e[n]=!0}(e,l)}}return function(){for(var i=arguments.length,t=Array(i),l=0;l<i;l++)t[l]=arguments[l];var r=new e;n(r,t);var o=[];for(var a in r)r[a]&&o.push(a);return o.join(" ")}}();void 0!==e&&e.exports?e.exports=i:void 0===(t=function(){return i}.apply(n,[]))||(e.exports=t)}()},function(e,n,i){var t=i(7).f,l=i(1),r=i(2)("toStringTag");e.exports=function(e,n,i){e&&!l(e=i?e:e.prototype,r)&&t(e,r,{configurable:!0,value:n})}},function(e,n,i){var t=i(20);e.exports=function(e){return Object(t(e))}},function(e,n,i){var t=i(1),l=i(24),r=i(16),o=i(63),a=r("IE_PROTO"),c=Object.prototype;e.exports=o?Object.getPrototypeOf:function(e){return e=l(e),t(e,a)?e[a]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?c:null}},function(e,n,i){"use strict";var t,l,r,o=i(25),a=i(5),c=i(1),p=i(2),y=i(17),h=p("iterator"),x=!1;[].keys&&("next"in(r=[].keys())?(l=o(o(r)))!==Object.prototype&&(t=l):x=!0),void 0==t&&(t={}),y||c(t,h)||a(t,h,function(){return this}),e.exports={IteratorPrototype:t,BUGGY_SAFARI_ITERATORS:x}},function(e,n,i){var t=i(21),l=Math.min;e.exports=function(e){return e>0?l(t(e),9007199254740991):0}},function(e,n,i){var t=i(1),l=i(14),r=i(68),o=i(15),a=r(!1);e.exports=function(e,n){var i,r=l(e),c=0,p=[];for(i in r)!t(o,i)&&t(r,i)&&p.push(i);for(;n.length>c;)t(r,i=n[c++])&&(~a(p,i)||p.push(i));return p}},function(e,n,i){var t=i(0),l=i(11),r=i(5),o=i(1),a=i(19),c=i(36),p=i(37),y=p.get,h=p.enforce,x=String(c).split("toString");l("inspectSource",function(e){return c.call(e)}),(e.exports=function(e,n,i,l){var c=!!l&&!!l.unsafe,p=!!l&&!!l.enumerable,y=!!l&&!!l.noTargetGet;"function"==typeof i&&("string"!=typeof n||o(i,"name")||r(i,"name",n),h(i).source=x.join("string"==typeof n?n:"")),e!==t?(c?!y&&e[n]&&(p=!0):delete e[n],p?e[n]=i:r(e,n,i)):p?e[n]=i:a(n,i)})(Function.prototype,"toString",function(){return"function"==typeof this&&y(this).source||c.call(this)})},function(e,n){var i={}.toString;e.exports=function(e){return i.call(e).slice(8,-1)}},function(e,n,i){var t=i(8),l=i(73),r=i(10),o=i(14),a=i(18),c=i(1),p=i(35),y=Object.getOwnPropertyDescriptor;n.f=t?y:function(e,n){if(e=o(e),n=a(n,!0),p)try{return y(e,n)}catch(e){}if(c(e,n))return r(!l.f.call(e,n),e[n])}},function(e,n,i){var t=i(0),l=i(31).f,r=i(5),o=i(29),a=i(19),c=i(71),p=i(65);e.exports=function(e,n){var i,y,h,x,s,u=e.target,d=e.global,f=e.stat;if(i=d?t:f?t[u]||a(u,{}):(t[u]||{}).prototype)for(y in n){if(x=n[y],h=e.noTargetGet?(s=l(i,y))&&s.value:i[y],!p(d?y:u+(f?".":"#")+y,e.forced)&&void 0!==h){if(typeof x==typeof h)continue;c(x,h)}(e.sham||h&&h.sham)&&r(x,"sham",!0),o(i,y,x,e)}}},function(e,n){var i=0,t=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++i+t).toString(36))}},function(e,n,i){var t=i(0),l=i(6),r=t.document,o=l(r)&&l(r.createElement);e.exports=function(e){return o?r.createElement(e):{}}},function(e,n,i){var t=i(8),l=i(4),r=i(34);e.exports=!t&&!l(function(){return 7!=Object.defineProperty(r("div"),"a",{get:function(){return 7}}).a})},function(e,n,i){var t=i(11);e.exports=t("native-function-to-string",Function.toString)},function(e,n,i){var t,l,r,o=i(76),a=i(0),c=i(6),p=i(5),y=i(1),h=i(16),x=i(15),s=a.WeakMap;if(o){var u=new s,d=u.get,f=u.has,g=u.set;t=function(e,n){return g.call(u,e,n),n},l=function(e){return d.call(u,e)||{}},r=function(e){return f.call(u,e)}}else{var v=h("state");x[v]=!0,t=function(e,n){return p(e,v,n),n},l=function(e){return y(e,v)?e[v]:{}},r=function(e){return y(e,v)}}e.exports={set:t,get:l,has:r,enforce:function(e){return r(e)?l(e):t(e,{})},getterFor:function(e){return function(n){var i;if(!c(n)||(i=l(n)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return i}}}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var t=Object.assign||function(e){for(var n=1;n<arguments.length;n++){var i=arguments[n];for(var t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t])}return e},l=o(i(22)),r=o(i(12));function o(e){return e&&e.__esModule?e:{default:e}}n.default=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if("undefined"==typeof document)throw new Error("`feather.replace()` only works in a browser environment.");var n=document.querySelectorAll("[data-feather]");Array.from(n).forEach(function(n){return function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=function(e){return Array.from(e.attributes).reduce(function(e,n){return e[n.name]=n.value,e},{})}(e),o=i["data-feather"];delete i["data-feather"];var a=r.default[o].toSvg(t({},n,i,{class:(0,l.default)(n.class,i.class)})),c=(new DOMParser).parseFromString(a,"image/svg+xml").querySelector("svg");e.parentNode.replaceChild(c,e)}(n,e)})}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var t,l=i(12),r=(t=l)&&t.__esModule?t:{default:t};n.default=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(console.warn("feather.toSvg() is deprecated. Please use feather.icons[name].toSvg() instead."),!e)throw new Error("The required `key` (icon name) parameter is missing.");if(!r.default[e])throw new Error("No icon matching '"+e+"'. See the complete list of icons at https://feathericons.com");return r.default[e].toSvg(n)}},function(e){e.exports={activity:["pulse","health","action","motion"],airplay:["stream","cast","mirroring"],"alert-circle":["warning","alert","danger"],"alert-octagon":["warning","alert","danger"],"alert-triangle":["warning","alert","danger"],"align-center":["text alignment","center"],"align-justify":["text alignment","justified"],"align-left":["text alignment","left"],"align-right":["text alignment","right"],anchor:[],archive:["index","box"],"at-sign":["mention","at","email","message"],award:["achievement","badge"],aperture:["camera","photo"],"bar-chart":["statistics","diagram","graph"],"bar-chart-2":["statistics","diagram","graph"],battery:["power","electricity"],"battery-charging":["power","electricity"],bell:["alarm","notification","sound"],"bell-off":["alarm","notification","silent"],bluetooth:["wireless"],"book-open":["read","library"],book:["read","dictionary","booklet","magazine","library"],bookmark:["read","clip","marker","tag"],box:["cube"],briefcase:["work","bag","baggage","folder"],calendar:["date"],camera:["photo"],cast:["chromecast","airplay"],circle:["off","zero","record"],clipboard:["copy"],clock:["time","watch","alarm"],"cloud-drizzle":["weather","shower"],"cloud-lightning":["weather","bolt"],"cloud-rain":["weather"],"cloud-snow":["weather","blizzard"],cloud:["weather"],codepen:["logo"],codesandbox:["logo"],code:["source","programming"],coffee:["drink","cup","mug","tea","cafe","hot","beverage"],columns:["layout"],command:["keyboard","cmd","terminal","prompt"],compass:["navigation","safari","travel","direction"],copy:["clone","duplicate"],"corner-down-left":["arrow","return"],"corner-down-right":["arrow"],"corner-left-down":["arrow"],"corner-left-up":["arrow"],"corner-right-down":["arrow"],"corner-right-up":["arrow"],"corner-up-left":["arrow"],"corner-up-right":["arrow"],cpu:["processor","technology"],"credit-card":["purchase","payment","cc"],crop:["photo","image"],crosshair:["aim","target"],database:["storage","memory"],delete:["remove"],disc:["album","cd","dvd","music"],"dollar-sign":["currency","money","payment"],droplet:["water"],edit:["pencil","change"],"edit-2":["pencil","change"],"edit-3":["pencil","change"],eye:["view","watch"],"eye-off":["view","watch","hide","hidden"],"external-link":["outbound"],facebook:["logo","social"],"fast-forward":["music"],figma:["logo","design","tool"],"file-minus":["delete","remove","erase"],"file-plus":["add","create","new"],"file-text":["data","txt","pdf"],film:["movie","video"],filter:["funnel","hopper"],flag:["report"],"folder-minus":["directory"],"folder-plus":["directory"],folder:["directory"],framer:["logo","design","tool"],frown:["emoji","face","bad","sad","emotion"],gift:["present","box","birthday","party"],"git-branch":["code","version control"],"git-commit":["code","version control"],"git-merge":["code","version control"],"git-pull-request":["code","version control"],github:["logo","version control"],gitlab:["logo","version control"],globe:["world","browser","language","translate"],"hard-drive":["computer","server","memory","data"],hash:["hashtag","number","pound"],headphones:["music","audio","sound"],heart:["like","love","emotion"],"help-circle":["question mark"],hexagon:["shape","node.js","logo"],home:["house","living"],image:["picture"],inbox:["email"],instagram:["logo","camera"],key:["password","login","authentication","secure"],layers:["stack"],layout:["window","webpage"],"life-bouy":["help","life ring","support"],link:["chain","url"],"link-2":["chain","url"],linkedin:["logo","social media"],list:["options"],lock:["security","password","secure"],"log-in":["sign in","arrow","enter"],"log-out":["sign out","arrow","exit"],mail:["email","message"],"map-pin":["location","navigation","travel","marker"],map:["location","navigation","travel"],maximize:["fullscreen"],"maximize-2":["fullscreen","arrows","expand"],meh:["emoji","face","neutral","emotion"],menu:["bars","navigation","hamburger"],"message-circle":["comment","chat"],"message-square":["comment","chat"],"mic-off":["record","sound","mute"],mic:["record","sound","listen"],minimize:["exit fullscreen","close"],"minimize-2":["exit fullscreen","arrows","close"],minus:["subtract"],monitor:["tv","screen","display"],moon:["dark","night"],"more-horizontal":["ellipsis"],"more-vertical":["ellipsis"],"mouse-pointer":["arrow","cursor"],move:["arrows"],music:["note"],navigation:["location","travel"],"navigation-2":["location","travel"],octagon:["stop"],package:["box","container"],paperclip:["attachment"],pause:["music","stop"],"pause-circle":["music","audio","stop"],"pen-tool":["vector","drawing"],percent:["discount"],"phone-call":["ring"],"phone-forwarded":["call"],"phone-incoming":["call"],"phone-missed":["call"],"phone-off":["call","mute"],"phone-outgoing":["call"],phone:["call"],play:["music","start"],"pie-chart":["statistics","diagram"],"play-circle":["music","start"],plus:["add","new"],"plus-circle":["add","new"],"plus-square":["add","new"],pocket:["logo","save"],power:["on","off"],printer:["fax","office","device"],radio:["signal"],"refresh-cw":["synchronise","arrows"],"refresh-ccw":["arrows"],repeat:["loop","arrows"],rewind:["music"],"rotate-ccw":["arrow"],"rotate-cw":["arrow"],rss:["feed","subscribe"],save:["floppy disk"],scissors:["cut"],search:["find","magnifier","magnifying glass"],send:["message","mail","email","paper airplane","paper aeroplane"],settings:["cog","edit","gear","preferences"],"share-2":["network","connections"],shield:["security","secure"],"shield-off":["security","insecure"],"shopping-bag":["ecommerce","cart","purchase","store"],"shopping-cart":["ecommerce","cart","purchase","store"],shuffle:["music"],"skip-back":["music"],"skip-forward":["music"],slack:["logo"],slash:["ban","no"],sliders:["settings","controls"],smartphone:["cellphone","device"],smile:["emoji","face","happy","good","emotion"],speaker:["audio","music"],star:["bookmark","favorite","like"],"stop-circle":["media","music"],sun:["brightness","weather","light"],sunrise:["weather","time","morning","day"],sunset:["weather","time","evening","night"],tablet:["device"],tag:["label"],target:["logo","bullseye"],terminal:["code","command line","prompt"],thermometer:["temperature","celsius","fahrenheit","weather"],"thumbs-down":["dislike","bad","emotion"],"thumbs-up":["like","good","emotion"],"toggle-left":["on","off","switch"],"toggle-right":["on","off","switch"],tool:["settings","spanner"],trash:["garbage","delete","remove","bin"],"trash-2":["garbage","delete","remove","bin"],triangle:["delta"],truck:["delivery","van","shipping","transport","lorry"],tv:["television","stream"],twitch:["logo"],twitter:["logo","social"],type:["text"],umbrella:["rain","weather"],unlock:["security"],"user-check":["followed","subscribed"],"user-minus":["delete","remove","unfollow","unsubscribe"],"user-plus":["new","add","create","follow","subscribe"],"user-x":["delete","remove","unfollow","unsubscribe","unavailable"],user:["person","account"],users:["group"],"video-off":["camera","movie","film"],video:["camera","movie","film"],voicemail:["phone"],volume:["music","sound","mute"],"volume-1":["music","sound"],"volume-2":["music","sound"],"volume-x":["music","sound","mute"],watch:["clock","time"],"wifi-off":["disabled"],wifi:["connection","signal","wireless"],wind:["weather","air"],"x-circle":["cancel","close","delete","remove","times","clear"],"x-octagon":["delete","stop","alert","warning","times","clear"],"x-square":["cancel","close","delete","remove","times","clear"],x:["cancel","close","delete","remove","times","clear"],youtube:["logo","video","play"],"zap-off":["flash","camera","lightning"],zap:["flash","camera","lightning"],"zoom-in":["magnifying glass"],"zoom-out":["magnifying glass"]}},function(e){e.exports={activity:'<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>',airplay:'<path d="M5 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-1"></path><polygon points="12 15 17 21 7 21 12 15"></polygon>',"alert-circle":'<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line>',"alert-octagon":'<polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line>',"alert-triangle":'<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line>',"align-center":'<line x1="18" y1="10" x2="6" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="18" y1="18" x2="6" y2="18"></line>',"align-justify":'<line x1="21" y1="10" x2="3" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="21" y1="18" x2="3" y2="18"></line>',"align-left":'<line x1="17" y1="10" x2="3" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="17" y1="18" x2="3" y2="18"></line>',"align-right":'<line x1="21" y1="10" x2="7" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="21" y1="18" x2="7" y2="18"></line>',anchor:'<circle cx="12" cy="5" r="3"></circle><line x1="12" y1="22" x2="12" y2="8"></line><path d="M5 12H2a10 10 0 0 0 20 0h-3"></path>',aperture:'<circle cx="12" cy="12" r="10"></circle><line x1="14.31" y1="8" x2="20.05" y2="17.94"></line><line x1="9.69" y1="8" x2="21.17" y2="8"></line><line x1="7.38" y1="12" x2="13.12" y2="2.06"></line><line x1="9.69" y1="16" x2="3.95" y2="6.06"></line><line x1="14.31" y1="16" x2="2.83" y2="16"></line><line x1="16.62" y1="12" x2="10.88" y2="21.94"></line>',archive:'<polyline points="21 8 21 21 3 21 3 8"></polyline><rect x="1" y="3" width="22" height="5"></rect><line x1="10" y1="12" x2="14" y2="12"></line>',"arrow-down-circle":'<circle cx="12" cy="12" r="10"></circle><polyline points="8 12 12 16 16 12"></polyline><line x1="12" y1="8" x2="12" y2="16"></line>',"arrow-down-left":'<line x1="17" y1="7" x2="7" y2="17"></line><polyline points="17 17 7 17 7 7"></polyline>',"arrow-down-right":'<line x1="7" y1="7" x2="17" y2="17"></line><polyline points="17 7 17 17 7 17"></polyline>',"arrow-down":'<line x1="12" y1="5" x2="12" y2="19"></line><polyline points="19 12 12 19 5 12"></polyline>',"arrow-left-circle":'<circle cx="12" cy="12" r="10"></circle><polyline points="12 8 8 12 12 16"></polyline><line x1="16" y1="12" x2="8" y2="12"></line>',"arrow-left":'<line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline>',"arrow-right-circle":'<circle cx="12" cy="12" r="10"></circle><polyline points="12 16 16 12 12 8"></polyline><line x1="8" y1="12" x2="16" y2="12"></line>',"arrow-right":'<line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline>',"arrow-up-circle":'<circle cx="12" cy="12" r="10"></circle><polyline points="16 12 12 8 8 12"></polyline><line x1="12" y1="16" x2="12" y2="8"></line>',"arrow-up-left":'<line x1="17" y1="17" x2="7" y2="7"></line><polyline points="7 17 7 7 17 7"></polyline>',"arrow-up-right":'<line x1="7" y1="17" x2="17" y2="7"></line><polyline points="7 7 17 7 17 17"></polyline>',"arrow-up":'<line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline>',"at-sign":'<circle cx="12" cy="12" r="4"></circle><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"></path>',award:'<circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline>',"bar-chart-2":'<line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line>',"bar-chart":'<line x1="12" y1="20" x2="12" y2="10"></line><line x1="18" y1="20" x2="18" y2="4"></line><line x1="6" y1="20" x2="6" y2="16"></line>',"battery-charging":'<path d="M5 18H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3.19M15 6h2a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-3.19"></path><line x1="23" y1="13" x2="23" y2="11"></line><polyline points="11 6 7 12 13 12 9 18"></polyline>',battery:'<rect x="1" y="6" width="18" height="12" rx="2" ry="2"></rect><line x1="23" y1="13" x2="23" y2="11"></line>',"bell-off":'<path d="M13.73 21a2 2 0 0 1-3.46 0"></path><path d="M18.63 13A17.89 17.89 0 0 1 18 8"></path><path d="M6.26 6.26A5.86 5.86 0 0 0 6 8c0 7-3 9-3 9h14"></path><path d="M18 8a6 6 0 0 0-9.33-5"></path><line x1="1" y1="1" x2="23" y2="23"></line>',bell:'<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path>',bluetooth:'<polyline points="6.5 6.5 17.5 17.5 12 23 12 1 17.5 6.5 6.5 17.5"></polyline>',bold:'<path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>',"book-open":'<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>',book:'<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>',bookmark:'<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>',box:'<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line>',briefcase:'<rect x="2" y="7" width="20" height="14" rx="2" ry="2"></rect><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path>',calendar:'<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line>',"camera-off":'<line x1="1" y1="1" x2="23" y2="23"></line><path d="M21 21H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3m3-3h6l2 3h4a2 2 0 0 1 2 2v9.34m-7.72-2.06a4 4 0 1 1-5.56-5.56"></path>',camera:'<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle>',cast:'<path d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6"></path><line x1="2" y1="20" x2="2.01" y2="20"></line>',"check-circle":'<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline>',"check-square":'<polyline points="9 11 12 14 22 4"></polyline><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>',check:'<polyline points="20 6 9 17 4 12"></polyline>',"chevron-down":'<polyline points="6 9 12 15 18 9"></polyline>',"chevron-left":'<polyline points="15 18 9 12 15 6"></polyline>',"chevron-right":'<polyline points="9 18 15 12 9 6"></polyline>',"chevron-up":'<polyline points="18 15 12 9 6 15"></polyline>',"chevrons-down":'<polyline points="7 13 12 18 17 13"></polyline><polyline points="7 6 12 11 17 6"></polyline>',"chevrons-left":'<polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline>',"chevrons-right":'<polyline points="13 17 18 12 13 7"></polyline><polyline points="6 17 11 12 6 7"></polyline>',"chevrons-up":'<polyline points="17 11 12 6 7 11"></polyline><polyline points="17 18 12 13 7 18"></polyline>',chrome:'<circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4"></circle><line x1="21.17" y1="8" x2="12" y2="8"></line><line x1="3.95" y1="6.06" x2="8.54" y2="14"></line><line x1="10.88" y1="21.94" x2="15.46" y2="14"></line>',circle:'<circle cx="12" cy="12" r="10"></circle>',clipboard:'<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect>',clock:'<circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>',"cloud-drizzle":'<line x1="8" y1="19" x2="8" y2="21"></line><line x1="8" y1="13" x2="8" y2="15"></line><line x1="16" y1="19" x2="16" y2="21"></line><line x1="16" y1="13" x2="16" y2="15"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="12" y1="15" x2="12" y2="17"></line><path d="M20 16.58A5 5 0 0 0 18 7h-1.26A8 8 0 1 0 4 15.25"></path>',"cloud-lightning":'<path d="M19 16.9A5 5 0 0 0 18 7h-1.26a8 8 0 1 0-11.62 9"></path><polyline points="13 11 9 17 15 17 11 23"></polyline>',"cloud-off":'<path d="M22.61 16.95A5 5 0 0 0 18 10h-1.26a8 8 0 0 0-7.05-6M5 5a8 8 0 0 0 4 15h9a5 5 0 0 0 1.7-.3"></path><line x1="1" y1="1" x2="23" y2="23"></line>',"cloud-rain":'<line x1="16" y1="13" x2="16" y2="21"></line><line x1="8" y1="13" x2="8" y2="21"></line><line x1="12" y1="15" x2="12" y2="23"></line><path d="M20 16.58A5 5 0 0 0 18 7h-1.26A8 8 0 1 0 4 15.25"></path>',"cloud-snow":'<path d="M20 17.58A5 5 0 0 0 18 8h-1.26A8 8 0 1 0 4 16.25"></path><line x1="8" y1="16" x2="8.01" y2="16"></line><line x1="8" y1="20" x2="8.01" y2="20"></line><line x1="12" y1="18" x2="12.01" y2="18"></line><line x1="12" y1="22" x2="12.01" y2="22"></line><line x1="16" y1="16" x2="16.01" y2="16"></line><line x1="16" y1="20" x2="16.01" y2="20"></line>',cloud:'<path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path>',code:'<polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline>',codepen:'<polygon points="12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2"></polygon><line x1="12" y1="22" x2="12" y2="15.5"></line><polyline points="22 8.5 12 15.5 2 8.5"></polyline><polyline points="2 15.5 12 8.5 22 15.5"></polyline><line x1="12" y1="2" x2="12" y2="8.5"></line>',codesandbox:'<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="7.5 4.21 12 6.81 16.5 4.21"></polyline><polyline points="7.5 19.79 7.5 14.6 3 12"></polyline><polyline points="21 12 16.5 14.6 16.5 19.79"></polyline><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line>',coffee:'<path d="M18 8h1a4 4 0 0 1 0 8h-1"></path><path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z"></path><line x1="6" y1="1" x2="6" y2="4"></line><line x1="10" y1="1" x2="10" y2="4"></line><line x1="14" y1="1" x2="14" y2="4"></line>',columns:'<path d="M12 3h7a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-7m0-18H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7m0-18v18"></path>',command:'<path d="M18 3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3H6a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3V6a3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3h12a3 3 0 0 0 3-3 3 3 0 0 0-3-3z"></path>',compass:'<circle cx="12" cy="12" r="10"></circle><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>',copy:'<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>',"corner-down-left":'<polyline points="9 10 4 15 9 20"></polyline><path d="M20 4v7a4 4 0 0 1-4 4H4"></path>',"corner-down-right":'<polyline points="15 10 20 15 15 20"></polyline><path d="M4 4v7a4 4 0 0 0 4 4h12"></path>',"corner-left-down":'<polyline points="14 15 9 20 4 15"></polyline><path d="M20 4h-7a4 4 0 0 0-4 4v12"></path>',"corner-left-up":'<polyline points="14 9 9 4 4 9"></polyline><path d="M20 20h-7a4 4 0 0 1-4-4V4"></path>',"corner-right-down":'<polyline points="10 15 15 20 20 15"></polyline><path d="M4 4h7a4 4 0 0 1 4 4v12"></path>',"corner-right-up":'<polyline points="10 9 15 4 20 9"></polyline><path d="M4 20h7a4 4 0 0 0 4-4V4"></path>',"corner-up-left":'<polyline points="9 14 4 9 9 4"></polyline><path d="M20 20v-7a4 4 0 0 0-4-4H4"></path>',"corner-up-right":'<polyline points="15 14 20 9 15 4"></polyline><path d="M4 20v-7a4 4 0 0 1 4-4h12"></path>',cpu:'<rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect><rect x="9" y="9" width="6" height="6"></rect><line x1="9" y1="1" x2="9" y2="4"></line><line x1="15" y1="1" x2="15" y2="4"></line><line x1="9" y1="20" x2="9" y2="23"></line><line x1="15" y1="20" x2="15" y2="23"></line><line x1="20" y1="9" x2="23" y2="9"></line><line x1="20" y1="14" x2="23" y2="14"></line><line x1="1" y1="9" x2="4" y2="9"></line><line x1="1" y1="14" x2="4" y2="14"></line>',"credit-card":'<rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect><line x1="1" y1="10" x2="23" y2="10"></line>',crop:'<path d="M6.13 1L6 16a2 2 0 0 0 2 2h15"></path><path d="M1 6.13L16 6a2 2 0 0 1 2 2v15"></path>',crosshair:'<circle cx="12" cy="12" r="10"></circle><line x1="22" y1="12" x2="18" y2="12"></line><line x1="6" y1="12" x2="2" y2="12"></line><line x1="12" y1="6" x2="12" y2="2"></line><line x1="12" y1="22" x2="12" y2="18"></line>',database:'<ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"></path><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"></path>',delete:'<path d="M21 4H8l-7 8 7 8h13a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"></path><line x1="18" y1="9" x2="12" y2="15"></line><line x1="12" y1="9" x2="18" y2="15"></line>',disc:'<circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="3"></circle>',"divide-circle":'<line x1="8" y1="12" x2="16" y2="12"></line><line x1="12" y1="16" x2="12" y2="16"></line><line x1="12" y1="8" x2="12" y2="8"></line><circle cx="12" cy="12" r="10"></circle>',"divide-square":'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="8" y1="12" x2="16" y2="12"></line><line x1="12" y1="16" x2="12" y2="16"></line><line x1="12" y1="8" x2="12" y2="8"></line>',divide:'<circle cx="12" cy="6" r="2"></circle><line x1="5" y1="12" x2="19" y2="12"></line><circle cx="12" cy="18" r="2"></circle>',"dollar-sign":'<line x1="12" y1="1" x2="12" y2="23"></line><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>',"download-cloud":'<polyline points="8 17 12 21 16 17"></polyline><line x1="12" y1="12" x2="12" y2="21"></line><path d="M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29"></path>',download:'<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line>',dribbble:'<circle cx="12" cy="12" r="10"></circle><path d="M8.56 2.75c4.37 6.03 6.02 9.42 8.03 17.72m2.54-15.38c-3.72 4.35-8.94 5.66-16.88 5.85m19.5 1.9c-3.5-.93-6.63-.82-8.94 0-2.58.92-5.01 2.86-7.44 6.32"></path>',droplet:'<path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z"></path>',"edit-2":'<path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"></path>',"edit-3":'<path d="M12 20h9"></path><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>',edit:'<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>',"external-link":'<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line>',"eye-off":'<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line>',eye:'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle>',facebook:'<path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path>',"fast-forward":'<polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon>',feather:'<path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17.5" y1="15" x2="9" y2="15"></line>',figma:'<path d="M5 5.5A3.5 3.5 0 0 1 8.5 2H12v7H8.5A3.5 3.5 0 0 1 5 5.5z"></path><path d="M12 2h3.5a3.5 3.5 0 1 1 0 7H12V2z"></path><path d="M12 12.5a3.5 3.5 0 1 1 7 0 3.5 3.5 0 1 1-7 0z"></path><path d="M5 19.5A3.5 3.5 0 0 1 8.5 16H12v3.5a3.5 3.5 0 1 1-7 0z"></path><path d="M5 12.5A3.5 3.5 0 0 1 8.5 9H12v7H8.5A3.5 3.5 0 0 1 5 12.5z"></path>',"file-minus":'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="9" y1="15" x2="15" y2="15"></line>',"file-plus":'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="12" y1="18" x2="12" y2="12"></line><line x1="9" y1="15" x2="15" y2="15"></line>',"file-text":'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline>',file:'<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline>',film:'<rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect><line x1="7" y1="2" x2="7" y2="22"></line><line x1="17" y1="2" x2="17" y2="22"></line><line x1="2" y1="12" x2="22" y2="12"></line><line x1="2" y1="7" x2="7" y2="7"></line><line x1="2" y1="17" x2="7" y2="17"></line><line x1="17" y1="17" x2="22" y2="17"></line><line x1="17" y1="7" x2="22" y2="7"></line>',filter:'<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>',flag:'<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"></path><line x1="4" y1="22" x2="4" y2="15"></line>',"folder-minus":'<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path><line x1="9" y1="14" x2="15" y2="14"></line>',"folder-plus":'<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path><line x1="12" y1="11" x2="12" y2="17"></line><line x1="9" y1="14" x2="15" y2="14"></line>',folder:'<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>',framer:'<path d="M5 16V9h14V2H5l14 14h-7m-7 0l7 7v-7m-7 0h7"></path>',frown:'<circle cx="12" cy="12" r="10"></circle><path d="M16 16s-1.5-2-4-2-4 2-4 2"></path><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line>',gift:'<polyline points="20 12 20 22 4 22 4 12"></polyline><rect x="2" y="7" width="20" height="5"></rect><line x1="12" y1="22" x2="12" y2="7"></line><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"></path><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"></path>',"git-branch":'<line x1="6" y1="3" x2="6" y2="15"></line><circle cx="18" cy="6" r="3"></circle><circle cx="6" cy="18" r="3"></circle><path d="M18 9a9 9 0 0 1-9 9"></path>',"git-commit":'<circle cx="12" cy="12" r="4"></circle><line x1="1.05" y1="12" x2="7" y2="12"></line><line x1="17.01" y1="12" x2="22.96" y2="12"></line>',"git-merge":'<circle cx="18" cy="18" r="3"></circle><circle cx="6" cy="6" r="3"></circle><path d="M6 21V9a9 9 0 0 0 9 9"></path>',"git-pull-request":'<circle cx="18" cy="18" r="3"></circle><circle cx="6" cy="6" r="3"></circle><path d="M13 6h3a2 2 0 0 1 2 2v7"></path><line x1="6" y1="9" x2="6" y2="21"></line>',github:'<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>',gitlab:'<path d="M22.65 14.39L12 22.13 1.35 14.39a.84.84 0 0 1-.3-.94l1.22-3.78 2.44-7.51A.42.42 0 0 1 4.82 2a.43.43 0 0 1 .58 0 .42.42 0 0 1 .11.18l2.44 7.49h8.1l2.44-7.51A.42.42 0 0 1 18.6 2a.43.43 0 0 1 .58 0 .42.42 0 0 1 .11.18l2.44 7.51L23 13.45a.84.84 0 0 1-.35.94z"></path>',globe:'<circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>',grid:'<rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect>',"hard-drive":'<line x1="22" y1="12" x2="2" y2="12"></line><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path><line x1="6" y1="16" x2="6.01" y2="16"></line><line x1="10" y1="16" x2="10.01" y2="16"></line>',hash:'<line x1="4" y1="9" x2="20" y2="9"></line><line x1="4" y1="15" x2="20" y2="15"></line><line x1="10" y1="3" x2="8" y2="21"></line><line x1="16" y1="3" x2="14" y2="21"></line>',headphones:'<path d="M3 18v-6a9 9 0 0 1 18 0v6"></path><path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path>',heart:'<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>',"help-circle":'<circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line>',hexagon:'<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>',home:'<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline>',image:'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline>',inbox:'<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path>',info:'<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line>',instagram:'<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>',italic:'<line x1="19" y1="4" x2="10" y2="4"></line><line x1="14" y1="20" x2="5" y2="20"></line><line x1="15" y1="4" x2="9" y2="20"></line>',key:'<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path>',layers:'<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline>',layout:'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line>',"life-buoy":'<circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4"></circle><line x1="4.93" y1="4.93" x2="9.17" y2="9.17"></line><line x1="14.83" y1="14.83" x2="19.07" y2="19.07"></line><line x1="14.83" y1="9.17" x2="19.07" y2="4.93"></line><line x1="14.83" y1="9.17" x2="18.36" y2="5.64"></line><line x1="4.93" y1="19.07" x2="9.17" y2="14.83"></line>',"link-2":'<path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path><line x1="8" y1="12" x2="16" y2="12"></line>',link:'<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>',linkedin:'<path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle>',list:'<line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line>',loader:'<line x1="12" y1="2" x2="12" y2="6"></line><line x1="12" y1="18" x2="12" y2="22"></line><line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line><line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line><line x1="2" y1="12" x2="6" y2="12"></line><line x1="18" y1="12" x2="22" y2="12"></line><line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line><line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>',lock:'<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path>',"log-in":'<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line>',"log-out":'<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line>',mail:'<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline>',"map-pin":'<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle>',map:'<polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"></polygon><line x1="8" y1="2" x2="8" y2="18"></line><line x1="16" y1="6" x2="16" y2="22"></line>',"maximize-2":'<polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line>',maximize:'<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path>',meh:'<circle cx="12" cy="12" r="10"></circle><line x1="8" y1="15" x2="16" y2="15"></line><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line>',menu:'<line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line>',"message-circle":'<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>',"message-square":'<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>',"mic-off":'<line x1="1" y1="1" x2="23" y2="23"></line><path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"></path><path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23"></path><line x1="12" y1="19" x2="12" y2="23"></line><line x1="8" y1="23" x2="16" y2="23"></line>',mic:'<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" y1="19" x2="12" y2="23"></line><line x1="8" y1="23" x2="16" y2="23"></line>',"minimize-2":'<polyline points="4 14 10 14 10 20"></polyline><polyline points="20 10 14 10 14 4"></polyline><line x1="14" y1="10" x2="21" y2="3"></line><line x1="3" y1="21" x2="10" y2="14"></line>',minimize:'<path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"></path>',"minus-circle":'<circle cx="12" cy="12" r="10"></circle><line x1="8" y1="12" x2="16" y2="12"></line>',"minus-square":'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="8" y1="12" x2="16" y2="12"></line>',minus:'<line x1="5" y1="12" x2="19" y2="12"></line>',monitor:'<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line>',moon:'<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>',"more-horizontal":'<circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle><circle cx="5" cy="12" r="1"></circle>',"more-vertical":'<circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="5" r="1"></circle><circle cx="12" cy="19" r="1"></circle>',"mouse-pointer":'<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path>',move:'<polyline points="5 9 2 12 5 15"></polyline><polyline points="9 5 12 2 15 5"></polyline><polyline points="15 19 12 22 9 19"></polyline><polyline points="19 9 22 12 19 15"></polyline><line x1="2" y1="12" x2="22" y2="12"></line><line x1="12" y1="2" x2="12" y2="22"></line>',music:'<path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle>',"navigation-2":'<polygon points="12 2 19 21 12 17 5 21 12 2"></polygon>',navigation:'<polygon points="3 11 22 2 13 21 11 13 3 11"></polygon>',octagon:'<polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon>',package:'<line x1="16.5" y1="9.4" x2="7.5" y2="4.21"></line><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line>',paperclip:'<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path>',"pause-circle":'<circle cx="12" cy="12" r="10"></circle><line x1="10" y1="15" x2="10" y2="9"></line><line x1="14" y1="15" x2="14" y2="9"></line>',pause:'<rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect>',"pen-tool":'<path d="M12 19l7-7 3 3-7 7-3-3z"></path><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path><path d="M2 2l7.586 7.586"></path><circle cx="11" cy="11" r="2"></circle>',percent:'<line x1="19" y1="5" x2="5" y2="19"></line><circle cx="6.5" cy="6.5" r="2.5"></circle><circle cx="17.5" cy="17.5" r="2.5"></circle>',"phone-call":'<path d="M15.05 5A5 5 0 0 1 19 8.95M15.05 1A9 9 0 0 1 23 8.94m-1 7.98v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>',"phone-forwarded":'<polyline points="19 1 23 5 19 9"></polyline><line x1="15" y1="5" x2="23" y2="5"></line><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>',"phone-incoming":'<polyline points="16 2 16 8 22 8"></polyline><line x1="23" y1="1" x2="16" y2="8"></line><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>',"phone-missed":'<line x1="23" y1="1" x2="17" y2="7"></line><line x1="17" y1="1" x2="23" y2="7"></line><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>',"phone-off":'<path d="M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67m-2.67-3.34a19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91"></path><line x1="23" y1="1" x2="1" y2="23"></line>',"phone-outgoing":'<polyline points="23 7 23 1 17 1"></polyline><line x1="16" y1="8" x2="23" y2="1"></line><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>',phone:'<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>',"pie-chart":'<path d="M21.21 15.89A10 10 0 1 1 8 2.83"></path><path d="M22 12A10 10 0 0 0 12 2v10z"></path>',"play-circle":'<circle cx="12" cy="12" r="10"></circle><polygon points="10 8 16 12 10 16 10 8"></polygon>',play:'<polygon points="5 3 19 12 5 21 5 3"></polygon>',"plus-circle":'<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line>',"plus-square":'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line>',plus:'<line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line>',pocket:'<path d="M4 3h16a2 2 0 0 1 2 2v6a10 10 0 0 1-10 10A10 10 0 0 1 2 11V5a2 2 0 0 1 2-2z"></path><polyline points="8 10 12 14 16 10"></polyline>',power:'<path d="M18.36 6.64a9 9 0 1 1-12.73 0"></path><line x1="12" y1="2" x2="12" y2="12"></line>',printer:'<polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect>',radio:'<circle cx="12" cy="12" r="2"></circle><path d="M16.24 7.76a6 6 0 0 1 0 8.49m-8.48-.01a6 6 0 0 1 0-8.49m11.31-2.82a10 10 0 0 1 0 14.14m-14.14 0a10 10 0 0 1 0-14.14"></path>',"refresh-ccw":'<polyline points="1 4 1 10 7 10"></polyline><polyline points="23 20 23 14 17 14"></polyline><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>',"refresh-cw":'<polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>',repeat:'<polyline points="17 1 21 5 17 9"></polyline><path d="M3 11V9a4 4 0 0 1 4-4h14"></path><polyline points="7 23 3 19 7 15"></polyline><path d="M21 13v2a4 4 0 0 1-4 4H3"></path>',rewind:'<polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon>',"rotate-ccw":'<polyline points="1 4 1 10 7 10"></polyline><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path>',"rotate-cw":'<polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>',rss:'<path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle>',save:'<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline>',scissors:'<circle cx="6" cy="6" r="3"></circle><circle cx="6" cy="18" r="3"></circle><line x1="20" y1="4" x2="8.12" y2="15.88"></line><line x1="14.47" y1="14.48" x2="20" y2="20"></line><line x1="8.12" y1="8.12" x2="12" y2="12"></line>',search:'<circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line>',send:'<line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>',server:'<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect><rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect><line x1="6" y1="6" x2="6.01" y2="6"></line><line x1="6" y1="18" x2="6.01" y2="18"></line>',settings:'<circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>',"share-2":'<circle cx="18" cy="5" r="3"></circle><circle cx="6" cy="12" r="3"></circle><circle cx="18" cy="19" r="3"></circle><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>',share:'<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path><polyline points="16 6 12 2 8 6"></polyline><line x1="12" y1="2" x2="12" y2="15"></line>',"shield-off":'<path d="M19.69 14a6.9 6.9 0 0 0 .31-2V5l-8-3-3.16 1.18"></path><path d="M4.73 4.73L4 5v7c0 6 8 10 8 10a20.29 20.29 0 0 0 5.62-4.38"></path><line x1="1" y1="1" x2="23" y2="23"></line>',shield:'<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>',"shopping-bag":'<path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path><line x1="3" y1="6" x2="21" y2="6"></line><path d="M16 10a4 4 0 0 1-8 0"></path>',"shopping-cart":'<circle cx="9" cy="21" r="1"></circle><circle cx="20" cy="21" r="1"></circle><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>',shuffle:'<polyline points="16 3 21 3 21 8"></polyline><line x1="4" y1="20" x2="21" y2="3"></line><polyline points="21 16 21 21 16 21"></polyline><line x1="15" y1="15" x2="21" y2="21"></line><line x1="4" y1="4" x2="9" y2="9"></line>',sidebar:'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="9" y1="3" x2="9" y2="21"></line>',"skip-back":'<polygon points="19 20 9 12 19 4 19 20"></polygon><line x1="5" y1="19" x2="5" y2="5"></line>',"skip-forward":'<polygon points="5 4 15 12 5 20 5 4"></polygon><line x1="19" y1="5" x2="19" y2="19"></line>',slack:'<path d="M14.5 10c-.83 0-1.5-.67-1.5-1.5v-5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5v5c0 .83-.67 1.5-1.5 1.5z"></path><path d="M20.5 10H19V8.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path><path d="M9.5 14c.83 0 1.5.67 1.5 1.5v5c0 .83-.67 1.5-1.5 1.5S8 21.33 8 20.5v-5c0-.83.67-1.5 1.5-1.5z"></path><path d="M3.5 14H5v1.5c0 .83-.67 1.5-1.5 1.5S2 16.33 2 15.5 2.67 14 3.5 14z"></path><path d="M14 14.5c0-.83.67-1.5 1.5-1.5h5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-5c-.83 0-1.5-.67-1.5-1.5z"></path><path d="M15.5 19H14v1.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"></path><path d="M10 9.5C10 8.67 9.33 8 8.5 8h-5C2.67 8 2 8.67 2 9.5S2.67 11 3.5 11h5c.83 0 1.5-.67 1.5-1.5z"></path><path d="M8.5 5H10V3.5C10 2.67 9.33 2 8.5 2S7 2.67 7 3.5 7.67 5 8.5 5z"></path>',slash:'<circle cx="12" cy="12" r="10"></circle><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>',sliders:'<line x1="4" y1="21" x2="4" y2="14"></line><line x1="4" y1="10" x2="4" y2="3"></line><line x1="12" y1="21" x2="12" y2="12"></line><line x1="12" y1="8" x2="12" y2="3"></line><line x1="20" y1="21" x2="20" y2="16"></line><line x1="20" y1="12" x2="20" y2="3"></line><line x1="1" y1="14" x2="7" y2="14"></line><line x1="9" y1="8" x2="15" y2="8"></line><line x1="17" y1="16" x2="23" y2="16"></line>',smartphone:'<rect x="5" y="2" width="14" height="20" rx="2" ry="2"></rect><line x1="12" y1="18" x2="12.01" y2="18"></line>',smile:'<circle cx="12" cy="12" r="10"></circle><path d="M8 14s1.5 2 4 2 4-2 4-2"></path><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line>',speaker:'<rect x="4" y="2" width="16" height="20" rx="2" ry="2"></rect><circle cx="12" cy="14" r="4"></circle><line x1="12" y1="6" x2="12.01" y2="6"></line>',square:'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>',star:'<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>',"stop-circle":'<circle cx="12" cy="12" r="10"></circle><rect x="9" y="9" width="6" height="6"></rect>',sun:'<circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>',sunrise:'<path d="M17 18a5 5 0 0 0-10 0"></path><line x1="12" y1="2" x2="12" y2="9"></line><line x1="4.22" y1="10.22" x2="5.64" y2="11.64"></line><line x1="1" y1="18" x2="3" y2="18"></line><line x1="21" y1="18" x2="23" y2="18"></line><line x1="18.36" y1="11.64" x2="19.78" y2="10.22"></line><line x1="23" y1="22" x2="1" y2="22"></line><polyline points="8 6 12 2 16 6"></polyline>',sunset:'<path d="M17 18a5 5 0 0 0-10 0"></path><line x1="12" y1="9" x2="12" y2="2"></line><line x1="4.22" y1="10.22" x2="5.64" y2="11.64"></line><line x1="1" y1="18" x2="3" y2="18"></line><line x1="21" y1="18" x2="23" y2="18"></line><line x1="18.36" y1="11.64" x2="19.78" y2="10.22"></line><line x1="23" y1="22" x2="1" y2="22"></line><polyline points="16 5 12 9 8 5"></polyline>',tablet:'<rect x="4" y="2" width="16" height="20" rx="2" ry="2"></rect><line x1="12" y1="18" x2="12.01" y2="18"></line>',tag:'<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"></path><line x1="7" y1="7" x2="7.01" y2="7"></line>',target:'<circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="6"></circle><circle cx="12" cy="12" r="2"></circle>',terminal:'<polyline points="4 17 10 11 4 5"></polyline><line x1="12" y1="19" x2="20" y2="19"></line>',thermometer:'<path d="M14 14.76V3.5a2.5 2.5 0 0 0-5 0v11.26a4.5 4.5 0 1 0 5 0z"></path>',"thumbs-down":'<path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"></path>',"thumbs-up":'<path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path>',"toggle-left":'<rect x="1" y="5" width="22" height="14" rx="7" ry="7"></rect><circle cx="8" cy="12" r="3"></circle>',"toggle-right":'<rect x="1" y="5" width="22" height="14" rx="7" ry="7"></rect><circle cx="16" cy="12" r="3"></circle>',tool:'<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path>',"trash-2":'<polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line>',trash:'<polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>',trello:'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><rect x="7" y="7" width="3" height="9"></rect><rect x="14" y="7" width="3" height="5"></rect>',"trending-down":'<polyline points="23 18 13.5 8.5 8.5 13.5 1 6"></polyline><polyline points="17 18 23 18 23 12"></polyline>',"trending-up":'<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline><polyline points="17 6 23 6 23 12"></polyline>',triangle:'<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>',truck:'<rect x="1" y="3" width="15" height="13"></rect><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"></polygon><circle cx="5.5" cy="18.5" r="2.5"></circle><circle cx="18.5" cy="18.5" r="2.5"></circle>',tv:'<rect x="2" y="7" width="20" height="15" rx="2" ry="2"></rect><polyline points="17 2 12 7 7 2"></polyline>',twitch:'<path d="M21 2H3v16h5v4l4-4h5l4-4V2zm-10 9V7m5 4V7"></path>',twitter:'<path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path>',type:'<polyline points="4 7 4 4 20 4 20 7"></polyline><line x1="9" y1="20" x2="15" y2="20"></line><line x1="12" y1="4" x2="12" y2="20"></line>',umbrella:'<path d="M23 12a11.05 11.05 0 0 0-22 0zm-5 7a3 3 0 0 1-6 0v-7"></path>',underline:'<path d="M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3"></path><line x1="4" y1="21" x2="20" y2="21"></line>',unlock:'<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path>',"upload-cloud":'<polyline points="16 16 12 12 8 16"></polyline><line x1="12" y1="12" x2="12" y2="21"></line><path d="M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3"></path><polyline points="16 16 12 12 8 16"></polyline>',upload:'<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line>',"user-check":'<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><polyline points="17 11 19 13 23 9"></polyline>',"user-minus":'<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><line x1="23" y1="11" x2="17" y2="11"></line>',"user-plus":'<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><line x1="20" y1="8" x2="20" y2="14"></line><line x1="23" y1="11" x2="17" y2="11"></line>',"user-x":'<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><line x1="18" y1="8" x2="23" y2="13"></line><line x1="23" y1="8" x2="18" y2="13"></line>',user:'<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle>',users:'<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path>',"video-off":'<path d="M16 16v1a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2m5.66 0H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10"></path><line x1="1" y1="1" x2="23" y2="23"></line>',video:'<polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>',voicemail:'<circle cx="5.5" cy="11.5" r="4.5"></circle><circle cx="18.5" cy="11.5" r="4.5"></circle><line x1="5.5" y1="16" x2="18.5" y2="16"></line>',"volume-1":'<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path>',"volume-2":'<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>',"volume-x":'<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><line x1="23" y1="9" x2="17" y2="15"></line><line x1="17" y1="9" x2="23" y2="15"></line>',volume:'<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>',watch:'<circle cx="12" cy="12" r="7"></circle><polyline points="12 9 12 12 13.5 13.5"></polyline><path d="M16.51 17.35l-.35 3.83a2 2 0 0 1-2 1.82H9.83a2 2 0 0 1-2-1.82l-.35-3.83m.01-10.7l.35-3.83A2 2 0 0 1 9.83 1h4.35a2 2 0 0 1 2 1.82l.35 3.83"></path>',"wifi-off":'<line x1="1" y1="1" x2="23" y2="23"></line><path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"></path><path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39"></path><path d="M10.71 5.05A16 16 0 0 1 22.58 9"></path><path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88"></path><path d="M8.53 16.11a6 6 0 0 1 6.95 0"></path><line x1="12" y1="20" x2="12.01" y2="20"></line>',wifi:'<path d="M5 12.55a11 11 0 0 1 14.08 0"></path><path d="M1.42 9a16 16 0 0 1 21.16 0"></path><path d="M8.53 16.11a6 6 0 0 1 6.95 0"></path><line x1="12" y1="20" x2="12.01" y2="20"></line>',wind:'<path d="M9.59 4.59A2 2 0 1 1 11 8H2m10.59 11.41A2 2 0 1 0 14 16H2m15.73-8.27A2.5 2.5 0 1 1 19.5 12H2"></path>',"x-circle":'<circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line>',"x-octagon":'<polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line>',"x-square":'<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="9" y1="9" x2="15" y2="15"></line><line x1="15" y1="9" x2="9" y2="15"></line>',x:'<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>',youtube:'<path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z"></path><polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02"></polygon>',"zap-off":'<polyline points="12.41 6.75 13 2 10.57 4.92"></polyline><polyline points="18.57 12.91 21 10 15.66 10"></polyline><polyline points="8 8 3 14 12 14 11 22 16 16"></polyline><line x1="1" y1="1" x2="23" y2="23"></line>',zap:'<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>',"zoom-in":'<circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line>',"zoom-out":'<circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line>'}},function(e){e.exports={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var t=Object.assign||function(e){for(var n=1;n<arguments.length;n++){var i=arguments[n];for(var t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t])}return e},l=function(){function e(e,n){for(var i=0;i<n.length;i++){var t=n[i];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(e,t.key,t)}}return function(n,i,t){return i&&e(n.prototype,i),t&&e(n,t),n}}(),r=a(i(22)),o=a(i(42));function a(e){return e&&e.__esModule?e:{default:e}}var c=function(){function e(n,i){var l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.name=n,this.contents=i,this.tags=l,this.attrs=t({},o.default,{class:"feather feather-"+n})}return l(e,[{key:"toSvg",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return"<svg "+function(e){return Object.keys(e).map(function(n){return n+'="'+e[n]+'"'}).join(" ")}(t({},this.attrs,e,{class:(0,r.default)(this.attrs.class,e.class)}))+">"+this.contents+"</svg>"}},{key:"toString",value:function(){return this.contents}}]),e}();n.default=c},function(e,n,i){"use strict";var t=o(i(12)),l=o(i(39)),r=o(i(38));function o(e){return e&&e.__esModule?e:{default:e}}e.exports={icons:t.default,toSvg:l.default,replace:r.default}},function(e,n,i){e.exports=i(0)},function(e,n,i){var t=i(2)("iterator"),l=!1;try{var r=0,o={next:function(){return{done:!!r++}},return:function(){l=!0}};o[t]=function(){return this},Array.from(o,function(){throw 2})}catch(e){}e.exports=function(e,n){if(!n&&!l)return!1;var i=!1;try{var r={};r[t]=function(){return{next:function(){return{done:i=!0}}}},e(r)}catch(e){}return i}},function(e,n,i){var t=i(30),l=i(2)("toStringTag"),r="Arguments"==t(function(){return arguments}());e.exports=function(e){var n,i,o;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(i=function(e,n){try{return e[n]}catch(e){}}(n=Object(e),l))?i:r?t(n):"Object"==(o=t(n))&&"function"==typeof n.callee?"Arguments":o}},function(e,n,i){var t=i(47),l=i(9),r=i(2)("iterator");e.exports=function(e){if(void 0!=e)return e[r]||e["@@iterator"]||l[t(e)]}},function(e,n,i){"use strict";var t=i(18),l=i(7),r=i(10);e.exports=function(e,n,i){var o=t(n);o in e?l.f(e,o,r(0,i)):e[o]=i}},function(e,n,i){var t=i(2),l=i(9),r=t("iterator"),o=Array.prototype;e.exports=function(e){return void 0!==e&&(l.Array===e||o[r]===e)}},function(e,n,i){var t=i(3);e.exports=function(e,n,i,l){try{return l?n(t(i)[0],i[1]):n(i)}catch(n){var r=e.return;throw void 0!==r&&t(r.call(e)),n}}},function(e,n){e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},function(e,n,i){var t=i(52);e.exports=function(e,n,i){if(t(e),void 0===n)return e;switch(i){case 0:return function(){return e.call(n)};case 1:return function(i){return e.call(n,i)};case 2:return function(i,t){return e.call(n,i,t)};case 3:return function(i,t,l){return e.call(n,i,t,l)}}return function(){return e.apply(n,arguments)}}},function(e,n,i){"use strict";var t=i(53),l=i(24),r=i(51),o=i(50),a=i(27),c=i(49),p=i(48);e.exports=function(e){var n,i,y,h,x=l(e),s="function"==typeof this?this:Array,u=arguments.length,d=u>1?arguments[1]:void 0,f=void 0!==d,g=0,v=p(x);if(f&&(d=t(d,u>2?arguments[2]:void 0,2)),void 0==v||s==Array&&o(v))for(i=new s(n=a(x.length));n>g;g++)c(i,g,f?d(x[g],g):x[g]);else for(h=v.call(x),i=new s;!(y=h.next()).done;g++)c(i,g,f?r(h,d,[y.value,g],!0):y.value);return i.length=g,i}},function(e,n,i){var t=i(32),l=i(54);t({target:"Array",stat:!0,forced:!i(46)(function(e){Array.from(e)})},{from:l})},function(e,n,i){var t=i(6),l=i(3);e.exports=function(e,n){if(l(e),!t(n)&&null!==n)throw TypeError("Can't set "+String(n)+" as a prototype")}},function(e,n,i){var t=i(56);e.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var e,n=!1,i={};try{(e=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(i,[]),n=i instanceof Array}catch(e){}return function(i,l){return t(i,l),n?e.call(i,l):i.__proto__=l,i}}():void 0)},function(e,n,i){var t=i(0).document;e.exports=t&&t.documentElement},function(e,n,i){var t=i(28),l=i(13);e.exports=Object.keys||function(e){return t(e,l)}},function(e,n,i){var t=i(8),l=i(7),r=i(3),o=i(59);e.exports=t?Object.defineProperties:function(e,n){r(e);for(var i,t=o(n),a=t.length,c=0;a>c;)l.f(e,i=t[c++],n[i]);return e}},function(e,n,i){var t=i(3),l=i(60),r=i(13),o=i(15),a=i(58),c=i(34),p=i(16)("IE_PROTO"),y=function(){},h=function(){var e,n=c("iframe"),i=r.length;for(n.style.display="none",a.appendChild(n),n.src=String("javascript:"),(e=n.contentWindow.document).open(),e.write("<script>document.F=Object<\/script>"),e.close(),h=e.F;i--;)delete h.prototype[r[i]];return h()};e.exports=Object.create||function(e,n){var i;return null!==e?(y.prototype=t(e),i=new y,y.prototype=null,i[p]=e):i=h(),void 0===n?i:l(i,n)},o[p]=!0},function(e,n,i){var t=i(4);e.exports=!!Object.getOwnPropertySymbols&&!t(function(){return!String(Symbol())})},function(e,n,i){var t=i(4);e.exports=!t(function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype})},function(e,n,i){"use strict";var t=i(26).IteratorPrototype,l=i(61),r=i(10),o=i(23),a=i(9),c=function(){return this};e.exports=function(e,n,i){var p=n+" Iterator";return e.prototype=l(t,{next:r(1,i)}),o(e,p,!1,!0),a[p]=c,e}},function(e,n,i){var t=i(4),l=/#|\.prototype\./,r=function(e,n){var i=a[o(e)];return i==p||i!=c&&("function"==typeof n?t(n):!!n)},o=r.normalize=function(e){return String(e).replace(l,".").toLowerCase()},a=r.data={},c=r.NATIVE="N",p=r.POLYFILL="P";e.exports=r},function(e,n){n.f=Object.getOwnPropertySymbols},function(e,n,i){var t=i(21),l=Math.max,r=Math.min;e.exports=function(e,n){var i=t(e);return i<0?l(i+n,0):r(i,n)}},function(e,n,i){var t=i(14),l=i(27),r=i(67);e.exports=function(e){return function(n,i,o){var a,c=t(n),p=l(c.length),y=r(o,p);if(e&&i!=i){for(;p>y;)if((a=c[y++])!=a)return!0}else for(;p>y;y++)if((e||y in c)&&c[y]===i)return e||y||0;return!e&&-1}}},function(e,n,i){var t=i(28),l=i(13).concat("length","prototype");n.f=Object.getOwnPropertyNames||function(e){return t(e,l)}},function(e,n,i){var t=i(0),l=i(69),r=i(66),o=i(3),a=t.Reflect;e.exports=a&&a.ownKeys||function(e){var n=l.f(o(e)),i=r.f;return i?n.concat(i(e)):n}},function(e,n,i){var t=i(1),l=i(70),r=i(31),o=i(7);e.exports=function(e,n){for(var i=l(n),a=o.f,c=r.f,p=0;p<i.length;p++){var y=i[p];t(e,y)||a(e,y,c(n,y))}}},function(e,n,i){var t=i(4),l=i(30),r="".split;e.exports=t(function(){return!Object("z").propertyIsEnumerable(0)})?function(e){return"String"==l(e)?r.call(e,""):Object(e)}:Object},function(e,n,i){"use strict";var t={}.propertyIsEnumerable,l=Object.getOwnPropertyDescriptor,r=l&&!t.call({1:2},1);n.f=r?function(e){var n=l(this,e);return!!n&&n.enumerable}:t},function(e,n,i){"use strict";var t=i(32),l=i(64),r=i(25),o=i(57),a=i(23),c=i(5),p=i(29),y=i(2),h=i(17),x=i(9),s=i(26),u=s.IteratorPrototype,d=s.BUGGY_SAFARI_ITERATORS,f=y("iterator"),g=function(){return this};e.exports=function(e,n,i,y,s,v,m){l(i,n,y);var w,M,b,z=function(e){if(e===s&&O)return O;if(!d&&e in H)return H[e];switch(e){case"keys":case"values":case"entries":return function(){return new i(this,e)}}return function(){return new i(this)}},A=n+" Iterator",k=!1,H=e.prototype,V=H[f]||H["@@iterator"]||s&&H[s],O=!d&&V||z(s),j="Array"==n&&H.entries||V;if(j&&(w=r(j.call(new e)),u!==Object.prototype&&w.next&&(h||r(w)===u||(o?o(w,u):"function"!=typeof w[f]&&c(w,f,g)),a(w,A,!0,!0),h&&(x[A]=g))),"values"==s&&V&&"values"!==V.name&&(k=!0,O=function(){return V.call(this)}),h&&!m||H[f]===O||c(H,f,O),x[n]=O,s)if(M={values:z("values"),keys:v?O:z("keys"),entries:z("entries")},m)for(b in M)!d&&!k&&b in H||p(H,b,M[b]);else t({target:n,proto:!0,forced:d||k},M);return M}},function(e,n){var i;i=function(){return this}();try{i=i||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(i=window)}e.exports=i},function(e,n,i){var t=i(0),l=i(36),r=t.WeakMap;e.exports="function"==typeof r&&/native code/.test(l.call(r))},function(e,n,i){var t=i(21),l=i(20);e.exports=function(e,n,i){var r,o,a=String(l(e)),c=t(n),p=a.length;return c<0||c>=p?i?"":void 0:(r=a.charCodeAt(c))<55296||r>56319||c+1===p||(o=a.charCodeAt(c+1))<56320||o>57343?i?a.charAt(c):r:i?a.slice(c,c+2):o-56320+(r-55296<<10)+65536}},function(e,n,i){"use strict";var t=i(77),l=i(37),r=i(74),o=l.set,a=l.getterFor("String Iterator");r(String,"String",function(e){o(this,{type:"String Iterator",string:String(e),index:0})},function(){var e,n=a(this),i=n.string,l=n.index;return l>=i.length?{value:void 0,done:!0}:(e=t(i,l,!0),n.index+=e.length,{value:e,done:!1})})},function(e,n,i){i(78),i(55);var t=i(45);e.exports=t.Array.from},function(e,n,i){i(79),e.exports=i(44)}])}); | |
13 | +//# sourceMappingURL=feather.min.js.map | |
0 | 14 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,2 @@ |
1 | +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ | |
2 | +var saveAs=saveAs||function(e){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,i=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},a=/Version\/[\d\.]+.*Safari/.test(navigator.userAgent),c=e.webkitRequestFileSystem,d=e.requestFileSystem||c||e.mozRequestFileSystem,u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",f=0,l=4e4,v=function(e){var t=function(){"string"==typeof e?n().revokeObjectURL(e):e.remove()};setTimeout(t,l)},p=function(e,t,n){t=[].concat(t);for(var o=t.length;o--;){var r=e["on"+t[o]];if("function"==typeof r)try{r.call(e,n||e)}catch(i){u(i)}}},w=function(e){return/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)?new Blob(["\uFEFF",e],{type:e.type}):e},y=function(t,u,l){l||(t=w(t));var y,m,S,h=this,R=t.type,O=!1,g=function(){p(h,"writestart progress write writeend".split(" "))},b=function(){if(m&&a&&"undefined"!=typeof FileReader){var o=new FileReader;return o.onloadend=function(){var e=o.result;m.location.href="data:attachment/file"+e.slice(e.search(/[,;]/)),h.readyState=h.DONE,g()},o.readAsDataURL(t),void(h.readyState=h.INIT)}if((O||!y)&&(y=n().createObjectURL(t)),m)m.location.href=y;else{var r=e.open(y,"_blank");void 0===r&&a&&(e.location.href=y)}h.readyState=h.DONE,g(),v(y)},E=function(e){return function(){return h.readyState!==h.DONE?e.apply(this,arguments):void 0}},N={create:!0,exclusive:!1};return h.readyState=h.INIT,u||(u="download"),r?(y=n().createObjectURL(t),void setTimeout(function(){o.href=y,o.download=u,i(o),g(),v(y),h.readyState=h.DONE})):(e.chrome&&R&&R!==s&&(S=t.slice||t.webkitSlice,t=S.call(t,0,t.size,s),O=!0),c&&"download"!==u&&(u+=".download"),(R===s||c)&&(m=e),d?(f+=t.size,void d(e.TEMPORARY,f,E(function(e){e.root.getDirectory("saved",N,E(function(e){var n=function(){e.getFile(u,N,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){m.location.href=e.toURL(),h.readyState=h.DONE,p(h,"writeend",t),v(e)},n.onerror=function(){var e=n.error;e.code!==e.ABORT_ERR&&b()},"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=h["on"+e]}),n.write(t),h.abort=function(){n.abort(),h.readyState=h.DONE},h.readyState=h.WRITING}),b)}),b)};e.getFile(u,{create:!1},E(function(e){e.remove(),n()}),E(function(e){e.code===e.NOT_FOUND_ERR?n():b()}))}),b)}),b)):void b())},m=y.prototype,S=function(e,t,n){return new y(e,t,n)};return"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob?function(e,t,n){return n||(e=w(e)),navigator.msSaveOrOpenBlob(e,t||"download")}:(m.abort=function(){var e=this;e.readyState=e.DONE,p(e,"abort")},m.readyState=m.INIT=0,m.WRITING=1,m.DONE=2,m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null,S)}}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content);"undefined"!=typeof module&&module.exports?module.exports.saveAs=saveAs:"undefined"!=typeof define&&null!==define&&null!==define.amd&&define([],function(){return saveAs}); | |
0 | 3 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,125 @@ |
1 | +/* canvas-toBlob.js | |
2 | + * A canvas.toBlob() implementation. | |
3 | + * 2016-05-26 | |
4 | + * | |
5 | + * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr | |
6 | + * License: MIT | |
7 | + * See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md | |
8 | + */ | |
9 | + | |
10 | +/*global self */ | |
11 | +/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, | |
12 | + plusplus: true */ | |
13 | + | |
14 | +/*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */ | |
15 | + | |
16 | +(function(view) { | |
17 | +"use strict"; | |
18 | +var | |
19 | + Uint8Array = view.Uint8Array | |
20 | + , HTMLCanvasElement = view.HTMLCanvasElement | |
21 | + , canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype | |
22 | + , is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i | |
23 | + , to_data_url = "toDataURL" | |
24 | + , base64_ranks | |
25 | + , decode_base64 = function(base64) { | |
26 | + var | |
27 | + len = base64.length | |
28 | + , buffer = new Uint8Array(len / 4 * 3 | 0) | |
29 | + , i = 0 | |
30 | + , outptr = 0 | |
31 | + , last = [0, 0] | |
32 | + , state = 0 | |
33 | + , save = 0 | |
34 | + , rank | |
35 | + , code | |
36 | + , undef | |
37 | + ; | |
38 | + while (len--) { | |
39 | + code = base64.charCodeAt(i++); | |
40 | + rank = base64_ranks[code-43]; | |
41 | + if (rank !== 255 && rank !== undef) { | |
42 | + last[1] = last[0]; | |
43 | + last[0] = code; | |
44 | + save = (save << 6) | rank; | |
45 | + state++; | |
46 | + if (state === 4) { | |
47 | + buffer[outptr++] = save >>> 16; | |
48 | + if (last[1] !== 61 /* padding character */) { | |
49 | + buffer[outptr++] = save >>> 8; | |
50 | + } | |
51 | + if (last[0] !== 61 /* padding character */) { | |
52 | + buffer[outptr++] = save; | |
53 | + } | |
54 | + state = 0; | |
55 | + } | |
56 | + } | |
57 | + } | |
58 | + // 2/3 chance there's going to be some null bytes at the end, but that | |
59 | + // doesn't really matter with most image formats. | |
60 | + // If it somehow matters for you, truncate the buffer up outptr. | |
61 | + return buffer; | |
62 | + } | |
63 | +; | |
64 | +if (Uint8Array) { | |
65 | + base64_ranks = new Uint8Array([ | |
66 | + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1 | |
67 | + , -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 | |
68 | + , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 | |
69 | + , -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 | |
70 | + , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 | |
71 | + ]); | |
72 | +} | |
73 | +if (HTMLCanvasElement && (!canvas_proto.toBlob || !canvas_proto.toBlobHD)) { | |
74 | + if (!canvas_proto.toBlob) | |
75 | + canvas_proto.toBlob = function(callback, type /*, ...args*/) { | |
76 | + if (!type) { | |
77 | + type = "image/png"; | |
78 | + } if (this.mozGetAsFile) { | |
79 | + callback(this.mozGetAsFile("canvas", type)); | |
80 | + return; | |
81 | + } if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) { | |
82 | + callback(this.msToBlob()); | |
83 | + return; | |
84 | + } | |
85 | + | |
86 | + var | |
87 | + args = Array.prototype.slice.call(arguments, 1) | |
88 | + , dataURI = this[to_data_url].apply(this, args) | |
89 | + , header_end = dataURI.indexOf(",") | |
90 | + , data = dataURI.substring(header_end + 1) | |
91 | + , is_base64 = is_base64_regex.test(dataURI.substring(0, header_end)) | |
92 | + , blob | |
93 | + ; | |
94 | + if (Blob.fake) { | |
95 | + // no reason to decode a data: URI that's just going to become a data URI again | |
96 | + blob = new Blob | |
97 | + if (is_base64) { | |
98 | + blob.encoding = "base64"; | |
99 | + } else { | |
100 | + blob.encoding = "URI"; | |
101 | + } | |
102 | + blob.data = data; | |
103 | + blob.size = data.length; | |
104 | + } else if (Uint8Array) { | |
105 | + if (is_base64) { | |
106 | + blob = new Blob([decode_base64(data)], {type: type}); | |
107 | + } else { | |
108 | + blob = new Blob([decodeURIComponent(data)], {type: type}); | |
109 | + } | |
110 | + } | |
111 | + callback(blob); | |
112 | + }; | |
113 | + | |
114 | + if (!canvas_proto.toBlobHD && canvas_proto.toDataURLHD) { | |
115 | + canvas_proto.toBlobHD = function() { | |
116 | + to_data_url = "toDataURLHD"; | |
117 | + var blob = this.toBlob(); | |
118 | + to_data_url = "toDataURL"; | |
119 | + return blob; | |
120 | + } | |
121 | + } else { | |
122 | + canvas_proto.toBlobHD = canvas_proto.toBlob; | |
123 | + } | |
124 | +} | |
125 | +}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); | ... | ... |
app/templates/base_page.html
... | ... | @@ -40,17 +40,18 @@ |
40 | 40 | <div class="sidebar-sticky collapse navbar-collapse" id="navbarSupportedContent"> |
41 | 41 | <ul class="nav flex-column" id="v_menu"> |
42 | 42 | <li class="nav-item"> |
43 | - <a aria-expanded="false" id="agents" class="main-nav nav-link" data-target="#agent" data-toggle="collapse" | |
43 | + <a aria-expanded="false" class="main-nav nav-link" data-target="#agent" data-toggle="collapse" | |
44 | 44 | href="#"> |
45 | 45 | <span data-feather="user"></span> |
46 | 46 | Agent |
47 | 47 | </a> |
48 | 48 | <ul aria-expanded="false" class="collapse" class="nav" data-parent="#v_menu" id="agent"> |
49 | - <li class="nav-item"><a id="liste_agents" class="sub_link nav-link " | |
49 | + <li class="nav-item"><a id="agents_list" class="sub_link nav-link " | |
50 | 50 | href="{{ url_for('main.agents') }}">Liste des |
51 | 51 | agents</a> |
52 | 52 | </li> |
53 | - <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Statistiques</a></li> | |
53 | + <li class="nav-item"><a id="agents_stats" class="sub_link nav-link" | |
54 | + href="{{ url_for('main.agents_stats') }}">Statistiques</a></li> | |
54 | 55 | <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Liste des responsabilités</a></li> |
55 | 56 | <li class="nav-item"><a id="capacities" class="sub_link nav-link " |
56 | 57 | href="{{ url_for('main.capacities') }}">Liste des |
... | ... | @@ -67,12 +68,11 @@ |
67 | 68 | Projet |
68 | 69 | </a> |
69 | 70 | <ul aria-expanded="false" class="collapse" data-parent="#v_menu" id="project"> |
70 | - <li class="nav-item"><a id="projects" class="sub_link nav-link " href="{{ url_for('main.projects') }}">Liste | |
71 | - des | |
72 | - projets</a></li> | |
73 | - <li class="nav-item"><a id="categories" class="sub_link nav-link" | |
71 | + <li class="nav-item"><a id="projects_list" class="sub_link nav-link " | |
72 | + href="{{ url_for('main.projects') }}">Liste des projets</a></li> | |
73 | + <li class="nav-item"><a id="categories_list" class="sub_link nav-link" | |
74 | 74 | href="{{ url_for('main.categories') }}">Liste des catégories</a></li> |
75 | - <li class="nav-item"><a id="labels" class="sub_link nav-link" href="{{ url_for('main.labels') }}">Liste | |
75 | + <li class="nav-item"><a id="labels_list" class="sub_link nav-link" href="{{ url_for('main.labels') }}">Liste | |
76 | 76 | des labels</a></li> |
77 | 77 | <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Listes des statuts de projets</a> |
78 | 78 | <li class="nav-item"><a id="projects_stats" class="sub_link nav-link" |
... | ... | @@ -86,7 +86,7 @@ |
86 | 86 | Service |
87 | 87 | </a> |
88 | 88 | <ul aria-expanded="false" class="collapse" data-parent="#v_menu" id="service"> |
89 | - <li class="nav-item"><a id="liste_services" class="sub_link nav-link " | |
89 | + <li class="nav-item"><a id="services_list" class="sub_link nav-link " | |
90 | 90 | href="{{ url_for('main.services') }}">Liste des |
91 | 91 | services</a> |
92 | 92 | </li> |
... | ... | @@ -99,13 +99,13 @@ |
99 | 99 | Chef de service |
100 | 100 | </a> |
101 | 101 | <ul aria-expanded="false" class="collapse" data-parent="#v_menu" id="cds"> |
102 | - <li class="nav-item"><a id="edit_agent" class="sub_link nav-link " | |
102 | + <li class="nav-item"><a id="agent_edit" class="sub_link nav-link " | |
103 | 103 | href="{{ url_for('main.agent_edit') }}">Ajouter/Modifier un |
104 | 104 | Agent</a></li> |
105 | 105 | <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Renseigner le statut d'un agent pour |
106 | 106 | un |
107 | 107 | semestre</a></li> |
108 | - <li class="nav-item"><a id="add_charge" class="sub_link nav-link " | |
108 | + <li class="nav-item"><a id="charge_add" class="sub_link nav-link " | |
109 | 109 | href="{{ url_for('main.charge_add') }}">Affecter un |
110 | 110 | agent à un |
111 | 111 | projet/service</a></li> |
... | ... | @@ -125,20 +125,25 @@ |
125 | 125 | <li class="nav-item"><a id="project_edit" class="sub_link nav-link" |
126 | 126 | href="{{ url_for('main.project_edit') }}">Ajouter/Modifier un projet</a></li> |
127 | 127 | <li class="nav-item"><a id="category_edit" class="sub_link nav-link" |
128 | - href="{{ url_for('main.category_edit') }}">Ajouter/Modifier une catégorie</a></li> | |
128 | + href="{{ url_for('main.category_edit') }}">Ajouter/Modifier une catégorie</a> | |
129 | + </li> | |
129 | 130 | <li class="nav-item"><a id="label_edit" class="sub_link nav-link" |
130 | 131 | href="{{ url_for('main.label_edit') }}">Ajouter/Modifier un label</a></li> |
131 | - <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une compétence</a></li> | |
132 | - <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une fonction</a></li> | |
133 | - <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une responsabilité</a></li> | |
132 | + <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une compétence</a> | |
133 | + </li> | |
134 | + <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une fonction</a> | |
135 | + </li> | |
136 | + <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une | |
137 | + responsabilité</a></li> | |
134 | 138 | <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Affecter un responsable de |
135 | 139 | projet</a></li> |
136 | 140 | <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Affecter un responsable de |
137 | 141 | service</a></li> |
138 | - <li class="nav-item"><a id="liste_periodes" class="sub_link nav-link " | |
142 | + <li class="nav-item"><a id="periods_list" class="sub_link nav-link " | |
139 | 143 | href="{{ url_for('main.periods') }}">Liste des |
140 | 144 | périodes</a></li> |
141 | - <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une période</a></li> | |
145 | + <li class="nav-item"><a class="sub_link nav-link disabled" href="#">Ajouter/Modifier une période</a> | |
146 | + </li> | |
142 | 147 | |
143 | 148 | </ul> |
144 | 149 | </li> |
... | ... | @@ -164,9 +169,9 @@ |
164 | 169 | {% include 'datatables-includes.html' %} |
165 | 170 | |
166 | 171 | <!-- Icons --> |
167 | - <script src="https://unpkg.com/feather-icons/dist/feather.min.js"></script> | |
172 | + <script src="{{ url_for('static', filename='lib/feather-4.28.0/feather.min.js') }}"></script> | |
168 | 173 | <script> |
169 | - feather.replace() | |
174 | + feather.replace(); | |
170 | 175 | </script> |
171 | 176 | |
172 | 177 | <script type="text/javascript" | ... | ... |
app/templates/charges-includes.html
1 | 1 | <script |
2 | - src="https://cdn.rawgit.com/eligrey/canvas-toBlob.js/f1a01896135ab378aa5c0118eadd81da55e698d8/canvas-toBlob.js"></script> | |
2 | + src="{{ url_for('static', filename='lib/svg2any/canvas-toBlob.js') }}"></script> | |
3 | 3 | <script |
4 | - src="https://cdn.rawgit.com/eligrey/FileSaver.js/e9d941381475b5df8b7d7691013401e171014e89/FileSaver.min.js"></script> | |
4 | + src="{{ url_for('static', filename='lib/svg2any/FileSaver.min.js') }}"></script> | |
5 | 5 | <script src="{{ url_for('main.static', filename='js/svg_to_any.js', version=config.VERSION) }}" |
6 | 6 | type="text/javascript"></script> |
7 | 7 | <script src="{{ url_for('main.static', filename='js/charges.js', version=config.VERSION) }}" | ... | ... |
app/templates/datatables-includes.html
... | ... | @@ -5,7 +5,8 @@ |
5 | 5 | src="{{ url_for('static', filename='lib/datatables-1.10.24/js/dataTables.buttons.min.js') }}"></script> |
6 | 6 | <script type="text/javascript" |
7 | 7 | src="{{ url_for('static', filename='lib/datatables-1.10.24/js/buttons.html5.min.js') }}"></script> |
8 | -<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script> | |
8 | +<script type="text/javascript" | |
9 | + src="{{ url_for('static', filename='lib/datatables-1.10.24/js/jszip.min.js') }}"></script> | |
9 | 10 | |
10 | 11 | <script src="{{ url_for('main.static', filename='js/style_tables.js', version=config.VERSION) }}" |
11 | 12 | type="text/javascript"></script> | ... | ... |
resources/lesia-btp.sqlite
No preview for this file type
tests/backend_tests.py
... | ... | @@ -86,3 +86,7 @@ class DbMgrTestCase(BaseTestCase): |
86 | 86 | categories = [_cl['name'] for _cl in category_labels] |
87 | 87 | self.assertEqual(['Domaine', 'Pôle'], categories) |
88 | 88 | |
89 | + def test_agents_status_counts(self): | |
90 | + status_counts = db_mgr.count_agents_by_status(3) | |
91 | + print(status_counts) | |
92 | + self.assertEqual(14, len(status_counts)) | ... | ... |