Compare commits

..
Author SHA1 Message Date
STEINNI cf292031fd threetobus now uses [UID] template, MessageBus upgraded to cnxId 2026-06-26 21:56:19 +00:00
STEINNI aefa5ab147 no local cursor rules 2026-06-26 15:39:02 +00:00
STEINNI e2f8766b9f working on simManage 2026-06-21 21:09:21 +00:00
STEINNI 06a7868882 better default agent props & speed & position numeric, not strings 2026-06-21 12:08:25 +00:00
STEINNI 54db203e86 untested collision/near miss detection, with prisms auto-refresh 2026-06-07 10:44:28 +00:00
STEINNI d172e06611 sim creation wired to DB with ownership 2026-06-05 20:27:57 +00:00
STEINNI b122cf153e centered windozzz 2026-06-05 16:23:40 +00:00
STEINNI 5207a3b18e started sims section & axes&grid settings for KFEditor 2026-06-05 15:45:27 +00:00
STEINNI ce9e73ac41 updateAgent API & snippet in KF console 2026-06-05 09:09:53 +00:00
STEINNI eb7312c7a8 tuned confirm boxes 2026-06-05 08:57:33 +00:00
STEINNI d301b78ea7 KF Editor => Reset KF button 2026-06-05 08:33:06 +00:00
STEINNI ea9b3d06cf graflow examples cleanup 2026-03-08 14:24:03 +00:00
STEINNI 4b9207546c Add buildoz as submodule 2026-03-08 13:46:42 +00:00
STEINNI 662e694f21 remove embedded buildoz 2026-03-08 13:44:15 +00:00
STEINNI cd2e74e6fd graflow: examples tuning, nodemove debugging 2026-03-08 13:34:10 +00:00
STEINNI a967576d4b graflow: autofit OK 2026-03-07 18:36:01 +00:00
STEINNI 61855a3416 graflow: improved subflow zoom-in 2026-03-07 15:15:07 +00:00
STEINNI 8421dd12b6 graflow: improved parent align: correction on parents if fakenodes 2026-03-07 14:22:45 +00:00
STEINNI 124bae719b graflow: align parent 2026-03-06 20:14:35 +00:00
STEINNI 24aad6bbf6 graflow: improved ortho walkarounds 2026-03-06 19:11:53 +00:00
STEINNI 2d87523020 graflow: improving ortho 2026-03-04 20:48:50 +00:00
STEINNI f81ae0611c graflow: test for all directions 2026-03-02 21:27:33 +00:00
STEINNI 30a95ca009 graflow: refacto & facto of buildSegment 2026-03-02 20:45:55 +00:00
STEINNI bc6a02fe10 graflow: small fix for loop always bezier 2026-03-02 20:37:58 +00:00
STEINNI e46ff1a817 graflow: autoplace attributes & better ICMP example 2026-03-02 19:07:06 +00:00
STEINNI f5fbdd6ccd graflow: fix1 to ortho wires 2026-03-02 18:27:15 +00:00
STEINNI be72b6f2db graflow: wireType straight 2026-03-01 13:27:00 +00:00
STEINNI 60db0393cc graflow: editable=>moving nodes 2026-02-28 22:18:14 +00:00
STEINNI a156db845a graflow split tests + fixed height bug + fixed subflow reenter loses style 2026-02-28 20:55:44 +00:00
STEINNI 8be5751107 graflow: source grooming + demo panels subflow compatible 2026-02-28 11:14:04 +00:00
STEINNI 3e0faa4866 graflow: replaced fixed by absolute in subflows 2026-02-28 10:57:06 +00:00
STEINNI 34ce9049c6 graflow: several bigfixes, for subflows, longlinks-fakenodes cleanup, multipass layerordering 2026-02-27 21:42:02 +00:00
STEINNI 6bc3c1e9b8 graflow: subflow polishing 2026-02-25 20:25:53 +00:00
STEINNI 0cf67a5c9f graflow: also embed button icons 2026-02-25 18:26:28 +00:00
STEINNI 0b4b7e2a2f graflow: subflow reference nodes & exit subflow 2026-02-25 18:25:33 +00:00
STEINNI e5bd91cd9f graflow: entering subflow ok 2026-02-22 20:59:58 +00:00
STEINNI e647bf01de graflow: entering subflow ok 2026-02-22 20:58:35 +00:00
STEINNI 46f08cfdce graflow: isolated attribute 2026-02-22 14:43:46 +00:00
STEINNI 91274c4542 graflow: added autoplace align 1st & last 2026-02-21 22:24:10 +00:00
STEINNI d9bdc34210 nicsys license 2026-02-21 22:08:59 +00:00
STEINNI 3c93683ca1 graflow: added icmp example & fixed grand-slam long-links 2026-02-21 21:32:53 +00:00
STEINNI 0d5107f09a graflow: cleanup minTension VS tension 2026-02-08 12:49:13 +00:00
STEINNI db45bcb4c5 graflow: tangents of go-around finally OK 2026-02-08 12:42:46 +00:00
STEINNI cf24657f9f graflow started zomminout 2026-01-26 08:03:10 +00:00
STEINNI 4bb306e8a1 merged back lonkwires 2026-01-24 18:26:04 +00:00
STEINNI bc80b3d4d6 cherrypicked subflow example 2026-01-21 17:16:43 +00:00
STEINNI aadba6b3e6 clean-without longbranches 2026-01-21 14:45:10 +00:00
58 changed files with 6806 additions and 2778 deletions

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
[submodule "app/thirdparty/buildoz"]
path = app/thirdparty/buildoz
url = https://gitea.internike.com/nike/buildoz.git
-72
View File
@@ -1,72 +0,0 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
}
.bzgf-node .body{
z-index: 1;
position: absolute;
inset: 0;
background: var(--eicui-base-color-grey-25);
border:2px solid var(--eicui-base-color-grey-50);
border-radius: 6px;
}
.bzgf-node .title {
font-weight: bold;
color: var(--app-color-black);
margin: .5em auto .2em auto;
}
.bzgf-node .subtitle {
font-size: .9em;
color: var(--eicui-base-color-primary-100);
width: 90%;
margin: auto;
}
.bzgf-node .port{
position: absolute;
height: 10px;
width: 10px;
background: var(--eicui-base-color-info-25);
border-radius: 10px;
}
.bzgf-node [data-direction="n"]{ top: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="w"]{ left: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-id="in2"]{ top: 25%; }
.bzgf-node [data-id="in3"]{ top: 75%; }
.bzgf-node [data-id="out2"]{ top: 25%; }
.bzgf-node [data-id="out3"]{ top: 75%; }
.bzgf-wire{ stroke: var(--eicui-base-color-info); stroke-width: 4px; stroke-dasharray: 10,5; }
</style>
<template>
<div class="bzgf-node" data-nodetype="eicBasic">
<div class="body">
<div class="title">{title}</div>
<div class="subtitle">{subtitle}</div>
</div>
<div class="port" data-type="in" data-id="in1" data-direction="w"></div>
<div class="port" data-type="in" data-id="in2" data-direction="w"></div>
<div class="port" data-type="in" data-id="in3" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="port" data-type="out" data-id="out2" data-direction="e"></div>
<div class="port" data-type="out" data-id="out3" data-direction="e"></div>
</div>
</template>
-173
View File
@@ -1,173 +0,0 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
border-width:2px;
border-style: solid;
border-radius: 6px;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
}
.bzgf-node .title {
font-weight: bold;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 2em;
color: white;
}
.bzgf-node .body { margin-top: 2em; }
.bzgf-node .body input {
width:4em;
font-size: .9em;
border-radius: 6px;
border: 1px solid #CCC;
}
.bzgf-node .body div{ font-size: 12px; text-align: left; line-height: 24px; }
.bzgf-node .port{
position: absolute;
height: 10px;
width: 10px;
border: 1px solid black;
border-radius: 10px;
}
.bzgf-node .port[data-type="in"] { background: #0F0; }
.bzgf-node .port[data-type="out"] { background: #FF0; }
.bzgf-node [data-direction="w"]{ left: -7px; top: calc(50% + 1em); transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -7px; top: calc(50% + 1em); transform: translateY(-50%);}
.bzgf-node [data-direction="n"]{ top: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node[data-nodetype="inc"]{
background: #DFD;
border-color: #090;
}
.bzgf-node[data-nodetype="inc"] .title{ background: #090; }
.bzgf-node[data-nodetype="wadder"]{
background: #DFD;
border-color: #090;
height:150px
}
.bzgf-node[data-nodetype="wadder"] .body{ display: grid; grid-gap: 4px; margin-left:0.5em; grid-template-columns: 1fr 1fr; align-items: center; }
.bzgf-node[data-nodetype="wadder"] .title{ background: #090; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp1"] { top:51px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp2"] { top:75px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp3"] { top:99px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp4"] { top:123px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp5"] { top:147px; }
.bzgf-node[data-nodetype="factor"]{
background: #DDF;
border-color: #009;
}
.bzgf-node[data-nodetype="factor"] .title{ background: #009; }
.bzgf-node[data-nodetype="multiplier"]{
background: #DDF;
border-color: #009;
height:110px
}
.bzgf-node[data-nodetype="multiplier"] .body{
font-size:40px;
font-weight: bold;
align-items: center;
display: flex;
justify-content: center;
margin-top: 1em;
}
.bzgf-node[data-nodetype="multiplier"] .title{ background: #009; }
.bzgf-node[data-nodetype="multiplier"] .port[data-id="inp1"] { top:37px; }
.bzgf-node[data-nodetype="multiplier"] .port[data-id="inp2"] { top:63px; }
.bzgf-node[data-nodetype="multiplier"] .port[data-id="inp3"] { top:89px; }
.bzgf-node[data-nodetype="input"],
.bzgf-node[data-nodetype="console"]{
background: #CCC;
border-color: #555;
}
.bzgf-node[data-nodetype="input"] .title,
.bzgf-node[data-nodetype="console"] .title{ background: #555; }
.bzgf-wire{ stroke: #0AF; stroke-width: 2; }
</style>
<template>
<div class="bzgf-node" data-nodetype="inc">
<div class="title">Fixed Increment</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<label>Increment:</label><input name="incvalue" type="text" value="1">
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="factor">
<div class="title">Fixed factor</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<label>Factor:</label><input name="factvalue" type="text" value="0.5">
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="wadder">
<div class="title">Adder</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp2" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp3" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp4" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp5" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<div>
<div>x <input type="text" name="weight1" value="1"></div>
<div>x <input type="text" name="weight2" value="1"></div>
<div>x <input type="text" name="weight3" value="1"></div>
<div>x <input type="text" name="weight4" value="1"></div>
<div>x <input type="text" name="weight5" value="1"></div>
</div>
<div style="font-size:40px;font-weight: bold;transform: translateY(-50%);">&sum;</div>
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="multiplier">
<div class="title">Multiply</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp2" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp3" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">x</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="console">
<div class="title">Console</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="body"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="input">
<div class="title">input</div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<label>Value:</label><input name="value" type="text" value="1">
</div>
</div>
</template>
-237
View File
@@ -1,237 +0,0 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
border-width:2px;
border-style: solid;
border-radius: 6px;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
background: black;
}
.bzgf-node .text {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
width: 100%;
height: 2em;
color: white;
transform: translateX(-50%), translateY(-50%);
}
.bzgf-node .port{
position: absolute;
height: 6px;
width: 6px;
background: #FFF;
z-index: 99;
opacity: 0.3;
}
.bzgf-node [data-direction="w"]{ left: -7px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -7px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="n"]{ top: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node[data-nodetype="start"],
.bzgf-node[data-nodetype="end"]{
border: 1px solid white;
width: 100px;
height: 30px;
border-radius: 50%;
}
.bzgf-node[data-nodetype="start"] .text,
.bzgf-node[data-nodetype="end"] .text{ width: 80%; }
.bzgf-node[data-nodetype="condition"]{
border: none;
width: 100px;
height: 100px;
}
.bzgf-node[data-nodetype="condition"] .frame{
border: 1px solid white;
transform: rotate(-45deg) scale(0.7071);
position: absolute;
inset: 0;
}
.bzgf-node[data-nodetype="condition"] .port[data-direction="w"]{ left: -5px; }
.bzgf-node[data-nodetype="condition"] [data-direction="e"]{ right: -5px; }
.bzgf-node[data-nodetype="condition"] [data-direction="n"]{ top: -5px; }
.bzgf-node[data-nodetype="condition"] [data-direction="s"]{ bottom: -5px; }
.bzgf-node[data-nodetype="process"]{
border: 1px solid white;
width: 150px;
height: 70px;
padding: 0;
}
.bzgf-node[data-nodetype="process"] .text{ width: 80%; }
.bzgf-node[data-nodetype="process"] .dbline{
border: 1px solid white;
width: 75%;
height: 100%;
position: absolute;
top: -1px;
left: 10%;
}
.bzgf-node[data-nodetype="database"]{
border: 1px solid white;
width: 100px;
height: 100px;
isolation: isolate;
}
.bzgf-node[data-nodetype="database"] .top{
z-index: 2;
height: 20%;
border: 1px solid white;
border-radius: 50%;
position: absolute;
top: -10%;
left: 0;
width: 100%;
background: black;
}
.bzgf-node[data-nodetype="database"] .text{
background: black;
width: 87%;
z-index: 1;
}
.bzgf-node[data-nodetype="database"] .bottom{
z-index: 0;
height: 20%;
border: 1px solid white;
border-radius: 50%;
position: absolute;
bottom: -10%;
left: 0;
width: 99%;
background: black;
clip-path: polygon( 0% 110%, 100% 110%, 100% 50%, 0% 50%);
}
.bzgf-node[data-nodetype="database"] [data-direction="n"]{ top: -17px; }
.bzgf-node[data-nodetype="database"] [data-direction="s"]{ bottom: -17px; }
.bzgf-node[data-nodetype="preparation"]{
width: 150px;
height: 80px;
padding: 0;
border: none;
}
.bzgf-node[data-nodetype="preparation"] .text{ width: 85%; }
.bzgf-node[data-nodetype="preparation"] .outerframe{
width: 100%;
height: 100%;
position: absolute;
background: white;
border: none;
padding: 0;
place-items: center;
clip-path: polygon(
10% 0%,
90% 0%,
100% 50%,
90% 100%,
10% 100%,
0% 50%
);
}
.bzgf-node[data-nodetype="preparation"] .innerframe{
width: calc(100% - 2px);
height: calc(100% - 2px);
position: absolute;
top: 1px;
left: 1px;
background: black;
clip-path: inherit;
display: grid;
place-items: center;
color: white;
}
.bzgf-wire{ stroke: #FF0; stroke-width: 2; }
</style>
<svg style="display:none" aria-hidden="true">
<template id="svg-arrows">
<defs>
<marker id="arrow"
viewBox="0 0 15 15"
refX="15"
refY="7"
markerWidth="15"
markerHeight="15"
orient="auto-start-reverse"
markerUnits="userSpaceOnUse">
<path d="M0,0 L15,7 L0,15 Z" fill="#FF0"/>
</marker>
</defs>
</template>
</svg>
<template>
<div class="bzgf-node" data-nodetype="start">
<div class="text">{text}</div>
<div class="port" data-id="out1" data-direction="s"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="end">
<div class="text">{text}</div>
<div class="port" data-id="inp1" data-direction="n"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="condition">
<div class="frame"></div>
<div class="text">{text}</div>
<div class="port" data-id="inp1" data-direction="n"></div>
<div class="port" data-id="out1" data-direction="w"></div>
<div class="port" data-id="out2" data-direction="s"></div>
<div class="port" data-id="out3" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="process">
<div class="dbline"></div>
<div class="text">{text}</div>
<div class="port" data-id="inout1" data-direction="n"></div>
<div class="port" data-id="inout2" data-direction="s"></div>
<div class="port" data-id="inout3" data-direction="w"></div>
<div class="port" data-id="inout4" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="database">
<div class="top"></div>
<div class="bottom"></div>
<div class="text">{text}</div>
<div class="port" data-id="inout1" data-direction="n"></div>
<div class="port" data-id="inout2" data-direction="s"></div>
<div class="port" data-id="inout3" data-direction="w"></div>
<div class="port" data-id="inout4" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="preparation">
<div class="outerframe">
<div class="innerframe">
<div class="text">{text}</div>
</div>
</div>
<div class="port" data-id="inp1" data-direction="n"></div>
<div class="port" data-id="out1" data-direction="s"></div>
<div class="port" data-id="inout1" data-direction="w"></div>
<div class="port" data-id="inout2" data-direction="e"></div>
</div>
</template>
+1 -1
View File
@@ -44,7 +44,7 @@ log(agtIds)
await removeAgent('00000000-aaaa-bbbb-cccc-dddddddddddd')
</div>
<div class="snippet" data-snippet="updateAgent" style="display:none;">
await updateAgent('00000000-aaaa-bbbb-cccc-dddddddddddd', { position: { x: 5, y: 10, z: 0 } })
</div>
<div class="snippet" data-snippet="selectAgent" style="display:none;">
await selectAgent('00000000-aaaa-bbbb-cccc-dddddddddddd')
-108
View File
@@ -1,108 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="/app/thirdparty/eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../../thirdparty/buildoz/buildoz.css">
<script src="../../thirdparty/buildoz/buildoz.js"></script>
<script src="../../thirdparty/buildoz/bzGraflow.js"></script>
<style>
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
left: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:99;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
}
bz-graflow.compunet{ grid-column: 1 / -1; width: 80vw; height: 40vh; background:black; }
bz-graflow.eic{ grid-column: 1 / -1; width: 80vw; height: 30vh; background: var(--eicui-base-color-grey-10); }
bz-graflow.organi{ width: 40vw; height: 100vh; background:black; }
</style>
<script>
window.addEventListener('load',()=>{
const grflw1 = document.querySelector('bz-graflow.compunet')
document.querySelector('[data-trigger="onAutoplace1H"]').addEventListener('click',
(evt) => { grflw1.autoPlace('horizontal', 80, 30, 1000) }
)
document.querySelector('[data-trigger="onAutoplace1V"]').addEventListener('click',
(evt) => { grflw1.autoPlace('vertical') }
)
const grflw2 = document.querySelector('bz-graflow.eic')
document.querySelector('[data-trigger="onAutoplace2H"]').addEventListener('click',
(evt) => { grflw2.autoPlace('horizontal', 80, 80, 1000) }
)
document.querySelector('[data-trigger="onAutoplace2V"]').addEventListener('click',
(evt) => { grflw2.autoPlace('vertical', 80, 80, 1000) }
)
const grflw3 = document.querySelector('bz-graflow.organi')
document.querySelector('[data-trigger="onAutoplace3H"]').addEventListener('click',
(evt) => { grflw3.autoPlace('horizontal', 80, 80, 1000) }
)
document.querySelector('[data-trigger="onAutoplace3V"]').addEventListener('click',
(evt) => { grflw3.autoPlace('vertical', 80, 50, 1000) }
)
document.querySelector('[data-id="compunet"]').addEventListener('change',
(evt) => { grflw1.setAttribute('tension', evt.target.value); grflw1.refresh() }
)
document.querySelector('[data-id="eic"]').addEventListener('change',
(evt) => { grflw2.setAttribute('tension', evt.target.value); grflw2.refresh() }
)
document.querySelector('[data-id="organi"]').addEventListener('change',
(evt) => { grflw3.setAttribute('tension', evt.target.value); grflw3.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="compunet" flow="/app/assets/json/bzGraflow/testFlow1.json" tension="60">
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace1H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace1V">Auto-place Vertical</button>
<div class-"cols-2"=""><label>tension</label><input data-id="compunet" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
<bz-graflow class="eic" flow="/app/assets/json/bzGraflow/testFlowEic.json" tension="60">
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace2H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace2V">Auto-place Vertical</button>
<div class-"cols-2"=""><label>tension</label><input data-id="eic" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
<bz-graflow class="organi" flow="/app/assets/json/bzGraflow/testFlow2.json" tension="60">
<div class="demooptions">
<button data-trigger="onAutoplace3H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace3V">Auto-place Vertical</button>
<div class-"cols-2"=""><label>tension</label><input data-id="organi" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
</body>
</html>
-55
View File
@@ -1,55 +0,0 @@
{
"nodesFile": "/app/assets/html/bzGraflow/nodesTest1.html",
"flow": {
"nodes":[
{ "nodeType": "inc",
"id": "aze",
"coords": { "x": 220, "y": 120}
},
{ "nodeType": "inc",
"subflow": "/app/assets/json/bzGraflow/testSubFlow1.json",
"portLinks": [
{ "parentPort": ["in1"], "subflowPort": ["inp1"] },
{ "parentPort": ["out1"], "subflowPort": ["out1"] }
],
"id": "aze2",
"coords": { "x": 220, "y": 10}
},
{ "nodeType": "factor",
"id": "qsd",
"coords": { "x": 470, "y": 170}
},
{ "nodeType": "factor",
"id": "qsd2",
"coords": { "x": 470, "y": 50}
},
{ "nodeType": "wadder",
"id": "wcx",
"coords": { "x": 720, "y": 50}
},
{ "nodeType": "multiplier",
"id": "ert",
"coords": { "x": 550, "y": 350}
},
{ "nodeType": "input",
"id": "0000",
"coords": { "x": 20, "y": 350}
},
{ "nodeType": "console",
"id": "9999",
"coords": { "x": 800, "y": 350}
}
],
"links": [
{ "from": ["0000", "out1"], "to": ["aze", "inp1"] },
{ "from": ["aze2", "out1"], "to": ["qsd2", "inp1"] },
{ "from": ["aze", "out1"], "to": ["qsd", "inp1"] },
{ "from": ["qsd2", "out1"], "to": ["ert", "inp2"] },
{ "from": ["0000", "out1"], "to": ["aze2", "inp1"] },
{ "from": ["qsd2", "out1"], "to": ["wcx", "inp2"] },
{ "from": ["wcx", "out1"], "to": ["ert", "inp1"] },
{ "from": ["qsd", "out1"], "to": ["wcx", "inp1"] },
{ "from": ["ert", "out1"], "to": ["9999", "inp1"] }
]
}
}
-46
View File
@@ -1,46 +0,0 @@
{
"nodesFile": "/app/assets/html/bzGraflow/nodesTest2.html",
"flow": {
"nodes":[
{ "nodeType": "start",
"id": "aze",
"coords": { "x": 220, "y": 20},
"markup": { "text": "Start" }
},
{ "nodeType": "process",
"id": "aze2",
"coords": { "x": 220, "y": 120},
"markup": { "text": "x = alph - 1" }
},
{ "nodeType": "condition",
"id": "qsd",
"coords": { "x": 250, "y": 270},
"markup": { "text": "x > 0" }
},
{ "nodeType": "preparation",
"id": "qsd2",
"coords": { "x": 250, "y": 470},
"markup": { "text": "prepare SQL" }
},
{ "nodeType": "database",
"id": "wcx",
"coords": { "x": 500, "y": 450},
"markup": { "text": "MySQL<br>Store" }
},
{ "nodeType": "end",
"id": "ert",
"coords": { "x": 250, "y": 650},
"markup": { "text": "End" }
}
],
"links": [
{ "from": ["aze", "out1"], "to": ["aze2", "inout1"], "endArrow":true },
{ "from": ["aze2", "inout2"], "to": ["qsd", "inp1"], "endArrow":true },
{ "from": ["qsd", "out1"], "to": ["aze2", "inout3"], "endArrow":true },
{ "from": ["qsd", "out2"], "to": ["qsd2", "inp1"], "endArrow":true },
{ "from": ["qsd2", "inout2"], "to": ["wcx", "inout3"], "startArrow":true , "endArrow":true },
{ "from": ["qsd2", "out1"], "to": ["ert", "inp1"], "endArrow":true },
{ "from": ["qsd2", "inout1"], "to": ["qsd2", "inout1"], "endArrow":true }
]
}
}
@@ -1,59 +0,0 @@
{
"nodesFile": "/app/assets/html/bzGraflow/nodesEIC.html",
"flow": {
"nodes":[
{ "nodeType": "eicBasic",
"id": "aze",
"ncoords": { "x": 50, "y": 120},
"markup": {
"title": "Build attendees list",
"subtitle": "Build an attendees list to email"
},
"data": { "a": "a1", "b":"b1"}
},
{ "nodeType": "eicBasic",
"id": "aze2",
"ncoords": { "x": 100, "y": 220},
"markup": {
"title": "Select message",
"subtitle": "Select an email template"
},
"data": { "a": "a2", "b":"b2"}
},
{ "nodeType": "eicBasic",
"id": "aze3",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "Data mapping",
"subtitle": "Associate content variables with attendees data"
},
"data": { "a": "a3", "b":"b3"}
},
{ "nodeType": "eicBasic",
"id": "aze4",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "Schedule mailing",
"subtitle": "Choose time to send the mail"
},
"data": { "a": "a3", "b":"b3"}
},
{ "nodeType": "eicBasic",
"id": "aze5",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "Stats",
"subtitle": "Access mailing statistics"
},
"data": { "a": "a3", "b":"b3"}
}
],
"links": [
{ "from": ["aze2", "out1"], "to": ["aze", "in1"] },
{ "from": ["aze2", "out2"], "to": ["aze3", "in1"] },
{ "from": ["aze", "out1"], "to": ["aze4", "in1"] },
{ "from": ["aze3", "out1"], "to": ["aze4", "in2"] },
{ "from": ["aze4", "out1"], "to": ["aze5", "in1"] }
]
}
}
+20
View File
@@ -1,4 +1,24 @@
[
{
"label": "Simulations Management",
"icon": "icon-lab2",
"collapsed": true,
"access": ["*"],
"items": [
{
"label": "Create a simulation",
"icon": "icon-new",
"route": "/sims/create",
"access": ["*"]
},
{
"label": "Play / Pause a simulation",
"icon": "icon-file-play",
"route": "/sims/manage",
"access": ["*"]
}
]
},
{
"label": "Live Arena",
"icon": "icon-bolt",
+11
View File
@@ -0,0 +1,11 @@
{
"maestro": {
"actionsChannel": "system:requests:maestro",
"lifecycleChannel": "system:maestro:lifecycle:[UID]"
},
"observer": {
"actionsChannel": "system:requests:observer",
"subscribeFrequencyMs": 1000,
"cameraDebounceMs": 600
}
}
+14
View File
@@ -37,6 +37,20 @@
"uri": "/api/keyframes/{kfId}/agents",
"method": "PUT"
}
},
"/sims": {
"list": {
"uri": "/api/sims",
"method": "POST"
},
"get": {
"uri": "/api/sims/{simulationUuid}",
"method": "GET"
},
"create": {
"uri": "/api/sims",
"method": "PUT"
}
}
}
}
@@ -1,6 +1,6 @@
[
{
"chan": "system:gps:agents",
"chan": "system:observer:subscribed[UID]:agents",
"events": [
{
"eventName": "move",
+63 -33
View File
@@ -27,6 +27,7 @@
--app-menu-collapsed-width: 50px;
--app-menu-expanded-width: 160px;
--app-menu-hover-max-width: 400px;
--app-menu-width: var(--app-menu-expanded-width);
@@ -80,6 +81,53 @@ menu[eicmenu] [menuitem] > a > i, menu[eicmenu] [menuitem] > .nolink > i{
menu[eicmenu] [menuitem] > a > button, menu[eicmenu] [menuitem] > .nolink button {
background: var(--app-color-primary);
}
/* Submenu vertical expand/collapse (overrides EICUI height:0 which breaks transitions) */
menu[eicmenu].app-menu > [menuitem] > ul {
max-height: 30rem;
height: auto !important;
overflow: hidden;
transition: max-height 0.6s ease-in-out, opacity 0.3s ease-in-out, padding 0.3s ease-in-out;
}
menu[eicmenu].app-menu > [menuitem] > ul[collapsed] {
max-height: 0;
height: auto !important;
padding-top: 0;
padding-bottom: 0;
}
/* Collapsed app menu: show main section icons, hide sub-entries */
menu[eicmenu].app-menu[collapsed] {
width: max-content;
transition: max-width 0.3s ease-in-out;
}
menu[eicmenu].app-menu[collapsed]:not(:hover) {
max-width: var(--app-menu-collapsed-width);
overflow-x: hidden;
}
menu[eicmenu].app-menu[collapsed]:hover {
max-width: var(--app-menu-hover-max-width);
overflow-x: hidden;
}
menu[eicmenu].app-menu[collapsed]:not(:hover) > [menuitem] > .nolink {
display: flex;
justify-content: center;
padding: var(--eicui-base-spacing-xs);
}
menu[eicmenu].app-menu[collapsed]:not(:hover) > [menuitem] > .nolink > label,
menu[eicmenu].app-menu[collapsed]:not(:hover) > [menuitem] > .nolink > button {
display: none;
}
menu[eicmenu].app-menu[collapsed]:not(:hover) > [menuitem] > .nolink > i {
font-size: larger;
margin: 0;
}
menu[eicmenu].app-menu[collapsed]:not(:hover) > [menuitem] > ul {
max-height: 0 !important;
opacity: 0;
padding: 0;
}
[eicapp] .app-workspace {
display: grid;
/*
@@ -299,33 +347,6 @@ article[eiccard][media] > header {
font-size: 1.6rem;
}
[device="tablet"] section .cols-2:not(.noflex), [device="mobile"] section .cols-2:not(.noflex) {
display: flex;
flex-direction: column;
grid-template-columns: none;
align-items: initial;
}
[device="tablet"] .cols-3, [device="mobile"] .cols-3,
[device="tablet"] .cols-4, [device="mobile"] .cols-4,
[device="tablet"] .cols-5, [device="mobile"] .cols-5,
[device="mobile"] .cols-6 {
display: flex;
flex-direction: column;
grid-template-columns: none;
}
[device="tablet"] .cols-6 {
grid-template-columns: 1fr 1fr 1fr;
}
[device="tablet"] .cols-8 {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
[device="mobile"] .cols-8 {
grid-template-columns: 1fr 1fr;
}
div.window > section:first-of-type > article[eiccard]:first-of-type{
height:100%;
border: 2px solid var(--app-color-primary);
@@ -366,7 +387,7 @@ input{
padding-left: 1em;
box-sizing: border-box;
height: 2em;
background-color: #6B5;
background-color: #CFC;
border: none;
}
@@ -376,20 +397,29 @@ div.window > section button[eicbutton][rounded] {
color: #222;
}
[eicdatagrid] .dataset .row:hover {
background-color: #483;
}
/* Customizations to buildoz*/
bz-select > button{
background: linear-gradient( to bottom, #251, #372 15%, #483 50%, #372 85%, #251 ) !important;
color:#EEE;
}
bz-select > button::after{ color:#EEE; }
bz-select option{
bz-select option,
div.options-container.portaled option{
background-color: #676;
color: #EEE;
}
bz-select option i{ margin-right:0.3em; }
bz-select option i.icon-atom1{ color:#FF4; }
bz-select option i.icon-bug{ color:#4DF; }
bz-select > div.options-container.open { max-height: 20em; }
bz-select option i,
div.options-container.portaled option i{ margin-right:0.3em; }
bz-select option i.icon-atom1,
div.options-container.portaled option i.icon-atom1{ color:#FF4; }
bz-select option i.icon-bug,
div.options-container.portaled option i.icon-bug{ color:#4DF; }
bz-select > div.options-container.open,
div.options-container.portaled.open { max-height: 20em; }
bz-toggler div.toggle-switch span.toggle-bar { background-color: #473; }
bz-toggler div.toggle-switch span.toggle-thumb { background-color:#9D8; }
Binary file not shown.
File diff suppressed because it is too large. Load diff

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+190
View File
@@ -0,0 +1,190 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="glyphs" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="play" d="M192 832l640-384-640-384z" />
<glyph unicode="&#xe901;" glyph-name="bolt" d="M665.6 563.2v409.6l-512-614.4h204.8v-409.6l512 614.4h-204.8z" />
<glyph unicode="&#xe902;" glyph-name="check" d="M0 409.6l102.4 102.4 256-256 563.2 563.2 102.4-102.4-665.6-665.6z" />
<glyph unicode="&#xe903;" glyph-name="download" d="M665.6 563.2v307.2h-307.2v-307.2h-256l409.6-409.6 409.6 409.6h-256zM0 51.2h1024v-102.4h-1024v102.4z" />
<glyph unicode="&#xe904;" glyph-name="servers" d="M0 870.4c0 56.32 46.080 102.4 102.4 102.4h819.2c56.554 0 102.4-45.846 102.4-102.4v0-102.4c0-56.554-45.846-102.4-102.4-102.4v0h-819.2c-56.554 0-102.4 45.846-102.4 102.4v0 102.4zM0 512c0 56.32 46.080 102.4 102.4 102.4h819.2c56.554 0 102.4-45.846 102.4-102.4v0-102.4c0-56.554-45.846-102.4-102.4-102.4v0h-819.2c-56.554 0-102.4 45.846-102.4 102.4v0 102.4zM0 153.6c0 56.32 46.080 102.4 102.4 102.4h819.2c56.554 0 102.4-45.846 102.4-102.4v0-102.4c0-56.554-45.846-102.4-102.4-102.4v0h-819.2c-56.554 0-102.4 45.846-102.4 102.4v0 102.4zM614.4 870.4v-102.4h102.4v102.4h-102.4zM819.2 870.4v-102.4h102.4v102.4h-102.4zM614.4 512v-102.4h102.4v102.4h-102.4zM819.2 512v-102.4h102.4v102.4h-102.4zM614.4 153.6v-102.4h102.4v102.4h-102.4zM819.2 153.6v-102.4h102.4v102.4h-102.4z" />
<glyph unicode="&#xe905;" glyph-name="backward1" d="M972.8 716.8v-512l-460.8 256 460.8 256zM512 716.8v-512l-460.8 256 460.8 256z" />
<glyph unicode="&#xe906;" glyph-name="deny" d="M870.4 153.6c0-113.108-91.692-204.8-204.8-204.8v0h-307.2c0 0 0 0-0.001 0-113.108 0-204.8 91.692-204.8 204.8 0 0.18 0 0.36 0.001 0.54v-0.028 613.888c0 28.277 22.923 51.2 51.2 51.2v0c28.277 0 51.2-22.923 51.2-51.2v0-307.2h51.2v409.6c0 28.277 22.923 51.2 51.2 51.2v0c28.277 0 51.2-22.923 51.2-51.2v0-409.6h51.2v460.8c0 28.277 22.923 51.2 51.2 51.2s51.2-22.923 51.2-51.2v0-460.8h51.2v409.6c0 28.277 22.923 51.2 51.2 51.2v0c28.277 0 51.2-22.923 51.2-51.2v0-665.6h51.2v307.2c0 28.277 22.923 51.2 51.2 51.2v0h51.2v-409.6z" />
<glyph unicode="&#xe907;" glyph-name="cancel" d="M512 533.197l-362.035 362.035-72.397-72.397 362.035-362.035-362.035-362.035 72.397-72.397 362.035 362.035 362.035-362.035 72.397 72.397-362.035 362.035 362.035 362.035-72.397 72.397-362.035-362.035z" />
<glyph unicode="&#xe908;" glyph-name="close" d="M150.016 98.816c-96.436 93.233-156.308 223.762-156.308 368.276 0 282.77 229.23 512 512 512 144.514 0 275.043-59.872 368.137-156.164l0.138-0.144c88.925-91.979 143.724-217.436 143.724-355.692 0-282.77-229.23-512-512-512-138.256 0-263.713 54.799-355.836 143.863l0.144-0.138zM583.68 460.8l144.896 144.896-72.192 72.192-144.384-144.896-144.896 144.896-72.192-72.192 144.896-144.896-144.896-144.896 72.192-72.192 144.896 144.896 144.896-144.896 72.192 72.192-144.896 144.896z" />
<glyph unicode="&#xe909;" glyph-name="envelope" d="M921.6 870.4c56.554 0 102.4-45.846 102.4-102.4v0-614.4c0-56.554-45.846-102.4-102.4-102.4v0h-819.2c-56.554 0-102.4 45.846-102.4 102.4v0 614.4c0 56.32 46.080 102.4 102.4 102.4h819.2zM697.856 404.48l326.144-250.88v102.4l-262.144 199.68 262.144 209.92v102.4l-512-409.6-512 409.6v-102.4l262.144-209.92-262.144-199.68v-102.4l326.144 250.88 185.856-148.48 185.856 148.48z" />
<glyph unicode="&#xe90a;" glyph-name="company" d="M537.6-51.2h-537.6v665.6l256-170.496v170.496l256-170.496v170.496l256-170.496v528.896h256v-1024h-486.4z" />
<glyph unicode="&#xe90b;" glyph-name="thumbs-down" d="M563.2-51.2c-56.554 0-102.4 45.846-102.4 102.4v0 307.2h-358.4c-56.554 0-102.4 45.846-102.4 102.4v0 102.4l117.76 313.344c23.921 54.755 76.246 93.003 137.847 96.24l0.393 0.016h409.6c56.554 0 102.4-45.846 102.4-102.4v0-409.6l-153.6-358.4v-153.6h-51.2zM870.4 460.8v512h153.6v-512h-153.6z" />
<glyph unicode="&#xe90c;" glyph-name="thumbs-up" d="M563.2 972.8h51.2v-153.6l153.6-358.4v-409.6c0-56.554-45.846-102.4-102.4-102.4v0h-409.6c-56.32 0-118.272 43.008-138.24 96.256l-117.76 313.344v102.4c0 56.554 45.846 102.4 102.4 102.4v0h358.4v307.2c0 56.554 45.846 102.4 102.4 102.4v0zM870.4 460.8h153.6v-512h-153.6v512z" />
<glyph unicode="&#xe90d;" glyph-name="image" d="M959.884 832c0.040-0.034 0.082-0.076 0.116-0.116v-767.77c-0.034-0.040-0.076-0.082-0.116-0.116h-895.77c-0.040 0.034-0.082 0.076-0.114 0.116v767.772c0.034 0.040 0.076 0.082 0.114 0.114h895.77zM960 896h-896c-35.2 0-64-28.8-64-64v-768c0-35.2 28.8-64 64-64h896c35.2 0 64 28.8 64 64v768c0 35.2-28.8 64-64 64v0zM832 672c0-53.020-42.98-96-96-96s-96 42.98-96 96 42.98 96 96 96 96-42.98 96-96zM896 128h-768v128l224 384 256-320h64l224 192z" />
<glyph unicode="&#xe90e;" glyph-name="help" horiz-adv-x="878" d="M512 164.571v109.714c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM658.286 548.571c0 104.571-109.714 182.857-208 182.857-93.143 0-162.857-40-212-121.714-5.143-8-2.857-18.286 4.571-24l75.429-57.143c2.857-2.286 6.857-3.429 10.857-3.429 5.143 0 10.857 2.286 14.286 6.857 26.857 34.286 38.286 44.571 49.143 52.571 9.714 6.857 28.571 13.714 49.143 13.714 36.571 0 70.286-23.429 70.286-48.571 0-29.714-15.429-44.571-50.286-60.571-40.571-18.286-96-65.714-96-121.143v-20.571c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v0c0 13.143 16.571 41.143 43.429 56.571 43.429 24.571 102.857 57.714 102.857 144.571zM877.714 438.857c0-242.286-196.571-438.857-438.857-438.857s-438.857 196.571-438.857 438.857 196.571 438.857 438.857 438.857 438.857-196.571 438.857-438.857z" />
<glyph unicode="&#xe90f;" glyph-name="hour-glass" d="M728.992 448c137.754 87.334 231.008 255.208 231.008 448 0 21.676-1.192 43.034-3.478 64h-889.042c-2.29-20.968-3.48-42.326-3.48-64 0-192.792 93.254-360.666 231.006-448-137.752-87.334-231.006-255.208-231.006-448 0-21.676 1.19-43.034 3.478-64h889.042c2.288 20.966 3.478 42.324 3.478 64 0.002 192.792-93.252 360.666-231.006 448zM160 0c0 186.912 80.162 345.414 224 397.708v100.586c-143.838 52.29-224 210.792-224 397.706v0h704c0-186.914-80.162-345.416-224-397.706v-100.586c143.838-52.294 224-210.796 224-397.708h-704zM619.626 290.406c-71.654 40.644-75.608 93.368-75.626 125.366v64.228c0 31.994 3.804 84.914 75.744 125.664 38.504 22.364 71.808 56.348 97.048 98.336h-409.582c25.266-42.032 58.612-76.042 97.166-98.406 71.654-40.644 75.606-93.366 75.626-125.366v-64.228c0-31.992-3.804-84.914-75.744-125.664-72.622-42.18-126.738-125.684-143.090-226.336h501.67c-16.364 100.708-70.53 184.248-143.212 226.406z" />
<glyph unicode="&#xe910;" glyph-name="pen" d="M1018.17 668.11l-286.058 286.058c-9.334 9.334-21.644 7.234-27.356-4.666l-38.354-79.904 267.198-267.198 79.904 38.354c11.9 5.712 14 18.022 4.666 27.356zM615.384 824.616l-263.384-21.95c-17.5-2.166-32.080-5.898-37.090-28.752-0.006-0.024-0.012-0.042-0.018-0.066-71.422-343.070-314.892-677.848-314.892-677.848l57.374-57.374 271.986 271.99c-5.996 12.53-9.36 26.564-9.36 41.384 0 53.020 42.98 96 96 96s96-42.98 96-96-42.98-96-96-96c-14.82 0-28.852 3.364-41.384 9.36l-271.988-271.986 57.372-57.374c0 0 334.778 243.47 677.848 314.892 0.024 0.006 0.042 0.012 0.066 0.018 22.854 5.010 26.586 19.59 28.752 37.090l21.95 263.384-273.232 273.232z" />
<glyph unicode="&#xe911;" glyph-name="sort-asc" horiz-adv-x="585" d="M585.143 548.571c0-20-16.571-36.571-36.571-36.571h-512c-20 0-36.571 16.571-36.571 36.571 0 9.714 4 18.857 10.857 25.714l256 256c6.857 6.857 16 10.857 25.714 10.857s18.857-4 25.714-10.857l256-256c6.857-6.857 10.857-16 10.857-25.714z" />
<glyph unicode="&#xe912;" glyph-name="sort-desc" horiz-adv-x="585" d="M585.143 329.143c0-9.714-4-18.857-10.857-25.714l-256-256c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-256 256c-6.857 6.857-10.857 16-10.857 25.714 0 20 16.571 36.571 36.571 36.571h512c20 0 36.571-16.571 36.571-36.571z" />
<glyph unicode="&#xe913;" glyph-name="unsorted" horiz-adv-x="585" d="M585.143 329.143c0-9.714-4-18.857-10.857-25.714l-256-256c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-256 256c-6.857 6.857-10.857 16-10.857 25.714 0 20 16.571 36.571 36.571 36.571h512c20 0 36.571-16.571 36.571-36.571zM585.143 548.571c0-20-16.571-36.571-36.571-36.571h-512c-20 0-36.571 16.571-36.571 36.571 0 9.714 4 18.857 10.857 25.714l256 256c6.857 6.857 16 10.857 25.714 10.857s18.857-4 25.714-10.857l256-256c6.857-6.857 10.857-16 10.857-25.714z" />
<glyph unicode="&#xe914;" glyph-name="market" d="M204.8 870.4h819.2l-153.6-460.8h-665.6c-28.277 0-51.2-22.923-51.2-51.2s22.923-51.2 51.2-51.2v0h665.6v-102.4h-665.6c-84.831 0-153.6 68.769-153.6 153.6s68.769 153.6 153.6 153.6v0h16.896l-68.096 204.8-51.2 153.6h-102.4v102.4h153.6c28.277 0 51.2-22.923 51.2-51.2v0-51.2zM256-51.2c-56.554 0-102.4 45.846-102.4 102.4s45.846 102.4 102.4 102.4v0c56.554 0 102.4-45.846 102.4-102.4s-45.846-102.4-102.4-102.4v0zM768-51.2c-56.554 0-102.4 45.846-102.4 102.4s45.846 102.4 102.4 102.4v0c56.554 0 102.4-45.846 102.4-102.4s-45.846-102.4-102.4-102.4v0z" />
<glyph unicode="&#xe915;" glyph-name="copy" d="M307.2 665.6v204.8c0 56.32 46.080 102.4 102.4 102.4h512c56.554 0 102.4-45.846 102.4-102.4v0-512c0-56.554-45.846-102.4-102.4-102.4v0h-204.8v-204.8c0-56.554-45.846-102.4-102.4-102.4v0h-512c-56.554 0-102.4 45.846-102.4 102.4v0 512c0 56.32 46.080 102.4 102.4 102.4h204.8zM409.6 665.6h204.8c56.554 0 102.4-45.846 102.4-102.4v0-204.8h204.8v512h-512v-204.8zM102.4 563.2v-512h512v512h-512z" />
<glyph unicode="&#xe916;" glyph-name="pause1" d="M256 768h153.6v-614.4h-153.6v614.4zM614.4 768h153.6v-614.4h-153.6v614.4z" />
<glyph unicode="&#xe917;" glyph-name="review" d="M426 212.667l342 342-60 60-282-280-110 110-60-60zM512 810.667q-18 0-30-12t-12-30 12-31 30-13 30 13 12 31-12 30-30 12zM810 810.667q34 0 60-26t26-60v-596q0-34-26-60t-60-26h-596q-34 0-60 26t-26 60v596q0 34 26 60t60 26h178q14 38 46 62t74 24 74-24 46-62h178z" />
<glyph unicode="&#xe918;" glyph-name="correction" d="M682 298.667v170h-170v128l-214-212 214-214v128h170zM512 810.667q-18 0-30-12t-12-30 12-31 30-13 30 13 12 31-12 30-30 12zM810 810.667q34 0 60-26t26-60v-596q0-34-26-60t-60-26h-596q-34 0-60 26t-26 60v596q0 34 26 60t60 26h178q14 38 46 62t74 24 74-24 46-62h178z" />
<glyph unicode="&#xe919;" glyph-name="mediation" d="M512 724.667q18 0 30 13t12 31-12 30-30 12-30-12-12-30 12-31 30-13zM554 340.667v256h-84v-256h84zM554 170.667v86h-84v-86h84zM810 810.667q34 0 60-26t26-60v-596q0-34-26-60t-60-26h-596q-34 0-60 26t-26 60v596q0 34 26 60t60 26h178q14 38 46 62t74 24 74-24 46-62h178z" />
<glyph unicode="&#xe91a;" glyph-name="coaching" d="M1024 530.744c0 200.926-58.792 363.938-131.482 365.226 0.292 0.006 0.578 0.030 0.872 0.030h-82.942c0 0-194.8-146.336-475.23-203.754-8.56-45.292-14.030-99.274-14.030-161.502s5.466-116.208 14.030-161.5c280.428-57.418 475.23-203.756 475.23-203.756h82.942c-0.292 0-0.578 0.024-0.872 0.032 72.696 1.288 131.482 164.298 131.482 365.224zM864.824 220.748c-9.382 0-19.532 9.742-24.746 15.548-12.63 14.064-24.792 35.96-35.188 63.328-23.256 61.232-36.066 143.31-36.066 231.124 0 87.81 12.81 169.89 36.066 231.122 10.394 27.368 22.562 49.266 35.188 63.328 5.214 5.812 15.364 15.552 24.746 15.552 9.38 0 19.536-9.744 24.744-15.552 12.634-14.064 24.796-35.958 35.188-63.328 23.258-61.23 36.068-143.312 36.068-231.122 0-87.804-12.81-169.888-36.068-231.124-10.39-27.368-22.562-49.264-35.188-63.328-5.208-5.806-15.36-15.548-24.744-15.548zM251.812 530.744c0 51.95 3.81 102.43 11.052 149.094-47.372-6.554-88.942-10.324-140.34-10.324-67.058 0-67.058 0-67.058 0l-55.466-94.686v-88.17l55.46-94.686c0 0 0 0 67.060 0 51.398 0 92.968-3.774 140.34-10.324-7.236 46.664-11.048 97.146-11.048 149.096zM368.15 317.828l-127.998 24.51 81.842-321.544c4.236-16.634 20.744-25.038 36.686-18.654l118.556 47.452c15.944 6.376 22.328 23.964 14.196 39.084l-123.282 229.152zM864.824 411.27c-3.618 0-7.528 3.754-9.538 5.992-4.87 5.42-9.556 13.86-13.562 24.408-8.962 23.6-13.9 55.234-13.9 89.078s4.938 65.478 13.9 89.078c4.006 10.548 8.696 18.988 13.562 24.408 2.010 2.24 5.92 5.994 9.538 5.994 3.616 0 7.53-3.756 9.538-5.994 4.87-5.42 9.556-13.858 13.56-24.408 8.964-23.598 13.902-55.234 13.902-89.078 0-33.842-4.938-65.478-13.902-89.078-4.004-10.548-8.696-18.988-13.56-24.408-2.008-2.238-5.92-5.992-9.538-5.992z" />
<glyph unicode="&#xe91b;" glyph-name="writing" d="M726 554.667v86h-428v-86h428zM726 384.667v84h-428v-84h428zM598 212.667v86h-300v-86h300zM512 810.667q-18 0-30-12t-12-30 12-31 30-13 30 13 12 31-12 30-30 12zM810 810.667q34 0 60-26t26-60v-596q0-34-26-60t-60-26h-596q-34 0-60 26t-26 60v596q0 34 26 60t60 26h178q14 38 46 62t74 24 74-24 46-62h178z" />
<glyph unicode="&#xe91c;" glyph-name="filter" d="M614.4 358.4l409.6 409.6v204.8h-1024v-204.8l409.6-409.6v-409.6l204.8 204.8v204.8z" />
<glyph unicode="&#xe91d;" glyph-name="home" d="M409.6-51.2h-256v512h-153.6l512 512 512-512h-153.6v-512h-256v307.2h-204.8v-307.2z" />
<glyph unicode="&#xe91e;" glyph-name="trash" d="M307.2 870.4l102.4 102.4h204.8l102.4-102.4h204.8v-102.4h-819.2v102.4h204.8zM153.6 665.6h716.8l-51.2-716.8h-614.4l-51.2 716.8zM409.6 563.2v-512h51.2v512h-51.2zM563.2 563.2v-512h51.2v512h-51.2z" />
<glyph unicode="&#xe91f;" glyph-name="check-rounded" d="M150.016 98.816c-96.436 93.233-156.308 223.762-156.308 368.276 0 282.77 229.23 512 512 512 144.514 0 275.043-59.872 368.137-156.164l0.138-0.144c88.925-91.979 143.724-217.436 143.724-355.692 0-282.77-229.23-512-512-512-138.256 0-263.713 54.799-355.836 143.863l0.144-0.138zM801.792 171.008c74.164 74.164 120.036 176.621 120.036 289.792 0 226.342-183.486 409.828-409.828 409.828-113.171 0-215.628-45.872-289.792-120.036v0c-74.164-74.164-120.036-176.621-120.036-289.792 0-226.342 183.486-409.828 409.828-409.828 113.171 0 215.628 45.872 289.792 120.036v0zM343.040 497.152l117.76-118.272 220.16 220.16 71.68-72.704-291.84-290.816-189.44 189.44 71.68 72.704z" />
<glyph unicode="&#xe920;" glyph-name="menu" d="M0 819.2h1024v-102.4h-1024v102.4zM0 512h1024v-102.4h-1024v102.4zM0 204.8h1024v-102.4h-1024v102.4z" />
<glyph unicode="&#xe921;" glyph-name="reply, back" d="M768 102.4v153.088c0 0.152 0.001 0.332 0.001 0.512 0 113.108-91.692 204.8-204.8 204.8 0 0-0.001 0-0.001 0h-153.6v-256l-307.2 307.2 307.2 307.2v-256h153.6c169.662 0 307.2-137.538 307.2-307.2v0-153.6h-102.4z" />
<glyph unicode="&#xe922;" glyph-name="link-ext" d="M204.8 460.8c0 56.32 46.080 102.4 102.4 102.4h409.6c56.32 0 102.4-46.080 102.4-102.4v-409.6c0-56.32-46.080-102.4-102.4-102.4h-409.6c-56.32 0-102.4 46.080-102.4 102.4v409.6zM307.2 460.8v-409.6h409.6v409.6h-102.4v102.4h-204.8v-102.4h-102.4zM460.8 776.704v-623.104h102.4v623.104l157.184-157.184 72.704 72.192-281.088 281.088-281.6-281.6 72.704-71.68 157.696 156.672z" />
<glyph unicode="&#xe923;" glyph-name="more" d="M512 358.4c-56.554 0-102.4 45.846-102.4 102.4s45.846 102.4 102.4 102.4v0c56.554 0 102.4-45.846 102.4-102.4s-45.846-102.4-102.4-102.4v0zM512 665.6c-56.554 0-102.4 45.846-102.4 102.4s45.846 102.4 102.4 102.4v0c56.554 0 102.4-45.846 102.4-102.4s-45.846-102.4-102.4-102.4v0zM512 51.2c-56.554 0-102.4 45.846-102.4 102.4s45.846 102.4 102.4 102.4v0c56.554 0 102.4-45.846 102.4-102.4s-45.846-102.4-102.4-102.4v0z" />
<glyph unicode="&#xe924;" glyph-name="new" d="M917.806 730.924c-22.212 30.292-53.174 65.7-87.178 99.704s-69.412 64.964-99.704 87.178c-51.574 37.82-76.592 42.194-90.924 42.194h-496c-44.112 0-80-35.888-80-80v-864c0-44.112 35.888-80 80-80h736c44.112 0 80 35.888 80 80v624c0 14.332-4.372 39.35-42.194 90.924zM785.374 785.374c30.7-30.7 54.8-58.398 72.58-81.374h-153.954v153.946c22.984-17.78 50.678-41.878 81.374-72.572zM896 16c0-8.672-7.328-16-16-16h-736c-8.672 0-16 7.328-16 16v864c0 8.672 7.328 16 16 16 0 0 495.956 0.002 496 0v-224c0-17.672 14.326-32 32-32h224v-624z" />
<glyph unicode="&#xe925;" glyph-name="locked" d="M204.8 563.2v102.4c0 169.662 137.538 307.2 307.2 307.2s307.2-137.538 307.2-307.2v0-102.4h51.2c56.554 0 102.4-45.846 102.4-102.4v0-409.6c0-56.554-45.846-102.4-102.4-102.4v0h-716.8c-56.554 0-102.4 45.846-102.4 102.4v0 409.6c0 56.32 46.080 102.4 102.4 102.4h51.2zM460.8 218.624v-116.224h102.4v116.224c30.824 18.035 51.2 50.978 51.2 88.681 0 56.554-45.846 102.4-102.4 102.4s-102.4-45.846-102.4-102.4c0-37.703 20.376-70.646 50.717-88.419l0.483-0.262zM358.4 665.6v-102.4h307.2v102.4c0 84.831-68.769 153.6-153.6 153.6s-153.6-68.769-153.6-153.6v0z" />
<glyph unicode="&#xe926;" glyph-name="unlocked" d="M204.8 563.2v102.4c0 169.662 137.538 307.2 307.2 307.2s307.2-137.538 307.2-307.2v0h-153.6v-102.4h204.8c56.554 0 102.4-45.846 102.4-102.4v0-409.6c0-56.554-45.846-102.4-102.4-102.4v0h-716.8c-56.554 0-102.4 45.846-102.4 102.4v0 409.6c0 56.32 46.080 102.4 102.4 102.4h51.2zM460.8 218.624v-116.224h102.4v116.224c30.824 18.035 51.2 50.978 51.2 88.681 0 56.554-45.846 102.4-102.4 102.4s-102.4-45.846-102.4-102.4c0-37.703 20.376-70.646 50.717-88.419l0.483-0.262zM358.4 665.6v-102.4h307.2v102.4c0 84.831-68.769 153.6-153.6 153.6s-153.6-68.769-153.6-153.6v0z" />
<glyph unicode="&#xe927;" glyph-name="health" d="M870.4 446.976v270.336c0 28.277-22.923 51.2-51.2 51.2s-51.2-22.923-51.2-51.2v0-512.512c0-141.385-114.615-256-256-256s-256 114.615-256 256v0 55.296c-146.222 25.392-256 151.328-256 302.903 0 0.071 0 0.141 0 0.212v-0.011 307.2c0 56.32 46.080 102.4 102.4 102.4h51.2c28.277 0 51.2-22.923 51.2-51.2v0c0-28.277-22.923-51.2-51.2-51.2v0h-51.2v-307.2c0-113.108 91.692-204.8 204.8-204.8s204.8 91.692 204.8 204.8v0 307.2h-51.2c-28.277 0-51.2 22.923-51.2 51.2v0c0 28.277 22.923 51.2 51.2 51.2v0h51.2c56.554 0 102.4-45.846 102.4-102.4v0-307.2c0-0.060 0-0.13 0-0.201 0-151.576-109.778-277.512-254.165-302.639l-1.835-0.264v-55.296c0-84.831 68.769-153.6 153.6-153.6s153.6 68.769 153.6 153.6v0 512c0 84.831 68.769 153.6 153.6 153.6s153.6-68.769 153.6-153.6v0-269.824c30.824-18.035 51.2-50.978 51.2-88.681 0-56.554-45.846-102.4-102.4-102.4s-102.4 45.846-102.4 102.4c0 37.703 20.376 70.646 50.717 88.419l0.483 0.262z" />
<glyph unicode="&#xe928;" glyph-name="big-bullet" d="M512 819.2c-197.939 0-358.4-160.41-358.4-358.4 0-197.888 160.461-358.4 358.4-358.4s358.4 160.512 358.4 358.4c0 197.99-160.461 358.4-358.4 358.4z" />
<glyph unicode="&#xe929;" glyph-name="share, workflow" d="M260.096 350.208c-27.575-26.972-65.35-43.615-107.012-43.615-84.548 0-153.088 68.54-153.088 153.088 0 0.393 0.001 0.787 0.004 1.179v-0.060c0.054 84.79 68.802 153.505 153.6 153.505 41.373 0 78.926-16.358 106.544-42.959l-0.048 0.046 457.728 228.864c-0.768 5.77-1.206 12.441-1.206 19.214 0 84.831 68.769 153.6 153.6 153.6s153.6-68.769 153.6-153.6c0-84.831-68.769-153.6-153.6-153.6-41.285 0-78.765 16.288-106.366 42.788l0.052-0.050-457.728-228.864c0.739-5.688 1.161-12.267 1.161-18.944s-0.422-13.256-1.24-19.711l0.079 0.767 457.728-228.864c27.575 26.972 65.35 43.615 107.012 43.615 84.548 0 153.088-68.54 153.088-153.088 0-0.393-0.001-0.787-0.004-1.179v0.060c-0.727-84.277-69.215-152.316-153.595-152.316-84.831 0-153.6 68.769-153.6 153.6 0 6.223 0.37 12.36 1.089 18.389l-0.071-0.729-457.728 228.864z" />
<glyph unicode="&#xe92a;" glyph-name="dashboard" d="M512-51.2c-282.77 0-512 229.23-512 512s229.23 512 512 512v0c282.77 0 512-229.23 512-512s-229.23-512-512-512v0zM225.28 168.448c80.288 55.312 179.647 88.345 286.72 88.345s206.432-33.033 288.44-89.464l-1.72 1.119c75.859 74.399 122.88 177.965 122.88 292.513 0 226.216-183.384 409.6-409.6 409.6s-409.6-183.384-409.6-409.6c0-114.548 47.021-218.114 122.814-292.449l0.066-0.064zM538.624 559.616l154.624 154.624 72.192-72.192-154.624-154.624c2.245-7.999 3.535-17.186 3.535-26.673 0-56.554-45.846-102.4-102.4-102.4s-102.4 45.846-102.4 102.4c0 56.554 45.846 102.4 102.4 102.4 9.488 0 18.674-1.29 27.393-3.705l-0.72 0.17z" />
<glyph unicode="&#xe92b;" glyph-name="code" d="M292.813 217.6c-12.083 0-24.269 4.25-33.997 12.902l-259.072 230.298 273.459 243.098c21.094 18.688 53.453 16.896 72.243-4.25s16.896-53.504-4.25-72.294l-187.341-166.554 172.954-153.702c21.146-18.79 23.040-51.149 4.25-72.294-10.086-11.418-24.166-17.203-38.246-17.203zM750.797 217.702l273.459 243.098-259.072 230.298c-21.146 18.79-53.504 16.896-72.243-4.25-18.79-21.146-16.896-53.504 4.25-72.294l172.954-153.754-187.341-166.502c-21.146-18.79-23.040-51.149-4.25-72.294 10.086-11.418 24.166-17.203 38.246-17.203 12.083 0 24.269 4.25 33.997 12.902zM511.283 145.152l102.4 614.4c4.659 27.904-14.182 54.272-42.086 58.931-28.006 4.71-54.323-14.182-58.88-42.086l-102.4-614.4c-4.659-27.904 14.182-54.272 42.086-58.931 2.867-0.461 5.632-0.666 8.448-0.666 24.576 0 46.285 17.766 50.432 42.752z" />
<glyph unicode="&#xe92c;" glyph-name="stop" d="M128 832h768v-768h-768z" />
<glyph unicode="&#xe92d;" glyph-name="snapshot" d="M304 352c0-114.876 93.124-208 208-208s208 93.124 208 208-93.124 208-208 208-208-93.124-208-208zM960 704h-224c-16 64-32 128-96 128h-256c-64 0-80-64-96-128h-224c-35.2 0-64-28.8-64-64v-576c0-35.2 28.8-64 64-64h896c35.2 0 64 28.8 64 64v576c0 35.2-28.8 64-64 64zM512 68c-156.85 0-284 127.148-284 284 0 156.85 127.15 284 284 284 156.852 0 284-127.15 284-284 0-156.852-127.146-284-284-284zM960 512h-128v64h128v-64z" />
<glyph unicode="&#xe92e;" glyph-name="toc" horiz-adv-x="1152" d="M224 832h-192c-17.6 0-32-14.4-32-32v-704c0-17.6 14.4-32 32-32h192c17.6 0 32 14.4 32 32v704c0 17.6-14.4 32-32 32zM192 640h-128v64h128v-64zM544 832h-192c-17.6 0-32-14.4-32-32v-704c0-17.6 14.4-32 32-32h192c17.6 0 32 14.4 32 32v704c0 17.6-14.4 32-32 32zM512 640h-128v64h128v-64zM765.088 782.52l-171.464-86.394c-15.716-7.918-22.096-27.258-14.178-42.976l287.978-571.548c7.918-15.718 27.258-22.098 42.976-14.178l171.464 86.392c15.716 7.92 22.096 27.26 14.178 42.974l-287.978 571.55c-7.92 15.718-27.26 22.1-42.976 14.18z" />
<glyph unicode="&#xe92f;" glyph-name="folder" d="M448 832l128-128h448v-704h-1024v832z" />
<glyph unicode="&#xe930;" glyph-name="folder-open" d="M832 0l192 512h-832l-192-512zM128 576l-128-576v832h288l128-128h416v-128z" />
<glyph unicode="&#xe931;" glyph-name="folder-add" d="M576 704l-128 128h-448v-832h1024v704h-448zM704 256h-128v-128h-128v128h-128v128h128v128h128v-128h128v-128z" />
<glyph unicode="&#xe932;" glyph-name="folder-remove" d="M576 704l-128 128h-448v-832h1024v704h-448zM704 256h-384v128h384v-128z" />
<glyph unicode="&#xe933;" glyph-name="align-center" d="M51.2 921.6h921.6v-102.4h-921.6v102.4zM51.2 512h921.6v-102.4h-921.6v102.4zM51.2 102.4h921.6v-102.4h-921.6v102.4zM204.8 716.8h614.4v-102.4h-614.4v102.4zM204.8 307.2h614.4v-102.4h-614.4v102.4z" />
<glyph unicode="&#xe934;" glyph-name="align-left" d="M51.2 921.6h921.6v-102.4h-921.6v102.4zM51.2 512h921.6v-102.4h-921.6v102.4zM51.2 102.4h921.6v-102.4h-921.6v102.4zM51.2 716.8h614.4v-102.4h-614.4v102.4zM51.2 307.2h614.4v-102.4h-614.4v102.4z" />
<glyph unicode="&#xe935;" glyph-name="align-right" d="M51.2 921.6h921.6v-102.4h-921.6v102.4zM51.2 512h921.6v-102.4h-921.6v102.4zM51.2 102.4h921.6v-102.4h-921.6v102.4zM358.4 716.8h614.4v-102.4h-614.4v102.4zM358.4 307.2h614.4v-102.4h-614.4v102.4z" />
<glyph unicode="&#xe936;" glyph-name="format-bold" d="M153.6 0v921.6h409.6c0.079 0 0.171 0 0.264 0 141.385 0 256-114.615 256-256 0-61.578-21.741-118.077-57.966-162.242l0.358 0.45c66.369-52.013 108.62-132.176 108.62-222.208 0-155.523-126.077-281.6-281.6-281.6-0.027 0-0.054 0-0.080 0h-435.195zM537.6 409.6h-179.2v-256h179.2c70.692 0 128 57.308 128 128s-57.308 128-128 128v0zM358.4 768v-204.8h153.6c56.554 0 102.4 45.846 102.4 102.4s-45.846 102.4-102.4 102.4v0h-153.6z" />
<glyph unicode="&#xe937;" glyph-name="font-size-down" d="M819.2 512v-409.6h-102.4v409.6h-204.8v102.4h512v-102.4h-204.8zM409.6 716.8v-614.4h-102.4v614.4h-307.2v102.4h768v-102.4h-358.4z" />
<glyph unicode="&#xe938;" glyph-name="qrcode" d="M320 896h-256v-256h256v256zM384 960v0-384h-384v384h384zM128 832h128v-128h-128zM960 896h-256v-256h256v256zM1024 960v0-384h-384v384h384zM768 832h128v-128h-128zM320 256h-256v-256h256v256zM384 320v0-384h-384v384h384zM128 192h128v-128h-128zM448 960h64v-64h-64zM512 896h64v-64h-64zM448 832h64v-64h-64zM512 768h64v-64h-64zM448 704h64v-64h-64zM512 640h64v-64h-64zM448 576h64v-64h-64zM448 448h64v-64h-64zM512 384h64v-64h-64zM448 320h64v-64h-64zM512 256h64v-64h-64zM448 192h64v-64h-64zM512 128h64v-64h-64zM448 64h64v-64h-64zM512 0h64v-64h-64zM960 448h64v-64h-64zM64 448h64v-64h-64zM128 512h64v-64h-64zM0 512h64v-64h-64zM256 512h64v-64h-64zM320 448h64v-64h-64zM384 512h64v-64h-64zM576 448h64v-64h-64zM640 512h64v-64h-64zM704 448h64v-64h-64zM768 512h64v-64h-64zM832 448h64v-64h-64zM896 512h64v-64h-64zM960 320h64v-64h-64zM576 320h64v-64h-64zM640 384h64v-64h-64zM704 320h64v-64h-64zM832 320h64v-64h-64zM896 384h64v-64h-64zM960 192h64v-64h-64zM576 192h64v-64h-64zM640 256h64v-64h-64zM768 256h64v-64h-64zM832 192h64v-64h-64zM896 256h64v-64h-64zM960 64h64v-64h-64zM640 128h64v-64h-64zM704 64h64v-64h-64zM768 128h64v-64h-64zM832 64h64v-64h-64zM640 0h64v-64h-64zM768 0h64v-64h-64zM896 0h64v-64h-64z" />
<glyph unicode="&#xe939;" glyph-name="format-underline" d="M819.2 512c0-169.662-137.538-307.2-307.2-307.2s-307.2 137.538-307.2 307.2v0 409.6h153.6v-409.6c0-84.831 68.769-153.6 153.6-153.6s153.6 68.769 153.6 153.6v0 409.6h153.6v-409.6zM102.4 102.4h819.2v-102.4h-819.2v102.4z" />
<glyph unicode="&#xe93a;" glyph-name="cart" d="M384 32c0-53.019-42.981-96-96-96s-96 42.981-96 96c0 53.019 42.981 96 96 96s96-42.981 96-96zM1024 32c0-53.019-42.981-96-96-96s-96 42.981-96 96c0 53.019 42.981 96 96 96s96-42.981 96-96zM1024 448v384h-768c0 35.346-28.654 64-64 64h-192v-64h128l48.074-412.054c-29.294-23.458-48.074-59.5-48.074-99.946 0-70.696 57.308-128 128-128h768v64h-768c-35.346 0-64 28.654-64 64 0 0.218 0.014 0.436 0.016 0.656l831.984 127.344z" />
<glyph unicode="&#xe93b;" glyph-name="format-color" d="M460.8-51.2v87.040l0.512 12.288 310.272 310.272h150.528c56.32 0 101.888-45.568 101.888-102.4v-204.8c0-56.554-45.846-102.4-102.4-102.4v0h-460.8zM460.8 119.808v579.584l106.496 105.984c18.453 18.526 43.984 29.989 72.192 29.989s53.739-11.463 72.189-29.986l144.899-144.899c18.402-18.509 29.777-44.022 29.777-72.192s-11.375-53.683-29.782-72.197l0.005 0.005-395.776-396.288zM0 870.912c0 55.808 45.568 101.888 102.4 101.888h204.8c56.554 0 102.4-45.846 102.4-102.4v0-819.2c0-56.554-45.846-102.4-102.4-102.4v0h-204.8c-56.554 0-102.4 45.846-102.4 102.4v0 819.2zM204.8 102.4c28.277 0 51.2 22.923 51.2 51.2s-22.923 51.2-51.2 51.2v0c-28.277 0-51.2-22.923-51.2-51.2s22.923-51.2 51.2-51.2v0z" />
<glyph unicode="&#xe93c;" glyph-name="price-tag" d="M992.666 952.064c-5.683 16.077-23.245 24.576-39.373 18.995s-24.627-23.296-19.046-39.424c47.565-136.704-46.848-238.797-118.835-293.478l-29.082 41.677c-9.779 13.978-31.642 25.6-48.64 25.805l-163.226-0.717c-16.998 0.307-42.24-7.475-56.166-17.306l-480.973-337.254c-23.296-16.384-28.928-48.486-12.646-71.885l218.573-312.73c16.384-23.296 42.547-20.48 65.894-4.198l480.973 337.306c13.824 9.779 29.798 30.874 35.43 47.002l51.098 161.024c5.632 16.077 2.202 40.602-7.578 54.579l-17.715 25.395c96.666 74.086 197.018 205.005 141.312 365.21zM768.87 472.934c-37.222-26.112-88.627-16.998-114.688 20.275-26.163 37.376-17.050 88.781 20.224 114.995 29.594 20.736 67.994 19.251 95.642-0.87-13.926-8.397-23.501-13.312-25.293-14.080-15.411-7.322-22.016-25.805-14.746-41.216 5.325-11.213 16.435-17.818 28.006-17.818 4.403 0 8.909 1.024 13.158 3.021 9.933 4.71 20.582 10.291 31.693 16.896 4.966-30.413-7.117-62.31-33.997-81.203z" />
<glyph unicode="&#xe93d;" glyph-name="paint-format" d="M1024 384v384h-192v64c0 35.2-28.8 64-64 64h-704c-35.2 0-64-28.8-64-64v-192c0-35.2 28.8-64 64-64h704c35.2 0 64 28.8 64 64v64h128v-256h-576v-128h-32c-17.674 0-32-14.326-32-32v-320c0-17.674 14.326-32 32-32h128c17.674 0 32 14.326 32 32v320c0 17.674-14.326 32-32 32h-32v64h576zM768 768h-704v64h704v-64z" />
<glyph unicode="&#xe93e;" glyph-name="camera" d="M304 352c0-114.876 93.124-208 208-208s208 93.124 208 208-93.124 208-208 208-208-93.124-208-208zM960 704h-224c-16 64-32 128-96 128h-256c-64 0-80-64-96-128h-224c-35.2 0-64-28.8-64-64v-576c0-35.2 28.8-64 64-64h896c35.2 0 64 28.8 64 64v576c0 35.2-28.8 64-64 64zM512 68c-156.85 0-284 127.148-284 284 0 156.85 127.15 284 284 284 156.852 0 284-127.15 284-284 0-156.852-127.146-284-284-284zM960 512h-128v64h128v-64z" />
<glyph unicode="&#xe93f;" glyph-name="film" d="M0 832v-768h1024v768h-1024zM192 128h-128v128h128v-128zM192 384h-128v128h128v-128zM192 640h-128v128h128v-128zM768 128h-512v640h512v-640zM960 128h-128v128h128v-128zM960 384h-128v128h128v-128zM960 640h-128v128h128v-128zM384 640v-384l256 192z" />
<glyph unicode="&#xe940;" glyph-name="video-camera" d="M384 672c0 88.366 71.634 160 160 160s160-71.634 160-160c0-88.366-71.634-160-160-160s-160 71.634-160 160zM0 672c0 88.366 71.634 160 160 160s160-71.634 160-160c0-88.366-71.634-160-160-160s-160 71.634-160 160zM768 352v96c0 35.2-28.8 64-64 64h-640c-35.2 0-64-28.8-64-64v-320c0-35.2 28.8-64 64-64h640c35.2 0 64 28.8 64 64v96l256-160v448l-256-160zM640 192h-512v192h512v-192z" />
<glyph unicode="&#xe941;" glyph-name="stack" d="M1024 640l-512 256-512-256 512-256 512 256zM512 811.030l342.058-171.030-342.058-171.030-342.058 171.030 342.058 171.030zM921.444 499.278l102.556-51.278-512-256-512 256 102.556 51.278 409.444-204.722zM921.444 307.278l102.556-51.278-512-256-512 256 102.556 51.278 409.444-204.722z" />
<glyph unicode="&#xe942;" glyph-name="phone" d="M704 320c-64-64-64-128-128-128s-128 64-192 128-128 128-128 192 64 64 128 128-128 256-192 256-192-192-192-192c0-128 131.5-387.5 256-512s384-256 512-256c0 0 192 128 192 192s-192 256-256 192z" />
<glyph unicode="&#xe943;" glyph-name="backward-step" d="M204.8 716.8h153.6v-512h-153.6v512zM819.2 716.8v-512l-460.8 256 460.8 256z" />
<glyph unicode="&#xe944;" glyph-name="fast-forward" d="M51.2 716.8l460.8-256-460.8-256v512zM512 716.8l460.8-256-460.8-256v512z" />
<glyph unicode="&#xe945;" glyph-name="pause2" d="M256 768h153.6v-614.4h-153.6v614.4zM614.4 768h153.6v-614.4h-153.6v614.4z" />
<glyph unicode="&#xe946;" glyph-name="play1" d="M204.8 768l614.4-307.2-614.4-307.2z" />
<glyph unicode="&#xe947;" glyph-name="map, pin" d="M512 960c-176.732 0-320-143.268-320-320 0-320 320-704 320-704s320 384 320 704c0 176.732-143.27 320-320 320zM512 448c-106.040 0-192 85.96-192 192s85.96 192 192 192 192-85.96 192-192-85.96-192-192-192z" />
<glyph unicode="&#xe948;" glyph-name="target1" d="M918.528 409.6h-252.928v102.4h252.928c-24.013 185.779-169.548 331.315-353.274 355.111l-2.054 0.217v-252.928h-102.4v252.928c-185.779-24.013-331.315-169.548-355.111-353.274l-0.217-2.054h252.928v-102.4h-252.928c24.013-185.779 169.548-331.315 353.274-355.111l2.054-0.217v252.928h102.4v-252.928c185.779 24.013 331.315 169.548 355.111 353.274l0.217 2.054zM512-51.2c-282.77 0-512 229.23-512 512s229.23 512 512 512v0c282.77 0 512-229.23 512-512s-229.23-512-512-512v0z" />
<glyph unicode="&#xe949;" glyph-name="usb" d="M768 563.2v-102.4h-204.8v307.2h102.4l-153.6 204.8-153.6-204.8h102.4v-409.6h-204.8v116.224c30.824 18.035 51.2 50.978 51.2 88.681 0 56.554-45.846 102.4-102.4 102.4s-102.4-45.846-102.4-102.4c0-37.703 20.376-70.646 50.717-88.419l0.483-0.262v-116.224c0-56.554 45.846-102.4 102.4-102.4v0h204.8v-116.224c-30.824-18.035-51.2-50.978-51.2-88.681 0-56.554 45.846-102.4 102.4-102.4s102.4 45.846 102.4 102.4c0 37.703-20.376 70.646-50.717 88.419l-0.483 0.262v218.624h204.8c56.554 0 102.4 45.846 102.4 102.4v0 102.4h51.2v204.8h-204.8v-204.8h51.2z" />
<glyph unicode="&#xe94a;" glyph-name="video-camera1" d="M819.2 614.4l204.8 204.8v-716.8l-204.8 204.8v-153.6c0-56.554-45.846-102.4-102.4-102.4v0h-614.4c-56.554 0-102.4 45.846-102.4 102.4v0 614.4c0 56.32 46.080 102.4 102.4 102.4h614.4c56.554 0 102.4-45.846 102.4-102.4v0-153.6zM409.6 256c113.108 0 204.8 91.692 204.8 204.8s-91.692 204.8-204.8 204.8v0c-113.108 0-204.8-91.692-204.8-204.8s91.692-204.8 204.8-204.8v0zM409.6 358.4c-56.554 0-102.4 45.846-102.4 102.4s45.846 102.4 102.4 102.4v0c56.554 0 102.4-45.846 102.4-102.4s-45.846-102.4-102.4-102.4v0z" />
<glyph unicode="&#xe94b;" glyph-name="cabinet" d="M160 0v768l133.344 128h405.344l133.312-128v-768h-672zM800 256v480h-608v-704h608v224zM768 512h-544v192h544v-192zM576 640h-160v-32h160v32zM768 288h-544v192h544v-192zM576 416h-160v-32h160v32zM768 64h-544v192h544v-192zM576 192h-160v-32h160v32z" />
<glyph unicode="&#xe94c;" glyph-name="cabinet1" d="M160-32v800l133.344 128h405.344l133.312-128v-800h-672zM192 0h608v736h-608v-736zM224 352h544v-320h-544v320zM416 224v-32h160v96h-32v-64h-96v64h-32v-64zM224 704h544v-320h-544v320zM416 544h160v96h-32v-64h-96v64h-32v-96z" />
<glyph unicode="&#xe94d;" glyph-name="history" horiz-adv-x="1088" d="M640 896c247.424 0 448-200.576 448-448s-200.576-448-448-448v96c94.024 0 182.418 36.614 248.902 103.098s103.098 154.878 103.098 248.902c0 94.022-36.614 182.418-103.098 248.902s-154.878 103.098-248.902 103.098c-94.022 0-182.418-36.614-248.902-103.098-51.14-51.138-84.582-115.246-97.306-184.902h186.208l-224-256-224 256h164.57c31.060 217.102 217.738 384 443.43 384zM832 512v-128h-256v320h128v-192z" />
<glyph unicode="&#xe94e;" glyph-name="camera1" d="M896 736l-480.128-0.544 0.128 94.56-256 1.984v-96h-64c-35.328 0-64-28.672-64-64v-544c0-35.328 28.672-64 64-64h800c35.328 0 64 28.672 64 64v544c0 35.328-28.672 64-64 64zM224 768h128v-96h-128v96zM384 161.344c-123.712 0-224 100.288-224 224s100.288 224 224 224c123.68 0 224-100.288 224-224s-100.32-224-224-224zM816 527.328c-35.36 0-64 28.64-64 64 0 35.328 28.64 64 64 64 35.328 0 64-28.672 64-64s-28.672-64-64-64zM384 524c-79.52 0-144-64.48-144-144s64.48-144 144-144 144 64.48 144 144-64.48 144-144 144z" />
<glyph unicode="&#xe94f;" glyph-name="camera2" d="M864 414.496l-160 64.096v128.256l160 64.128c17.696 0 32-14.368 32-32.064v-192.384c0-17.696-14.304-32.032-32-32.032zM560 638.944c-79.52 0-144 64.608-144 144.288s64.48 144.288 144 144.288 144-64.608 144-144.288c0-79.712-64.48-144.288-144-144.288zM272 638.944c-79.52 0-144 64.608-144 144.288s64.48 144.288 144 144.288 144-64.608 144-144.288c0-79.712-64.48-144.288-144-144.288zM672 638.944v-288.576h-178.624c-1.664-26.624-13.312-49.568-30.624-62.56h18.048l127.648-287.872h-31.808l-42.56 96h-85.12v-159.936h-31.904v159.936h-86.464l-43.232-96h-31.84l129.664 287.872h12.064c-17.312 12.992-28.96 35.936-30.624 62.56h-206.624v288.576h512zM417.024 277.888c-1.312 0.32-2.528 0.992-3.808 1.44l-68.224-151.424h72.032v149.984zM448.928 280.192v-152.32h70.944l-68.032 153.44c-0.928-0.448-1.888-0.736-2.912-1.12z" />
<glyph unicode="&#xe950;" glyph-name="film1" d="M128 768v-704h704v704h-704zM256 128h-64v64h64v-64zM256 224h-64v64h64v-64zM256 320h-64v64h64v-64zM256 448h-64v64h64v-64zM256 544h-64v64h64v-64zM256 640h-64v64h64v-64zM640 128h-320v256h320v-256zM640 448h-320v256h320v-256zM768 128h-64v64h64v-64zM768 224h-64v64h64v-64zM768 320h-64v64h64v-64zM768 448h-64v64h64v-64zM768 544h-64v64h64v-64zM768 640h-64v64h64v-64z" />
<glyph unicode="&#xe951;" glyph-name="chronometer" d="M897.728 365.728c0-221.856-179.84-401.728-401.728-401.728-221.856 0-401.728 179.872-401.728 401.728 0 215.104 169.152 390.144 381.664 400.672v69.312h-30.112c-17.76 0-32.16 14.4-32.16 32.16s14.4 32.128 32.16 32.128h96.384c17.76 0 32.16-14.368 32.16-32.128s-14.4-32.16-32.16-32.16h-34.112v-68.896c216.224-6.4 389.632-183.328 389.632-401.088zM475.936 642.912v73.312c-99.488-5.632-187.712-52.48-248.512-123.456l52.896-52.896-22.72-22.752-50.080 50.112c-40.768-57.536-65.024-127.584-65.024-203.488 0-3.392 0.48-8.032 0.48-8.032h77.824v-32.16h-75.52c7.808-65.664 33.824-127.584 72.576-177.088l39.776 39.776 22.72-22.72-41.472-41.504c60.128-63.872 143.616-105.504 237.056-110.784v87.328h32.128v-87.744c95.648 3.264 181.44 44.576 243.168 109.12l-45.568 45.568 22.72 22.72 44.064-44.032c39.68 49.92 66.368 112.672 74.304 179.328h-81.6v32.16h83.872c0.096 3.328 0.512 4.64 0.512 8.032 0 78.016-25.6 149.792-68.416 208.16l-52.736-52.736-22.72 22.72 55.232 55.2c-62.304 70.496-152.096 116.192-252.8 119.584v-73.728h-32.16zM510.048 355.68h112.512c8.864 0 16.064-7.232 16.064-16.064 0-8.864-7.2-16.096-16.064-16.096h-128.576c-8.864 0-16.064 7.232-16.064 16.096v222.944c0 8.864 7.2 16.064 16.064 16.064s16.064-7.2 16.064-16.064v-206.88z" />
<glyph unicode="&#xe952;" glyph-name="chart" d="M127.584 832h-31.584v-768h832v30.816l-799.872 1.6-0.544 735.584zM544 800c0 17.696-14.336 32-32 32h-96c-17.696 0-32-14.304-32-32v-640h160v640zM352 608c0 17.664-14.336 32-32 32h-96c-17.696 0-32-14.336-32-32v-448h160v448zM736 416c0 17.696-14.336 32-32 32h-96c-17.696 0-32-14.304-32-32v-256h160v256zM896 256h-96c-17.696 0-32-14.304-32-32v-64h160v64c0 17.696-14.336 32-32 32z" />
<glyph unicode="&#xe953;" glyph-name="lab" d="M618.624 350.688c0 0-53.248-68-121.28 0-65.984 64-113.984 0-113.984 0l-158.944-313.28c-4.608-17.056 5.536-34.592 22.592-39.168h527.904c17.056 4.576 27.2 22.080 22.624 39.168l-178.912 313.28zM862.048 53.44l-255.328 429.696v0.8l-0.448 251.808h17.632c26.432 0 47.936 21.472 47.936 47.968 0 26.464-21.504 47.936-47.936 47.936h-255.84c-26.464 0-47.936-21.472-47.936-47.936 0-26.496 21.472-47.968 47.936-47.968h15.424l-0.512-251.872-221.056-430.432c-13.696-51.168 16.672-103.744 67.808-117.44h564.512c51.2 13.696 81.568 66.272 67.808 117.44zM785.696-31.936l-547.456 0.608c-34.080 9.152-54.304 44.224-45.184 78.272l222.304 435.712 0.672 285.056h-47.936c-8.8 0-15.968 7.168-15.968 16 0 8.8 7.168 15.968 15.968 15.968h255.84c8.8 0 15.936-7.168 15.936-15.968 0-8.832-7.136-16-15.936-16h-47.936l0.8-284 254.048-437.312c9.152-34.144-11.104-69.216-45.152-78.336zM527.36 879.616c0-17.664 14.336-32 32-32s32 14.336 32 32-14.304 32-32 32-32-14.304-32-32zM559.36 959.616c26.496 0 48 21.472 48 48s-21.504 48-48 48-48-21.472-48-48 21.504-48 48-48zM431.36 879.616c17.696 0 32 14.336 32 32s-14.304 32-32 32-32-14.336-32-32 14.304-32 32-32z" />
<glyph unicode="&#xe954;" glyph-name="satellite" horiz-adv-x="1064" d="M0 292.384l356.384-356.384c0 0 85.088 201.952-34.656 321.696-118.432 118.432-321.728 34.688-321.728 34.688zM956 264.064l-180.992-180.992 22.624-22.624 180.992 180.992-22.624 22.624zM1046.496 218.816l-203.616 203.68c-24.992 24.928-65.568 24.928-90.496 0l-17.856-17.856-49.92 49.92 89.504 89.504c24.992 24.992 22.176 68.352-2.816 93.344l-110.304 110.304c-24.992 24.992-65.504 24.992-90.496 0l-81.376-78.528-42.88 42.88 2.912 2.88c24.992 24.992 24.992 65.536 0 90.528l-203.648 203.68c-24.992 24.992-65.504 24.992-90.528 0l-135.744-135.776c-24.992-24.992-24.992-65.536 0-90.528l203.648-203.648c24.992-24.992 65.504-24.992 90.528 0l44.512 44.512 44.096-44.48-81.888-81.888c-24.992-24.992-15.552-164.096-15.552-164.096l55.136-55.136c0 0 139.072-9.44 164.064 15.552l70.848 70.816 49.92-49.92-27.968-27.968c-24.992-24.992-24.992-65.504 0-90.496l203.68-203.616c24.992-24.992 65.504-24.992 90.496 0l135.744 135.744c24.992 25.088 24.992 65.6 0 90.592zM41.856 850.752l135.776 135.776c12.48 12.512 32.736 12.512 45.248 0l-181.024-181.024c-12.512 12.48-12.512 32.768 0 45.248zM64.48 782.88l181.024 181.024 22.624-22.624-181.024-181.024-22.624 22.624zM109.728 737.632l181.024 181.024 22.624-22.656-180.992-180.992-22.656 22.624zM155.008 692.352l180.992 181.024 22.656-22.624-181.024-181.024-22.624 22.624zM200.256 647.104l181.024 181.024 22.624-22.624-181.024-181.024-22.624 22.624zM290.752 601.856c-12.48-12.512-32.736-12.512-45.248 0l181.024 181.024c12.512-12.512 12.512-32.768 0-45.248l-135.776-135.776zM381.056 432.064l-16.96 16.992 233.92 233.92 16.992-16.96-233.952-233.952zM639.2 264.064l135.808 135.808c12.512 12.448 32.736 12.448 45.248 0l-181.056-181.056c-12.512 12.512-12.512 32.736 0 45.248zM1023.872 150.944l-135.744-135.744c-12.512-12.512-32.736-12.512-45.248 0l-135.776 135.776 180.992 180.992-22.624 22.624-181.056-180.992-22.624 22.624 181.056 181.056 180.992-181.056c12.544-12.544 12.544-32.8 0.032-45.28zM1001.248 218.816l-180.992-180.992 22.624-22.624 180.992 180.992-22.624 22.624zM910.752 309.312l-180.992-180.992 22.624-22.624 180.992 180.992-22.624 22.624z" />
<glyph unicode="&#xe955;" glyph-name="spaceinvaders" horiz-adv-x="1056" d="M958.816 160.576v190.304h-93.12v-191.008h-97.184v-94.496h-225.536v95.2h225.536v95.104h-479.712v-95.136l192.96-0.672v-95.136h-193.632v94.432h-97.152v192.32h-93.152v-190.304h-97.824v288.128h95.84v92.512h95.136v97.824h97.824v95.808h95.808v-96.096l287.456-0.768v96.864h95.808v-97.152h97.824v-95.168h94.496v-95.136h96.448v-287.424h-97.824zM384.608 543.84h-95.808v-95.84h95.808v95.84zM767.872 543.84h-95.808v-95.84h95.808v95.84zM190.976 831.264h97.824v-95.808h-97.824v95.808zM865.696 831.264v-95.808h-97.824v95.808h97.824z" />
<glyph unicode="&#xe956;" glyph-name="display" d="M0 896v-640h1024v640h-1024zM960 320h-896v512h896v-512zM672 192h-320l-32-128-64-64h512l-64 64z" />
<glyph unicode="&#xe957;" glyph-name="bomb" horiz-adv-x="1168" d="M1063.296 706.304l105.088-14.848-93.44-49.472 67.744-61.888-98.080 12.384 60.704-126.24-121.44 91.584-100.448-121.28 46.72 150.944-147.168-79.2 102.752 111.36-7.040 27.392c-27.744-13.824-67.040-27.936-108.128-26.304-54.496 0-122.176 38.016-203.040 105.984 0 0-91.552 96.832-168.512 96.832-79.168 0-71.424-119.104-71.328-120.288h89.664v-81.024c113.984-43.904 191.008-154.176 191.008-283.68 0-168-136.192-304.192-304.192-304.192s-304.16 136.256-304.16 304.256c0 129.472 79.008 239.776 192.992 283.68v81.024h80.128c-0.096 0.608-9.216 87.808 36.8 136.192 24.544 25.792 54.528 38.688 90.016 38.688 106.784 0 202.624-112.384 202.624-112.384 70.24-60.288 127.52-90.4 171.84-90.4 17.984 0 54.592 11.328 73.408 17.568l-57.824 45.504 100.448-7.392-77.056 118.784 126.112-89.088 14.016 84.16 23.328-76.736 93.44 111.36-21.024-123.744 107.424 24.736-93.376-74.272z" />
<glyph unicode="&#xe958;" glyph-name="tools" d="M889.056 706.048c30.688-74.016 16.064-162.368-44.128-222.56-66.272-66.272-166.432-76.64-244.288-32.704l-56.288-61.472 40.16-40.32 24 24c12.256 12.288 32.16 12.288 44.416 0l194.624-196.608c12.288-12.256 12.288-32.16 0-44.416l-88.832-88.832c-12.256-12.288-32.16-12.288-44.416 0l-194.624 196.608c-12.288 12.256-12.288 32.16 0 44.416l21.92 21.92-38.272 38.368-269.152-294.048c-24.544-24.544-64.32-24.544-88.832 0l-22.208 22.208c-24.544 24.544-24.544 64.32 0 88.832l306.624 256.8-203.648 204.192-64.32 0.032-74.432 119.68 59.904 60 122.4-74.912 0.8-62.976 206.016-206.816 59.936 50.176c-58.592 79.872-52.48 192.384 19.712 264.576 59.904 59.904 147.776 74.784 221.6 44.672l-131.968-130.144 111.072-111.072 132.224 130.4zM196.8 130.112c-12.256 12.256-32.128 12.256-44.416 0-12.288-12.288-12.288-32.16 0-44.448 12.288-12.256 32.16-12.256 44.416 0 12.288 12.32 12.288 32.192 0 44.448z" />
<glyph unicode="&#xe959;" glyph-name="bus" horiz-adv-x="1056" d="M704 31.616c0-17.696 14.304-32 32-32h32c17.664 0 32 14.304 32 32v65.984h-96v-65.984zM256 31.616c0-17.696 14.304-32 32-32h32c17.696 0 32 14.304 32 32v65.984h-96v-65.984zM159.52 136.672c0-21.44 17.408-38.88 38.88-38.88h659.072c21.472 0 38.88 17.44 38.88 38.88 0 21.504 0 22.88 0 22.88h-736.832c0 0 0-1.376 0-22.88zM1024 639.616v64h-127.68l0.032 34.816c0 77.792-79.648 157.984-383.168 157.984-266.816 0-353.664-80.192-353.664-157.984v-34.816h-127.52v-64h-32v-128h32v-64h127.52v-255.168h736l0.704 479.168h95.776v-32h-32v-128h32v-32h-96v-32h128v64h32v128h-32zM159.52 479.616h-95.52v32h32v128h-32v32h95.52v-192zM400 801.6h256c8.832 0 16-7.168 16-16s-7.168-16-16-16h-256c-8.832 0-16 7.168-16 16s7.168 16 16 16zM225.312 664.672c0 21.472 17.408 38.88 38.88 38.88h208.448c21.472 0 38.88-17.408 38.88-38.88v-114.656c0-21.504-17.408-38.912-38.88-38.912h-208.448c-21.472 0-38.88 17.408-38.88 38.912v114.656zM287.616 264.384c-32.224 0-58.304 26.112-58.304 58.304 0 32.256 26.080 58.304 58.304 58.304s58.336-26.048 58.336-58.304c0.032-32.192-26.112-58.304-58.336-58.304zM384 415.616h288v-32h-288v32zM673.024 257.824h-288.192v30.88h288.192v-30.88zM673.024 321.568h-288.192v30.88h288.192v-30.88zM768.256 262.368c-32.224 0-58.304 26.112-58.304 58.304s26.080 58.304 58.304 58.304 58.336-26.112 58.336-58.304-26.112-58.304-58.336-58.304zM832.16 550.016c0-21.504-17.408-38.912-38.912-38.912h-209.984c-21.504 0-38.912 17.408-38.912 38.912v114.656c0 21.472 17.408 38.88 38.912 38.88h209.984c21.504 0 38.912-17.408 38.912-38.88v-114.656z" />
<glyph unicode="&#xe95a;" glyph-name="stop2" d="M689.984 896h-369.632l-264.352-263.648v-368.672l264.352-263.68 369.632 2.336 262.016 261.344v368.672l-262.016 263.648zM920 276.832l-243.328-242.656-343.2-2.176-245.472 244.832v342.368l245.472 244.8h343.232l243.328-244.8v-342.368zM774.112 448.736c6.144 1.632 11.296 4.512 15.36 8.64 3.648 3.712 6.336 7.744 8 12.128 1.696 4.416 2.528 9.504 2.528 15.36 0 6.368-1.088 11.904-3.328 16.64-2.208 4.672-5.568 8.544-10.048 11.52-3.936 2.56-8.48 4.384-13.696 5.44s-11.68 1.632-19.424 1.632h-20.512v-73.76h16.864c10.016 0 18.112 0.8 24.256 2.4zM640.096 504.8c-4.896 6.432-10.848 11.264-17.824 14.464s-14.784 4.8-23.456 4.8c-8.992 0-16.864-1.568-23.584-4.672-6.72-3.168-12.672-8-17.856-14.592-4.896-6.336-8.672-14.304-11.328-23.872-2.624-9.6-3.936-20.448-3.936-32.544 0-24.448 5.12-43.168 15.36-56.128 10.272-12.96 24.032-19.424 41.312-19.424 17.248 0 31.008 6.464 41.216 19.424s15.328 31.68 15.328 56.128c0 12.352-1.344 23.264-4 32.768-2.656 9.536-6.4 17.408-11.232 23.648zM340.032 848l-236.032-235.392v-329.152l236.032-235.424 330.016 2.080 233.952 233.344v329.152l-233.952 235.392h-330.016zM336.064 386.72c-2.976-7.072-7.136-13.056-12.448-17.984-6.016-5.408-12.8-9.6-20.352-12.512-7.552-2.944-16.992-4.384-28.352-4.384-13.536 0-24.992 1.408-34.464 4.192s-18.368 6.208-26.688 10.304v31.008h1.76c8.192-7.616 17.44-13.536 27.776-17.728s20.32-6.272 29.92-6.272c13.696 0 24.032 2.848 31.040 8.544 7.040 5.728 10.528 13.216 10.528 22.56 0 7.36-1.856 13.44-5.536 18.080s-9.536 8.096-17.568 10.336c-5.792 1.696-11.040 3.072-15.776 4.128-4.768 1.088-10.752 2.56-17.92 4.416-6.432 1.664-12.224 3.776-17.28 6.368-5.088 2.56-9.632 5.952-13.536 10.112-3.84 4.096-6.848 8.896-8.96 14.432-2.112 5.568-3.2 11.936-3.2 19.232 0 15.104 5.888 27.712 17.664 37.952s26.816 15.328 45.088 15.328c10.432 0 20.32-1.056 29.632-3.136s17.952-5.024 25.888-8.832v-29.536h-1.888c-5.952 5.344-13.536 9.984-22.816 14.016s-19.040 6.016-29.216 6.016c-11.52 0-20.832-2.688-27.936-8.064s-10.656-12.416-10.656-21.152c0-7.904 2.080-14.176 6.272-18.848s10.24-8.096 18.176-10.24c5.248-1.408 11.68-3.040 19.296-4.8s13.92-3.424 18.944-4.928c12.832-3.936 22.24-9.856 28.16-17.792 5.952-7.904 8.896-17.664 8.896-29.248 0-7.296-1.472-14.464-4.448-21.568zM508.384 515.584h-60.512v-160.256h-30.752v160.256h-58.496v28h149.76v-28zM708.256 541.6h46.752c11.008 0 20.384-0.928 28.128-2.752 7.744-1.856 14.592-4.8 20.512-8.864 6.912-4.736 12.352-10.784 16.256-18.048 3.904-7.328 5.888-16.128 5.888-26.432 0-8.096-1.44-15.744-4.32-22.944-2.88-7.232-6.848-13.376-11.936-18.432-6.4-6.336-13.984-11.136-22.624-14.368-8.672-3.264-19.616-4.864-32.864-4.864h-20.992v-69.504h-24.736v186.208zM681.12 448.416c0-15.136-1.92-28.768-5.76-40.96s-9.376-22.4-16.672-30.688c-7.584-8.672-16.448-15.104-26.56-19.232-10.144-4.128-21.28-6.176-33.472-6.176-12.608 0-23.936 2.112-34.016 6.368s-18.752 10.592-26.016 19.040c-7.168 8.288-12.672 18.464-16.512 30.56-3.84 12.128-5.76 25.824-5.76 41.088 0 15.68 1.952 29.472 5.824 41.312 3.872 11.872 9.408 22.048 16.576 30.56 7.2 8.288 15.84 14.56 25.984 18.848 10.112 4.32 21.472 6.464 33.984 6.464 12.672 0 24.096-2.208 34.272-6.656 10.144-4.416 18.752-10.624 25.76-18.656 7.104-8.192 12.608-18.304 16.544-30.432 3.872-12.096 5.824-25.92 5.824-41.44z" />
<glyph unicode="&#xe95b;" glyph-name="atom" d="M789.984 446.816c73.376-79.136 106.24-156.992 77.728-206.912-28.448-49.792-111.392-60.064-215.616-35.648-31.2-104.288-81.728-172.384-138.912-172.384-57.248 0-107.744 68.32-138.88 172.896-105.376-25.12-189.312-15.040-217.984 35.136-28.512 49.92 4.384 127.872 77.76 207.104-74.784 79.872-108.448 158.72-79.68 209.024 28.8 50.432 113.536 60.384 219.648 34.784 31.168 104.8 81.856 173.312 139.168 173.312 57.28 0 107.808-68.288 138.944-172.832 105.12 24.96 188.928 14.848 217.568-35.264 28.672-50.336-5.024-129.248-79.744-209.216zM184.064 638.688c-22.016-38.528 8.352-101.696 72.64-168.48 26.208 25.568 56.384 50.944 89.984 75.328 4.096 40.512 10.336 78.944 18.88 113.92-89.824 23.072-159.392 17.92-181.504-20.768zM343.072 500.448c-23.040-17.536-44.064-35.328-62.912-53.088 19.104-17.856 39.712-35.776 63.040-53.44-0.96 17.76-1.632 35.712-1.632 54.080 0 17.792 0.576 35.264 1.504 52.448zM346.656 348.992c-33.632 24.288-63.712 49.6-90.016 75.072-63.136-66.176-92.448-128.608-70.624-166.816 21.984-38.432 90.816-43.776 179.84-21.184-8.544 34.784-15.136 72.608-19.2 112.928zM642.848 325.28c-14.272-9.376-28.864-18.592-44.064-27.456-15.424-8.992-30.848-17.248-46.208-25.12 26.336-11.2 52.096-20.96 76.544-28.448 5.728 25.088 10.176 52.448 13.728 81.024zM513.152 66.56c43.808 0 82.688 57.12 107.84 145.824-34.72 9.984-71.392 23.872-108.768 40.768-36.704-16.672-72.608-30.080-106.784-40.096 25.088-88.928 63.904-146.496 107.712-146.496zM397.536 245.056c23.744 7.392 48.576 16.576 74.112 27.456-15.424 7.904-30.944 16.256-46.432 25.28-14.368 8.416-28.192 17.056-41.728 25.92 3.488-28.064 8.448-53.952 14.048-78.656zM383.552 571.008c14.112 9.248 28.576 18.336 43.584 27.136 14.816 8.672 29.632 16.64 44.416 24.256-25.632 10.944-50.72 20.608-74.592 28.064-5.568-24.64-9.888-51.488-13.408-79.456zM513.152 829.44c-43.936 0-83.008-57.664-108.128-147.008 34.144-10.048 70.112-23.84 106.752-40.544 37.504 17.184 74.176 30.912 109.088 41.088-25.088 88.864-63.872 146.464-107.712 146.464zM628.832 651.040c-24.576-7.648-50.24-17.12-76.736-28.512 14.88-7.648 29.824-15.68 44.736-24.416 16.064-9.376 31.424-19.136 46.432-29.056-3.52 29.28-8.608 56.32-14.432 81.984zM647.68 524.672c-21.44 14.912-44.096 29.472-68.032 43.392-22.912 13.376-45.632 25.056-68.096 35.968-22.176-10.816-44.672-22.816-67.232-35.968-22.816-13.28-44.608-27.168-65.12-41.312-1.984-25.504-3.328-51.616-3.328-78.784 0-27.456 1.12-54.176 3.104-79.968 20.064-13.792 41.248-27.264 63.392-40.192 23.552-13.728 46.912-25.728 70.016-36.864 22.816 11.072 45.984 23.328 69.184 36.864 23.008 13.408 44.864 27.36 65.568 41.664 1.952 25.408 3.328 51.424 3.328 78.496 0 26.304-0.96 51.936-2.784 76.704zM837.984 257.248c21.824 38.144-7.744 100.48-70.752 166.496-25.632-24.768-54.976-49.344-87.552-72.992-4.096-41.024-10.432-79.968-19.136-115.328 87.872-21.92 155.68-16.256 177.44 21.824zM683.296 395.84c22.048 16.832 42.272 33.92 60.512 50.912-18.304 17.28-38.048 34.656-60.384 51.776 0.8-16.608 1.376-33.408 1.376-50.528-0.032-17.728-0.608-35.072-1.504-52.16zM839.904 638.688c-21.952 38.368-90.56 43.808-179.36 21.312 8.736-35.776 15.488-74.848 19.52-116.512 32.608-23.84 61.76-48.64 87.296-73.568 64.416 66.912 94.624 130.176 72.544 168.768zM518.4 382.016c-37.664 0-68.192 30.816-68.192 68.864 0 38.016 30.528 68.864 68.192 68.864 37.632 0 68.16-30.848 68.16-68.864 0-38.080-30.528-68.864-68.16-68.864z" />
<glyph unicode="&#xe95c;" glyph-name="globe" d="M725.056 608.384h165.504c22.176-49.312 35.424-103.328 37.696-160.384h-189.888c-0.8 60.288-5.792 113.408-13.312 160.384zM652.736 835.328c94.944-36.896 172.864-106.72 221.696-194.88h-154.752c-17.568 89.76-44.256 153.568-66.944 194.88zM514.176 640.448v223.872c34.112-1.504 67.264-6.912 98.944-15.776 24-40.416 55.008-107.904 74.56-208.096h-173.504zM303.648 255.552c-7.488 47.008-12.672 99.808-13.472 160.384h191.936v-160.384h-178.464zM303.328 608.384h178.784v-160.384h-192.128c0.8 60.352 5.856 113.376 13.344 160.384zM383.616 849.248c31.584 8.512 64.48 13.92 98.496 15.008v-223.808h-173.504c19.68 100.736 50.912 168.48 75.008 208.8zM117.152 640.448c49.632 89.6 129.984 159.776 227.072 196.192-22.88-41.28-49.888-105.44-67.648-196.192h-159.424zM257.92 448h-193.92c2.112 56.992 14.944 111.168 37.056 160.384h170.112c-7.456-47.008-12.48-100.096-13.248-160.384zM271.584 255.552h-169.28c-22.208 49.376-36.448 103.168-38.528 160.384h194.272c0.768-60.576 6.016-113.312 13.536-160.384zM276.832 223.488c17.888-91.648 45.312-155.744 68.288-196.544-97.44 36.256-177.824 106.72-227.52 196.544h159.232zM482.112 223.488v-223.808c-33.664 1.056-66.144 6.368-97.44 14.72-24.16 39.552-55.552 107.616-75.392 209.088h172.832zM687.072 223.488c-19.744-100.864-50.944-168.672-75.008-208.384-31.328-8.672-64.192-13.376-97.888-14.88v223.264h172.896zM514.176 415.936h191.936c-0.736-60.576-6.016-113.344-13.504-160.384h-178.432v160.384zM706.304 448h-192.128v160.384h178.752c7.52-47.008 12.576-100.032 13.376-160.384zM738.24 415.936h189.632c-2.112-57.184-16.192-110.976-38.304-160.384h-164.864c7.488 47.072 12.736 99.808 13.536 160.384zM874.176 223.488c-48.672-88.512-126.944-158.368-222.304-195.2 22.88 40.832 49.952 104.512 67.616 195.2h154.688z" />
<glyph unicode="&#xe95d;" glyph-name="globe1" d="M496 896c-256.256 0-464-207.744-464-464s207.744-464 464-464 464 207.744 464 464-207.744 464-464 464zM344.064 836.672c-22.848-41.248-49.888-105.44-67.616-196.192h-159.456c49.632 89.568 129.984 159.776 227.072 196.192zM100.928 608.416h170.112c-7.488-46.976-12.512-100.096-13.28-160.384h-193.92c2.144 56.992 14.976 111.168 37.088 160.384zM63.616 415.968h194.304c0.736-60.576 6.016-113.312 13.504-160.384h-169.28c-22.208 49.376-36.416 103.168-38.528 160.384zM117.44 223.52h159.264c17.888-91.648 45.312-155.744 68.288-196.544-97.472 36.288-177.824 106.752-227.552 196.544zM481.984-0.288c-33.664 1.056-66.144 6.368-97.44 14.72-24.16 39.552-55.552 107.616-75.392 209.088h172.832v-223.808zM481.984 255.584h-178.496c-7.488 47.008-12.672 99.808-13.472 160.384h191.936v-160.384zM481.984 448.032h-192.128c0.8 60.352 5.856 113.376 13.344 160.384h178.784v-160.384zM481.984 640.48h-173.504c19.68 100.736 50.912 168.512 75.008 208.8 31.584 8.512 64.48 13.92 98.496 15.040v-223.84zM928.096 448.032h-189.856c-0.8 60.288-5.824 113.408-13.312 160.384h165.504c22.176-49.312 35.456-103.36 37.664-160.384zM874.304 640.48h-154.784c-17.568 89.792-44.224 153.6-66.912 194.88 94.944-36.928 172.864-106.72 221.696-194.88zM514.016 864.352c34.144-1.504 67.264-6.912 98.944-15.776 24.032-40.416 55.040-107.904 74.592-208.096h-173.536v223.872zM514.016 608.416h178.784c7.488-47.008 12.544-100.032 13.344-160.384h-192.128v160.384zM514.016 415.968h191.936c-0.736-60.576-5.984-113.376-13.472-160.384h-178.464v160.384zM514.016 0.288v223.264h172.864c-19.744-100.864-50.912-168.672-74.976-208.384-31.296-8.704-64.16-13.376-97.888-14.88zM651.744 28.352c22.848 40.832 49.92 104.512 67.584 195.2h154.72c-48.704-88.512-126.944-158.4-222.304-195.2zM889.44 255.584h-164.864c7.488 47.072 12.736 99.808 13.536 160.384h189.664c-2.144-57.184-16.256-110.976-38.336-160.384z" />
<glyph unicode="&#xe95e;" glyph-name="grid" d="M42.667 853.334v-896h895.147v896h-895.147zM852.565 554.667h-213.163v213.333h213.163v-213.333zM852.565 298.667h-213.163v213.333h213.163v-213.333zM852.565 42.667h-213.163v213.333h213.163v-213.333zM127.915 256h213.163v-213.333h-213.163v213.333zM127.915 512h213.163v-213.333h-213.163v213.333zM127.915 768h213.163v-213.333h-213.163v213.333zM596.821 554.667h-213.12v213.333h213.163v-213.333zM596.821 298.667h-213.12v213.333h213.163v-213.333zM383.701 256h213.163v-213.333h-213.163v213.333z" />
<glyph unicode="&#xe95f;" glyph-name="flag" d="M810.581 853.419v-17.707c-42.624 12.629-75.477 19.669-114.688 19.669-76.501 0-152.747-23.851-224.512-46.891-68.48-21.931-134.272-42.752-197.333-42.752-47.744 0-86.741 12.459-126.635 38.059l-62.080 42.24v-656.043l15.488-12.587c54.016-34.731 109.653-51.669 174.251-51.669 76.459 0 149.632 23.851 221.355 46.933 68.48 22.016 136.832 42.752 199.979 42.752 40.021 0 71.595-9.344 114.261-27.264v-275.584h85.333v940.843h-85.419zM810.667 281.899c-42.667 12.672-75.563 18.816-114.731 18.816-76.501 0-152.747-23.851-224.512-46.848-68.523-22.016-130.176-42.837-193.237-42.837-40.021 0-64.853 8.747-107.52 26.667v461.568c42.667-12.629 67.328-18.816 106.496-18.816 76.416 0 148.565 23.851 220.331 46.891 68.48 22.016 136.32 42.795 199.424 42.795 39.979-0.043 71.083-8.789 113.749-26.667v-461.568z" />
<glyph unicode="&#xe960;" glyph-name="lock" d="M810.667 554.667v128c0 85.333-85.333 213.333-298.667 213.333s-298.667-128-298.667-213.333v-128h-85.333v-469.333c0-70.571 57.429-128 128-128h512c70.571 0 128 57.429 128 128v469.333h-85.333zM298.667 725.334c0 0 42.667 85.333 213.333 85.333s213.333-85.333 213.333-85.333v-170.667h-426.667v170.667zM810.667 85.334c0-23.509-19.115-42.667-42.667-42.667h-512c-23.552 0-42.667 19.157-42.667 42.667v384h597.333v-384zM469.333 225.152v-97.152h85.333v97.152c25.429 14.805 42.667 41.984 42.667 73.515 0 47.104-38.229 85.333-85.333 85.333s-85.333-38.229-85.333-85.333c0-31.488 17.237-58.709 42.667-73.515z" />
<glyph unicode="&#xe961;" glyph-name="unlocked1" d="M810.667 938.667c-170.667 0-213.333-128-213.333-213.333v-213.333h-597.333v-469.333c0-70.571 57.429-128 128-128h512c70.571 0 128 57.429 128 128v469.333h-85.333v256c0 0 0 85.333 128 85.333s128-85.333 128-85.333v-170.667h85.333v128c0 85.333-42.667 213.333-213.333 213.333zM682.667 42.667c0-23.509-19.115-42.667-42.667-42.667h-512c-23.552 0-42.667 19.157-42.667 42.667v384h597.333v-384zM341.333 182.486v-97.152h85.333v97.152c25.429 14.805 42.667 41.984 42.667 73.515 0 47.104-38.229 85.333-85.333 85.333s-85.333-38.229-85.333-85.333c0-31.488 17.237-58.709 42.667-73.515z" />
<glyph unicode="&#xe962;" glyph-name="camera3" d="M533.291 554.667c-106.027 0-191.957-85.973-191.957-192s85.931-192 191.957-192c105.984 0 191.957 85.973 191.957 192s-85.973 192-191.957 192zM458.965 491.392c21.931 12.757 47.147 20.608 74.368 20.608 76.416 0 138.923-57.941 147.584-132.139-73.813 56.832-161.067 91.904-221.952 111.531zM960 725.334h-206.251l-28.416 85.333h-426.667l-28.416-85.333h-163.584c-47.104 0-106.667-38.229-106.667-85.333v-512c0-47.104 59.563-85.333 106.667-85.333h853.333c47.104 0 64 38.229 64 85.333v512c0 47.104-16.896 85.333-64 85.333zM533.333 85.334c-153.173 0-277.333 124.16-277.333 277.333s124.16 277.333 277.333 277.333 277.333-124.16 277.333-277.333-124.16-277.333-277.333-277.333zM938.667 554.667h-85.333v85.333h85.333v-85.333z" />
<glyph unicode="&#xe963;" glyph-name="calculator" d="M170.667 256h128v128h-128v-128zM213.333 341.334h42.667v-42.667h-42.667v42.667zM341.333 256h128v128h-128v-128zM384 341.334h42.667v-42.667h-42.667v42.667zM341.333 85.334h128v128h-128v-128zM384 170.667h42.667v-42.667h-42.667v42.667zM170.667 85.334h128v128h-128v-128zM213.333 170.667h42.667v-42.667h-42.667v42.667zM512 256h128v128h-128v-128zM554.667 341.334h42.667v-42.667h-42.667v42.667zM426.667 512h42.667v42.667h-42.667v-42.667zM341.333 512h42.667v42.667h-42.667v-42.667zM170.667 426.667h682.667v384h-682.667v-384zM213.333 768h597.333v-298.667h-597.333v298.667zM853.333 938.667h-682.667c-70.699 0-128-57.301-128-128v-768c0-70.699 57.301-128 128-128h682.667c70.699 0 128 57.301 128 128v768c0 70.699-57.301 128-128 128zM896 42.667c0-23.595-19.072-42.667-42.667-42.667h-682.667c-23.595 0-42.667 19.072-42.667 42.667v768c0 23.595 19.072 42.667 42.667 42.667h682.667c23.595 0 42.667-19.072 42.667-42.667v-768zM512 85.334h128v128h-128v-128zM554.667 170.667h42.667v-42.667h-42.667v42.667zM682.667 85.334h170.667v298.667h-170.667v-298.667zM725.333 341.334h85.333v-213.333h-85.333v213.333zM256 512h42.667v42.667h-42.667v-42.667z" />
<glyph unicode="&#xe964;" glyph-name="database" d="M512 960c-282.77 0-512-71.634-512-160v-128c0-88.366 229.23-160 512-160s512 71.634 512 160v128c0 88.366-229.23 160-512 160zM512 416c-282.77 0-512 71.634-512 160v-192c0-88.366 229.23-160 512-160s512 71.634 512 160v192c0-88.366-229.23-160-512-160zM512 128c-282.77 0-512 71.634-512 160v-192c0-88.366 229.23-160 512-160s512 71.634 512 160v192c0-88.366-229.23-160-512-160z" />
<glyph unicode="&#xe965;" glyph-name="diamond" d="M742.741 854.742h-461.483l-281.259-278.741 512-577.408 512 577.408-281.259 278.741zM921.344 553.472l-0.597 2.603h-379.819l182.101 196.651 198.315-199.253zM443.648 196.864l-299.648 316.544h197.333l-19.84-9.515 122.155-307.029zM364.245 513.408h295.424l-147.669-369.237-147.755 369.237zM682.667 513.408h197.248l-299.648-316.544 122.155 307.029-19.755 9.515zM512 587.563l-166.997 181.845h333.909l-166.912-181.845zM300.928 751.104l182.101-195.029h-379.861l-0.512-0.981 198.272 196.011z" />
<glyph unicode="&#xe966;" glyph-name="atom1" d="M512 554.71c-70.656 0-128-57.344-128-128s57.344-128 128-128 128 57.344 128 128-57.344 128-128 128zM905.856 539.094c-13.867 4.48-26.368 11.605-37.077 21.035-17.237-31.744-38.485-64.299-61.397-96.939-35.627 45.781-76.288 91.989-121.643 137.344-45.013 45.013-91.392 85.845-137.643 121.771 109.952 77.483 215.637 124.117 290.859 124.117 30.549 0 53.931-7.893 69.461-23.424 16.896-16.896 24.363-43.435 23.040-77.056 2.432 0.171 4.693 0.768 7.168 0.768 12.288 0 23.979-2.517 34.944-6.315 2.645 47.829-8.704 86.485-34.987 112.811-23.851 23.851-57.344 35.925-99.627 35.925-87.168 0-205.312-52.011-326.912-139.819-121.6 87.808-239.744 139.861-326.912 139.861-9.045 0-17.536-0.853-25.771-1.963 11.648-11.264 20.437-25.173 26.027-40.747 75.221-0.085 180.821-46.72 290.688-124.16-46.336-36.011-92.757-76.843-137.728-121.856-44.8-44.843-85.632-91.307-121.856-137.984-36.48 51.669-66.56 102.912-88.107 151.595-14.763 33.237-24.619 63.744-30.379 91.307-4.224-0.555-8.32-1.323-12.672-1.323-11.008 0-21.419 2.176-31.403 5.248 5.717-33.963 17.28-71.595 35.456-112.555 24.192-54.656 58.24-112.299 100.053-170.155-41.771-57.771-75.733-115.413-99.968-170.027-51.584-116.352-52.949-207.403-3.883-256.469 23.851-23.851 57.344-35.925 99.627-35.925 128.853 0 325.376 113.323 500.693 288.725 44.928 44.971 85.803 91.563 121.984 138.368 118.187-166.997 152.064-309.333 100.48-360.917-15.531-15.531-38.912-23.424-69.461-23.424-40.235 0-89.387 13.568-143.104 37.845-5.675-13.653-14.080-25.771-24.533-35.925 62.208-28.8 119.637-44.587 167.637-44.587 42.283 0 75.776 12.075 99.627 35.925 74.155 74.155 27.349 244.523-104.491 427.136 27.093 37.589 51.84 75.136 71.808 111.787zM185.216 6.827c-30.549 0-53.931 7.893-69.461 23.424-35.2 35.2-30.592 111.36 12.715 208.981 21.547 48.64 51.584 99.797 87.979 151.467 36.224-46.635 77.013-93.099 121.771-137.813 45.269-45.269 91.904-85.376 138.496-121.429-110.208-77.824-216.192-124.629-291.499-124.629zM655.744 283.051c-46.677-46.677-95.232-88.832-143.531-125.525-48.427 36.779-97.024 78.805-143.829 125.525-46.677 46.677-88.704 95.104-125.568 143.531 36.864 48.512 79.019 96.981 125.696 143.701 46.635 46.677 95.232 88.832 143.573 125.611 48.299-36.736 96.853-78.891 143.488-125.525 48.469-48.469 90.197-96.64 125.952-143.36-36.864-48.64-78.976-97.152-125.781-143.957zM938.667 682.71c-23.595 0-42.667-19.072-42.667-42.667s19.072-42.667 42.667-42.667 42.667 19.072 42.667 42.667-19.072 42.667-42.667 42.667zM597.333 128.043c-23.595 0-42.667-19.072-42.667-42.667s19.072-42.667 42.667-42.667 42.667 19.072 42.667 42.667-19.072 42.667-42.667 42.667zM85.333 768.043c23.595 0 42.667 19.072 42.667 42.667s-19.072 42.667-42.667 42.667-42.667-19.072-42.667-42.667 19.072-42.667 42.667-42.667z" />
<glyph unicode="&#xe967;" glyph-name="syringe" d="M836.352 720.854l60.331-60.331 60.331 60.331-150.827 150.827-60.373-60.331 60.331-60.331-90.539-90.539-181.035 181.035-60.331-60.331 60.331-60.331-452.48-452.565 103.424-103.467-118.528-183.168 183.168 118.485 103.424-103.424 452.608 452.565 60.331-60.331 60.331 60.331-181.035 180.992 90.539 90.581zM745.813 509.611l-90.581-90.496-90.496 90.539-30.165-30.165 90.496-90.539-60.331-60.373-90.496 90.539-30.165-30.165 90.496-90.539-60.331-60.331-90.496 90.539-30.165-30.165 90.496-90.539-90.496-90.496-150.827 150.869 392.149 392.192 150.912-150.869z" />
<glyph unicode="&#xe968;" glyph-name="health1" d="M886.827 802.432c-257.749 36.651-515.029 36.736-773.376-0.085-66.773-9.984-113.451-73.173-113.451-140.928v-469.333c0-67.755 38.741-130.987 105.899-141.056 128.896-18.347 252.416-27.605 382.635-27.605s273.323 9.301 402.517 27.648c66.859 10.027 132.949 73.259 132.949 141.013v469.248c0 67.755-69.931 130.987-137.173 141.099zM85.333 661.334c0 25.813 7.595 52.821 32.597 56.576 112.725 16 221.269 24.533 334.037 26.112l-167.211-296.789h-199.424v214.101zM938.667 192.086c0-25.813-38.741-52.779-63.829-56.533-249.813-35.541-499.584-35.456-748.757-0.043-25.429 3.797-40.747 30.72-40.747 56.576v169.813h250.069l75.563 117.675 36.224-306.347 219.392 188.672h272.085v-169.813zM938.667 447.232h-302.421l-121.941-120.021-46.549 417.109c6.997 0.043 13.781 0.384 20.779 0.384 126.208 0 265.301-9.045 389.888-26.709 25.429-3.84 60.245-30.805 60.245-56.576v-214.187zM682.752 640.086h42.496v-42.752h-42.496zM768 640.086h42.752v-42.752h-42.752z" />
<glyph unicode="&#xe969;" glyph-name="pill" d="M874.069 788.694c-99.84 99.797-262.229 99.797-362.112 0l-361.984-362.027c-99.797-99.84-99.84-262.229 0-362.027s262.187-99.797 362.027 0l362.069 362.027c99.755 99.84 99.84 262.229 0 362.027zM813.739 728.363c66.517-66.56 66.517-174.848 0-241.365l-181.077-180.992-241.323 241.323 180.992 181.035c66.603 66.56 174.848 66.56 241.408 0z" />
<glyph unicode="&#xe96a;" glyph-name="lab1" d="M895.872 224.342c0 0-298.069 299.136-298.624 330.325v42.752h85.504v256h-384.085v-256h85.333l0.171-42.752c-0.555-31.189-298.624-330.325-298.624-330.325-56.192-63.061-44.416-114.603-34.432-137.899s48.171-86.443 75.819-86.443h727.552c27.648 0 65.792 63.104 75.776 86.4s21.803 74.88-34.389 137.941zM851.883 120.022c-3.755-8.704-13.312-24.235-21.333-34.688h-679.68c-8.021 10.453-17.579 25.984-21.291 34.688-6.144 14.251 8.192 34.304 18.261 45.909 320.555 321.792 321.024 350.635 321.664 388.693v127.957l-85.632 0.085 0.128 85.248h213.248l0.128-85.248h-85.376l-0.043-129.493c0.64-36.565 1.109-65.451 321.664-387.243 10.027-11.605 24.32-31.659 18.261-45.909zM512 426.667h-42.752l-256-256v-42.752h554.752v42.752l-256 256zM426.752 298.667l42.496 85.248h42.752l42.752-85.248h-128z" />
<glyph unicode="&#xe96b;" glyph-name="graph" d="M981.248-0.085h-85.248v42.752h-42.752v-42.752h-85.12v42.752h-42.752v-42.752h-85.248v42.752h-42.752v-42.752h-85.248v42.752h-42.752v-42.752h-85.248v42.752h-42.752v-42.752h-187.776l224.853 135.125 111.275 325.205 165.291-290.517 320.299 533.675-73.131 43.947-245.205-408.576-186.709 328.149-162.517-474.795-222.507-133.717v880.256h-85.248v-1024h1024v128h-42.752zM981.248 938.667h42.752v-42.752h-42.752zM853.248 938.667h42.752v-42.752h-42.752zM725.376 938.667h42.752v-42.752h-42.752zM597.376 938.667h42.752v-42.752h-42.752zM469.376 938.667h42.752v-42.752h-42.752zM341.376 938.667h42.752v-42.752h-42.752zM213.376 938.667h42.752v-42.752h-42.752zM85.376 938.667h42.752v-42.752h-42.752zM981.248 810.667h42.752v-42.752h-42.752zM853.248 810.667h42.752v-42.752h-42.752zM725.376 810.667h42.752v-42.752h-42.752zM597.376 810.667h42.752v-42.752h-42.752zM469.376 810.667h42.752v-42.752h-42.752zM341.376 810.667h42.752v-42.752h-42.752zM213.376 810.667h42.752v-42.752h-42.752zM85.376 810.667h42.752v-42.752h-42.752zM981.248 682.795h42.752v-42.752h-42.752zM725.376 682.795h42.752v-42.752h-42.752zM597.376 682.795h42.752v-42.752h-42.752zM341.376 682.795h42.752v-42.752h-42.752zM213.376 682.795h42.752v-42.752h-42.752zM85.376 682.795h42.752v-42.752h-42.752zM981.248 554.795h42.752v-42.752h-42.752zM597.376 554.795h42.752v-42.752h-42.752zM341.376 554.795h42.752v-42.752h-42.752zM213.376 554.795h42.752v-42.752h-42.752zM85.376 554.795h42.752v-42.752h-42.752zM981.248 426.71h42.752v-42.752h-42.752zM853.248 426.71h42.752v-42.752h-42.752zM213.376 426.71h42.752v-42.752h-42.752zM85.376 426.71h42.752v-42.752h-42.752zM981.248 298.71h42.752v-42.752h-42.752zM853.248 298.71h42.752v-42.752h-42.752zM469.376 298.71h42.752v-42.752h-42.752zM213.376 298.71h42.752v-42.752h-42.752zM85.376 298.71h42.752v-42.752h-42.752zM981.248 170.838h42.752v-42.752h-42.752zM853.248 170.838h42.752v-42.752h-42.752zM725.376 170.838h42.752v-42.752h-42.752zM469.376 170.838h42.752v-42.752h-42.752zM85.376 170.838h42.752v-42.752h-42.752z" />
<glyph unicode="&#xe96c;" glyph-name="chat" horiz-adv-x="1152" d="M1088 58.834c0-45.5 26.028-84.908 64-104.184v-15.938c-10.626-1.454-21.472-2.224-32.5-2.224-68.008 0-129.348 28.528-172.722 74.264-26.222-6.982-54.002-10.752-82.778-10.752-159.058 0-288 114.616-288 256s128.942 256 288 256c159.058 0 288-114.616 288-256 0-55.348-19.764-106.592-53.356-148.466-6.824-14.824-10.644-31.312-10.644-48.7zM512 960c278.458 0 504.992-180.614 511.836-405.52-49.182 21.92-103.586 33.52-159.836 33.52-95.56 0-185.816-33.446-254.138-94.178-70.846-62.972-109.862-147.434-109.862-237.822 0-44.672 9.544-87.888 27.736-127.788-5.228-0.126-10.468-0.212-15.736-0.212-27.156 0-53.81 1.734-79.824 5.044-109.978-109.978-241.25-129.7-368.176-132.596v26.916c68.536 33.578 128 94.74 128 164.636 0 9.754-0.758 19.33-2.164 28.696-115.796 76.264-189.836 192.754-189.836 323.304 0 229.75 229.23 416 512 416z" />
<glyph unicode="&#xe975;" glyph-name="user-check" d="M960 352l-288-288-96 96-64-64 160-160 352 352zM448 192h320v115.128c-67.22 39.2-156.308 66.11-256 74.26v52.78c70.498 39.728 128 138.772 128 237.832 0 159.058 0 288-192 288s-192-128.942-192-288c0-99.060 57.502-198.104 128-237.832v-52.78c-217.102-17.748-384-124.42-384-253.388h448v64z" />
<glyph unicode="&#xe981;" glyph-name="spinner" d="M512-64c-136.76 0-265.334 53.258-362.040 149.96-96.702 96.706-149.96 225.28-149.96 362.040 0 96.838 27.182 191.134 78.606 272.692 50 79.296 120.664 143.372 204.356 185.3l43-85.832c-68.038-34.084-125.492-86.186-166.15-150.67-41.746-66.208-63.812-142.798-63.812-221.49 0-229.382 186.618-416 416-416s416 186.618 416 416c0 78.692-22.066 155.282-63.81 221.49-40.66 64.484-98.114 116.584-166.15 150.67l43 85.832c83.692-41.928 154.358-106.004 204.356-185.3 51.422-81.558 78.604-175.854 78.604-272.692 0-136.76-53.258-265.334-149.96-362.040-96.706-96.702-225.28-149.96-362.040-149.96z" />
<glyph unicode="&#xe984;" glyph-name="refresh" d="M1024 576h-384l143.53 143.53c-72.53 72.526-168.96 112.47-271.53 112.47s-199-39.944-271.53-112.47c-72.526-72.53-112.47-168.96-112.47-271.53s39.944-199 112.47-271.53c72.53-72.526 168.96-112.47 271.53-112.47s199 39.944 271.528 112.472c6.056 6.054 11.86 12.292 17.456 18.668l96.32-84.282c-93.846-107.166-231.664-174.858-385.304-174.858-282.77 0-512 229.23-512 512s229.23 512 512 512c141.386 0 269.368-57.326 362.016-149.984l149.984 149.984v-384z" />
<glyph unicode="&#xe994;" glyph-name="cog" d="M933.79 349.75c-53.726 93.054-21.416 212.304 72.152 266.488l-100.626 174.292c-28.75-16.854-62.176-26.518-97.846-26.518-107.536 0-194.708 87.746-194.708 195.99h-201.258c0.266-33.41-8.074-67.282-25.958-98.252-53.724-93.056-173.156-124.702-266.862-70.758l-100.624-174.292c28.97-16.472 54.050-40.588 71.886-71.478 53.638-92.908 21.512-211.92-71.708-266.224l100.626-174.292c28.65 16.696 61.916 26.254 97.4 26.254 107.196 0 194.144-87.192 194.7-194.958h201.254c-0.086 33.074 8.272 66.57 25.966 97.218 53.636 92.906 172.776 124.594 266.414 71.012l100.626 174.29c-28.78 16.466-53.692 40.498-71.434 71.228zM512 240.668c-114.508 0-207.336 92.824-207.336 207.334 0 114.508 92.826 207.334 207.336 207.334 114.508 0 207.332-92.826 207.332-207.334-0.002-114.51-92.824-207.334-207.332-207.334z" />
<glyph unicode="&#xe995;" glyph-name="cogs" d="M363.722 237.948l41.298 57.816-45.254 45.256-57.818-41.296c-10.722 5.994-22.204 10.774-34.266 14.192l-11.682 70.084h-64l-11.68-70.086c-12.062-3.418-23.544-8.198-34.266-14.192l-57.818 41.298-45.256-45.256 41.298-57.816c-5.994-10.72-10.774-22.206-14.192-34.266l-70.086-11.682v-64l70.086-11.682c3.418-12.060 8.198-23.544 14.192-34.266l-41.298-57.816 45.254-45.256 57.818 41.296c10.722-5.994 22.204-10.774 34.266-14.192l11.682-70.084h64l11.68 70.086c12.062 3.418 23.544 8.198 34.266 14.192l57.818-41.296 45.254 45.256-41.298 57.816c5.994 10.72 10.774 22.206 14.192 34.266l70.088 11.68v64l-70.086 11.682c-3.418 12.060-8.198 23.544-14.192 34.266zM224 96c-35.348 0-64 28.654-64 64s28.652 64 64 64 64-28.654 64-64-28.652-64-64-64zM1024 576v64l-67.382 12.25c-1.242 8.046-2.832 15.978-4.724 23.79l57.558 37.1-24.492 59.128-66.944-14.468c-4.214 6.91-8.726 13.62-13.492 20.13l39.006 56.342-45.256 45.254-56.342-39.006c-6.512 4.766-13.22 9.276-20.13 13.494l14.468 66.944-59.128 24.494-37.1-57.558c-7.812 1.892-15.744 3.482-23.79 4.724l-12.252 67.382h-64l-12.252-67.382c-8.046-1.242-15.976-2.832-23.79-4.724l-37.098 57.558-59.128-24.492 14.468-66.944c-6.91-4.216-13.62-8.728-20.13-13.494l-56.342 39.006-45.254-45.254 39.006-56.342c-4.766-6.51-9.278-13.22-13.494-20.13l-66.944 14.468-24.492-59.128 57.558-37.1c-1.892-7.812-3.482-15.742-4.724-23.79l-67.384-12.252v-64l67.382-12.25c1.242-8.046 2.832-15.978 4.724-23.79l-57.558-37.1 24.492-59.128 66.944 14.468c4.216-6.91 8.728-13.618 13.494-20.13l-39.006-56.342 45.254-45.256 56.342 39.006c6.51-4.766 13.22-9.276 20.13-13.492l-14.468-66.944 59.128-24.492 37.102 57.558c7.81-1.892 15.742-3.482 23.788-4.724l12.252-67.384h64l12.252 67.382c8.044 1.242 15.976 2.832 23.79 4.724l37.1-57.558 59.128 24.492-14.468 66.944c6.91 4.216 13.62 8.726 20.13 13.492l56.342-39.006 45.256 45.256-39.006 56.342c4.766 6.512 9.276 13.22 13.492 20.13l66.944-14.468 24.492 59.13-57.558 37.1c1.892 7.812 3.482 15.742 4.724 23.79l67.382 12.25zM672 468.8c-76.878 0-139.2 62.322-139.2 139.2s62.32 139.2 139.2 139.2 139.2-62.322 139.2-139.2c0-76.878-62.32-139.2-139.2-139.2z" />
<glyph unicode="&#xe999;" glyph-name="bug" d="M1024 384v64h-193.29c-5.862 72.686-31.786 139.026-71.67 192.25h161.944l70.060 280.24-62.090 15.522-57.94-231.76h-174.68c-0.892 0.694-1.796 1.374-2.698 2.056 6.71 19.502 10.362 40.422 10.362 62.194 0.002 105.76-85.958 191.498-191.998 191.498s-192-85.738-192-191.5c0-21.772 3.65-42.692 10.362-62.194-0.9-0.684-1.804-1.362-2.698-2.056h-174.68l-57.94 231.76-62.090-15.522 70.060-280.24h161.944c-39.884-53.222-65.806-119.562-71.668-192.248h-193.29v-64h193.37c3.802-45.664 15.508-88.812 33.638-127.75h-123.992l-70.060-280.238 62.090-15.524 57.94 231.762h112.354c58.692-78.032 147.396-127.75 246.66-127.75s187.966 49.718 246.662 127.75h112.354l57.94-231.762 62.090 15.524-70.060 280.238h-123.992c18.13 38.938 29.836 82.086 33.636 127.75h193.37z" />
<glyph unicode="&#xe9a8;" glyph-name="complaint" d="M1010.174 44.25l-548.634 499.458 25.534 25.598c20.894 20.954 32.188 48.030 33.918 75.61 1.002 0.45 2.002 0.912 2.958 1.442l102.99 64.402c13.934 16.392 12.916 42.268-2.284 57.502l-179.12 179.608c-15.19 15.234-40.998 16.262-57.344 2.284l-64.236-103.268c-0.526-0.966-0.99-1.966-1.44-2.974-27.502-1.736-54.5-13.056-75.398-34.006l-97.428-97.702c-20.898-20.956-32.184-48.026-33.918-75.604-1.004-0.45-2.004-0.916-2.964-1.446l-102.986-64.406c-13.942-16.39-12.916-42.264 2.276-57.496l179.12-179.604c15.194-15.238 40.996-16.262 57.35-2.286l64.228 103.27c0.528 0.958 0.988 1.96 1.442 2.966 27.502 1.738 54.504 13.050 75.398 34.004l28.292 28.372 498.122-550.114c14.436-15.944 36.7-18.518 49.474-5.712l50.356 50.488c12.764 12.808 10.196 35.132-5.706 49.614z" />
<glyph unicode="&#xe9ac;" glyph-name="bin" d="M128 640v-640c0-35.2 28.8-64 64-64h576c35.2 0 64 28.8 64 64v640h-704zM320 64h-64v448h64v-448zM448 64h-64v448h64v-448zM576 64h-64v448h64v-448zM704 64h-64v448h64v-448zM848 832h-208v80c0 26.4-21.6 48-48 48h-224c-26.4 0-48-21.6-48-48v-80h-208c-26.4 0-48-21.6-48-48v-80h832v80c0 26.4-21.6 48-48 48zM576 832h-192v63.198h192v-63.198z" />
<glyph unicode="&#xe9b3;" glyph-name="target" d="M1024 512h-100.924c-27.64 178.24-168.836 319.436-347.076 347.076v100.924h-128v-100.924c-178.24-27.64-319.436-168.836-347.076-347.076h-100.924v-128h100.924c27.64-178.24 168.836-319.436 347.076-347.076v-100.924h128v100.924c178.24 27.64 319.436 168.836 347.076 347.076h100.924v128zM792.822 512h-99.762c-19.284 54.55-62.51 97.778-117.060 117.060v99.762c107.514-24.49 192.332-109.31 216.822-216.822zM512 384c-35.346 0-64 28.654-64 64s28.654 64 64 64c35.346 0 64-28.654 64-64s-28.654-64-64-64zM448 728.822v-99.762c-54.55-19.282-97.778-62.51-117.060-117.060h-99.762c24.49 107.512 109.31 192.332 216.822 216.822zM231.178 384h99.762c19.282-54.55 62.51-97.778 117.060-117.060v-99.762c-107.512 24.49-192.332 109.308-216.822 216.822zM576 167.178v99.762c54.55 19.284 97.778 62.51 117.060 117.060h99.762c-24.49-107.514-109.308-192.332-216.822-216.822z" />
<glyph unicode="&#xe9b8;" glyph-name="evaluation" d="M928 832h-288c0 70.692-57.306 128-128 128-70.692 0-128-57.308-128-128h-288c-17.672 0-32-14.328-32-32v-832c0-17.674 14.328-32 32-32h832c17.674 0 32 14.326 32 32v832c0 17.672-14.326 32-32 32zM512 896c35.346 0 64-28.654 64-64s-28.654-64-64-64c-35.346 0-64 28.654-64 64s28.654 64 64 64zM896 0h-768v768h128v-96c0-17.672 14.328-32 32-32h448c17.674 0 32 14.328 32 32v96h128v-768zM448 101.49l-205.254 237.254 58.508 58.51 146.746-114.744 274.742 242.744 58.514-58.508z" />
<glyph unicode="&#xe9bc;" glyph-name="tree" d="M976 192h-16v208c0 61.756-50.242 112-112 112h-272v128h16c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-160c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-128h-272c-61.756 0-112-50.244-112-112v-208h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h160c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v192h256v-192h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h160c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v192h256v-192h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h160c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48zM192 0h-128v128h128v-128zM576 0h-128v128h128v-128zM448 704v128h128v-128h-128zM960 0h-128v128h128v-128z" />
<glyph unicode="&#xe9cb;" glyph-name="link" d="M440.236 324.234c-13.31 0-26.616 5.076-36.77 15.23-95.134 95.136-95.134 249.934 0 345.070l192 192c46.088 46.086 107.36 71.466 172.534 71.466s126.448-25.38 172.536-71.464c95.132-95.136 95.132-249.934 0-345.070l-87.766-87.766c-20.308-20.308-53.23-20.308-73.54 0-20.306 20.306-20.306 53.232 0 73.54l87.766 87.766c54.584 54.586 54.584 143.404 0 197.99-26.442 26.442-61.6 41.004-98.996 41.004s-72.552-14.562-98.996-41.006l-192-191.998c-54.586-54.586-54.586-143.406 0-197.992 20.308-20.306 20.306-53.232 0-73.54-10.15-10.152-23.462-15.23-36.768-15.23zM256-52c-65.176 0-126.45 25.38-172.534 71.464-95.134 95.136-95.134 249.934 0 345.070l87.764 87.764c20.308 20.306 53.234 20.306 73.54 0 20.308-20.306 20.308-53.232 0-73.54l-87.764-87.764c-54.586-54.586-54.586-143.406 0-197.992 26.44-26.44 61.598-41.002 98.994-41.002s72.552 14.562 98.998 41.006l192 191.998c54.584 54.586 54.584 143.406 0 197.992-20.308 20.308-20.306 53.232 0 73.54 20.306 20.306 53.232 20.306 73.54-0.002 95.132-95.134 95.132-249.932 0.002-345.068l-192.002-192c-46.090-46.088-107.364-71.466-172.538-71.466z" />
<glyph unicode="&#xe9cd;" glyph-name="attachment" d="M665.832 632.952l-64.952 64.922-324.81-324.742c-53.814-53.792-53.814-141.048 0-194.844 53.804-53.792 141.060-53.792 194.874 0l389.772 389.708c89.714 89.662 89.714 235.062 0 324.726-89.666 89.704-235.112 89.704-324.782 0l-409.23-409.178c-0.29-0.304-0.612-0.576-0.876-0.846-125.102-125.096-125.102-327.856 0-452.906 125.054-125.056 327.868-125.056 452.988 0 0.274 0.274 0.516 0.568 0.82 0.876l0.032-0.034 279.332 279.292-64.986 64.92-279.33-279.262c-0.296-0.268-0.564-0.57-0.846-0.844-89.074-89.058-233.98-89.058-323.076 0-89.062 89.042-89.062 233.922 0 322.978 0.304 0.304 0.604 0.582 0.888 0.846l-0.046 0.060 409.28 409.166c53.712 53.738 141.144 53.738 194.886 0 53.712-53.734 53.712-141.148 0-194.84l-389.772-389.7c-17.936-17.922-47.054-17.922-64.972 0-17.894 17.886-17.894 47.032 0 64.92l324.806 324.782z" />
<glyph unicode="&#xe9d7;" glyph-name="star-empty" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538zM512 206.502l-223.462-117.48 42.676 248.83-180.786 176.222 249.84 36.304 111.732 226.396 111.736-226.396 249.836-36.304-180.788-176.222 42.678-248.83-223.462 117.48z" />
<glyph unicode="&#xe9d8;" glyph-name="star-half" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538zM512 206.502l-0.942-0.496 0.942 570.768 111.736-226.396 249.836-36.304-180.788-176.222 42.678-248.83-223.462 117.48z" />
<glyph unicode="&#xe9d9;" glyph-name="star-full" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538z" />
<glyph unicode="&#xe9da;" glyph-name="heart" d="M755.188 896c-107.63 0-200.258-87.554-243.164-179-42.938 91.444-135.578 179-243.216 179-148.382 0-268.808-120.44-268.808-268.832 0-301.846 304.5-380.994 512.022-679.418 196.154 296.576 511.978 387.206 511.978 679.418 0 148.392-120.43 268.832-268.812 268.832z" />
<glyph unicode="&#xea15;" glyph-name="play2" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM384 672l384-224-384-224z" />
<glyph unicode="&#xea16;" glyph-name="pause" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM320 640h128v-384h-128zM576 640h128v-384h-128z" />
<glyph unicode="&#xea17;" glyph-name="stop1" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM320 640h384v-384h-384z" />
<glyph unicode="&#xea18;" glyph-name="previous" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM448 448l256 192v-384zM320 640h128v-384h-128v384z" />
<glyph unicode="&#xea19;" glyph-name="next" d="M512 960c282.77 0 512-229.23 512-512s-229.23-512-512-512-512 229.23-512 512 229.23 512 512 512zM512 32c229.75 0 416 186.25 416 416s-186.25 416-416 416-416-186.25-416-416 186.25-416 416-416zM576 448l-256 192v-384zM704 640h-128v-384h128v384z" />
<glyph unicode="&#xea1a;" glyph-name="backward" d="M512-64c282.77 0 512 229.23 512 512s-229.23 512-512 512-512-229.23-512-512 229.23-512 512-512zM512 864c229.75 0 416-186.25 416-416s-186.25-416-416-416-416 186.25-416 416 186.25 416 416 416zM704 288l-224 160 224 160zM448 288l-224 160 224 160z" />
<glyph unicode="&#xea1b;" glyph-name="forward2" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM320 608l224-160-224-160zM576 608l224-160-224-160z" />
<glyph unicode="&#xea2d;" glyph-name="loop" d="M128 640h640v-192l256 256-256 256v-192h-768v-384h128zM896 256h-640v192l-256-256 256-256v192h768v384h-128z" />
<glyph unicode="&#xea61;" glyph-name="font-size-up" d="M64 448h384v-128h-128v-384h-128v384h-128zM960 704h-251.75v-768h-136.5v768h-251.75v128h640z" />
<glyph unicode="&#xea64;" glyph-name="format-italic" d="M896 896v-64h-128l-320-768h128v-64h-448v64h128l320 768h-128v64z" />
<glyph unicode="&#xea7f;" glyph-name="embed" d="M576 224l96-96 320 320-320 320-96-96 224-224zM448 672l-96 96-320-320 320-320 96 96-224 224z" />
<glyph unicode="&#xeaac;" glyph-name="steam" d="M704 672c0 53.019 42.981 96 96 96s96-42.981 96-96c0-53.019-42.981-96-96-96s-96 42.981-96 96zM958.392 830.392c-87.478 87.476-229.306 87.476-316.786 0-35.578-35.578-56.684-80.146-63.322-126.392v0l-204.694-310.228c-27.506-1.41-54.776-8.416-79.966-21.016l-157.892 123.424c-36.55 28.574-89.342 22.102-117.912-14.448-28.572-36.55-22.102-89.342 14.448-117.912l155.934-121.892c-16.96-66.782 0.672-140.538 52.93-192.794 78.906-78.904 206.832-78.904 285.736 0 48.466 48.466 67.15 115.428 56.076 178.166l249.054 222.986c46.248 6.638 90.816 27.744 126.394 63.322 87.478 87.476 87.478 229.306 0 316.784zM384 57.302c-74.39 0-134.698 60.304-134.698 134.698 0 0.712 0.042 1.414 0.054 2.124l66.912-52.304c15.36-12.006 33.582-17.824 51.674-17.824 24.962 0 49.672 11.080 66.238 32.272 28.572 36.55 22.102 89.342-14.448 117.912l-63.5 49.636c8.962 1.878 18.248 2.88 27.768 2.88 74.392 0 134.698-60.304 134.698-134.698s-60.306-134.696-134.698-134.696zM800 512c-88.366 0-160 71.634-160 160s71.634 160 160 160 160-71.634 160-160-71.634-160-160-160z" />
<glyph unicode="&#xeaae;" glyph-name="dropbox" d="M736 928l-224-192 288-192 224 192zM512 736l-224 192-288-192 224-192zM800 544l224-192-288-160-224 192zM512 384l-288 160-224-192 288-160zM728.156 114.43l-216.156 185.278-216.158-185.278-135.842 75.468v-93.898l352-160 352 160v93.898z" />
<glyph unicode="&#xeabd;" glyph-name="tux" d="M567.656 223.084c-81.944-38.118-158.158-37.716-209.34-34.020-61.052 4.41-110.158 21.124-131.742 35.732-13.3 9.006-31.384 5.522-40.39-7.782-9.004-13.302-5.52-31.386 7.782-40.39 34.698-23.486 96.068-40.954 160.162-45.58 10.866-0.784 22.798-1.278 35.646-1.278 55.782 0 126.626 5.316 202.42 40.57 14.564 6.778 20.878 24.074 14.104 38.64-6.776 14.566-24.076 20.872-38.642 14.108zM890.948 266.184c2.786 252.688 28.762 730.206-454.97 691.612-477.6-38.442-350.964-542.968-358.082-711.95-6.308-89.386-35.978-198.648-77.896-309.846h129.1c13.266 47.122 23.024 93.72 27.232 138.15 7.782-5.428 16.108-10.674 24.994-15.7 14.458-8.518 26.884-19.844 40.040-31.834 30.744-28.018 65.59-59.774 133.712-63.752 4.572-0.262 9.174-0.394 13.676-0.394 68.896 0 116.014 30.154 153.878 54.382 18.14 11.612 33.818 21.64 48.564 26.452 41.91 13.12 78.532 34.296 105.904 61.252 4.276 4.208 8.242 8.538 11.962 12.948 15.246-55.878 36.118-118.758 59.288-181.504h275.65c-66.174 102.224-134.436 202.374-133.052 330.184zM124.11 403.648c0 0.016 0 0.030-0.002 0.046-4.746 82.462 34.71 151.832 88.126 154.936 53.412 3.106 100.56-61.228 105.304-143.692 0-0.014 0.004-0.030 0.004-0.044 0.256-4.446 0.368-8.846 0.37-13.206-16.924-4.256-32.192-10.436-45.872-17.63-0.052 0.612-0.092 1.216-0.152 1.83 0 0.008 0 0.018 0 0.026-4.57 46.81-29.572 82.16-55.852 78.958-26.28-3.204-43.88-43.75-39.312-90.558 0-0.010 0.004-0.018 0.004-0.026 1.992-20.408 7.868-38.636 16.042-52.444-2.034-1.604-7.784-5.812-14.406-10.656-4.97-3.634-11.020-8.058-18.314-13.43-19.882 26.094-33.506 63.58-35.94 105.89zM665.26 199.822c-1.9-43.586-58.908-84.592-111.582-101.044l-0.296-0.096c-21.9-7.102-41.428-19.6-62.104-32.83-34.732-22.224-70.646-45.208-122.522-45.208-3.404 0-6.894 0.104-10.326 0.296-47.516 2.778-69.742 23.032-97.88 48.676-14.842 13.526-30.19 27.514-49.976 39.124l-0.424 0.244c-42.706 24.104-69.212 54.082-70.908 80.194-0.842 12.98 4.938 24.218 17.182 33.4 26.636 19.972 44.478 33.022 56.284 41.658 13.11 9.588 17.068 12.48 20 15.264 2.096 1.986 4.364 4.188 6.804 6.562 24.446 23.774 65.36 63.562 128.15 63.562 38.404 0 80.898-14.8 126.17-43.902 21.324-13.878 39.882-20.286 63.38-28.4 16.156-5.578 34.468-11.902 58.992-22.404l0.396-0.164c22.88-9.404 49.896-26.564 48.66-54.932zM652.646 302.194c-4.4 2.214-8.974 4.32-13.744 6.286-22.106 9.456-39.832 15.874-54.534 20.998 8.116 15.894 13.16 35.72 13.624 57.242 0 0.010 0 0.022 0 0.030 1.126 52.374-25.288 94.896-58.996 94.976-33.71 0.078-61.95-42.314-63.076-94.686 0-0.010 0-0.018 0-0.028-0.038-1.714-0.042-3.416-0.020-5.11-20.762 9.552-41.18 16.49-61.166 20.76-0.092 1.968-0.204 3.932-0.244 5.92 0 0.016 0 0.036 0 0.050-1.938 95.412 56.602 174.39 130.754 176.402 74.15 2.014 135.828-73.7 137.772-169.11 0-0.018 0-0.038 0-0.052 0.874-43.146-10.66-82.866-30.37-113.678z" />
<glyph unicode="&#xeadf;" glyph-name="pdf" d="M842.012 370.52c-13.648 13.446-43.914 20.566-89.972 21.172-31.178 0.344-68.702-2.402-108.17-7.928-17.674 10.198-35.892 21.294-50.188 34.658-38.462 35.916-70.568 85.772-90.576 140.594 1.304 5.12 2.414 9.62 3.448 14.212 0 0 21.666 123.060 15.932 164.666-0.792 5.706-1.276 7.362-2.808 11.796l-1.882 4.834c-5.894 13.592-17.448 27.994-35.564 27.208l-10.916 0.344c-20.202 0-36.664-10.332-40.986-25.774-13.138-48.434 0.418-120.892 24.98-214.738l-6.288-15.286c-17.588-42.876-39.63-86.060-59.078-124.158l-2.528-4.954c-20.46-40.040-39.026-74.028-55.856-102.822l-17.376-9.188c-1.264-0.668-31.044-16.418-38.028-20.644-59.256-35.38-98.524-75.542-105.038-107.416-2.072-10.17-0.53-23.186 10.014-29.212l16.806-8.458c7.292-3.652 14.978-5.502 22.854-5.502 42.206 0 91.202 52.572 158.698 170.366 77.93 25.37 166.652 46.458 244.412 58.090 59.258-33.368 132.142-56.544 178.142-56.544 8.168 0 15.212 0.78 20.932 2.294 8.822 2.336 16.258 7.368 20.792 14.194 8.926 13.432 10.734 31.932 8.312 50.876-0.72 5.622-5.21 12.574-10.068 17.32zM211.646 145.952c7.698 21.042 38.16 62.644 83.206 99.556 2.832 2.296 9.808 8.832 16.194 14.902-47.104-75.124-78.648-105.066-99.4-114.458zM478.434 760.314c13.566 0 21.284-34.194 21.924-66.254s-6.858-54.56-16.158-71.208c-7.702 24.648-11.426 63.5-11.426 88.904 0 0-0.566 48.558 5.66 48.558v0zM398.852 322.506c9.45 16.916 19.282 34.756 29.33 53.678 24.492 46.316 39.958 82.556 51.478 112.346 22.91-41.684 51.444-77.12 84.984-105.512 4.186-3.542 8.62-7.102 13.276-10.65-68.21-13.496-127.164-29.91-179.068-49.862v0zM828.902 326.348c-4.152-2.598-16.052-4.1-23.708-4.1-24.708 0-55.272 11.294-98.126 29.666 16.468 1.218 31.562 1.838 45.102 1.838 24.782 0 32.12 0.108 56.35-6.072 24.228-6.18 24.538-18.734 20.382-21.332v0zM917.806 730.924c-22.21 30.292-53.174 65.7-87.178 99.704s-69.412 64.964-99.704 87.178c-51.574 37.82-76.592 42.194-90.924 42.194h-496c-44.112 0-80-35.888-80-80v-864c0-44.112 35.886-80 80-80h736c44.112 0 80 35.888 80 80v624c0 14.332-4.372 39.35-42.194 90.924v0zM785.374 785.374c30.7-30.7 54.8-58.398 72.58-81.374h-153.954v153.946c22.982-17.78 50.678-41.878 81.374-72.572v0zM896 16c0-8.672-7.328-16-16-16h-736c-8.672 0-16 7.328-16 16v864c0 8.672 7.328 16 16 16 0 0 495.956 0.002 496 0v-224c0-17.672 14.324-32 32-32h224v-624z" />
<glyph unicode="&#xeae2;" glyph-name="xls" d="M743.028 576h-135.292l-95.732-141.032-95.742 141.032h-135.29l162.162-242.464-182.972-269.536h251.838v91.576h-50.156l50.156 74.994 111.396-166.57h140.444l-182.976 269.536 162.164 242.464zM917.806 730.924c-22.21 30.292-53.174 65.7-87.178 99.704s-69.412 64.964-99.704 87.178c-51.574 37.82-76.592 42.194-90.924 42.194h-496c-44.112 0-80-35.888-80-80v-864c0-44.112 35.886-80 80-80h736c44.112 0 80 35.888 80 80v624c0 14.332-4.372 39.35-42.194 90.924v0zM785.374 785.374c30.7-30.7 54.8-58.398 72.58-81.374h-153.954v153.946c22.982-17.78 50.678-41.878 81.374-72.572v0zM896 16c0-8.672-7.328-16-16-16h-736c-8.672 0-16 7.328-16 16v864c0 8.672 7.328 16 16 16 0 0 495.956 0.002 496 0v-224c0-17.672 14.324-32 32-32h224v-624z" />
<glyph unicode="&#xeae8;" glyph-name="codepen" d="M945.75 591.958l-448 298.666c-10.748 7.166-24.752 7.166-35.5 0l-448-298.666c-8.902-5.934-14.25-15.926-14.25-26.624v-298.666c0-10.7 5.348-20.692 14.25-26.624l448-298.666c5.374-3.584 11.562-5.376 17.75-5.376s12.376 1.792 17.75 5.376l448 298.666c8.902 5.934 14.25 15.926 14.25 26.624v298.666c0 10.698-5.348 20.69-14.25 26.624zM480 305.124l-166.312 110.876 166.312 110.874 166.312-110.874-166.312-110.876zM512 582.458v221.75l358.31-238.876-166.31-110.874-192 128zM448 582.458l-192-128-166.312 110.874 358.312 238.876v-221.75zM198.312 416l-134.312-89.542v179.082l134.312-89.54zM256 377.542l192-128v-221.748l-358.312 238.872 166.312 110.876zM512 249.542l192 128 166.312-110.876-358.312-238.874v221.75zM761.688 416l134.312 89.54v-179.084l-134.312 89.544z" />
<glyph unicode="&#xf002;" glyph-name="search" horiz-adv-x="951" d="M658.286 475.428c0 141.143-114.857 256-256 256s-256-114.857-256-256 114.857-256 256-256 256 114.857 256 256zM950.857 0c0-40-33.143-73.143-73.143-73.143-19.429 0-38.286 8-51.429 21.714l-196 195.429c-66.857-46.286-146.857-70.857-228-70.857-222.286 0-402.286 180-402.286 402.286s180 402.286 402.286 402.286 402.286-180 402.286-402.286c0-81.143-24.571-161.143-70.857-228l196-196c13.143-13.143 21.143-32 21.143-51.429z" />
<glyph unicode="&#xf007;" glyph-name="user" horiz-adv-x="731" d="M731.429 151.428c0-83.429-54.857-151.429-121.714-151.429h-488c-66.857 0-121.714 68-121.714 151.429 0 150.286 37.143 324 186.857 324 46.286-45.143 109.143-73.143 178.857-73.143s132.571 28 178.857 73.143c149.714 0 186.857-173.714 186.857-324zM585.143 658.286c0-121.143-98.286-219.429-219.429-219.429s-219.429 98.286-219.429 219.429 98.286 219.429 219.429 219.429 219.429-98.286 219.429-219.429z" />
<glyph unicode="&#xf011;" glyph-name="logoff" horiz-adv-x="878" d="M877.714 438.857c0-241.714-197.143-438.857-438.857-438.857s-438.857 197.143-438.857 438.857c0 138.857 64 266.857 175.429 350.286 32.571 24.571 78.286 18.286 102.286-14.286 24.571-32 17.714-78.286-14.286-102.286-74.286-56-117.143-141.143-117.143-233.714 0-161.143 131.429-292.571 292.571-292.571s292.571 131.429 292.571 292.571c0 92.571-42.857 177.714-117.143 233.714-32 24-38.857 70.286-14.286 102.286 24 32.571 70.286 38.857 102.286 14.286 111.429-83.429 175.429-211.429 175.429-350.286zM512 877.714v-365.714c0-40-33.143-73.143-73.143-73.143s-73.143 33.143-73.143 73.143v365.714c0 40 33.143 73.143 73.143 73.143s73.143-33.143 73.143-73.143z" />
<glyph unicode="&#xf040;" glyph-name="edit" horiz-adv-x="866" d="M207.429 73.143l52 52-134.286 134.286-52-52v-61.143h73.143v-73.143h61.143zM506.286 603.428c0 7.429-5.143 12.571-12.571 12.571-3.429 0-6.857-1.143-9.714-4l-309.714-309.714c-2.857-2.857-4-6.286-4-9.714 0-7.429 5.143-12.571 12.571-12.571 3.429 0 6.857 1.143 9.714 4l309.714 309.714c2.857 2.857 4 6.286 4 9.714zM475.429 713.143l237.714-237.714-475.429-475.429h-237.714v237.714zM865.714 658.286c0-19.429-8-38.286-21.143-51.429l-94.857-94.857-237.714 237.714 94.857 94.286c13.143 13.714 32 21.714 51.429 21.714s38.286-8 52-21.714l134.286-133.714c13.143-13.714 21.143-32.571 21.143-52z" />
<glyph unicode="&#xf046;" glyph-name="checked" horiz-adv-x="955" d="M804.571 419.428v-181.714c0-90.857-73.714-164.571-164.571-164.571h-475.429c-90.857 0-164.571 73.714-164.571 164.571v475.429c0 90.857 73.714 164.571 164.571 164.571h475.429c22.857 0 45.714-4.571 66.857-14.286 5.143-2.286 9.143-7.429 10.286-13.143 1.143-6.286-0.571-12-5.143-16.571l-28-28c-3.429-3.429-8.571-5.714-13.143-5.714-1.714 0-3.429 0.571-5.143 1.143-8.571 2.286-17.143 3.429-25.714 3.429h-475.429c-50.286 0-91.429-41.143-91.429-91.429v-475.429c0-50.286 41.143-91.429 91.429-91.429h475.429c50.286 0 91.429 41.143 91.429 91.429v145.143c0 4.571 1.714 9.143 5.143 12.571l36.571 36.571c4 4 8.571 5.714 13.143 5.714 2.286 0 4.571-0.571 6.857-1.714 6.857-2.857 11.429-9.143 11.429-16.571zM936.571 698.857l-465.143-465.143c-18.286-18.286-46.857-18.286-65.143 0l-245.714 245.714c-18.286 18.286-18.286 46.857 0 65.143l62.857 62.857c18.286 18.286 46.857 18.286 65.143 0l150.286-150.286 369.714 369.714c18.286 18.286 46.857 18.286 65.143 0l62.857-62.857c18.286-18.286 18.286-46.857 0-65.143z" />
<glyph unicode="&#xf05a;" glyph-name="info" horiz-adv-x="878" d="M585.143 164.571v91.429c0 10.286-8 18.286-18.286 18.286h-54.857v292.571c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-91.429c0-10.286 8-18.286 18.286-18.286h54.857v-182.857h-54.857c-10.286 0-18.286-8-18.286-18.286v-91.429c0-10.286 8-18.286 18.286-18.286h256c10.286 0 18.286 8 18.286 18.286zM512 676.571v91.429c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-91.429c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM877.714 438.857c0-242.286-196.571-438.857-438.857-438.857s-438.857 196.571-438.857 438.857 196.571 438.857 438.857 438.857 438.857-196.571 438.857-438.857z" />
<glyph unicode="&#xf065;" glyph-name="expand" horiz-adv-x="878" d="M431.429 347.428c0-4.571-2.286-9.714-5.714-13.143l-189.714-189.714 82.286-82.286c6.857-6.857 10.857-16 10.857-25.714 0-20-16.571-36.571-36.571-36.571h-256c-20 0-36.571 16.571-36.571 36.571v256c0 20 16.571 36.571 36.571 36.571 9.714 0 18.857-4 25.714-10.857l82.286-82.286 189.714 189.714c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l65.143-65.143c3.429-3.429 5.714-8.571 5.714-13.143zM877.714 841.143v-256c0-20-16.571-36.571-36.571-36.571-9.714 0-18.857 4-25.714 10.857l-82.286 82.286-189.714-189.714c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-65.143 65.143c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l189.714 189.714-82.286 82.286c-6.857 6.857-10.857 16-10.857 25.714 0 20 16.571 36.571 36.571 36.571h256c20 0 36.571-16.571 36.571-36.571z" />
<glyph unicode="&#xf067;" glyph-name="plus" horiz-adv-x="805" d="M804.571 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-237.714v-237.714c0-30.286-24.571-54.857-54.857-54.857h-109.714c-30.286 0-54.857 24.571-54.857 54.857v237.714h-237.714c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h237.714v237.714c0 30.286 24.571 54.857 54.857 54.857h109.714c30.286 0 54.857-24.571 54.857-54.857v-237.714h237.714c30.286 0 54.857-24.571 54.857-54.857z" />
<glyph unicode="&#xf071;" glyph-name="warning" d="M585.143 165.143v108.571c0 10.286-8 18.857-18.286 18.857h-109.714c-10.286 0-18.286-8.571-18.286-18.857v-108.571c0-10.286 8-18.857 18.286-18.857h109.714c10.286 0 18.286 8.571 18.286 18.857zM584 378.857l10.286 262.286c0 3.429-1.714 8-5.714 10.857-3.429 2.857-8.571 6.286-13.714 6.286h-125.714c-5.143 0-10.286-3.429-13.714-6.286-4-2.857-5.714-8.571-5.714-12l9.714-261.143c0-7.429 8.571-13.143 19.429-13.143h105.714c10.286 0 18.857 5.714 19.429 13.143zM576 912.571l438.857-804.571c12.571-22.286 12-49.714-1.143-72s-37.143-36-62.857-36h-877.714c-25.714 0-49.714 13.714-62.857 36s-13.714 49.714-1.143 72l438.857 804.571c12.571 23.429 37.143 38.286 64 38.286s51.429-14.857 64-38.286z" />
<glyph unicode="&#xf073;" glyph-name="calendar" horiz-adv-x="951" d="M73.143 0h164.571v164.571h-164.571v-164.571zM274.286 0h182.857v164.571h-182.857v-164.571zM73.143 201.143h164.571v182.857h-164.571v-182.857zM274.286 201.143h182.857v182.857h-182.857v-182.857zM73.143 420.571h164.571v164.571h-164.571v-164.571zM493.714 0h182.857v164.571h-182.857v-164.571zM274.286 420.571h182.857v164.571h-182.857v-164.571zM713.143 0h164.571v164.571h-164.571v-164.571zM493.714 201.143h182.857v182.857h-182.857v-182.857zM292.571 694.857v164.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-164.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM713.143 201.143h164.571v182.857h-164.571v-182.857zM493.714 420.571h182.857v164.571h-182.857v-164.571zM713.143 420.571h164.571v164.571h-164.571v-164.571zM731.429 694.857v164.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-164.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM950.857 731.428v-731.429c0-40-33.143-73.143-73.143-73.143h-804.571c-40 0-73.143 33.143-73.143 73.143v731.429c0 40 33.143 73.143 73.143 73.143h73.143v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h219.429v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h73.143c40 0 73.143-33.143 73.143-73.143z" />
<glyph unicode="&#xf075;" glyph-name="comment" d="M1024 438.857c0-202.286-229.143-365.714-512-365.714-28 0-56 1.714-82.857 4.571-74.857-66.286-164-113.143-262.857-138.286-20.571-5.714-42.857-9.714-65.143-12.571-12.571-1.143-24.571 8-27.429 21.714v0.571c-2.857 14.286 6.857 22.857 15.429 33.143 36 40.571 77.143 74.857 104 170.286-117.714 66.857-193.143 170.286-193.143 286.286 0 201.714 229.143 365.714 512 365.714s512-163.429 512-365.714z" />
<glyph unicode="&#xf081;" glyph-name="twitter" horiz-adv-x="878" d="M731.429 602.286c-21.714-9.714-44.571-16-69.143-19.429 25.143 14.857 44 38.857 53.143 66.857-23.429-13.714-49.143-24-76.571-29.143-21.714 23.429-53.143 37.714-87.429 37.714-66.286 0-120-53.714-120-120 0-9.143 0.571-18.857 2.857-27.429-100 5.143-188.571 52.571-248 125.714-10.286-17.714-16.571-38.857-16.571-60.571 0-41.714 19.429-78.286 52-100-20 0.571-38.857 6.286-57.143 14.857v-1.143c0-58.286 44-106.857 98.857-117.714-10.286-2.857-18.286-4.571-29.143-4.571-7.429 0-14.857 1.143-22.286 2.286 15.429-47.429 59.429-82.286 112-83.429-41.143-32-92.571-51.429-149.143-51.429-9.714 0-19.429 0.571-28.571 1.714 53.143-33.714 116-53.714 184-53.714 220.571 0 341.714 182.857 341.714 341.714 0 5.143 0 10.286-0.571 15.429 23.429 16.571 44 37.714 60 62.286zM877.714 713.143v-548.571c0-90.857-73.714-164.571-164.571-164.571h-548.571c-90.857 0-164.571 73.714-164.571 164.571v548.571c0 90.857 73.714 164.571 164.571 164.571h548.571c90.857 0 164.571-73.714 164.571-164.571z" />
<glyph unicode="&#xf082;" glyph-name="facebook" horiz-adv-x="878" d="M713.143 877.714c90.857 0 164.571-73.714 164.571-164.571v-548.571c0-90.857-73.714-164.571-164.571-164.571h-107.429v340h113.714l17.143 132.571h-130.857v84.571c0 38.286 10.286 64 65.714 64l69.714 0.571v118.286c-12 1.714-53.714 5.143-101.714 5.143-101.143 0-170.857-61.714-170.857-174.857v-97.714h-114.286v-132.571h114.286v-340h-304c-90.857 0-164.571 73.714-164.571 164.571v548.571c0 90.857 73.714 164.571 164.571 164.571h548.571z" />
<glyph unicode="&#xf096;" glyph-name="square-o" horiz-adv-x="805" d="M640 804.571h-475.429c-50.286 0-91.429-41.143-91.429-91.429v-475.429c0-50.286 41.143-91.429 91.429-91.429h475.429c50.286 0 91.429 41.143 91.429 91.429v475.429c0 50.286-41.143 91.429-91.429 91.429zM804.571 713.143v-475.429c0-90.857-73.714-164.571-164.571-164.571h-475.429c-90.857 0-164.571 73.714-164.571 164.571v475.429c0 90.857 73.714 164.571 164.571 164.571h475.429c90.857 0 164.571-73.714 164.571-164.571z" />
<glyph unicode="&#xf0ac;" glyph-name="website" horiz-adv-x="878" d="M438.857 877.714c242.286 0 438.857-196.571 438.857-438.857s-196.571-438.857-438.857-438.857-438.857 196.571-438.857 438.857 196.571 438.857 438.857 438.857zM595.429 580c-4.571-3.429-7.429-9.714-13.143-10.857 2.857 0.571 5.714 10.857 7.429 13.143 3.429 4 8 6.286 12.571 8.571 9.714 4 19.429 5.143 29.714 6.857 9.714 2.286 21.714 2.286 29.143-6.286-1.714 1.714 12 13.714 13.714 14.286 5.143 2.857 13.714 1.714 17.143 6.857 1.143 1.714 1.143 12.571 1.143 12.571-9.714-1.143-13.143 8-13.714 16 0-0.571-1.143-2.286-3.429-4.571 0.571 8.571-10.286 2.286-14.286 3.429-13.143 3.429-11.429 12.571-15.429 22.286-2.286 5.143-8.571 6.857-10.857 12-2.286 3.429-3.429 10.857-8.571 11.429-3.429 0.571-9.714-12-10.857-11.429-5.143 2.857-7.429-1.143-11.429-3.429-3.429-2.286-6.286-1.143-9.714-2.857 10.286 3.429-4.571 9.143-9.714 8 8 2.286 4 10.857-0.571 14.857h2.857c-1.143 5.143-17.143 9.714-22.286 13.143s-32.571 9.143-38.286 5.714c-6.857-4 1.714-15.429 1.714-21.143 0.571-6.857-6.857-8.571-6.857-14.286 0-9.714 18.286-8 13.714-21.143-2.857-8-13.714-9.714-18.286-16-4.571-5.714 0.571-16 5.143-20 4.571-3.429-8-9.143-9.714-10.286-9.714-4.571-17.143 9.714-19.429 18.286-1.714 6.286-2.286 13.714-9.143 17.143-3.429 1.143-14.286 2.857-16.571-0.571-3.429 8.571-15.429 12-23.429 14.857-11.429 4-21.143 4-33.143 2.286 4 0.571-1.143 18.286-10.857 15.429 2.857 5.714 1.714 12 2.857 17.714 1.143 4.571 3.429 9.143 6.857 13.143 1.143 2.286 13.714 15.429 9.714 16 9.714-1.143 20.571-1.714 28.571 6.286 5.143 5.143 7.429 13.714 12.571 19.429 7.429 8.571 16.571-2.286 24.571-2.857 11.429-0.571 10.857 12 4.571 17.714 7.429-0.571 1.143 13.143-2.857 14.857-5.143 1.714-24.571-3.429-14.286-7.429-2.286 1.143-16-27.429-24-13.143-2.286 2.857-3.429 14.857-8.571 15.429-4.571 0-7.429-5.143-9.143-8.571 2.857 7.429-16 12.571-20 13.143 8.571 5.714 1.714 12-4.571 15.429-4.571 2.857-18.857 5.143-22.857 0.571-10.857-13.143 11.429-14.857 17.143-18.286 1.714-1.143 8.571-5.143 4.571-8-3.429-1.714-13.714-4.571-14.857-6.857-3.429-5.143 4-10.857-1.143-16-5.143 5.143-5.143 13.714-9.143 19.429 5.143-6.286-20.571-2.857-20-2.857-8.571 0-22.286-5.714-28.571 2.857-1.143 2.286-1.143 15.429 2.286 12.571-5.143 4-8.571 8-12 10.286-18.857-6.286-36.571-14.286-53.714-23.429 2.286-0.571 4-0.571 6.857 0.571 4.571 1.714 8.571 4.571 13.143 6.857 5.714 2.286 17.714 9.143 24 4 0.571 1.143 2.286 2.286 2.857 2.857 4-4.571 8-9.143 11.429-14.286-4.571 2.286-12 1.143-17.143 0.571-4-1.143-10.857-2.286-12.571-6.857 1.714-2.857 4-7.429 2.857-10.286-7.429 5.143-13.143 13.714-23.429 14.857-4.571 0-9.143 0-12.571-0.571-54.857-30.286-101.143-74.286-134.286-126.857 2.286-2.286 4.571-4 6.857-4.571 5.714-1.714 0-18.286 10.857-9.714 3.429-2.857 4-6.857 1.714-10.857 0.571 0.571 23.429-14.286 25.143-15.429 4-3.429 10.286-7.429 12-12 1.143-4-2.286-8.571-5.714-10.286-0.571 1.143-9.143 9.714-10.286 7.429-1.714-2.857 0-18.286 6.286-17.714-9.143-0.571-5.143-36-7.429-42.857 0-0.571 1.143-0.571 1.143-0.571-1.714-6.857 4-33.714 15.429-30.857-7.429-1.714 13.143-28 16-29.714 7.429-5.143 16-8.571 21.143-16 5.714-8 5.714-20 13.714-26.286-2.286-6.857 12-14.857 11.429-24.571-1.143-0.571-1.714-0.571-2.857-1.143 2.857-8 13.714-8 17.714-15.429 2.286-4.571 0-15.429 7.429-13.143 1.143 12.571-7.429 25.143-13.714 35.429-3.429 5.714-6.857 10.857-9.714 16.571-2.857 5.143-3.429 11.429-5.714 17.143 2.286-0.571 14.857-5.143 13.714-6.857-4.571-11.429 18.286-31.429 24.571-38.857 1.714-1.714 14.857-18.857 8-18.857 7.429 0 17.714-11.429 21.143-17.143 5.143-8.571 4-19.429 7.429-28.571 3.429-11.429 19.429-16.571 28.571-21.714 8-4 14.857-9.714 22.857-12.571 12-4.571 14.857-0.571 25.143 1.143 14.857 2.286 16.571-14.286 28.571-20.571 7.429-4 23.429-9.714 31.429-6.286-3.429-1.143 12-24.571 13.143-26.286 5.143-6.857 14.857-10.286 20.571-17.143 1.714 1.143 3.429 2.857 4 5.143-2.286-6.286 8.571-18.286 14.286-17.143 6.286 1.143 8 13.714 8 18.286-11.429-5.714-21.714-1.143-28 10.286-1.143 2.857-10.286 18.857-2.286 18.857 10.857 0 3.429 8.571 2.286 16.571s-9.143 13.143-13.143 20c-3.429-6.857-14.857-5.143-18.286 0.571 0-1.714-1.714-4.571-1.714-6.857-2.857 0-5.714-0.571-8.571 0.571 1.143 6.857 1.714 15.429 3.429 22.857 2.857 10.286 21.714 30.286-2.857 29.143-8.571-0.571-12-4-14.857-11.429-2.857-6.857-1.714-13.143-9.714-16.571-5.143-2.286-22.286-1.143-27.429 1.714-10.857 6.286-18.286 26.286-18.286 37.714-0.571 15.429 7.429 29.143 0 43.429 3.429 2.857 6.857 8.571 10.857 11.429 3.429 2.286 7.429-1.714 9.143 5.143-1.714 1.143-4 3.429-4.571 3.429 8.571-4 24.571 5.714 32 0 4.571-3.429 9.714-4.571 12.571 1.143 0.571 1.714-4 8.571-1.714 13.143 1.714-9.714 8-11.429 16.571-5.143 3.429-3.429 12.571-2.286 18.857-5.714 6.286-4 7.429-10.286 14.857-1.714 4.571-6.857 5.143-6.857 6.857-13.714 1.714-6.286 5.143-22.286 10.857-25.143 12-7.429 9.143 12.571 8 19.429-0.571 0.571-0.571 19.429-1.143 19.429-18.286 4-11.429 18.286-1.143 28 1.714 1.143 14.857 5.714 20.571 10.286 5.143 4.571 11.429 12.571 8.571 20 2.857 0 5.1Line truncated
<glyph unicode="&#xf0c0;" glyph-name="users" horiz-adv-x="1097" d="M338.857 438.857c-59.429-1.714-113.143-27.429-151.429-73.143h-76.571c-57.143 0-110.857 27.429-110.857 90.857 0 46.286-1.714 201.714 70.857 201.714 12 0 71.429-48.571 148.571-48.571 26.286 0 51.429 4.571 76 13.143-1.714-12.571-2.857-25.143-2.857-37.714 0-52 16.571-103.429 46.286-146.286zM950.857 74.857c0-92.571-61.143-148-152.571-148h-499.429c-91.429 0-152.571 55.429-152.571 148 0 129.143 30.286 327.429 197.714 327.429 19.429 0 90.286-79.429 204.571-79.429s185.143 79.429 204.571 79.429c167.429 0 197.714-198.286 197.714-327.429zM365.714 804.571c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286 65.714 146.286 146.286 146.286 146.286-65.714 146.286-146.286zM768 585.143c0-121.143-98.286-219.429-219.429-219.429s-219.429 98.286-219.429 219.429 98.286 219.429 219.429 219.429 219.429-98.286 219.429-219.429zM1097.143 456.571c0-63.429-53.714-90.857-110.857-90.857h-76.571c-38.286 45.714-92 71.429-151.429 73.143 29.714 42.857 46.286 94.286 46.286 146.286 0 12.571-1.143 25.143-2.857 37.714 24.571-8.571 49.714-13.143 76-13.143 77.143 0 136.571 48.571 148.571 48.571 72.571 0 70.857-155.429 70.857-201.714zM1024 804.571c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286 65.714 146.286 146.286 146.286 146.286-65.714 146.286-146.286z" />
<glyph unicode="&#xf0ca;" glyph-name="list-ul" d="M219.429 146.286c0-60.571-49.143-109.714-109.714-109.714s-109.714 49.143-109.714 109.714 49.143 109.714 109.714 109.714 109.714-49.143 109.714-109.714zM219.429 438.857c0-60.571-49.143-109.714-109.714-109.714s-109.714 49.143-109.714 109.714 49.143 109.714 109.714 109.714 109.714-49.143 109.714-109.714zM1024 201.143v-109.714c0-9.714-8.571-18.286-18.286-18.286h-694.857c-9.714 0-18.286 8.571-18.286 18.286v109.714c0 9.714 8.571 18.286 18.286 18.286h694.857c9.714 0 18.286-8.571 18.286-18.286zM219.429 731.428c0-60.571-49.143-109.714-109.714-109.714s-109.714 49.143-109.714 109.714 49.143 109.714 109.714 109.714 109.714-49.143 109.714-109.714zM1024 493.714v-109.714c0-9.714-8.571-18.286-18.286-18.286h-694.857c-9.714 0-18.286 8.571-18.286 18.286v109.714c0 9.714 8.571 18.286 18.286 18.286h694.857c9.714 0 18.286-8.571 18.286-18.286zM1024 786.286v-109.714c0-9.714-8.571-18.286-18.286-18.286h-694.857c-9.714 0-18.286 8.571-18.286 18.286v109.714c0 9.714 8.571 18.286 18.286 18.286h694.857c9.714 0 18.286-8.571 18.286-18.286z" />
<glyph unicode="&#xf0ce;" glyph-name="table" horiz-adv-x="951" d="M292.571 164.571v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM292.571 384v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM585.143 164.571v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM292.571 603.428v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM585.143 384v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM877.714 164.571v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM585.143 603.428v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM877.714 384v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM877.714 603.428v109.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM950.857 786.286v-621.714c0-50.286-41.143-91.429-91.429-91.429h-768c-50.286 0-91.429 41.143-91.429 91.429v621.714c0 50.286 41.143 91.429 91.429 91.429h768c50.286 0 91.429-41.143 91.429-91.429z" />
<glyph unicode="&#xf0ec;" glyph-name="exchange" d="M1024 274.286v-109.714c0-9.714-8.571-18.286-18.286-18.286h-786.286v-109.714c0-9.714-8-18.286-18.286-18.286-5.143 0-9.714 2.286-13.714 5.714l-182.286 182.857c-3.429 3.429-5.143 8-5.143 12.571 0 5.143 1.714 9.714 5.143 13.143l182.857 182.857c3.429 3.429 8.571 5.143 13.143 5.143 9.714 0 18.286-8 18.286-18.286v-109.714h786.286c9.714 0 18.286-8 18.286-18.286zM1024 585.143c0-4.571-1.714-9.714-5.143-13.143l-182.857-182.857c-3.429-3.429-8.571-5.143-13.143-5.143-9.714 0-18.286 8.571-18.286 18.286v109.714h-786.286c-9.714 0-18.286 8.571-18.286 18.286v109.714c0 9.714 8.571 18.286 18.286 18.286h786.286v109.714c0 10.286 8 18.286 18.286 18.286 5.143 0 9.714-2.286 13.714-5.714l182.286-182.286c3.429-3.429 5.143-8.571 5.143-13.143z" />
<glyph unicode="&#xf0f3;" glyph-name="alert" d="M521.143-18.286c0 5.143-4 9.143-9.143 9.143-45.143 0-82.286 37.143-82.286 82.286 0 5.143-4 9.143-9.143 9.143s-9.143-4-9.143-9.143c0-55.429 45.143-100.571 100.571-100.571 5.143 0 9.143 4 9.143 9.143zM987.429 146.286c0-40-33.143-73.143-73.143-73.143h-256c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286h-256c-40 0-73.143 33.143-73.143 73.143 84.571 71.429 182.857 199.429 182.857 475.429 0 109.714 90.857 229.714 242.286 252-2.857 6.857-4.571 14.286-4.571 22.286 0 30.286 24.571 54.857 54.857 54.857s54.857-24.571 54.857-54.857c0-8-1.714-15.429-4.571-22.286 151.429-22.286 242.286-142.286 242.286-252 0-276 98.286-404 182.857-475.429z" />
<glyph unicode="&#xf100;" glyph-name="chevron-left" horiz-adv-x="603" d="M358.286 164.571c0-4.571-2.286-9.714-5.714-13.143l-28.571-28.571c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-266.286 266.286c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l266.286 266.286c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l28.571-28.571c3.429-3.429 5.714-8.571 5.714-13.143s-2.286-9.714-5.714-13.143l-224.571-224.571 224.571-224.571c3.429-3.429 5.714-8.571 5.714-13.143zM577.714 164.571c0-4.571-2.286-9.714-5.714-13.143l-28.571-28.571c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-266.286 266.286c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l266.286 266.286c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l28.571-28.571c3.429-3.429 5.714-8.571 5.714-13.143s-2.286-9.714-5.714-13.143l-224.571-224.571 224.571-224.571c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xf101;" glyph-name="chevron-right" horiz-adv-x="567" d="M340 402.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l224.571 224.571-224.571 224.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143zM559.429 402.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l224.571 224.571-224.571 224.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xf104;" glyph-name="angle-left" horiz-adv-x="384" d="M358.286 640c0-4.571-2.286-9.714-5.714-13.143l-224.571-224.571 224.571-224.571c3.429-3.429 5.714-8.571 5.714-13.143s-2.286-9.714-5.714-13.143l-28.571-28.571c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-266.286 266.286c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l266.286 266.286c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l28.571-28.571c3.429-3.429 5.714-8 5.714-13.143z" />
<glyph unicode="&#xf105;" glyph-name="angle-right" horiz-adv-x="347" d="M340 402.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8-5.714 13.143 0 4.571 2.286 9.714 5.714 13.143l224.571 224.571-224.571 224.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xf106;" glyph-name="angle-up" horiz-adv-x="658" d="M614.286 274.286c0-4.571-2.286-9.714-5.714-13.143l-28.571-28.571c-3.429-3.429-8-5.714-13.143-5.714-4.571 0-9.714 2.286-13.143 5.714l-224.571 224.571-224.571-224.571c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l266.286 266.286c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xf107;" glyph-name="angle-down" horiz-adv-x="658" d="M614.286 530.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-266.286 266.286c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8 5.714 13.143 5.714 4.571 0 9.714-2.286 13.143-5.714l224.571-224.571 224.571 224.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l28.571-28.571c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xf1c6;" glyph-name="zip" horiz-adv-x="878" d="M365.714 731.428v73.143h-73.143v-73.143h73.143zM438.857 658.286v73.143h-73.143v-73.143h73.143zM365.714 585.143v73.143h-73.143v-73.143h73.143zM438.857 512v73.143h-73.143v-73.143h73.143zM838.857 733.714c21.143-21.143 38.857-63.429 38.857-93.714v-658.286c0-30.286-24.571-54.857-54.857-54.857h-768c-30.286 0-54.857 24.571-54.857 54.857v914.286c0 30.286 24.571 54.857 54.857 54.857h512c30.286 0 72.571-17.714 93.714-38.857zM585.143 873.143v-214.857h214.857c-3.429 9.714-8.571 19.429-12.571 23.429l-178.857 178.857c-4 4-13.714 9.143-23.429 12.571zM804.571 0v585.143h-237.714c-30.286 0-54.857 24.571-54.857 54.857v237.714h-73.143v-73.143h-73.143v73.143h-292.571v-877.714h731.429zM446.286 412c48.571-164 61.143-199.429 61.143-199.429 2.857-9.714 4.571-19.429 4.571-29.714 0-63.429-61.714-109.714-146.286-109.714s-146.286 46.286-146.286 109.714c0 10.286 1.714 20 4.571 29.714 0 0 12 35.429 68.571 226.286v73.143h73.143v-73.143h45.143c16.571 0 30.857-10.857 35.429-26.857zM365.714 146.286c40.571 0 73.143 16.571 73.143 36.571s-32.571 36.571-73.143 36.571-73.143-16.571-73.143-36.571 32.571-36.571 73.143-36.571z" />
<glyph unicode="&#xf1d8;" glyph-name="send" horiz-adv-x="1025" d="M1008 944.571c12-8.571 17.714-22.286 15.429-36.571l-146.286-877.714c-1.714-10.857-8.571-20-18.286-25.714-5.143-2.857-11.429-4.571-17.714-4.571-4.571 0-9.143 1.143-13.714 2.857l-258.857 105.714-138.286-168.571c-6.857-8.571-17.143-13.143-28-13.143-4 0-8.571 0.571-12.571 2.286-14.286 5.143-24 18.857-24 34.286v199.429l493.714 605.143-610.857-528.571-225.714 92.571c-13.143 5.143-21.714 17.143-22.857 31.429-0.571 13.714 6.286 26.857 18.286 33.714l950.857 548.571c5.714 3.429 12 5.143 18.286 5.143 7.429 0 14.857-2.286 20.571-6.286z" />
<glyph unicode="&#xf1e5;" glyph-name="preview" d="M402.286 768v-438.857c0-20-16.571-36.571-36.571-36.571v0-329.143c0-20-16.571-36.571-36.571-36.571h-292.571c-20 0-36.571 16.571-36.571 36.571v292.571l142.286 498.857c2.286 8 9.714 13.143 17.714 13.143h242.286zM585.143 768v-402.286h-146.286v402.286h146.286zM1024 256v-292.571c0-20-16.571-36.571-36.571-36.571h-292.571c-20 0-36.571 16.571-36.571 36.571v329.143c-20 0-36.571 16.571-36.571 36.571v438.857h242.286c8 0 15.429-5.143 17.714-13.143zM420.571 932.571v-128h-201.143v128c0 10.286 8 18.286 18.286 18.286h164.571c10.286 0 18.286-8 18.286-18.286zM804.571 932.571v-128h-201.143v128c0 10.286 8 18.286 18.286 18.286h164.571c10.286 0 18.286-8 18.286-18.286z" />
<glyph unicode="&#xf200;" glyph-name="stats" horiz-adv-x="987" d="M438.857 442.286l312-312c-79.429-80.571-190.286-130.286-312-130.286-242.286 0-438.857 196.571-438.857 438.857s196.571 438.857 438.857 438.857v-435.429zM545.714 438.857h441.714c0-121.714-49.714-232.571-130.286-312zM950.857 512h-438.857v438.857c242.286 0 438.857-196.571 438.857-438.857z" />
<glyph unicode="&#xf204;" glyph-name="toggle-off" horiz-adv-x="1170" d="M658.286 438.857c0 161.143-131.429 292.571-292.571 292.571s-292.571-131.429-292.571-292.571 131.429-292.571 292.571-292.571 292.571 131.429 292.571 292.571zM1097.143 438.857c0 161.143-131.429 292.571-292.571 292.571h-220.571c89.143-66.857 147.429-173.143 147.429-292.571s-58.286-225.714-147.429-292.571h220.571c161.143 0 292.571 131.429 292.571 292.571zM1170.286 438.857c0-201.714-164-365.714-365.714-365.714h-438.857c-201.714 0-365.714 164-365.714 365.714s164 365.714 365.714 365.714h438.857c201.714 0 365.714-164 365.714-365.714z" />
<glyph unicode="&#xf205;" glyph-name="toggle-on" horiz-adv-x="1170" d="M0 438.857c0 201.714 164 365.714 365.714 365.714h438.857c201.714 0 365.714-164 365.714-365.714s-164-365.714-365.714-365.714h-438.857c-201.714 0-365.714 164-365.714 365.714zM804.571 146.286c161.143 0 292.571 131.429 292.571 292.571s-131.429 292.571-292.571 292.571-292.571-131.429-292.571-292.571 131.429-292.571 292.571-292.571z" />
<glyph unicode="&#xf234;" glyph-name="user-add" horiz-adv-x="1170" d="M402.286 438.857c-121.143 0-219.429 98.286-219.429 219.429s98.286 219.429 219.429 219.429 219.429-98.286 219.429-219.429-98.286-219.429-219.429-219.429zM950.857 365.714h201.143c9.714 0 18.286-8.571 18.286-18.286v-109.714c0-9.714-8.571-18.286-18.286-18.286h-201.143v-201.143c0-9.714-8.571-18.286-18.286-18.286h-109.714c-9.714 0-18.286 8.571-18.286 18.286v201.143h-201.143c-9.714 0-18.286 8.571-18.286 18.286v109.714c0 9.714 8.571 18.286 18.286 18.286h201.143v201.143c0 9.714 8.571 18.286 18.286 18.286h109.714c9.714 0 18.286-8.571 18.286-18.286v-201.143zM530.286 237.714c0-40 33.143-73.143 73.143-73.143h146.286v-136c-28-20.571-63.429-28.571-97.714-28.571h-499.429c-91.429 0-152.571 54.857-152.571 148 0 129.143 30.286 327.429 197.714 327.429 9.143 0 15.429-4 22.286-9.714 56-42.857 110.286-69.714 182.286-69.714s126.286 26.857 182.286 69.714c6.857 5.714 13.143 9.714 22.286 9.714 48.571 0 91.429-18.286 124-54.857h-127.429c-40 0-73.143-33.143-73.143-73.143v-109.714z" />
<glyph unicode="&#xf271;" glyph-name="calendar-plus" horiz-adv-x="951" d="M877.714 804.571c40 0 73.143-33.143 73.143-73.143v-731.429c0-40-33.143-73.143-73.143-73.143h-804.571c-40 0-73.143 33.143-73.143 73.143v731.429c0 40 33.143 73.143 73.143 73.143h73.143v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h219.429v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h73.143zM658.286 859.428v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286zM219.429 859.428v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286zM877.714 0v585.143h-804.571v-585.143h804.571zM512 329.143h128c10.286 0 18.286-8 18.286-18.286v-36.571c0-10.286-8-18.286-18.286-18.286h-128v-128c0-10.286-8-18.286-18.286-18.286h-36.571c-10.286 0-18.286 8-18.286 18.286v128h-128c-10.286 0-18.286 8-18.286 18.286v36.571c0 10.286 8 18.286 18.286 18.286h128v128c0 10.286 8 18.286 18.286 18.286h36.571c10.286 0 18.286-8 18.286-18.286v-128z" />
<glyph unicode="&#xf272;" glyph-name="calendar-minus" horiz-adv-x="951" d="M658.286 310.857v-36.571c0-10.286-8-18.286-18.286-18.286h-329.143c-10.286 0-18.286 8-18.286 18.286v36.571c0 10.286 8 18.286 18.286 18.286h329.143c10.286 0 18.286-8 18.286-18.286zM73.143 0h804.571v585.143h-804.571v-585.143zM292.571 694.857v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM731.429 694.857v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM950.857 731.428v-731.429c0-40-33.143-73.143-73.143-73.143h-804.571c-40 0-73.143 33.143-73.143 73.143v731.429c0 40 33.143 73.143 73.143 73.143h73.143v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h219.429v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h73.143c40 0 73.143-33.143 73.143-73.143z" />
<glyph unicode="&#xf273;" glyph-name="calendar-failed" horiz-adv-x="951" d="M634.857 159.428l-26.286-26.286c-6.857-6.857-18.286-6.857-25.714 0l-107.429 108-107.429-108c-7.429-6.857-18.857-6.857-25.714 0l-26.286 26.286c-6.857 6.857-6.857 18.286 0 25.714l108 107.429-108 107.429c-6.857 7.429-6.857 18.857 0 25.714l26.286 26.286c6.857 6.857 18.286 6.857 25.714 0l107.429-107.429 107.429 107.429c7.429 6.857 18.857 6.857 25.714 0l26.286-26.286c6.857-6.857 6.857-18.286 0-25.714l-107.429-107.429 107.429-107.429c6.857-7.429 6.857-18.857 0-25.714zM73.143 0h804.571v585.143h-804.571v-585.143zM292.571 694.857v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM731.429 694.857v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM950.857 731.428v-731.429c0-40-33.143-73.143-73.143-73.143h-804.571c-40 0-73.143 33.143-73.143 73.143v731.429c0 40 33.143 73.143 73.143 73.143h73.143v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h219.429v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h73.143c40 0 73.143-33.143 73.143-73.143z" />
<glyph unicode="&#xf274;" glyph-name="calendar-check" horiz-adv-x="951" d="M744.571 400l-292.571-292.571c-7.429-6.857-18.857-6.857-26.286 0l-164.571 164.571c-6.857 7.429-6.857 18.857 0 25.714l26.286 26.286c6.857 6.857 18.286 6.857 25.714 0l125.714-125.714 253.714 253.714c7.429 6.857 18.857 6.857 25.714 0l26.286-26.286c6.857-6.857 6.857-18.286 0-25.714zM73.143 0h804.571v585.143h-804.571v-585.143zM292.571 694.857v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM731.429 694.857v164.571c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-164.571c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM950.857 731.428v-731.429c0-40-33.143-73.143-73.143-73.143h-804.571c-40 0-73.143 33.143-73.143 73.143v731.429c0 40 33.143 73.143 73.143 73.143h73.143v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h219.429v54.857c0 50.286 41.143 91.429 91.429 91.429h36.571c50.286 0 91.429-41.143 91.429-91.429v-54.857h73.143c40 0 73.143-33.143 73.143-73.143z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M192 128l640 384-640 384z"],"isMulticolor":false,"isMulticolor2":false,"tags":["play"],"defaultCode":59648,"grid":0},"properties":{"id":1,"order":630,"ligatures":"","prevSize":32,"code":59648,"name":"play"},"setIdx":0,"setId":24,"iconIdx":0},{"icon":{"paths":["M665.6 396.8v-409.6l-512 614.4h204.8v409.6l512-614.4h-204.8z"],"isMulticolor":false,"isMulticolor2":false,"tags":["bolt"],"defaultCode":59649,"grid":0},"properties":{"id":2,"order":759,"ligatures":"","prevSize":32,"code":59649,"name":"bolt"},"setIdx":0,"setId":24,"iconIdx":1},{"icon":{"paths":["M0 550.4l102.4-102.4 256 256 563.2-563.2 102.4 102.4-665.6 665.6z"],"isMulticolor":false,"isMulticolor2":false,"tags":["check"],"defaultCode":59650,"grid":0},"properties":{"id":3,"order":758,"ligatures":"","prevSize":32,"code":59650,"name":"check"},"setIdx":0,"setId":24,"iconIdx":2},{"icon":{"paths":["M665.6 396.8v-307.2h-307.2v307.2h-256l409.6 409.6 409.6-409.6h-256zM0 908.8h1024v102.4h-1024v-102.4z"],"isMulticolor":false,"isMulticolor2":false,"tags":["download"],"defaultCode":59651,"grid":0},"properties":{"id":4,"order":760,"ligatures":"","prevSize":32,"code":59651,"name":"download"},"setIdx":0,"setId":24,"iconIdx":3},{"icon":{"paths":["M0 89.6c0-56.32 46.080-102.4 102.4-102.4h819.2c56.554 0 102.4 45.846 102.4 102.4v0 102.4c0 56.554-45.846 102.4-102.4 102.4v0h-819.2c-56.554 0-102.4-45.846-102.4-102.4v0-102.4zM0 448c0-56.32 46.080-102.4 102.4-102.4h819.2c56.554 0 102.4 45.846 102.4 102.4v0 102.4c0 56.554-45.846 102.4-102.4 102.4v0h-819.2c-56.554 0-102.4-45.846-102.4-102.4v0-102.4zM0 806.4c0-56.32 46.080-102.4 102.4-102.4h819.2c56.554 0 102.4 45.846 102.4 102.4v0 102.4c0 56.554-45.846 102.4-102.4 102.4v0h-819.2c-56.554 0-102.4-45.846-102.4-102.4v0-102.4zM614.4 89.6v102.4h102.4v-102.4h-102.4zM819.2 89.6v102.4h102.4v-102.4h-102.4zM614.4 448v102.4h102.4v-102.4h-102.4zM819.2 448v102.4h102.4v-102.4h-102.4zM614.4 806.4v102.4h102.4v-102.4h-102.4zM819.2 806.4v102.4h102.4v-102.4h-102.4z"],"isMulticolor":false,"isMulticolor2":false,"tags":["servers"],"defaultCode":59652,"grid":0},"properties":{"id":5,"order":761,"ligatures":"","prevSize":32,"code":59652,"name":"servers"},"setIdx":0,"setId":24,"iconIdx":4},{"icon":{"paths":["M972.8 243.2v512l-460.8-256 460.8-256zM512 243.2v512l-460.8-256 460.8-256z"],"isMulticolor":false,"isMulticolor2":false,"tags":["backward1"],"defaultCode":59653,"grid":0},"properties":{"id":6,"order":762,"ligatures":"","prevSize":32,"code":59653,"name":"backward1"},"setIdx":0,"setId":24,"iconIdx":5},{"icon":{"paths":["M870.4 806.4c0 113.108-91.692 204.8-204.8 204.8v0h-307.2c0 0 0 0-0.001 0-113.108 0-204.8-91.692-204.8-204.8 0-0.18 0-0.36 0.001-0.54v0.028-613.888c0-28.277 22.923-51.2 51.2-51.2v0c28.277 0 51.2 22.923 51.2 51.2v0 307.2h51.2v-409.6c0-28.277 22.923-51.2 51.2-51.2v0c28.277 0 51.2 22.923 51.2 51.2v0 409.6h51.2v-460.8c0-28.277 22.923-51.2 51.2-51.2s51.2 22.923 51.2 51.2v0 460.8h51.2v-409.6c0-28.277 22.923-51.2 51.2-51.2v0c28.277 0 51.2 22.923 51.2 51.2v0 665.6h51.2v-307.2c0-28.277 22.923-51.2 51.2-51.2v0h51.2v409.6z"],"isMulticolor":false,"isMulticolor2":false,"tags":["deny"],"defaultCode":59654,"grid":0},"properties":{"id":7,"order":763,"ligatures":"","prevSize":32,"code":59654,"name":"deny"},"setIdx":0,"setId":24,"iconIdx":6},{"icon":{"paths":["M512 426.803l-362.035-362.035-72.397 72.397 362.035 362.035-362.035 362.035 72.397 72.397 362.035-362.035 362.035 362.035 72.397-72.397-362.035-362.035 362.035-362.035-72.397-72.397-362.035 362.035z"],"isMulticolor":false,"isMulticolor2":false,"tags":["cancel"],"defaultCode":59655,"grid":0},"properties":{"id":8,"order":764,"ligatures":"","prevSize":32,"code":59655,"name":"cancel"},"setIdx":0,"setId":24,"iconIdx":7},{"icon":{"paths":["M150.016 861.184c-96.436-93.233-156.308-223.762-156.308-368.276 0-282.77 229.23-512 512-512 144.514 0 275.043 59.872 368.137 156.164l0.138 0.144c88.925 91.979 143.724 217.436 143.724 355.692 0 282.77-229.23 512-512 512-138.256 0-263.713-54.799-355.836-143.863l0.144 0.138zM583.68 499.2l144.896-144.896-72.192-72.192-144.384 144.896-144.896-144.896-72.192 72.192 144.896 144.896-144.896 144.896 72.192 72.192 144.896-144.896 144.896 144.896 72.192-72.192-144.896-144.896z"],"isMulticolor":false,"isMulticolor2":false,"tags":["close"],"defaultCode":59656,"grid":0},"properties":{"id":9,"order":631,"ligatures":"","prevSize":32,"code":59656,"name":"close"},"setIdx":0,"setId":24,"iconIdx":8},{"icon":{"paths":["M921.6 89.6c56.554 0 102.4 45.846 102.4 102.4v0 614.4c0 56.554-45.846 102.4-102.4 102.4v0h-819.2c-56.554 0-102.4-45.846-102.4-102.4v0-614.4c0-56.32 46.080-102.4 102.4-102.4h819.2zM697.856 555.52l326.144 250.88v-102.4l-262.144-199.68 262.144-209.92v-102.4l-512 409.6-512-409.6v102.4l262.144 209.92-262.144 199.68v102.4l326.144-250.88 185.856 148.48 185.856-148.48z"],"isMulticolor":false,"isMulticolor2":false,"tags":["envelope"],"defaultCode":59657,"grid":0},"properties":{"id":10,"order":632,"ligatures":"","prevSize":32,"codeLine truncated
+618
View File
@@ -0,0 +1,618 @@
@font-face {
font-family: 'glyphs';
src: url('/app/assets/styles/fonts/glyphs.eot');
src: url('/app/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/app/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/app/assets/styles/fonts/glyphs.woff') format('woff'),
url('/app/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'glyphs' !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
span[class*="icon-"][primary]:before { color: var(--app-color-primary); }
span[class*="icon-"][secondary] { color: var(--app-color-secondary); }
span[class*="icon-"][success] { color: var(--app-color-success); }
span[class*="icon-"][danger] { color: var(--app-color-danger); }
span[class*="icon-"][warning] { color: var(--app-color-warning); }
span[class*="icon-"][accent] { color: var(--app-color-accent); }
span[class*="icon-"][info] { color: var(--app-color-info); }
[class*="icon-"][xxsmall] { font-size: var(--eicui-base-icon-size-2xs); }
[class*="icon-"][xsmall] { font-size: var(--eicui-base-icon-size-xs) !important; }
[class*="icon-"][small] { font-size: var(--eicui-base-icon-size-s) !important; }
[class*="icon-"][medium] { font-size: var(--eicui-base-icon-size-m) !important; }
[class*="icon-"][large] { font-size: var(--eicui-base-icon-size-l) !important; }
[class*="icon-"][xlarge] { font-size: var(--eicui-base-icon-size-xl) !important; }
[class*="icon-"][xxlarge] { font-size: var(--eicui-base-icon-size-2xl); }
[class*="icon-"][xxxlarge] { font-size: var(--eicui-base-icon-size-3xl); }
[class*="icon-"][xxxxlarge] { font-size: var(--eicui-base-icon-size-4xl); }
@keyframes spin {
0% { transform: rotate(0deg) ; }
100% { transform: rotate(360deg) ; }
}
@keyframes uturn {
0% { transform: rotate(-180deg) ; }
100% { transform: rotate(0deg) ; }
}
@keyframes uturn-ccw {
0% { transform: rotate(180deg) ; }
100% { transform: rotate(0deg) ; }
}
.spin { animation: spin 1s infinite linear; }
.arrow-expand:before {
content: "\f106" !important;
animation: uturn-ccw 0.3s 1 linear;
}
.arrow-collapse:before {
content: "\f107" !important;
animation: uturn 0.3s 1 normal linear;
}
.icon-backward1:before {
content: "\e905";
}
.icon-backward-step:before {
content: "\e943";
}
.icon-fast-forward:before {
content: "\e944";
}
.icon-pause2:before {
content: "\e945";
}
.icon-play1:before {
content: "\e946";
}
.icon-target1:before {
content: "\e948";
}
.icon-usb:before {
content: "\e949";
}
.icon-video-camera1:before {
content: "\e94a";
}
.icon-price-tag:before {
content: "\e93c";
}
.icon-align-center:before {
content: "\e933";
}
.icon-align-left:before {
content: "\e934";
}
.icon-align-right:before {
content: "\e935";
}
.icon-format-color:before {
content: "\e93b";
}
.icon-format-bold:before {
content: "\e936";
}
.icon-font-size-down:before {
content: "\e937";
}
.icon-format-underline:before {
content: "\e939";
}
.icon-big-bullet:before {
content: "\e928";
}
.icon-code:before {
content: "\e92b";
}
.icon-check-rounded:before {
content: "\e91f";
}
.icon-dashboard:before {
content: "\e92a";
}
.icon-more:before {
content: "\e923";
}
.icon-locked:before {
content: "\e925";
}
.icon-unlocked:before {
content: "\e926";
}
.icon-menu:before {
content: "\e920";
}
.icon-reply:before {
content: "\e921";
}
.icon-back:before {
content: "\e921";
}
.icon-link-ext:before {
content: "\e922";
}
.icon-share:before {
content: "\e929";
}
.icon-workflow:before {
content: "\e929";
}
.icon-health:before {
content: "\e927";
}
.icon-copy:before {
content: "\e915";
}
.icon-filter:before {
content: "\e91c";
}
.icon-deny:before {
content: "\e906";
}
.icon-home:before {
content: "\e91d";
}
.icon-pause1:before {
content: "\e916";
}
.icon-market:before {
content: "\e914";
}
.icon-thumbs-down:before {
content: "\e90b";
}
.icon-thumbs-up:before {
content: "\e90c";
}
.icon-trash:before {
content: "\e91e";
}
.icon-bolt:before {
content: "\e901";
}
.icon-check:before {
content: "\e902";
}
.icon-cancel:before {
content: "\e907";
}
.icon-close:before {
content: "\e908";
}
.icon-download:before {
content: "\e903";
}
.icon-envelope:before {
content: "\e909";
}
.icon-company:before {
content: "\e90a";
}
.icon-servers:before {
content: "\e904";
}
.icon-cabinet:before {
content: "\e94b";
}
.icon-cabinet1:before {
content: "\e94c";
}
.icon-camera1:before {
content: "\e94e";
}
.icon-camera2:before {
content: "\e94f";
}
.icon-film1:before {
content: "\e950";
}
.icon-chronometer:before {
content: "\e951";
}
.icon-chart:before {
content: "\e952";
}
.icon-lab:before {
content: "\e953";
}
.icon-satellite:before {
content: "\e954";
}
.icon-spaceinvaders:before {
content: "\e955";
}
.icon-bomb:before {
content: "\e957";
}
.icon-tools:before {
content: "\e958";
}
.icon-bus:before {
content: "\e959";
}
.icon-stop2:before {
content: "\e95a";
}
.icon-atom:before {
content: "\e95b";
}
.icon-globe:before {
content: "\e95c";
}
.icon-globe1:before {
content: "\e95d";
}
.icon-grid:before {
content: "\e95e";
}
.icon-flag:before {
content: "\e95f";
}
.icon-lock:before {
content: "\e960";
}
.icon-unlocked1:before {
content: "\e961";
}
.icon-camera3:before {
content: "\e962";
}
.icon-calculator:before {
content: "\e963";
}
.icon-diamond:before {
content: "\e965";
}
.icon-atom1:before {
content: "\e966";
}
.icon-syringe:before {
content: "\e967";
}
.icon-health1:before {
content: "\e968";
}
.icon-pill:before {
content: "\e969";
}
.icon-lab1:before {
content: "\e96a";
}
.icon-graph:before {
content: "\e96b";
}
.icon-review:before {
content: "\e917";
}
.icon-correction:before {
content: "\e918";
}
.icon-mediation:before {
content: "\e919";
}
.icon-writing:before {
content: "\e91b";
}
.icon-snapshot:before {
content: "\e92d";
}
.icon-toc:before {
content: "\e92e";
}
.icon-folder:before {
content: "\e92f";
}
.icon-folder-open:before {
content: "\e930";
}
.icon-folder-add:before {
content: "\e931";
}
.icon-folder-remove:before {
content: "\e932";
}
.icon-qrcode:before {
content: "\e938";
}
.icon-chat:before {
content: "\e96c";
}
.icon-bug:before {
content: "\e999";
}
.icon-font-size-up:before {
content: "\ea61";
}
.icon-format-italic:before {
content: "\ea64";
}
.icon-stop:before {
content: "\e92c";
}
.icon-play:before {
content: "\e900";
}
.icon-history:before {
content: "\e94d";
}
.icon-spinner:before {
content: "\e981";
}
.icon-cog:before {
content: "\e994";
}
.icon-star-empty:before {
content: "\e9d7";
}
.icon-star-half:before {
content: "\e9d8";
}
.icon-star-full:before {
content: "\e9d9";
}
.icon-heart:before {
content: "\e9da";
}
.icon-pdf:before {
content: "\eadf";
}
.icon-pen:before {
content: "\e910";
}
.icon-coaching:before {
content: "\e91a";
}
.icon-cart:before {
content: "\e93a";
}
.icon-phone:before {
content: "\e942";
}
.icon-hour-glass:before {
content: "\e90f";
}
.icon-refresh:before {
content: "\e984";
}
.icon-complaint:before {
content: "\e9a8";
}
.icon-evaluation:before {
content: "\e9b8";
}
.icon-link:before {
content: "\e9cb";
}
.icon-loop:before {
content: "\ea2d";
}
.icon-image:before {
content: "\e90d";
}
.icon-new:before {
content: "\e924";
}
.icon-map:before {
content: "\e947";
}
.icon-pin:before {
content: "\e947";
}
.icon-user-check:before {
content: "\e975";
}
.icon-cogs:before {
content: "\e995";
}
.icon-bin:before {
content: "\e9ac";
}
.icon-attachment:before {
content: "\e9cd";
}
.icon-xls:before {
content: "\eae2";
}
.icon-paint-format:before {
content: "\e93d";
}
.icon-camera:before {
content: "\e93e";
}
.icon-film:before {
content: "\e93f";
}
.icon-video-camera:before {
content: "\e940";
}
.icon-stack:before {
content: "\e941";
}
.icon-display:before {
content: "\e956";
}
.icon-database:before {
content: "\e964";
}
.icon-target:before {
content: "\e9b3";
}
.icon-tree:before {
content: "\e9bc";
}
.icon-play2:before {
content: "\ea15";
}
.icon-pause:before {
content: "\ea16";
}
.icon-stop1:before {
content: "\ea17";
}
.icon-previous:before {
content: "\ea18";
}
.icon-next:before {
content: "\ea19";
}
.icon-backward:before {
content: "\ea1a";
}
.icon-forward2:before {
content: "\ea1b";
}
.icon-embed:before {
content: "\ea7f";
}
.icon-steam:before {
content: "\eaac";
}
.icon-dropbox:before {
content: "\eaae";
}
.icon-tux:before {
content: "\eabd";
}
.icon-codepen:before {
content: "\eae8";
}
.icon-sort-asc:before {
content: "\e911";
}
.icon-sort-desc:before {
content: "\e912";
}
.icon-unsorted:before {
content: "\e913";
}
.icon-help:before {
content: "\e90e";
}
.icon-plus:before {
content: "\f067";
}
.icon-search:before {
content: "\f002";
}
.icon-user:before {
content: "\f007";
}
.icon-logoff:before {
content: "\f011";
}
.icon-edit:before {
content: "\f040";
}
.icon-checked:before {
content: "\f046";
}
.icon-info:before {
content: "\f05a";
}
.icon-expand:before {
content: "\f065";
}
.icon-warning:before {
content: "\f071";
}
.icon-calendar:before {
content: "\f073";
}
.icon-comment:before {
content: "\f075";
}
.icon-twitter:before {
content: "\f081";
}
.icon-facebook:before {
content: "\f082";
}
.icon-square-o:before {
content: "\f096";
}
.icon-website:before {
content: "\f0ac";
}
.icon-users:before {
content: "\f0c0";
}
.icon-list-ul:before {
content: "\f0ca";
}
.icon-table:before {
content: "\f0ce";
}
.icon-exchange:before {
content: "\f0ec";
}
.icon-alert:before {
content: "\f0f3";
}
.icon-chevron-left:before {
content: "\f100";
}
.icon-chevron-right:before {
content: "\f101";
}
.icon-angle-left:before {
content: "\f104";
}
.icon-angle-right:before {
content: "\f105";
}
.icon-angle-up:before {
content: "\f106";
}
.icon-angle-down:before {
content: "\f107";
}
.icon-zip:before {
content: "\f1c6";
}
.icon-send:before {
content: "\f1d8";
}
.icon-preview:before {
content: "\f1e5";
}
.icon-stats:before {
content: "\f200";
}
.icon-toggle-off:before {
content: "\f204";
}
.icon-toggle-on:before {
content: "\f205";
}
.icon-user-add:before {
content: "\f234";
}
.icon-calendar-plus:before {
content: "\f271";
}
.icon-calendar-minus:before {
content: "\f272";
}
.icon-calendar-failed:before {
content: "\f273";
}
.icon-calendar-check:before {
content: "\f274";
}
+2704 -553
View File
File diff suppressed because it is too large. Load diff
+5
View File
@@ -21,6 +21,11 @@
"role": [ "*" ],
"controller" : "/editors/EditorsController"
},
{
"url": "/sims",
"role": [ "*" ],
"controller" : "/sims/SimsController"
},
{
"url": "/system",
"role": "*",
+1
View File
@@ -14,6 +14,7 @@
],
"json": [
{"name":"global/app-menu-map.json"},
{"id":"busChannels", "name":"global/busChannels.json"},
{"path": "/app/controllers/common/", "name": "errorController.json", "comment": "Trick to preload errorController stuff, to still have error messages if S3 is down."}
]
}
@@ -3,6 +3,7 @@ class DashboardsController extends WindozController {
constructor(params) {
super(params)
this.arenaConfig = app.Assets.Store.json.arenaConfig
this.busChannels = app.Assets.Store.json.busChannels
this.eventsMapping = app.Assets.Store.json.eventsMapping
console.log('=============>DashboardsController constructor')
}
@@ -21,6 +22,7 @@ class DashboardsController extends WindozController {
const ttb = new app.LoadedModules.Threetobus({
eventsMapping: this.eventsMapping,
sceneSize: this.arenaConfig.arenaSize,
observer: this.busChannels.observer,
})
ttb.initScene({
axes: true,
+51
View File
@@ -0,0 +1,51 @@
class SimsController extends WindozController {
constructor(params) {
super(params)
}
async create() {
const models = {
sims: new SimsModel('/sims'),
keyframes: new KeyframesModel('/keyframes')
}
this.loadWindow(
'sims/CreateSimView',
{
title: '<i class="icon-new"></i> Create a simulation',
static: true,
expanded: false,
withSettings: false,
windowStyle: WindozDomContent.boxFromPrefs('sims.createsimview', { x: 'center', y: 'center', w: 600, h: 300 }),
},
{
models: models,
}
)
}
async manage() {
const models = {
sims: new SimsModel('/sims')
}
this.loadWindow(
'sims/ManageSimView',
{
title: '<i class="icon-file-play"></i> Play / Pause a simulation',
static: true,
expanded: false,
withSettings: false,
windowStyle: WindozDomContent.boxFromPrefs('sims.managesimview', { x: 50, y: 50, w: 1000, h: 600 }),
},
{
models: models,
}
)
}
}
app.registerClass('SimsController', SimsController)
+36
View File
@@ -0,0 +1,36 @@
{
"routes": [
{
"url": "/create",
"role": [ "*" ],
"controller" : "/sims/SimsController",
"method": "create"
},
{
"url": "/manage",
"role": [ "*" ],
"controller" : "/sims/SimsController",
"method": "manage"
}
],
"models": [
"SimsModel",
"KeyframesModel"
],
"views": [
"sims/CreateSimView",
"sims/ManageSimView"
],
"controllerDependencies": [
"/helpers/basicDialogs",
"/helpers/activeAttributes"
],
"assets": {
"styles": [
],
"html": [
],
"json": [
]
}
}
+17 -3
View File
@@ -47,7 +47,13 @@ app.helpers.formBuilder = {
}
if(component){
component.classList.add('formbuilder-field')
component.value = this.getPathInObj(fieldsValues, propName) || fieldsObj[propName].default
const rawValue = this.getPathInObj(fieldsValues, propName) ?? fieldsObj[propName].default
if(fieldsObj[propName].type === 'number') {
const n = Number(rawValue)
component.value = Number.isFinite(n) ? n : 0
} else {
component.value = rawValue
}
fieldRow.append(component)
allFields.push(fieldRow)
}
@@ -77,6 +83,14 @@ app.helpers.formBuilder = {
return(target[parts[parts.length - 1]] )
},
#fieldValue(el) {
if(el?.type === 'number') {
const n = Number(el.value)
return(Number.isFinite(n) ? n : el.value)
}
return(el.value)
},
getFieldsValues(rootSel){
const result = {}
document.querySelectorAll(`${rootSel} .formbuilder-field`).forEach(el => {
@@ -89,14 +103,14 @@ app.helpers.formBuilder = {
}
target = target[key]
}
target[path[path.length - 1]] = el.value
target[path[path.length - 1]] = this.#fieldValue(el)
})
return(result)
},
getFieldValue(rootSel, name){
const comp = document.querySelector(`${rootSel} .formbuilder-field[name="${name}"]`)
if(comp) return(comp.value)
if(comp) return(this.#fieldValue(comp))
else return(null)
},
+10 -1
View File
@@ -48,7 +48,16 @@ app.helpers.kfConsole = {
this.kfArena.removeAgent(aid)
},
updateAgent: async (aid, properties) => {
if(!Object.keys(this.kfArena.agents).includes(aid)) throw(`Agent ${aid} not on scene !`)
const agent = this.kfArena.agents[aid]
const values = { ...agent.values, ...properties }
if(properties.position) values.position = { ...agent.values.position, ...properties.position }
if(properties.speed) values.speed = { ...agent.values.speed, ...properties.speed }
agent.values = values
if(properties.position) this.kfArena.moveAgent(aid, values.position)
if(properties.speed) this.kfArena.changeAgentSpeed(aid, values.speed)
if(this.currentlySelectedAid === aid) this.fillAgentProperties(aid, agent.props, agent.values)
this.updateKfButtons()
},
selectAgent: async (aid) => {
if(!Object.keys(this.kfArena.agents).includes(aid)) throw(`Agent ${aid} not on scene !`)
+8 -1
View File
@@ -276,12 +276,19 @@ class WindozDomContent extends View {
left = box.x ? box.x : defaults.x
top = box.y ? box.y : defaults.y
width = box.w ? box.w : defaults.w
height = box.x ? box.h : defaults.h
height = box.h ? box.h : defaults.h
} else {
left = defaults.x
top = defaults.y
width = defaults.w
height = defaults.h
const ws = document.querySelector('[eicapp] .app-workspace')?.getBoundingClientRect()
const areaLeft = ws?.left ?? 0
const areaTop = ws?.top ?? 0
const areaWidth = ws?.width ?? window.innerWidth
const areaHeight = ws?.height ?? window.innerHeight
if(left === 'center') left = Math.round(areaLeft + (areaWidth - width) / 2)
if(top === 'center') top = Math.round(areaTop + (areaHeight - height) / 2)
}
return({
width: `${width}px`,
+9 -1
View File
@@ -43,7 +43,15 @@ class AgentsModel extends WindozModel {
async getDefaultProps(id){
const aprops = await this.getProperties(id)
const defaults={ position: { x:0, y:0, z:0 }, speed: { x:0, y:0, z:0 }}
for(const p in aprops) defaults[p] = aprops[p].default
for(const p in aprops) {
const prop = aprops[p]
if(prop?.type === 'number') {
const n = Number(prop.default)
defaults[p] = Number.isFinite(n) ? n : 0
} else {
defaults[p] = prop.default
}
}
return(defaults)
}
}
+18 -1
View File
@@ -38,14 +38,31 @@ class KeyframesModel extends WindozModel {
)
}
#normalizeAxisVector(vec) {
if(!vec || typeof(vec) !== 'object') return(null)
const axes = ['x', 'y', 'z']
const out = {}
for(const axis of axes) {
const n = Number(vec[axis])
if(!Number.isFinite(n)) return(null)
out[axis] = n
}
return(out)
}
async save(kfId, data) {
const kfData = Object.keys(data).map(aid => {
const { position, speed, ...storeValues} = data[aid].values
const gpsPosition = this.#normalizeAxisVector(position)
const gpsSpeed = this.#normalizeAxisVector(speed)
if(!gpsPosition || !gpsSpeed) {
throw(new Error(`Agent ${aid}: position and speed must be numeric vectors`))
}
return({
aid: aid,
type: data[aid].type,
storeValues: storeValues,
gpsValues: { position: data[aid].values.position, speed: data[aid].values.speed }
gpsValues: { position: gpsPosition, speed: gpsSpeed },
})
})
+86
View File
@@ -0,0 +1,86 @@
class SimsModel extends WindozBusModel {
constructor() {
super()
this.ressource = '/sims'
this.busChannels = app.Assets.Store.json.busChannels
}
async list() {
const endpoint = {...app.config.api[this.ressource].list}
const [listResponse, statusList] = await Promise.all([
this.request(endpoint.uri, endpoint.method),
this.getSimulationsStatus(),
])
const sims = listResponse?.payload ?? []
const statuses = Array.isArray(statusList) ? statusList : (statusList?.simulations ?? [])
const stateBySimulationId = new Map(
statuses.map(item => [item.simulationId, item.state])
)
return({
...listResponse,
payload: sims.map(sim => ({
...sim,
state: stateBySimulationId.get(sim.simulationUuid) ?? 'idle',
})),
})
}
async get(simulationUuid) {
let endpoint = {...app.config.api[this.ressource].get}
endpoint.uri = endpoint.uri.replace('{simulationUuid}', simulationUuid)
return(
this.request(endpoint.uri, endpoint.method)
)
}
async create(simData) {
let endpoint = {...app.config.api[this.ressource].create}
return(
this.request(endpoint.uri, endpoint.method, simData)
)
}
async startSimulation(simulationUuid) {
return(this.busActionRequest(
this.busChannels.maestro.actionsChannel,
'STARTSIMULATION',
{
simulationUuid,
infraId: null,
},
60000
))
}
async stopSimulation(simulationUuid) {
return(this.busActionRequest(
this.busChannels.maestro.actionsChannel,
'STOPSIMULATION',
{ simulationUuid },
30000
))
}
async pauseSimulation(simulationUuid) {
return(this.busActionRequest(
this.busChannels.maestro.actionsChannel,
'PAUSESIMULATION',
{ simulationUuid },
30000
))
}
async getSimulationsStatus() {
return(this.busActionRequest(
this.busChannels.maestro.actionsChannel,
'GETSIMULATIONSSTATUS',
{},
15000
))
}
}
app.registerClass('SimsModel', SimsModel)
+1 -1
View File
@@ -99,7 +99,7 @@ class Snaptobus{
processBusEvent(eventType, chan, payload, userId, x){
const chanObj = this._curBusConfig.find(item => item.chan==chan)
const chanObj = this._curBusConfig.find(item => app.MessageBus.chanMatch(chan, item.chan))
if(!chanObj) return
const eventObj = chanObj.events.find(item => item.eventName==eventType)
if(!eventObj) return
+115 -6
View File
@@ -9,6 +9,16 @@ export class Threetobus{
this._curEventsMapping = []
this._stagedEventsMapping = options.eventsMapping
this.sceneSize = options.sceneSize
this._observerConfig = {
actionsChannel: 'system:requests:observer',
subscribeFrequencyMs: 1000,
cameraDebounceMs: 600,
...options.observer,
}
this._frustumRenderEngine = null
this._frustumDebounceTimer = null
this._frustumCameraChangeHandler = null
this._frustumWatching = false
this.commitConfig()
this.cameras = {}
@@ -19,8 +29,8 @@ export class Threetobus{
}
busReconnect(){
this.commitConfig() // To resubscribe...
//TODO : Not ideal because if we're in the middle of non-commited changes...
this.commitConfig()
if(this._frustumWatching) this._scheduleFrustumResubscribe()
}
get EventsMapping() { return this._stagedEventsMapping }
@@ -34,9 +44,14 @@ export class Threetobus{
if(this._curEventsMapping.map(item => item.chan).includes(chanObj.chan)) chansToKeep.push(chanObj)
else chansToAdd.push(chanObj)
}
const chansToDel = this._curEventsMapping.filter(item => (!chansToKeep.map(c=>c.chan).includes(item.chan) && !chansToAdd.map(c=>c.chan).includes(item.chan)))
await app.MessageBus.subscribe(chansToAdd.map(item => item.chan))
await app.MessageBus.unSubscribe(chansToDel.map(item => item.chan))
const chansToDel = this._curEventsMapping.filter(item => (
!chansToKeep.map(c => c.chan).includes(item.chan)
&& !chansToAdd.map(c => c.chan).includes(item.chan)
))
if(app.MessageBus?.connected) {
if(chansToAdd.length) await app.MessageBus.subscribe(chansToAdd.map(item => item.chan))
if(chansToDel.length) await app.MessageBus.unSubscribe(chansToDel.map(item => item.chan))
}
// console.log('subscribe:', chansToAdd.map(item => item.chan))
// console.log('unSubscribe:', chansToDel)
@@ -88,7 +103,8 @@ export class Threetobus{
// if yes : how to discriminate static value from event-mapping definition ?
if(mapping.child) id += '_'+mapping.child
if(id){
const obj3D = this.scene.getObjectByName(id)
let obj3D = this.scene.getObjectByName(id)
if(!obj3D) obj3D = this._ensurePlaceholderAgent(id)
if(obj3D){
this.assignFromConfig(payload, mapping, obj3D)
}
@@ -161,6 +177,99 @@ export class Threetobus{
return(path.split('.').reduce((acc, key) => acc?.[key], obj))
}
watchCameraFrustum(renderEngine) {
if(!renderEngine || renderEngine.mode !== '3D') return
if(!app.MessageBus?.config?.enabled) {
console.warn('[Threetobus] MessageBus disabled — camera frustum watch skipped')
return
}
this._frustumRenderEngine = renderEngine
this._frustumWatching = true
if(!this._frustumCameraChangeHandler) {
this._frustumCameraChangeHandler = () => this._scheduleFrustumResubscribe()
renderEngine.controls.addEventListener('change', this._frustumCameraChangeHandler)
}
app.MessageBus.whenConnected(() => {
this.commitConfig()
this._scheduleFrustumResubscribe()
})
}
stopWatchingCameraFrustum() {
this._frustumWatching = false
if(this._frustumDebounceTimer) {
clearTimeout(this._frustumDebounceTimer)
this._frustumDebounceTimer = null
}
if(this._frustumRenderEngine?.controls && this._frustumCameraChangeHandler) {
this._frustumRenderEngine.controls.removeEventListener('change', this._frustumCameraChangeHandler)
}
this._frustumRenderEngine = null
this._frustumCameraChangeHandler = null
}
_scheduleFrustumResubscribe() {
if(!this._frustumWatching) return
if(this._frustumDebounceTimer) clearTimeout(this._frustumDebounceTimer)
this._frustumDebounceTimer = setTimeout(() => {
this._frustumDebounceTimer = null
this._resubscribeCameraFrustum()
}, this._observerConfig.cameraDebounceMs)
}
async _resubscribeCameraFrustum() {
if(!this._frustumWatching || !this._frustumRenderEngine) return
if(!app.MessageBus?.connected) return
const camera = this._frustumRenderEngine.camera
if(!camera?.isPerspectiveCamera) return
const planes = this._cameraFrustumPlanes(camera)
const chan = this._observerConfig.actionsChannel
try {
await app.MessageBus.requestBusAction(
chan,
'SUBSCRIBEFRUSTUM',
{
planes,
frequency: this._observerConfig.subscribeFrequencyMs,
},
10000
)
} catch(err) {
console.warn('[Threetobus] SUBSCRIBEFRUSTUM failed:', err)
}
}
_cameraFrustumPlanes(camera) {
camera.updateMatrixWorld(true)
const matrix = new THREE.Matrix4().multiplyMatrices(
camera.projectionMatrix,
camera.matrixWorldInverse
)
const frustum = new THREE.Frustum().setFromProjectionMatrix(matrix)
return(frustum.planes.map(plane => ({
nx: plane.normal.x,
ny: plane.normal.y,
nz: plane.normal.z,
d: plane.constant,
})))
}
_ensurePlaceholderAgent(agentId) {
const geo = new THREE.BoxGeometry(0.4, 0.4, 0.4)
const mat = new THREE.MeshStandardMaterial({ color: 0x44aa88 })
const obj3D = new THREE.Mesh(geo, mat)
obj3D.name = agentId
this.tweensRegistry[agentId] = { move: null, rotate: null }
this.scene.add(obj3D)
return(obj3D)
}
initScene(options){
// Scene
this.scene = new THREE.Scene()
Vendored Submodule
+1
Submodule app/thirdparty/buildoz added at 9690401dad.
-206
View File
@@ -1,206 +0,0 @@
bz-select {
display: block;
margin: .5em 0 .5em 0;
position:relative;
}
bz-select[disabled] > button{
opacity: 0.6;
cursor: not-allowed;
pointer-events: none;
filter: grayscale(30%);
}
bz-select > button{
width:100%;
text-align: left;
font-family: sans;
font-size: .9em;
border-radius: 1em;
border: none;
padding: 0.2em .2em .3em .5em;
background: linear-gradient( to bottom, #555, #aaa 15%, #ccc 50%, #aaa 85%, #555 );
}
bz-select > button::after {
content: "\00BB";
transform: rotate(90deg);
position: absolute;
right: 0.5em;
top: 0;
pointer-events: none;
font-size: 1.5em;
color: #444;
}
bz-select > div.options-container{
pointer-events: none;
position: absolute;
top: 1.8em;
left: 0;
width: 100%;
z-index: 99;
max-height: 0;
overflow: auto;
transition: max-height 0.4s ease;
}
bz-select > div.options-container.open{ pointer-events: auto; max-height: 10em;}
bz-select option{
background-color: #DDD;
border: 1px solid black;
color: #000;
padding: 0.2em .2em .5em .5em;
margin: -1em 0 0 0;
border-radius: 1em;
height: 1em;
font-family: sans;
font-size: .9em;
opacity: 0;
pointer-events: none;
transition:
margin-top 0.3s ease,
opacity 0.3s ease;
}
bz-select option.open{
margin: 0;
opacity: 1;
pointer-events: auto;
}
bz-select option:hover{
background-color: #44F;
color: #FFF;
}
/************************************************************************************/
bz-toggler{
outline: none;
min-height: 1.5em;
padding: 0.75em;
display: inline-table;
max-width: fit-content;
transition: all 0.5s;
}
bz-toggler div.toggle-label-left{
padding-right: 0.3em;
display: inline;
vertical-align: middle;
text-align: right;
font-size:.8em;
}
bz-toggler div.toggle-label-right{
padding-left: 0.3em;
display: inline;
vertical-align: middle;
text-align: left;
font-size:.8em;
}
bz-toggler div.toggle-switch{
user-select: none;
height: inherit;
cursor: pointer;
display: inline;
vertical-align: middle;
text-align: center;
}
bz-toggler div.toggle-switch span.toggle-bar {
display: inline-block;
position: relative;
background-color: #CCC;
}
bz-toggler div.toggle-switch span.toggle-thumb {
display: inline-block;
border-radius: 50%;
background-color: white;
position: absolute;
z-index: 1;
}
bz-toggler div.toggle-switch span.toggle-thumb:not(.turned-on) {
left: 0;
transition: all 0.4s;
}
bz-toggler div.toggle-switch span.toggle-thumb.turned-on {
transition: all 0.4s;
}
bz-toggler div.toggle-switch span.toggle-bar {
width: 2em;
height: 0.75em;
border-radius: .75em;
}
bz-toggler div.toggle-switch span.toggle-thumb {
height: 1em;
width: 1em;
top: 50%;
transform: translateY(-50%);
}
bz-toggler div.toggle-switch span.toggle-thumb.turned-on {
left : 1em;
}
/************************************************************************************/
bz-slidepane {
display: block;
position: absolute;
background-color: #000A;
}
bz-slidepane[side="top"] { top:0; left:0; width: 100%; height:0; border-bottom: 2px solid #DDD; }
bz-slidepane[side="bottom"] { bottom:0; left:0; width: 100%; height:0; border-top: 2px solid #DDD;}
bz-slidepane[side="left"] { top:0; left:0; height:100%; width:0; border-right: 2px solid #DDD;}
bz-slidepane[side="right"] { top:0; right:0; height:100%; width:0; border-left: 2px solid #DDD; }
bz-slidepane[side="top"] div.handle {
position: absolute;
bottom: -12px;
left: 50%;
width: 40px;
height: 11px;
background: repeating-linear-gradient( to top, rgba(255,255,255,1) 0, rgba(255,255,255,1) 2px, rgba(0,0,0,0.2) 3px, rgba(0,0,0,0.2) 4px );
transform: translateX(-50%);
cursor: ns-resize;
}
bz-slidepane[side="bottom"] div.handle {
position: absolute;
top: -12px;
left: 50%;
width: 40px;
height: 11px;
background: repeating-linear-gradient( to bottom, rgba(255,255,255,1) 0, rgba(255,255,255,1) 2px, rgba(0,0,0,0.2) 3px, rgba(0,0,0,0.2) 4px );
transform: translateX(-50%);
cursor: ns-resize;
}
bz-slidepane[side="left"] div.handle {
position: absolute;
right: -12px;
top: 50%;
width: 11px;
height: 40px;
background: repeating-linear-gradient( to left, rgba(255,255,255,1) 0, rgba(255,255,255,1) 2px, rgba(0,0,0,0.2) 3px, rgba(0,0,0,0.2) 4px );
transform: translateY(-50%);
cursor: ew-resize;
}
bz-slidepane[side="right"] div.handle {
position: absolute;
left: -12px;
top: 50%;
width: 11px;
height: 40px;
background: repeating-linear-gradient( to right, rgba(255,255,255,1) 0, rgba(255,255,255,1) 2px, rgba(0,0,0,0.2) 3px, rgba(0,0,0,0.2) 4px );
transform: translateY(-50%);
cursor: ew-resize;
}
/************************************************************************************/
bz-graflow {
position: relative;
display: block;
width: 100vw;
height: 50vh;
box-sizing: border-box;
}
bz-graflow .bzgf-main-container{
width: 100%;
height: 100%;
position: relative;
box-sizing: border-box;
}
-332
View File
@@ -1,332 +0,0 @@
class Buildoz extends HTMLElement {
constructor(){
super() // always call super() first!
this.attrs = {}
}
static get observedAttributes(){ //observable attributes triggering attributeChangedCallback
// anything added here will be observed for all buildoz tags
// in your child, add you local 'color' observable attr with :
// return([...super.observedAttributes, 'color'])
return(['name'])
}
static define(name, cls){
const tag = `bz-${name}`
if(!customElements.get(tag)) { // no wild redefinition
customElements.define(tag, cls)
}
return cls
}
connectedCallback(){ // added to the DOM
this.classList.add('buildoz')
}
disconnectedCallback(){ // removed from the DOM
}
attributeChangedCallback(name, oldValue, newValue) {
this.attrs[name] = newValue
if(name=='name') this.name = newValue
}
getBZAttribute(attrName){ // Little helper for defaults
return(this.getAttribute(attrName) || this.defaultAttrs[attrName] )
}
}
class BZselect extends Buildoz {
#value
#fillFromMarkup = true
constructor(){
super()
this.value = null
this.open = false
this.value = null
this.generalClickEvent = null
this.defaultAttrs = {
label: 'Select...',
}
}
connectedCallback() {
super.connectedCallback()
this.button = document.createElement('button')
this.button.textContent = this.getBZAttribute('label')
this.prepend(this.button)
this.button.addEventListener('click', this.toggle.bind(this))
if(!this.optionscontainer) this.optionscontainer = document.createElement('div')
this.optionscontainer.classList.add('options-container')
this.append(this.optionscontainer)
this.options = this.querySelectorAll('option')
if(this.#fillFromMarkup){ //can only do it once and only if fillOptions was not already called !!
for(const opt of this.options){
this.optionscontainer.append(opt) // Will move is to the right parent
opt.addEventListener('click', this.onClick.bind(this))
if(opt.getAttribute('selected') !== null) this.onOption(opt.value, true)
}
this.#fillFromMarkup = false
}
}
// static get observedAttributes(){ // Only if you want actions on attr change
// return([...super.observedAttributes, 'disabled'])
// }
// attributeChangedCallback(name, oldValue, newValue) {
// super.attributeChangedCallback(name, oldValue, newValue)
// }
get value(){ return(this.#value) }
set value(v) {
this.#value = v
if(this.options && this.options.length>0) {
const opt = Array.from(this.options).find(opt => opt.value==v)
if(v || (opt && opt.textContent)) this.button.textContent = opt.textContent
else this.button.textContent = this.getBZAttribute('label')
this.dispatchEvent(new Event('change', {
bubbles: true,
composed: false,
cancelable: false
}))
}
}
toggle(){
for(const opt of this.options){
if(this.open) {
opt.classList.remove('open')
this.optionscontainer.classList.remove('open')
} else {
document.querySelectorAll('bz-select').forEach((sel) => {
if((sel!==this) && sel.open) sel.toggle()
})
opt.classList.add('open')
this.optionscontainer.classList.add('open')
}
}
this.open = !this.open
}
onClick(evt){
evt.stopPropagation()
const opt = evt.target.closest('option')
if(opt && opt.value) this.onOption(opt.value)
}
onOption(value, silent=false){
if(this.getAttribute('disabled') !== null) return
this.value = value
if(!silent) this.toggle()
}
addOption(value, markup){
// Caution: you cannot count on connectedCallback to have run already, because one might fill before adding to the DOM
const opt = document.createElement('option')
opt.setAttribute('value', value)
opt.innerHTML = markup
opt.addEventListener('click',this.onClick.bind(this))
if(!this.optionscontainer) this.optionscontainer = document.createElement('div')
this.optionscontainer.append(opt)
this.options = this.querySelectorAll('option')
this.#fillFromMarkup = false
}
fillOptions(opts, erase = true){
// Caution: you cannot count on connectedCallback to have run already, because one might fill before adding to the DOM
if(erase){
this.options = this.querySelectorAll('option')
this.options.forEach(node => { node.remove() })
this.options = this.querySelectorAll('option')
this.onOption('', true) // unselect last
}
for(const opt of opts) this.addOption(opt.value, opt.markup)
}
}
Buildoz.define('select', BZselect)
class BZtoggler extends Buildoz {
#value
constructor(){
super()
this.open = false
this.defaultAttrs = {
labelLeft:'',
labelRight:'',
trueValue: 'yes',
falseValue: 'no',
classOn:'',
classOff:'',
tabindex:0,
disabled:false
}
}
connectedCallback(){
super.connectedCallback()
this.labelRight = document.createElement('div')
this.labelRight.classList.add('toggle-label-right')
this.labelRight.innerHTML = this.getBZAttribute('labelRight')
this.labelLeft = document.createElement('div')
this.labelLeft.classList.add('toggle-label-left')
this.labelLeft.innerHTML = this.getBZAttribute('labelLeft')
this.switch = document.createElement('div')
this.switch.classList.add('toggle-switch')
this.toggleBar = document.createElement('span')
this.toggleBar.classList.add('toggle-bar')
this.thumb = document.createElement('span')
this.thumb.classList.add('toggle-thumb')
this.toggleBar.append(this.thumb)
this.switch.append(this.toggleBar)
this.appendChild(this.labelLeft)
this.appendChild(this.switch)
this.appendChild(this.labelRight)
this.setAttribute('tabindex', this.getBZAttribute('tabindex'))
this.switch.addEventListener('click', this.toggle.bind(this))
}
turnOn() {
if(this.getBZAttribute('classOff')) this.switch.classList.remove(this.getBZAttribute('classOff'))
if(this.getBZAttribute('classOn')) this.switch.classList.add(this.getBZAttribute('classOn'))
this.thumb.classList.add('turned-on')
this.#value = this.getBZAttribute('trueValue')
this.focus()
}
turnOff() {
if(this.getBZAttribute('classOn')) this.switch.classList.remove(this.getBZAttribute('classOn'))
if(this.getBZAttribute('classOff'))this.switch.classList.add(this.getBZAttribute('classOff'))
this.thumb.classList.remove('turned-on')
this.#value = this.getBZAttribute('falseValue')
this.focus()
}
toggle(event) {
if(event) { event.preventDefault(); event.stopPropagation(); }
if(this.getBZAttribute('disabled')) return
if(this.#value == this.getBZAttribute('trueValue')) this.turnOff()
else this.turnOn()
this.dispatchEvent(new Event('change', {
bubbles: true,
composed: false,
cancelable: false
}))
}
get value(){ return(this.#value) }
set value(v) {
this.#value = v
if(this.defaultAttrs){
if(this.#value == this.getBZAttribute('trueValue')) this.turnOn()
else this.turnOff()
this.dispatchEvent(new Event('change', {
bubbles: true,
composed: false,
cancelable: false
}))
}
}
}
Buildoz.define('toggler', BZtoggler)
class BZslidePane extends Buildoz {
constructor(){
super()
this.open = false
this.defaultAttrs = {
side: 'bottom'
}
this.dragMove = this.dragMove.bind(this)
this.dragEnd = this.dragEnd.bind(this)
// Fill with innerHTML or other DOM manip should not allow coating to be removed
this._observer = new MutationObserver(muts => { this.coat() })
}
connectedCallback(){
super.connectedCallback()
this.coat()
this._observer.observe(this, { childList: true }) // Do this last
}
disconnectedCallback() {
super.disconnectedCallback()
this._observer.disconnect()
}
coat(){
if(this.handle && this.querySelector(this.dispatchEvent.handle)) return
this._observer.disconnect()
if(this.querySelector(this.dispatchEvent.handle)) this.querySelector(this.dispatchEvent.handle).remove()
this.handle = document.createElement('div')
this.handle.classList.add('handle')
this.prepend(this.handle)
this.handle.addEventListener('pointerdown', this.dragStart.bind(this))
this._observer.observe(this, { childList: true })
}
dragStart(evt){
evt.target.setPointerCapture(evt.pointerId)
this.dragStartX = evt.clientX
this.dragStartY = evt.clientY
this.handle.addEventListener('pointermove', this.dragMove)
this.handle.addEventListener('pointerup', this.dragEnd)
}
dragMove(evt){
const box = this.getBoundingClientRect()
const parentBox = this.parentElement.getBoundingClientRect()
let width, height
switch(this.getAttribute('side')){
case 'top':
height = (evt.clientY > box.top) ? (evt.clientY - box.top) : 0
if(height>(parentBox.height/2)) height = Math.floor(parentBox.height/2)
this.style.height = height+'px'
break
case 'bottom':
height = (evt.clientY < box.bottom) ? (box.bottom - evt.clientY) : 0
if(height>(parentBox.height/2)) height = Math.floor(parentBox.height/2)
this.style.height = height+'px'
break
case 'left':
width = (evt.clientX > box.left) ? (evt.clientX - box.left) : 0
if(width>(parentBox.width/2)) width = Math.floor(parentBox.width/2)
this.style.width = width+'px'
break
case'right':
width = (evt.clientX < box.right) ? (box.right - evt.clientX) : 0
if(width>(parentBox.width/2)) width = Math.floor(parentBox.width/2)
this.style.width = width+'px'
break
}
}
dragEnd(evt){
evt.target.releasePointerCapture(evt.pointerId)
this.handle.removeEventListener('pointermove', this.dragMove)
this.handle.removeEventListener('pointerup', this.dragEnd)
}
}
Buildoz.define('slidepane', BZslidePane)
-610
View File
@@ -1,610 +0,0 @@
class BZgraflow extends Buildoz{
constructor(){
super()
this.defaultAttrs = { tension: 100 }
this.stagedNodes = { }
this.stagedWires = { }
this.arrowDefs = null
}
static _loadedNodeStyles = new Set() // Allow multi instances or re-loadNodes, but avoid reinjecting same styles !
connectedCallback() {
super.connectedCallback()
const flowUrl = this.getBZAttribute('flow')
if(!flowUrl) {
console.warn('BZgraflow: No flow URL !?')
return
}
this.mainContainer = document.createElement('div')
this.mainContainer.classList.add('bzgf-main-container')
this.shadow = this.mainContainer.attachShadow({ mode: 'open' })
const style = document.createElement('style')
style.textContent = `
.bzgf-wires-container,
.bzgf-nodes-container{ position: absolute; inset: 0; width: 100%; height: 100%; }
.bzgf-nodes-container .bzgf-node{ position:absolute; }
.bzgf-nodes-container .bzgf-fake-node{
position: absolute;
width: 5px;
height: 5px;
backgrround: transparent;
border-style: none;
}
`
this.shadow.appendChild(style)
this.nodesContainer = document.createElement('div')
this.nodesContainer.classList.add('bzgf-nodes-container')
this.wiresContainer = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
this.wiresContainer.setAttribute('overflow','visible')
this.wiresContainer.classList.add('bzgf-wires-container')
this.shadow.append(this.wiresContainer)
this.shadow.append(this.nodesContainer)
this.append(this.mainContainer)
this.loadFlow(flowUrl) // Let it load async
}
error(msg, err){
this.innerHTML = `<div style="background:red;color:black;margin: auto;width: fit-content;">${msg}</div>`
if(err) console.error(msg, err)
else console.error(msg)
}
async loadFlow(url){
const res = await fetch(url+'?'+crypto.randomUUID())
const buf = await res.text()
let flowObj
try{
flowObj = JSON.parse(buf)
} catch(err){
this.error('Could not parse flow JSON!?', err)
return
}
if(!flowObj.nodesFile){
this.error('No nodesFile in JSON!?')
return
}
await this.loadNodes(flowObj.nodesFile)
this.flow = flowObj.flow
this.refresh()
}
async loadNodes(url) {
const res = await fetch(url+'?'+crypto.randomUUID())
const html = await res.text()
// Get nodes
const doc = new DOMParser().parseFromString(html, 'text/html')
this.nodesRegistry = {}
for(const tpl of doc.querySelectorAll('template')){
if(tpl.id=='svg-arrows'){
this.arrowDefs = tpl.querySelector('defs').cloneNode(true)
this.wiresContainer.appendChild(this.arrowDefs)
} else {
const rootEl = tpl.content.querySelector('.bzgf-node')
if(!rootEl) continue
this.nodesRegistry[rootEl.dataset.nodetype] = rootEl
}
}
// Now load styles (once)
if(!BZgraflow._loadedNodeStyles.has(url)) {
const styles = doc.querySelectorAll('style')
styles.forEach(styleEl => {
const style = document.createElement('style')
style.textContent = styleEl.textContent
this.shadow.appendChild(style)
})
BZgraflow._loadedNodeStyles.add(url)
}
}
addNode(node){
const id = node.id
if(!(node.nodeType in this.nodesRegistry)){ console.warn(`Unknown node type (${node.nodeType})`); return(null)}
const nodeDef = this.nodesRegistry[node.nodeType]
this.stagedNodes[id] = nodeDef.cloneNode(true)
for(const token in node.markup){
this.stagedNodes[id].innerHTML = this.stagedNodes[id].innerHTML.replace(new RegExp(`\{${token}\}`, 'g'), node.markup[token])
}
if(typeof(node.data)=='object') Object.assign(this.stagedNodes[id].dataset, node.data)
const portEls = this.stagedNodes[id].querySelectorAll('.port')
this.stagedNodes[id].style.left = (node.coords && node.coords.x) ? `${node.coords.x}px` : '10%'
this.stagedNodes[id].style.top = (node.coords && node.coords.y) ? `${node.coords.y}px` : '10%'
this.stagedNodes[id].dataset.id = id
this.stagedNodes[id].ports = Object.fromEntries(Array.from(portEls).map(item => ([item.dataset.id, { ...item.dataset, el:item }])))
this.nodesContainer.append(this.stagedNodes[id])
return(this.stagedNodes[id])
}
addFakeNode(nid, x, y, w, h){
this.stagedNodes[nid] = document.createElement('div')
this.stagedNodes[nid].classList.add('bzgf-fake-node')
this.stagedNodes[nid].style.left = `${x}px`
this.stagedNodes[nid].style.top = `${y}px`
this.stagedNodes[nid].style.width = `${w}px`
this.stagedNodes[nid].style.height = `${h}px`
this.stagedNodes[nid].dataset.id = nid
this.nodesContainer.append(this.stagedNodes[nid])
return(this.stagedNodes[nid])
}
addWire(link){
const [idNode1, idPort1] = link.from
const [idNode2, idPort2] = link.to
const path = this.bezierNodes(idNode1, idPort1, idNode2, idPort2, this.getBZAttribute('tension'))
const id = `${idNode1}_${idNode2}`
this.stagedWires[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path')
this.stagedWires[id].setAttribute('d', path)
this.stagedWires[id].setAttribute('fill', 'none')
if(this.arrowDefs && link.endArrow) this.stagedWires[id].setAttribute('marker-end','url(#arrow)')
if(this.arrowDefs && link.startArrow) this.stagedWires[id].setAttribute('marker-start','url(#arrow)')
this.stagedWires[id].classList.add('bzgf-wire')
this.stagedWires[id].dataset.id = id
this.wiresContainer.append(this.stagedWires[id])
return(this.stagedWires[id])
}
clear(){
this.nodesContainer.innerHTML = ''
this.wiresContainer.innerHTML = ''
if(this.arrowDefs) this.wiresContainer.appendChild(this.arrowDefs)
}
refresh(){
this.clear()
let forceAutoplace = false
for(const node of this.flow.nodes){
if((!node.coords) || (!node.coords.x) ||(!node.coords.y)) forceAutoplace=true
this.addNode(node)
}
for(const link of this.flow.links){
this.addWire(link)
}
if(forceAutoplace){
const bb=this.getBoundingClientRect()
//TODO compute tensions from ports
if(bb.width > bb.height) this.autoPlace('horizontal', 80, 30, 500)
else this.autoPlace('vertical', 80, 30, 200)
}
}
bezierNodes(idNode1, idPort1, idNode2, idPort2, tensionMin=60) {
const svgRect = this.wiresContainer.getBoundingClientRect()
const node1 = this.stagedNodes[idNode1]
const port1 = node1.ports[idPort1]
const node2 = this.stagedNodes[idNode2]
const port2 = node2.ports[idPort2]
if(!node1 || !node2 || !port1 || !port2) {
console.warn('Link on bad node / port ', idNode1, idPort1, idNode2, idPort2)
return('')
}
const bb1 = port1.el.getBoundingClientRect()
const bb2 = port2.el.getBoundingClientRect()
const x1 = Math.floor(bb1.x + (bb1.width/2)) - svgRect.left
const y1 = Math.floor(bb1.y + (bb1.height/2)) - svgRect.top
const x2 = Math.floor(bb2.x + (bb2.width/2)) - svgRect.left
const y2 = Math.floor(bb2.y + (bb2.height/2)) - svgRect.top
const loop = (idNode1==idNode2) && (idPort1==idPort2)
const dist = Math.abs(x2 - x1) + Math.abs(y2 - y1)
let tension = dist * 0.4
if(tension < tensionMin) tension = parseInt(tensionMin)
const dirVect = {
n: { x: 0, y: -1 },
s: { x: 0, y: 1 },
e: { x: 1, y: 0 },
w: { x: -1, y: 0 },
}
let c1x = x1 + (dirVect[port1.direction].x * tension)
let c1y = y1 + (dirVect[port1.direction].y * tension)
let c2x = x2 + (dirVect[port2.direction].x * tension)
let c2y = y2 + (dirVect[port2.direction].y * tension)
if(loop){
if(['n', 's'].includes(port1.direction)) {
c1x += tension
c2x -= tension
}
if(['e', 'w'].includes(port1.direction)){
c1y += 1*tension
c2y -= 1*tension
}
}
return(`M ${x1} ${y1} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`)
}
bezierInterNodes(idNode1, idPort1, idNode2, idPort2, interNodes, orientation='horizontal', tensionMin=60) {
const svgRect = this.wiresContainer.getBoundingClientRect()
const makeCubicBezier = (x1, y1, x2, y2, orientation) => {
const dist = Math.abs(x2 - x1) + Math.abs(y2 - y1)
let tension = dist * 0.4
if(tension < tensionMin) tension = parseInt(tensionMin)
let c1x, c1y, c2x, c2y
if(orientation=='horizontal'){
c1x = x1 + tension
c1y = y1
c2x = x2 - tension
c2y = y2
} else {
c1x = x1
c1y = y1 + tension
c2x = x2
c2y = y2 - tension
}
return(`C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`)
}
const directPath = this.bezierNodes(idNode1, idPort1, idNode2, idPort2, tensionMin)
const startPath = directPath.substring(0,directPath.indexOf('C'))
const endPath = directPath.substring(directPath.lastIndexOf(',')+1).trim()
let path = startPath
let [ , x1, y1] = startPath.split(' ')
x1 = parseInt(x1)
y1 = parseInt(y1)
for(const interNode of interNodes){
const bb = this.stagedNodes[interNode].getBoundingClientRect()
let x2; let y2;
if(orientation=='horizontal'){
x2 = bb.x -svgRect.left
y2 =Math.floor(bb.y + (bb.height/2)) - svgRect.top
path += makeCubicBezier(x1, y1, x2, y2, orientation)
x2 += bb.width
path += ` L ${x2} ${y2} `
} else {
x2 = Math.floor(bb.x + (bb.width/2)) - svgRect.left
y2 = bb.y - svgRect.top
path += makeCubicBezier(x1, y1, x2, y2, orientation)
y2 += bb.height
path += ` L ${x2} ${y2} `
}
x1 = x2
y1 = y2
}
let [x2, y2] = endPath.split(' ')
x2 = parseInt(x2)
y2 = parseInt(y2)
path += ' '+makeCubicBezier(x1, y1, x2, y2, orientation)
return(path)
}
autoPlace(orientation = 'horizontal', gapx = 80, gapy = 80, tween=1000){
// Loops create infinite recursion in dfs for getting parents & adjacency lists: Remove them !
let linksWithoutBackEdges
if(this.hasAnyLoop(this.flow.nodes, this.flow.links)){
console.warn('Loop(s) detected... Cannot auto-place !')
const backEdges = this.findBackEdges(this.flow.nodes, this.flow.links)
linksWithoutBackEdges = this.flow.links.filter((link, idx) => (!backEdges.includes(idx)) && (link.from[0] != link.to[0]))
} else {
linksWithoutBackEdges = this.flow.links
}
const { parents, adj } = this.buildGraphStructures(this.flow.nodes, linksWithoutBackEdges)
const layers = this.computeLayers(this.flow.nodes, parents)
// Compute indexes for each layer (int part) & add sub-index for ports
// Also compute max width/height for each layer
let maxHeight = 0; let maxWidth = 0
const layerHeights = []; const layerWidths = [];
const indexes = {} // indexes[nid] = { base: <int>, ports: { [portId]: <float in [0,1)> } }
for(const layer of layers){
let totHeight = 0; let totWidth = 0
for(const [idx, nid] of layer.entries()){
const bb = this.stagedNodes[nid].getBoundingClientRect()
totHeight += bb.height + gapy
totWidth += bb.width + gapx
indexes[nid] = { base: idx, ports: this.computePortOffsets(nid, orientation) }
}
if(totHeight>maxHeight) maxHeight = totHeight
layerHeights.push(totHeight)
if(totWidth>maxWidth) maxWidth = totWidth
layerWidths.push(totWidth)
}
// If any long-links, create placeholders for skipped layers
this.flow.longLinks = this.findLongLinks(this.flow.links)
for(const link of this.flow.longLinks){
for(const layerIdx of link.skippedLayers){
const nid = `longLinkPlaceHolder_${crypto.randomUUID()}`
layers[layerIdx].push(nid)
link.interNodes.push(nid)
}
}
// Reorder layers to avoid crossings thanks to indexes
this.reorderLayers(layers, parents, indexes, orientation)
// Finally place everything
if(orientation=='horizontal'){
let x = gapx
for(const [idx, layer] of layers.entries()){
let wMax = this.getMaxWidth(layer)
let y = ((maxHeight - layerHeights[idx]) / 2) + gapy
for(const nid of layer){
if(!nid.startsWith('longLinkPlaceHolder_')) {
const bb = this.stagedNodes[nid].getBoundingClientRect()
this.moveNode(nid, x, y, orientation, tween)
y += gapy + bb.height
} else {
this.addFakeNode(nid, x, y, wMax, 10)
this.moveNode(nid, x, y, orientation, tween)
y += gapy + 10 //TODO
}
}
x += wMax + gapx
}
} else if(orientation=='vertical'){
let y = gapy
for(const [idx, layer] of layers.entries()){
let hMax = this.getMaxHeight(layer)
let x = ((maxWidth - layerWidths[idx]) / 2) + gapx
for(const nid of layer){
if(!nid.startsWith('longLinkPlaceHolder_')){
const bb = this.stagedNodes[nid].getBoundingClientRect()
this.moveNode(nid, x, y, orientation, tween)
x += gapx + bb.width
} else {
this.addFakeNode(nid, x, y, 10, hMax)
this.moveNode(nid, x, y, orientation, tween)
x += gapx + 10 //TODO
}
}
y += hMax + gapy
}
}
}
getMaxWidth(layer){
return(layer.filter(nid =>
!nid.startsWith('longLinkPlaceHolder_'))
.map(nid => this.stagedNodes[nid].getBoundingClientRect().width)
.reduce((a, b) => a > b ? a : b, 0)
)
}
getMaxHeight(layer){
return(layer.filter(nid =>
!nid.startsWith('longLinkPlaceHolder_'))
.map(nid => this.stagedNodes[nid].getBoundingClientRect().height)
.reduce((a, b) => a > b ? a : b, 0)
)
}
computePortOffsets(nid, orientation = 'horizontal'){
const node = this.stagedNodes[nid]
if(!node || !node.ports) return({})
const axis = (orientation === 'vertical') ? 'x' : 'y'
const nodeRect = node.getBoundingClientRect()
const ports = Object.entries(node.ports)
.map(([pid, p]) => {
const r = p.el.getBoundingClientRect()
const pos = (axis === 'x')
? (r.left + (r.width / 2) - nodeRect.left)
: (r.top + (r.height / 2) - nodeRect.top)
return({ pid, pos })
})
.sort((a, b) => a.pos - b.pos) // smaller pos => "higher/left" => smaller offset
const denom = ports.length + 1
const offsets = {}
for(const [rank, item] of ports.entries()){
offsets[item.pid] = rank / denom // always < 1
}
return(offsets)
}
reorderLayers(layers, parents, indexes, orientation = 'horizontal'){
const swap = (vect, todo) => {
for(const s of todo){
[vect[s[0]], vect[s[1]]] = [vect[s[1]], vect[s[0]]]
}
}
const adjIndex = (nid, portId) => {
const info = indexes?.[nid]
const base = (info && info.base !== undefined) ? info.base : 0
const off = (portId && info?.ports?.[portId] !== undefined) ? info.ports[portId] : 0
return(base + off)
}
for(const [lidx, layer] of layers.entries()){
if(lidx==0) continue
const toSwap = []
for(let i=0; i<layer.length; i++){
const nid1 = layer[i]
if(nid1.startsWith('longLinkPlaceHolder_')) continue
// some parents can be in far layers, but at least one is in the prev layer (by definition of layer)
const pnid1 = parents[nid1].find((nid => layers[lidx-1].includes(nid)))
for(let j=i+1; j<layer.length; j++){
const nid2 = layer[j]
if(nid2.startsWith('longLinkPlaceHolder_')) continue
const pnid2 = parents[nid2].find((nid => layers[lidx-1].includes(nid)))
const link1 = (pnid1) ? this.getLink(pnid1, nid1) : null
const link2 = (pnid2) ? this.getLink(pnid2, nid2) : null
const p1 = adjIndex(pnid1, link1?.from?.[1])
const p2 = adjIndex(pnid2, link2?.from?.[1])
const c1 = adjIndex(nid1, link1?.to?.[1])
const c2 = adjIndex(nid2, link2?.to?.[1])
if(((p1 - p2) * (c1 - c2)) < 0) { // crossing (now refined by per-port ordering)
toSwap.push([i, j])
}
}
}
swap(layer, toSwap)
}
}
moveNode(nid, destx, desty, orientation, duration = 200, cb) {
const t0 = performance.now()
const bb = this.stagedNodes[nid].getBoundingClientRect()
const parentbb = this.stagedNodes[nid].parentElement.getBoundingClientRect()
const x0=bb.x - parentbb.x
const y0 = bb.y - parentbb.y
function frame(t) {
const p = Math.min((t - t0) / duration, 1)
const k = p * p * (3 - 2 * p) // smoothstep
const x = x0 + (destx - x0) * k
const y = y0 + (desty - y0) * k
this.stagedNodes[nid].style.left = `${x}px`
this.stagedNodes[nid].style.top = `${y}px`
this.updateWires(nid, orientation)
if(p < 1) requestAnimationFrame(frame.bind(this))
}
requestAnimationFrame(frame.bind(this))
}
updateWires(nid, orientation){
const wires = Object.keys(this.stagedWires)
.filter(id => (id.startsWith(nid+'_')||id.endsWith('_'+nid)))
.map(id => this.stagedWires[id])
for(const wire of wires){
const [nid1, nid2] = wire.dataset.id.split('_')
const lnk = this.getLink(nid1, nid2)
const longLink = this.flow.longLinks.find(item => (item.link.from[0] == lnk.from[0] && item.link.from[1] == lnk.from[1] && item.link.to[0] == lnk.to[0] && item.link.to[1] == lnk.to[1]))
if(longLink) {
const path = this.bezierInterNodes(nid1, lnk.from[1], nid2, lnk.to[1], longLink.interNodes, orientation, this.getBZAttribute('tension'))
wire.setAttribute('d', path)
} else {
const path = this.bezierNodes(nid1, lnk.from[1], nid2, lnk.to[1], this.getBZAttribute('tension'))
wire.setAttribute('d', path)
}
}
}
getLink(nid1, nid2){
return(this.flow.links.find(item => ((item.from[0]==nid1) && (item.to[0]==nid2))))
}
buildGraphStructures(nodes, links, includeLinkIndexes = false) {
const parents = {}
const adj = {}
nodes.forEach(n => {
parents[n.id] = []
adj[n.id] = []
})
links.forEach((link, idx) => {
const from = link.from[0]
const to = link.to[0]
if(link.from[0] !== link.to[0]) { // Skip self-loops
parents[to].push(from)
if(includeLinkIndexes) {
adj[from].push({ to, linkIdx: idx })
} else {
adj[from].push(to)
}
}
})
return({ parents, adj })
}
computeLayers(nodes, parents) {
const layer = {}
const dfs = (id) => {
if (layer[id] !== undefined) return(layer[id])
if (parents[id].length === 0) {
layer[id] = 0
} else {
layer[id] = 1 + Math.max(...parents[id].map(dfs))
}
return(layer[id])
}
nodes.forEach(n => dfs(n.id))
const t = []
for(const nid in layer) {
if(!t[layer[nid]]) t[layer[nid]]=[]
t[layer[nid]].push(nid)
}
return(t)
}
hasAnyLoop(nodes, links) {
if(links.some(l => l.from[0] === l.to[0])) return(true) // self-loops
const { adj } = this.buildGraphStructures(nodes, links)
const visiting = new Set();
const visited = new Set()
const dfs = (nid) => {
if(visiting.has(nid)) {
return(true)
}
if(visited.has(nid)) return(false)
visiting.add(nid)
for(const m of adj[nid]) {
if(dfs(m)) {
return(true)
}
}
visiting.delete(nid)
visited.add(nid)
return(false)
}
return(nodes.map(n => n.id).some(dfs))
}
findBackEdges(nodes, links) {
const { adj } = this.buildGraphStructures(nodes, links, true)
const color = {}; nodes.forEach(n => color[n.id] = 'white')
const backEdges = []
function dfs(u) {
color[u] = 'gray'
for (const neighbor of adj[u]) {
const v = neighbor.to
const linkIdx = neighbor.linkIdx
if (color[v] === 'gray') {
backEdges.push(linkIdx) // 👈 cycle edge - return link index
} else if (color[v] === 'white') {
dfs(v)
}
}
color[u] = 'black'
}
nodes.forEach(n => {
if (color[n.id] === 'white') dfs(n.id)
})
return(backEdges)
}
findLongLinks(links) {
let linksWithoutBackEdges
if(this.hasAnyLoop(this.flow.nodes, this.flow.links)){
console.warn('Loop(s) detected... Cannot auto-place !')
const backEdges = this.findBackEdges(this.flow.nodes, this.flow.links)
linksWithoutBackEdges = this.flow.links.filter((link, idx) => (!backEdges.includes(idx)) && (link.from[0] != link.to[0]))
} else {
linksWithoutBackEdges = this.flow.links
}
/// Yes that means we ignore long & back links !
const { parents } = this.buildGraphStructures(this.flow.nodes, linksWithoutBackEdges)
const layers = this.computeLayers(this.flow.nodes, parents)
const crossLayerLinks = []
for(const link of links){
const from = link.from[0]
const to = link.to[0]
const idx1 = layers.findIndex(layer => layer.includes(from))
const idx2 = layers.findIndex(layer => layer.includes(to))
if(Math.abs(idx1-idx2)>1) {
const lowerIdx = idx1<idx2 ? idx1 : idx2
const higherIdx = idx1>idx2 ? idx1 : idx2
crossLayerLinks.push({
link,
linkIdx: link.linkIdx,
interNodes: [],
skippedLayers: Array.from({ length: higherIdx - lowerIdx - 1 }, (_, i) => lowerIdx + i + 1),
})
}
}
return(crossLayerLinks)
}
}
Buildoz.define('graflow', BZgraflow)
+4 -3
View File
@@ -3370,9 +3370,10 @@ class DataGrid extends EicComponent {
if(this.options.rowActions && Array.isArray(this.options.rowActions)) {
for(let action of this.options.rowActions) {
let button = ui.create(`<button eicbutton rounded title="${action.title ? action.title: ''}">${action.icon}</button>`);
button.addEventListener('click', action.callback.bind(row.getAttribute('data-id') != '' ? JSON.parse(row.getAttribute('data-id')): this));
actions.appendChild(button);
const severityAttr = action.severity ? ` ${action.severity}` : ''
let button = ui.create(`<button eicbutton rounded${severityAttr} title="${action.title ? action.title: ''}">${action.icon}</button>`)
button.addEventListener('click', action.callback.bind(row.getAttribute('data-id') != '' ? JSON.parse(row.getAttribute('data-id')): this))
actions.appendChild(button)
}
}
@@ -1,3 +1,15 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
class ProfilePreferencesResetDialog extends WindozDialogContent {
actions = [
{
+12
View File
@@ -1,3 +1,15 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
class myProfileView extends WindozDomContent {
DOMContentLoaded() {
+79 -16
View File
@@ -1,8 +1,20 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
class KeyframeView extends WindozDomContent {
constructor() {
super()
Object.assign(this, app.helpers.activeAttributes, app.helpers.formBuilder, app.helpers.kfConsole)
Object.assign(this, app.helpers.activeAttributes, app.helpers.formBuilder, app.helpers.kfConsole, app.helpers.basicDialogs)
}
DOMContentFocused(options) {
@@ -57,13 +69,42 @@ class KeyframeView extends WindozDomContent {
this.kfArena.onclickAgent = this.onclickAgent.bind(this)
this.kfArena.startRendering()
this.output('settingsMenu', app.Assets.Store.html.spaceViewSetting)
this.outputs.settingsMenu.querySelectorAll('input[type="toggler"]').forEach(el => {
const tog = new InputToggler(el)
if(this.kfArena[tog._el.name]?.layers){
tog.value = this.kfArena.camera.layers.test(this.kfArena[tog._el.name].layers) ? 'yes' : 'no'
}
tog.onToggle = this.settingsToggle.bind(this)
})
this.outputs.btnAddAgent.disabled = true
this.outputs.btnRemoveAgent.disabled = true
this.outputs.btnSaveKF.disabled = true
this.outputs.btnResetKF.disabled = true
this.outputs.kfName.addEventListener('keyup', this.updateKfButtons.bind(this))
this.currentlySelectedAid = null
}
settingsToggle(value, object){
if(['grid','axes'].includes(object._el.name)){
const layerId = {'grid':1,'axes':2}[object._el.name]
if(value=='yes'){
this.kfArena.camera.layers.enable(layerId)
} else {
this.kfArena.camera.layers.disable(layerId)
}
}
}
deselectSceneAgent(){
if(!this.currentlySelectedAid) return
const obj3D = this.kfArena.scene.getObjectByName(this.currentlySelectedAid)
if(obj3D) this.kfArena.clearHighlight3DObj(obj3D, this.kfArena.scene)
this.currentlySelectedAid = null
this.outputs.btnRemoveAgent.disabled = true
}
async onChangeAgent(event){
if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value)
if(!this.outputs.agentsSelector.value) return
@@ -73,36 +114,52 @@ class KeyframeView extends WindozDomContent {
} else {
this.currentAgentType = await this.models.agents.getProperties(this.outputs.agentsSelector.value)
this.fillAgentProperties('', this.currentAgentType)
// Deselect any on-scene selection
if(this.currentlySelectedAid){
this.kfArena.clearHighlight3DObj(this.kfArena.scene.getObjectByName(this.currentlySelectedAid), this.kfArena.scene)
}
this.currentlySelectedAid = null
this.deselectSceneAgent()
}
}
async onChangeKeyframe(event){
if(!this.outputs.keyframesSelector.value) return
let kfData = await this.models.keyframes.getKeyframe(this.outputs.keyframesSelector.value).then(data => data.payload)
await this.loadKeyframe(this.outputs.keyframesSelector.value)
}
async onResetKF(evt){
if(!this.currentKeyframe.kfId) return
const kfName = this.currentKeyframe.kfName
const kfId = this.currentKeyframe.kfId
await this.confirmDialog({
title: 'Reset keyframe ?',
message: `<p>You are about to discard all unsaved changes<br>and reload the saved version of "<b>${kfName}</b>".<br><br>
Are you sure?</p>`,
okLabel: 'Reset',
severity: 'warning',
okPromise: async () => {
await this.loadKeyframe(kfId)
}
})
}
async loadKeyframe(kfId){
let kfData = await this.models.keyframes.getKeyframe(kfId).then(data => data.payload)
this.currentKeyframe = {
kfId: kfData.info.ekf_uuid,
kfName: kfData.info.ekf_name,
prevKfId: kfData.info.ekf_prev_uuid,
}
this.outputs.kfName.value = kfData.info.ekf_name
this.deselectSceneAgent()
this.kfArena.reloadAgents(kfData.agents)
this.outputs.agentProperties.innerHTML = ''
this.outputs.btnAddAgent.disabled = true
this.updateKfButtons()
}
onclickAgent(obj3D){
const aid = obj3D.name
if(this.currentlySelectedAid == aid){ // Deselect
this.kfArena.clearHighlight3DObj(obj3D, this.kfArena.scene)
this.currentlySelectedAid = null
this.outputs.btnRemoveAgent.disabled = true
this.deselectSceneAgent()
} else { // Select
if(this.currentlySelectedAid){
this.kfArena.clearHighlight3DObj(this.kfArena.scene.getObjectByName(this.currentlySelectedAid), this.kfArena.scene)
}
this.deselectSceneAgent()
this.currentlySelectedAid = aid
this.outputs.btnRemoveAgent.disabled = false
if(this.kfArena.agents[aid]) {
@@ -127,6 +184,10 @@ class KeyframeView extends WindozDomContent {
onRemoveAgent(event){
if(!this.currentlySelectedAid) return
this.kfArena.removeAgent(this.currentlySelectedAid)
this.currentlySelectedAid = null
this.outputs.btnRemoveAgent.disabled = true
if(this.currentAgentType) this.fillAgentProperties('', this.currentAgentType)
this.updateKfButtons()
}
async newAgent(aType, AgentValues){
@@ -139,20 +200,21 @@ class KeyframeView extends WindozDomContent {
updateKfButtons(){
if((Object.keys(this.kfArena.agents).length > 0) && (this.outputs.kfName.value.length > 5)) { this.outputs.btnSaveKF.disabled = false }
else { this.outputs.btnSaveKF.disabled = true }
this.outputs.btnResetKF.disabled = !this.currentKeyframe.kfId
}
onPropsChanged(evt, comp){
if(this.currentlySelectedAid && this.kfArena.agents[this.currentlySelectedAid]){
const AgentValues = this.getFieldsValues('div[data-output="agentProperties"]')
this.kfArena.agents[this.currentlySelectedAid].values = AgentValues
const val = Number.parseInt(comp.value, 10)
if((comp.name.startsWith('position.')) && (!Number.isNaN(val))){
const val = Number(comp.value)
if((comp.name.startsWith('position.')) && (Number.isFinite(val))){
this.kfArena.moveAgent(this.currentlySelectedAid, {
x: this.getFieldValue('div[data-output="agentProperties"]', 'position.x'),
y: this.getFieldValue('div[data-output="agentProperties"]', 'position.y'),
z: this.getFieldValue('div[data-output="agentProperties"]', 'position.z'),
})
} else if((comp.name.startsWith('speed.')) && (!Number.isNaN(val))){
} else if((comp.name.startsWith('speed.')) && (Number.isFinite(val))){
this.kfArena.changeAgentSpeed(this.currentlySelectedAid, {
x: this.getFieldValue('div[data-output="agentProperties"]', 'speed.x'),
y: this.getFieldValue('div[data-output="agentProperties"]', 'speed.y'),
@@ -218,6 +280,7 @@ class KeyframeView extends WindozDomContent {
await this.models.keyframes.save(this.currentKeyframe.kfId, this.kfArena.agents)
this.outputs.btnSaveKF.disabled = true
this.updateKfButtons()
ui.growl.append('Keyframe saved!','success',3000)
setTimeout(() => { this.outputs.btnSaveKF.disabled = false}, 3000)
}
@@ -1,3 +1,15 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
import * as THREE from 'three' //'/app/thirdparty/Three/three.module.js'
export class AgentPreview{
@@ -1,3 +1,15 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as TWEEN from 'three/examples/jsm/libs/tween.module.js'
+33
View File
@@ -0,0 +1,33 @@
<style>
.create-sim > section {
padding: 1em;
display: grid;
grid-gap: .5em;
}
.create-sim bz-select[data-output="keyframesSelector"] {
margin-top: 1em;
}
.create-sim .cols-2 { align-items: baseline; }
.create-sim button[eicbutton][rounded] {
background-color: #367;
color: #DDD !important;
padding: .5em 1em !important;
justify-self: center;
}
</style>
<article eiccard class="create-sim">
<header>
<h1>Create a simulation</h1>
</header>
<section>
<div class="cols-2">
<label>Simulation first keyframe:</label>
<bz-select label="Existing keyframes..." data-output="keyframesSelector"></bz-select>
</div>
<div class="cols-2">
<label>Simulation Name:</label>
<input type="text" data-output="simName" placeholder="(min 5 chars)"/>
</div>
<button eicbutton rounded data-output="btnCreateSim" data-trigger="onCreateSim">Create Simulation</button>
</section>
</article>
+37
View File
@@ -0,0 +1,37 @@
class CreateSimView extends WindozDomContent {
constructor() {
super()
Object.assign(this, app.helpers.activeAttributes, app.helpers.basicDialogs)
}
async DOMContentLoaded(options) {
this.models = options.models
const components = ui.eicfy(this.el)
this.setupTriggers(components)
this.setupRefs(components)
this.models.keyframes.list('', null).then(data => data.payload).then(kflist => {
this.outputs.keyframesSelector.fillOptions(kflist.map(item => {
return({
markup: item.ekf_name,
value: item.ekf_uuid
})
}))
})
}
onCreateSim(comp, event) {
if(!this.outputs.keyframesSelector.value) return
if(!this.outputs.simName.value) return
this.models.sims.create({
kfId: this.outputs.keyframesSelector.value,
simName: this.outputs.simName.value
}).then(data => {
const simulationUuid = data?.payload?.simulationUuid ?? 'unknown'
ui.growl.append(`Simulation created (${simulationUuid})`, 'success', 4000)
})
this.unload()
}
}
app.registerClass('CreateSimView', CreateSimView)
+18
View File
@@ -0,0 +1,18 @@
<style>
.manage-sim > section {
height: 100%;
padding: 0;
}
.manage-sim .sim-list .row {
grid-template-columns: 2fr 2fr 1fr 6em 10em;
}
.manage-sim .sim-list .cell { text-align: center; }
</style>
<article eiccard class="manage-sim">
<header>
<h1>Play / Pause / Stop a simulation</h1>
</header>
<section>
<div eicdatagrid class="sim-list"></div>
</section>
</article>
+205
View File
@@ -0,0 +1,205 @@
class ManageSimView extends WindozDomContent {
#lifecycleEventTypes = [
'onYourMarks',
'bigBang',
'simulationPaused',
'simulationResumed',
'simulationStopped',
'simulationPrepareFailed',
]
constructor() {
super()
Object.assign(this, app.helpers.activeAttributes, app.helpers.basicDialogs)
this.lifecycleChan = app.Assets.Store.json.busChannels.maestro.lifecycleChannel
this.lifecycleChan = this.lifecycleChan.replace(/\[UID\]/g, app.User.identity.uuid)
}
async DOMContentLoaded(options) {
this.models = options.models
this.wasBlured = false
this._refreshSeq = 0
this.lifecycleSubscribed = false
ui.eicfy(this.el)
const view = this
this.simGrid = new DataGrid(this.find('.sim-list'), {
headers: [
{ label: 'Simulation', sortable: true },
{ label: 'Primordial frame', sortable: true },
{ label: 'Owner', sortable: true },
{ label: 'Status', sortable: true },
{ label: '', sortable: false },
],
height: '480px',
rowActions: [
{
icon: '<i class="icon-play"></i>',
title: 'Start simulation',
severity: 'success',
callback: async function(event) {
await view.onPlaySim(this, event.currentTarget)
},
},
{
icon: '<i class="icon-pause"></i>',
title: 'Pause simulation',
severity: 'secondary',
callback: async function(event) {
await view.onPauseSim(this, event.currentTarget)
},
},
{
icon: '<i class="icon-stop"></i>',
title: 'Stop simulation',
severity: 'danger',
callback: async function(event) {
await view.onStopSim(this, event.currentTarget)
},
},
],
})
this.simGrid.enableFooter = false
await this.refreshSimList()
}
async DOMContentFocused() {
await this.subscribeLifecycle()
if(!this.wasBlured) return
this.wasBlured = false
this.refreshSimList()
}
async DOMContentBlured() {
this.wasBlured = true
await this.unsubscribeLifecycle()
}
async subscribeLifecycle() {
if(this.lifecycleSubscribed || !app.MessageBus?.connected) return
await app.MessageBus.subscribe([this.lifecycleChan])
for(const eventType of this.#lifecycleEventTypes) {
app.MessageBus.addBusListener(eventType, [this.lifecycleChan], this.lifecycleListener, 'ManageSimView')
}
this.lifecycleSubscribed = true
}
async unsubscribeLifecycle() {
if(!this.lifecycleSubscribed || !app.MessageBus?.connected) return
for(const eventType of this.#lifecycleEventTypes) {
app.MessageBus.removeBusListener(eventType, this.lifecycleListener, 'ManageSimView')
}
await app.MessageBus.unSubscribe([this.lifecycleChan])
this.lifecycleSubscribed = false
}
lifecycleListener(realChan, payload, sender) {
console.log('[ManageSimView] maestro lifecycle', { realChan, payload, sender })
}
async refreshSimList() {
const seq = ++this._refreshSeq
this.simGrid.loading = true
this.simGrid.clear()
try {
const data = await this.models.sims.list()
if(seq !== this._refreshSeq) return
const sims = data?.payload ?? []
this.simGrid.clear()
for(const sim of sims) {
const row = this.simGrid.addRow(
{ simulationUuid: sim.simulationUuid },
[
sim.sim_name ?? '',
sim.ekf_name ?? '',
sim.usr_name ?? '',
sim.state ?? 'idle',
],
true
)
this.updateSimButtons(sim.state ?? 'idle', row)
}
this.simGrid.updateFilters()
} finally {
if(seq === this._refreshSeq) this.simGrid.loading = false
}
}
updateSimButtons(state, rowEl) {
const buttons = rowEl?.querySelectorAll('.cell.actions button[eicbutton]')
if(!buttons || buttons.length < 3) return
const enabledByState = {
idle: [true, false, false],
preparing: [false, false, false],
live: [false, true, true],
paused: [true, false, true],
}
const enabled = enabledByState[state] ?? [false, false, false]
for(let i = 0; i < 3; i++) {
buttons[i].disabled = !enabled[i]
}
}
async onPlaySim(rowId, button) {
const simulationUuid = rowId?.simulationUuid
if(!simulationUuid) return
const row = button.closest('.row')
button.disabled = true
try {
const result = await this.models.sims.startSimulation(simulationUuid)
ui.growl.append(
`Simulation started (${result.agentIds?.length ?? 0} agent(s))`,
'success',
4000
)
await this.refreshSimList()
} catch(err) {
ui.growl.append(String(err), 'error', 6000)
const state = row?.querySelectorAll('.cell')[4]?.innerText?.trim() || 'idle'
this.updateSimButtons(state, row)
}
}
async onPauseSim(rowId, button) {
const simulationUuid = rowId?.simulationUuid
if(!simulationUuid) return
const row = button.closest('.row')
button.disabled = true
try {
await this.models.sims.pauseSimulation(simulationUuid)
ui.growl.append('Simulation paused', 'success', 3000)
await this.refreshSimList()
} catch(err) {
ui.growl.append(String(err), 'error', 6000)
const state = row?.querySelectorAll('.cell')[4]?.innerText?.trim() || 'idle'
this.updateSimButtons(state, row)
}
}
async onStopSim(rowId, button) {
const simulationUuid = rowId?.simulationUuid
if(!simulationUuid) return
const row = button.closest('.row')
button.disabled = true
try {
await this.models.sims.stopSimulation(simulationUuid)
ui.growl.append('Simulation stopped', 'success', 3000)
await this.refreshSimList()
} catch(err) {
ui.growl.append(String(err), 'error', 6000)
const state = row?.querySelectorAll('.cell')[4]?.innerText?.trim() || 'idle'
this.updateSimButtons(state, row)
}
}
}
app.registerClass('ManageSimView', ManageSimView)
+11 -4
View File
@@ -1,8 +1,15 @@
<style>
article[eiccard] section:has(.confirm-dialog) {
padding: 0;
}
.confirm-dialog > section {
margin:0 !important;
}
</style>
<div class="confirm-dialog">
<section>
<alert eicalert ${severity} ${muted}>
${message}
</alert>
<section eicalert ${severity}>
${message}
</section>
</div>
@@ -1,3 +1,15 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
/**
* @category MyEic
* @subcategory Views
+23 -4
View File
@@ -1,3 +1,15 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
class SpaceView extends WindozDomContent {
constructor() {
@@ -6,16 +18,20 @@ class SpaceView extends WindozDomContent {
//this.tileMarkup = app.Assets.Store.html['/app/assets/html/mailing/tile.html']
}
DOMContentFocused(options) {
if(this.wasBlured){ // Avoid 2nd refesh on DomContentLoaded
//this.refreshyoustuff()
DOMContentFocused() {
if(this.wasBlured && this.viewMode === '3D' && this.ttb && this.renderingEngine) {
this.ttb.watchCameraFrustum(this.renderingEngine)
}
this.wasBlured = false
}
DOMContentBlured(options) { this.wasBlured = true }
DOMContentBlured() {
this.wasBlured = true
if(this.viewMode === '3D' && this.ttb) this.ttb.stopWatchingCameraFrustum()
}
DOMContentLoaded(options) {
this.viewMode = options.mode
this.windowPrefsId = `live.spaceview.${options.mode}`
for(let model in options.models) this[model] = options.models[model]
this.ttb = options.ttb
@@ -23,6 +39,9 @@ class SpaceView extends WindozDomContent {
this.setupTriggers(components)
this.setupRefs(components)
this.renderingEngine = this.ttb.startRendering(this.outputs.ttbCanvas, options.mode)
if(options.mode === '3D') {
this.ttb.watchCameraFrustum(this.renderingEngine)
}
this.output('settingsMenu',app.Assets.Store.html.spaceViewSetting)
this.outputs.settingsMenu.querySelectorAll('input[type="toggler"]').forEach(el => {
const tog = new InputToggler(el)
+76 -69
View File
@@ -84,26 +84,26 @@ class MessageBus {
*/
constructor(config, userInfo){
this.config = config
if(this.config.debug) console.log('Lauching Websocket worker...');
if(this.config.debug) console.log('Lauching Websocket worker...')
this.config.hostname = (('host' in this.config) && ( this.config.host!='')) ? this.config.host : document.location.hostname
this.userInfo = userInfo
this.createWorker();
this.createWorker()
this.activeSubscriptions = [];
this.promisesRegister = { };
this.promisesRegister = { }
this.bus2jsEventsRegister = []; // items: { eventType:'string', RegisteredCb: function, realCb: function }
this.whenConnectedQ = [];
this.connected = false;
this.whenConnectedQ = []
this.connected = false
}
/**
*
*/
createWorker() {
if(!this.config.pathToWorker.endsWith('.js')) this.config.pathToWorker+='.js';
this.MessageBusWorker = new Worker(this.config.pathToWorker+'?'+crypto.randomUUID());
if(!this.config.pathToWorker.endsWith('.js')) this.config.pathToWorker+='.js'
this.MessageBusWorker = new Worker(this.config.pathToWorker+'?'+crypto.randomUUID())
this.MessageBusWorker.postMessage({ 'action':'start', 'config': this.config, 'userInfo': this.userInfo });
this.MessageBusWorker.onmessage = this.receiveFromWorker.bind(this);
if(this.config.debug) console.log('Websocket worker launched.');
this.MessageBusWorker.onmessage = this.receiveFromWorker.bind(this)
if(this.config.debug) console.log('Websocket worker launched.')
}
/**
@@ -111,9 +111,9 @@ class MessageBus {
* @param {*} callBack
*/
whenConnected(callBack){
if(typeof(callBack) != 'function') return;
if(this.connected) callBack();
else this.whenConnectedQ.push(callBack);
if(typeof(callBack) != 'function') return
if(this.connected) callBack()
else this.whenConnectedQ.push(callBack)
}
/**
@@ -135,8 +135,8 @@ class MessageBus {
* @param {*} callBack
*/
ifConnected(callBack){
if(typeof(callBack) != 'function') return;
if(this.connected) callBack();
if(typeof(callBack) != 'function') return
if(this.connected) callBack()
}
/**
@@ -152,17 +152,17 @@ class MessageBus {
* This method gives (and resolves) a promise, taking care of all lower-level details
*/
requestWssGwAction(action, payload=null, timeOut=5000){
if(!action) return;
let request = {'action':action, 'payload':payload};
request.reqid = crypto.randomUUID();
if(!action) return
let request = {'action':action, 'payload':payload}
request.reqid = crypto.randomUUID()
return(new Promise((resolve, fail) => {
let timeOutID = setTimeout(() => {
fail(`Timeout (>${timeOut}ms) for action ${action}`);
if(this.promisesRegister[request.reqid]) delete(this.promisesRegister[request.reqid])
}, timeOut);
this.promisesRegister[request.reqid] = [resolve, fail, timeOutID];
this.MessageBusWorker.postMessage(request);
}));
}, timeOut)
this.promisesRegister[request.reqid] = [resolve, fail, timeOutID]
this.MessageBusWorker.postMessage(request)
}))
}
/**
@@ -172,18 +172,18 @@ class MessageBus {
* This method gives (and resolves) a promise, taking care of all lower-level details
*/
requestBusAction(chan, action, payload=null, timeOut=5000){
if(!action) return;
let request = {'action':action, 'payload':payload};
request.reqid = crypto.randomUUID();
if(!action) return
let request = {'action':action, 'payload':payload}
request.reqid = crypto.randomUUID()
return(new Promise((resolve, fail) => {
let timeOutID = setTimeout(() => {
fail(`Timeout (>${timeOut}ms) for action ${action}`);
if(this.promisesRegister[request.reqid]) delete(this.promisesRegister[request.reqid])
}, timeOut);
this.promisesRegister[request.reqid] = [resolve, fail, timeOutID];
}, timeOut)
this.promisesRegister[request.reqid] = [resolve, fail, timeOutID]
if(!chan.startsWith(this.config.frontBusPrefix)) chan = this.config.frontBusPrefix+chan
this.send(chan, JSON.stringify(request))
}));
}))
}
/**
@@ -193,18 +193,18 @@ class MessageBus {
* This method gives (and resolves) a promise, taking care of all lower-level details
*/
requestMidasAction(chan, action, data=null, timeOut=5000){
if(!action) return;
if(!action) return
let request = {payload: {'action':action, 'data':data}}
request.reqid = crypto.randomUUID();
request.reqid = crypto.randomUUID()
return(new Promise((resolve, fail) => {
let timeOutID = setTimeout(() => {
fail(`Timeout (>${timeOut}ms) for action ${action}`);
if(this.promisesRegister[request.reqid]) delete(this.promisesRegister[request.reqid])
}, timeOut);
this.promisesRegister[request.reqid] = [resolve, fail, timeOutID];
}, timeOut)
this.promisesRegister[request.reqid] = [resolve, fail, timeOutID]
if(!chan.startsWith(this.config.frontBusPrefix)) chan = this.config.frontBusPrefix+chan
this.send(chan, JSON.stringify(request))
}));
}))
}
/**
@@ -230,9 +230,9 @@ class MessageBus {
*/
send(chan, msg){
// You can publish to an unsubscribed chan, userchans are the best example !
// if(this.activeSubscriptions.indexOf(chan)<0) return;
var request = {'action':'PUB', 'payload': { 'chan':chan, 'msg': msg}};
this.MessageBusWorker.postMessage(request);
// if(this.activeSubscriptions.indexOf(chan)<0) return
var request = {'action':'PUB', 'payload': { 'chan':chan, 'msg': msg}}
this.MessageBusWorker.postMessage(request)
}
/**
@@ -322,11 +322,13 @@ class MessageBus {
/**
* Helper method to match a chan with globbing
*
* @param {string} myChan (no glob)
* @param {string} targetChan PATTERN (possible glob)
* @param {string} myChan (no glob, no user expansion)
* @param {string} targetChan PATTERN (possible glob and user expansion)
* @returns {boolean}
*/
chanMatch(myChan, targetChan) {
targetChan = targetChan.replace(/\[UID\]/g, this.userInfo.uuid)
targetChan = targetChan.replace(/\[CNXID\]/g, this.cnxId)
let re = new RegExp('^'+targetChan.replace(/\*/g,'(.+)')+'$','g')
return(myChan.match(re)!=null)
}
@@ -339,28 +341,28 @@ class MessageBus {
var workermsg = e.data;
if('event' in workermsg){
// event "ReceiveFromServer" is the general case of a message from server, found in data, with its own struct.
// other type og event are generated by the worker, about the connection
// other type of event are generated by the worker, about the connection
switch(workermsg.event){
case 'ReceiveFromServer':
this.receiveFromServer(JSON.parse(workermsg.data));
break;
this.receiveFromServer(JSON.parse(workermsg.data))
break
case 'connected':
this.connected = true;
if(this.config.debug) console.log('received connected event from worker !');
this.executewhenConnectedQ();
app.events.trigger('MessageBus.Connected');
break;
this.connected = true
if(this.config.debug) console.log('received connected event from worker !')
this.executewhenConnectedQ()
app.events.trigger('MessageBus.Connected')
break
case 'closed':
if(this.config.debug) console.log('received closed event from worker!');
this.activeSubscriptions = [];
this.callBacksRegister = { };
this.whenConnectedQ = [];
if(this.config.debug) console.log('received closed event from worker!')
this.activeSubscriptions = []
this.callBacksRegister = { }
this.whenConnectedQ = []
this.connected = false;
app.events.trigger('MessageBus.Closed');
break;
break
default:
if(this.config.debug) console.warn('Unknown Websocket Worker message:', workermsg);
if(this.config.debug) console.warn('Unknown Websocket Worker message:', workermsg)
}
}
}
@@ -377,35 +379,40 @@ class MessageBus {
receiveFromServer(srvdata) {
// See protocol reminder comment at the bottom
if('action' in srvdata){ // Reply to a request
let action = srvdata.action;
let payload = ('payload' in srvdata) ? srvdata.payload : null;
let action = srvdata.action
let payload = ('payload' in srvdata) ? srvdata.payload : null
// Piggyback on the results of some actions for this module internal use
switch(action){
case 'WELCOME':
console.log('Received WSS welcome', srvdata)
this.cnxId = srvdata.cnxId
this.serverTimeDelta = Date.now() - srvdata.serverTime
break
case 'SUB':
if(this.activeSubscriptions.indexOf(payload)<0) this.activeSubscriptions = this.activeSubscriptions.concat(payload);
break;
if(this.activeSubscriptions.indexOf(payload)<0) this.activeSubscriptions = this.activeSubscriptions.concat(payload)
break
case 'SUBLST':
if(this.activeSubscriptions.indexOf(payload)<0) this.activeSubscriptions = this.activeSubscriptions.concat(payload);
break;
if(this.activeSubscriptions.indexOf(payload)<0) this.activeSubscriptions = this.activeSubscriptions.concat(payload)
break
}
app.events.trigger('MessageBus.anyAction', srvdata);
} else { // Low-level event : Redis Event, contrary to requ/reply with wssGateway, or other later
if(('event' in srvdata) && (srvdata.event == 'REDISMSG')){
var payload = ('payload' in srvdata) ? srvdata.payload : null;
var payload = ('payload' in srvdata) ? srvdata.payload : null
if(payload && payload.msg && (payload.msg.eventType || payload.msg.action)) {
if(payload.msg.eventType){
var eventType = payload.msg.eventType;
var eventType = payload.msg.eventType
app.events.trigger('MessageBus.event.'+eventType, {
chan: payload.chan,
sender: payload.msg.sender,
eventType: payload.msg.eventType,
payload: payload.msg.payload,
});
})
} else if(payload.msg.action && payload.msg.reqid) {
let reqid = payload.msg.reqid;
let action = payload.msg.action;
let actionPayload = ('payload' in payload.msg) ? payload.msg.payload : null;
let err = ('err' in payload.msg) ? payload.msg.err : null;
let reqid = payload.msg.reqid
let action = payload.msg.action
let actionPayload = ('payload' in payload.msg) ? payload.msg.payload : null
let err = ('err' in payload.msg) ? payload.msg.err : null
let success = payload.msg.success;
if(reqid in this.promisesRegister) {
clearTimeout(this.promisesRegister[reqid][2]); // Stop timeout timer
@@ -416,12 +423,12 @@ class MessageBus {
app.events.trigger('MessageBus.anyMessage', {
chan: payload.chan,
msg : payload.msg,
});
})
} else if(payload && payload.bmsg){
app.events.trigger('MessageBus.promiscuousMessage', { // Repill msg : decapsulate & use spcific event
chan: payload.bmsg.chan,
msg : payload.bmsg.msg,
});
})
}
else {
console.warn('Weird bus message (discarted) :', srvdata)
@@ -431,9 +438,9 @@ class MessageBus {
// For request-reply, settle promise
if(srvdata.reqid && (srvdata.reqid in this.promisesRegister)) {
let payload = ('payload' in srvdata) ? srvdata.payload : null;
let err = ('err' in srvdata) ? srvdata.err : null;
let success = srvdata.success;
let payload = ('payload' in srvdata) ? srvdata.payload : null
let err = ('err' in srvdata) ? srvdata.err : null
let success = srvdata.success
clearTimeout(this.promisesRegister[srvdata.reqid][2]); // Stop timeout timer
if(success) this.promisesRegister[srvdata.reqid][0](payload); // resolve
else this.promisesRegister[srvdata.reqid][1](`MsgBus action failed.\nError: ${err}`); // Fail
+185
View File
@@ -0,0 +1,185 @@
{
"nodes": [
{
"id": "concept.p42",
"name": "P42",
"type": "concept",
"scope": "project",
"userDoc": {
"statements": [
"Project 42 (or P42 for short) is a general purpose simulation engine",
"Its goal is to provide a flexible and powerful tool for simulating and analyzing the widest possible range of complex systems",
"It is a platform for building and running simulations, for analyzing the results of those simulations",
"It aims at allowing users to easily create and spot emerging phenomenons in complex systems"
],
"humor": [
"Why 42 ? Well, the author hopes this project will help answering non-obvious questions, and you should know 42 is the answer to THE BIGGEST question."
]
},
"developperDoc": {
}
},
{
"id": "concept.godProcess",
"name": "God process",
"type": "concept",
"scope": "platform",
"userDoc": {
"statements": [
"A god-process is a process that is responsible for a specific part of the overall management of the simulation",
"Contrary to agents, it is not part of the simulation per-se, as it remains neutral to what happens in the arena of the simulation",
"Contrary to agents, it has access to everything that happens in the arena of the simulation in order to perform its tasks, and is therefore in a \"god-like\" position."
],
"humor": [
"Ironically, the author of P42 is a firm non-believer",
"In the unix world, a background process is called a \"daemon\", and therefore, you can call a god-process a \"god-daemon\""
]
},
"developperDoc": {
"constraints": [
"All god-daemons are kept in separated folders, in /op/p42GodDaemons",
"All god-daemons should depend on the same Redis P42 library that standardizes accesses to Redis Pub/Sub and Redis database",
"God-daemons can have access to the arena bus, the management bus or (generally) both.",
"God-daemons can fire events on the arena bus that will be received by agents",
"God-daemons can fire events on the management bus that will be received by the interface",
"God-daemons can fire events on the management bus that will be received by other god-daemons",
"God-daemons can fire events on the arena bus that will be received by other god-daemons",
"God-daemons must never update agents data directly (that's the agent's job)",
"Agents can make requests to God-daemons via the arena bus, and god-daemon should always reply with a valid response (even if empty or error)"
]
},
"relations": [
{ "type": "uses", "target": "concept.arenaBus" },
{ "type": "uses", "target": "concept.managementBus" }
]
},
{
"id": "concept.arenaBus",
"name": "Arena Bus",
"type": "concept",
"scope": "platform",
"userDoc": {
"statements": [
"The Arena Bus is a message bus that is used to communicate between agents and god-processes",
"It is a Redis backed PUB/SUB message bus, and is used to provide communications between agents, between agents and god-processes, and between god-processes",
"For agents, this bus represents their sole window to the simulation's world (arena)",
"For God-daemons, the bus allows to receive agent events (monitoring), send world-state change events to interested agents, and to provide agents with request-reply services"
]
},
"developperDoc": {
"constraints": [
"For scalability, the arena bus can use several different Redis daemons, each one representing a shard of the Arena (bus and agents storages)",
"To respect arena isolation, events on the arena bus shall not cary any information which is not directly related to the arena (agents, god-processes, etc.)"
]
}
},
{
"id": "concept.managementBus",
"name": "Management Bus",
"type": "concept",
"scope": "platform",
"userDoc": {
"statements": [
"The Management Bus is a message bus that is used to communicate between god-processes, and between god-processes and the interface",
"It is a Redis backed PUB/SUB message bus"
]
},
"developperDoc": {
"constraints": [
"For simplicity, the management bus only uses a single Redis daemon",
"In order to keep the arena bus as little loaded as possible, inter-god-daemons events shall use the management bus instead of the arena bus"
]
}
},
{
"id": "concept.PRNGs",
"name": "PRNGs",
"type": "concept",
"scope": "agent api",
"userDoc": {
"statements": [
"PRNGs (Pseudo-Random Number Generator) are provided to agents needing random numbers",
"Agents cannot use any other random number generator than the PRNGs provided to them by the PRGN God-Daemon",
"This ensures reproducibility of the simulation, and prevents agents from using non-reproductible randomness"
]
},
"developperDoc": {
"constraints": [
"Random numbers are provided to agents upon request to the God-Daemon PRNG service",
"Seed based PRNGs (Pseudo-Random Number Generator) are used to generate random numbers for agents",
"PRNGs must ensure a high enough entropy for each agent",
"PRNGs must ensure reproducibility from one run to the next, by storing all seeds with the arena state",
"Agents shall never have access to seeds, nor to any other information that could be used to reproduce the same random numbers",
"PRNGs must be thread-safe, and must be able to handle concurrent requests from multiple agents"
]
}
},
{
"id": "feature.horizontal-scaling",
"name": "horizontal scaling",
"type": "feature",
"scope": "performance",
"userDoc": {
"statements": [
"Horizontally scalable by design, allowing users to easily scale their simulations to handle large amounts of data and agents",
"The limit is only the computing power users are ready top pay for"
]
},
"developperDoc": {
"constraints": [
"All runners are containerized, and are executed by a dedicated container orchestrator, which uses a dedicated Redis that represents a shard of the Arena (bus and agents storages)"
],
"statements": [
"Uses a distributed architecture that uses any number of containerized runners that execute agents code, as well as the code of god-processes",
"Communication between agents, god-processes and interface is handled by two REDIS backed PUB/SUB message buses"
]
}
},
{
"id": "feature.strongArenaIsolation",
"name": "Strong arena isolation",
"type": "feature",
"scope": "simulation",
"userDoc": {
"statements": [
"Designed to maintain strong isolation between the arena of the simulation and the rest of the system",
"Agents are isolated from each other, and from the rest of the system to ensure no unwanted data contamination could tamper the agent's behavior"
]
},
"developperDoc": {
"constraints": [
"No event shall be ported bewteen arena and management busses",
"No reply to an agent request and no payload of an arena event should leak any \"overview\" of the simulation state to the agent, neither any management data of the system"
],
"statements": [
"Uses two different busses: one for letting agents communicate with each other, or with the god-processes, and a second isolated one for managing the simulation state",
"Likewise, agents internal states and properties belong to the arena, and are stored in a dedicated REDIS database, isolated from the general system databases"
]
},
"relations": [
{ "type": "uses", "target": "concept.arenaBus" },
{ "type": "uses", "target": "concept.managementBus" }
]
},
{
"id": "feature.reproductibility",
"name": "Reproductibility",
"type": "feature",
"scope": "simulation",
"userDoc": {
"statements": [
"Designed to ensure that the simulation can be reproduced exactly the same way, from one run to the next",
"Same initial conditions should lead to the same final state, unless the simulation is voluntarily stochastic (agents use non-reproductible randomness)"
]
},
"developperDoc": {
"constraints": [ ],
"statements": [ ]
},
"relations": [
{ "type": "uses", "target": "concept.PRNGs" },
{ "type": "uses", "target": "concept.managementBus" }
]
}
]
}
+107
View File
@@ -0,0 +1,107 @@
In SPARC, the app menu is created from app/assets/json/global/app-menu-map.json
Each entry defines a route.
A "high level" route is then configured in app/config/baseRoutes.json that delegates a group of URLs to a controller.
Then, a controller, in its associated .json file defines in its "routes" section the sub-route managed by the controller,
and the method to be called inside that controller.
In SPARC, models inherit from the core and from WindozModel a mecanism that gets the URL from app/assets/json/global/services.json
That configuration file associates actions grouped in sections to API urls and http method.
Sections are identified by an URL-prefix (only used as label), and correspond to API "services".
The server-side of this API is served by the node daemon in p42api.
p42api has a folder 'api' with one file / module per API service, they are all declared in and imported by api/index.js.
Each module defines a mapping object, that contains all the complete urls served, http-method, and local handling method.
We are now focusing on P42 God Daemons (in folder p42GodDaemons).
Every daemon in there is connected to several Redis. At least one Arena redis, and one System Redis.
PUB/SUB channels are prefixed accordingly, following the configuration token "chansNamespace"
and anything outside the configured combination Redis host & port + chansNamespace is illegal.
In the future, there might be several different Redis (in mesh) serving the same chansNamespace.
GPS Daemon is the global positionning system of the arena.
It holds the current position of every agent in the arena.
Agents change their 3D speed vector whenever they want by informing GPS (via the agentVectorChangeChannel)
A typical agent event looks like
{ "eventType": "change", "payload": { "newVector": { "x": 5, "y": -2.34, "z": 0 } }, "sender": "agent42" }
On every speed vector change, GPS computes the 4D worldline of the agent,
and scans all other worldlines to find those intersecting, or approaching less than a configurable distance.
Each collision/ near-miss is then registered.
As time passes, GPS fires events towards concerned agents based on this register.
On every speed vector change, this register is searched and all entries containing the agent changing its speed are deleted.
To speed-up and limit the intersection computations, we will take an approach using rectangular 4-prisms :
Each pair of wordlines to test for collision / near-miss is enclosed in a 4-prism of a certain configurable time-height (thus how far in the future we test),
and we just test for intersecting prisms.
Only if the prisms intersect do we compute the real minimal-distance and its time, that we keep in the register.
Comparing a pair of worldlines should be a separated method and the looping through all agents in a separated method as well.
The reason for this remark is to take provision for a future where I might want to paralellize this (instead of looping through), in a GPU.
We need to think about how we start a new simulation from GPS point of view :
As we are in a distributed context, here is the workflow I'm thinking of :
1. Some orchestrator process will put all agents data in the arena Redis store.
2. Then it will start all agents processes, in a special mode "onYourMarks" where they can initialize, time is frozen to zero, any non initialization computation is forbidden.
3. When each agent is initialized, it fires an arena event "readyToStart"
4. When the orchestrator has accounted for all agents, it fires an "arenaStart" event, that unleashes all agents.
Now where is GPS in all of this :
GPS should behave like an agent: listen for "onYourMarks" event, initialize, send "readToStart" when done, and start time-ticking when it received a "bigBang" event.
Contrary to agents, GPS daemon itself is supposed to be running already.
So the initialization is mainly doing a first agents scan to fill its registry. (with an unvalued T0 and collision-ticks not running). Scanning all agents means going into redis store to get their vector (its only after this step than GPS become the positions authority)
Upon receiving "bigBang", T0 is valued, and the collisionsTicks starts.
That's the general idea.
Please check if you don't see incoherence, gap or edge case.
5. GPS time communicated to agents is simulation time, thus with T(bigBang) = 0
Therefore, when the orchestrator send a "bigBang" event, GPS starts general scan
and does the pre-compute with all positions at T=0
For eventual time-elapsed computations internal to GPS, it can keep a reference, say bigBangEpoch to epoch (miliseconds)
at the moment he receives the "bigBang" event.
From then on, current Simulation time is now() - bigBangEpoch
Next step: the embrio of simOrchestrator.
Can you create a second GodDaemon called like that, aside GPS, that uses the same config, the same general pattern, adapted start & stop scripts,
So, the first thing you must understand, is that all busses, thus all meshes and all redisConnexions can carry both types of messages :
1. Request-reply: action request (possibly with reqid) requestor to provider. After action completion (or rejection), the provider answers the requestor (private chan replacing {uuid} with sender) with a reply (on the same reqid if present).
The payload must contain "action", with an imperative form.
Action must be verified to arrive on a specific chan, and the sender be allowed by access-rights.
2. Events broadcasting: not a request, just a message for anybody interested (so no "rejection" per se, but eventual ignore). No answer, but eventual local processing which might or not endup firing other event(s).
The payload must contain "eventType", with a generally a past tense. (like "he guys, I UPDATED my color")
Event routing combines chan & eventType (for example, and "updated" eventType could appear on a agentColor chan, and on a agentHealth chan, with different meanings and thus handling)
These two types can happen anywhere, it is not a "per mesh drift".
Probably, most Actions will concentrate in the SYSTEM mesh, because the management by the front-end and API is mostly user driven (user action becomes a request on the system bus).
Probably, the ARENA will be mostly event-driven, because agents have no overview of the arena (so to who ask for what?)
Nevertheless, there will be many cases where this is not true:
GODs emitting events that other gods or even the Front-End should be aware of.
The observer feeding the GUI on arena changes in an event-driven way.
Agent in the Arena requesting a service from a known god. (like "Hey GPS, give me my latest vector")
And maybe even someday clever agents that provide actions to other agents in their proximity for example.
"Action" folder was originally meant for...actions !
Now we need to find a clean, elegant, universal (across daemons & across meshes)
way of coexist both actions and events.
Describe a proposal that stays close to what we have, but separates events from actions.
We have another issue: If I'm not mistaken, a front-end "sender" UID is actually his login UID.
That means that a user opening 2 browsers is viewed as the same sender on both.
Therefore, using sender as upsert key in the subscriptions registry of observer is problematic,
because we should allow the same user to view different things on different browsers.
Maybe in the second browser he's viewing another angle, or meybe he's not viewing this particular sim at all.
Back to business.
I slightly changed the listSims query, so we can display sim name, primordial frame name and owner name.
Now that this mecanism is in place in the gateway, Let's change Observer so that it uses a combination of sender and cnxId as key for its frustum register, instead of just sender