Convert the whole site to use Pelican instead of Jekyll

This commit is contained in:
2019-11-05 06:21:56 +01:00
parent 49961a3007
commit d5c1c942f0
534 changed files with 7315 additions and 6642 deletions

1
content/.well-known/dat Normal file
View File

@@ -0,0 +1 @@
dat://f2f8fde752df4c5c69506b22fbcc62fd572829c9a72e5053c15d13170b731461

View File

@@ -0,0 +1,88 @@
==================================================================
https://keybase.io/gergelypolonkai
--------------------------------------------------------------------
I hereby claim:
* I am an admin of https://gergely.polonkai.eu
* I am gergelypolonkai (https://keybase.io/gergelypolonkai) on keybase.
* I have a public key with fingerprint 13D6 0476 B35A FCA8 BC01 3A32 F42B BA58 B074 0C4C
To do so, I am signing this object:
{
"body": {
"key": {
"eldest_kid": "0101ceab57f101e57c410a43bdc8d929f98285ab06539bff10fda8b753edc5f6cc910a",
"fingerprint": "13d60476b35afca8bc013a32f42bba58b0740c4c",
"host": "keybase.io",
"key_id": "f42bba58b0740c4c",
"kid": "0101ceab57f101e57c410a43bdc8d929f98285ab06539bff10fda8b753edc5f6cc910a",
"uid": "71a6ab9599863d4b04753bed0d7f6b19",
"username": "gergelypolonkai"
},
"merkle_root": {
"ctime": 1509017295,
"hash_meta": "d9782d9deba8b4b08e84498faa9f35ad2ebe9470bd368defd2a9810a31aa75b6",
"seqno": 1632302
},
"revoke": {
"sig_ids": [
"17d13b369e345bc73cf3120c9a42e61ea78de28fdfbf9897780a8bb6e9f952dc0f"
]
},
"service": {
"hostname": "gergely.polonkai.eu",
"protocol": "https:"
},
"type": "web_service_binding",
"version": 1
},
"ctime": 1509017302,
"expire_in": 157680000,
"prev": "44dc7f3d5323a6c9f8b70e5276a300cd40406c53ce17cdde5613b585adc4fea9",
"seqno": 12,
"tag": "signature"
}
which yields the signature:
-----BEGIN PGP MESSAGE-----
Version: Keybase OpenPGP v2.0.76
Comment: https://keybase.io/crypto
yMPWAnicrZN9TFVlHMevgjbvQF5qOlKUDirxIpz3l2u+MKFVu3f8USQEeX3ezvV0
4Z7bveeiqGg6c+LLiKmbQqJpCtnK8DW1NSVzBIJmKmG4MmabbCmmtykz7Dkst9z6
s/PPOc/Z9/f9fX+f53nOxsc4nKPuZ58s+cKKc4/qbFsbcZTePXd1OQNNXM24ljN+
MvIiFZiELa/fwIyLYTmWQwRASdHpF5EUJHIsEAWIkYo1XtM1lVclAFlZEjSoU5GO
gQoVSSAYSbqMkEb1TA6jGwEfCQVDRsCitpyAZVZUZChIQEe0ALGcAAReF3kIgaRC
VhFZJCJauNgM2xU0HARhkmuY9B9deEfi/Yf+f84dGbFTOCADqEmapsoCFiHNLgmQ
YBYrugw5zRaGSSgAKglV00F9pKI6aFaYAT8wmJocppKE/BXEGzJNy2aMLMNWchKr
sZzCaxKdE4QXeyuJBagB1hSVxxomkGai3VSiiqKm6gBoOiWGeQKJJiosxIKsYqJj
HmgqzStwACgSlGmcMHk3YNIOssALLE8ThEiV6Sd287Dho/TCjKuM4RTMCVCQNSKI
EkSKgHSB41mkAZEnMkeAQu15Vcc6pMQ0RVFZmgjKhAKUeIxYnXm7xm4WqjLQiLm9
XU9jyH3CIZdEaLBgyLRMZFZQwWLLCoZdNh6rOmhXLCHQ+4+XFxoBTM8MragiobBh
BugwVPk0OTpaDkOWBo0Q8Rq2QlJklaWP3YdUUUtRxEjRBSxRDkBGmk43mSUSr8hA
YFmERVZkZSQJiHAKwphIMgUi0aOBkagToP0LJW1lAR/1pAADwIqECFPTdqY81jHK
6Rg7ZrR9mRzOcYlPrtgeR8LwzLmNgwXNzf2+Ceq4aAK++cG6LeUH9u2f4QGPWh3h
w7Wx41dtLSuoOVYSt2+b2dm+/nHfC7daEy5IRW/x0YL2xPy2lom/7Dbi6zcsO+Tc
MyehK6nhdm2MJ++e68z4S+ndv76+5nPg/3b077sGSy7z+g7psCM9Njlzd88nsYlL
X75dJ26/k9nblJDS1t/SXDxlyuxpO8tc7++9n93a5ahP9TQ6nj9Y0rPubsKM1Mdl
8/JPnJ46dWDlrJw1bT+mrL4wqe5W0sm0rPQTj2BaZNJ7pVNbVo9/Jt09PWnr9Y2v
peOtTi2DzCk6d3D4p1L51bieNSeaXuLfuHotGOXMuPmucikxv+RAc07Kxb6uvqwH
mycOXmkI6MMfXy/+JryLG6oqTm26wXX8tunLcZXu75JOvTjwdVrWRndvU/oqvc4/
4c9bQ+7T67scD/N6+/fWl2845Vt16fzsg9OyZh5rzPzUYn5oaOju6KlDnxUML/g+
O/m45+LR2rzojbOvPFwEDm05Ujh/0YX985aUeRZu+6gwv78+552M6ULu5WtN1QfY
6oF7PU2V3UbX/Vlrr2c4t2GhV+1IxhXxyRnOe8c/nH7k57nu9YlxnRM7ht6Muek+
6mss9E76ozRSdOXhnZVdC2ImR5YVfpUxOXj+zgpvrrCzL7ph0QPfitrnPHOj/nbj
8pjTWwae3RSI/2vH2UtjQwu3p/wNxkcCqw==
=SRX1
-----END PGP MESSAGE-----
And finally, I am proving ownership of this host by posting or
appending to this document.
View my publicly-auditable identity here: https://keybase.io/gergelypolonkai
==================================================================

View File

@@ -0,0 +1,25 @@
Ethical Hacking 2012
####################
:date: 2011-05-12T20:54:42Z
:category: blog
:tags: conference
:url: blog/2011/5/12/ethical-hacking-2011.html
:save_as: blog/2011/5/12/ethical-hacking-2011.html
:status: published
:author: Gergely Polonkai
Today I went to the Ethical Hacking conference with my boss. It was my first appearance at such
conferences, but I hope there will be more. Although we just started to redesign our IT security
infrastructure with a 90% clear goal, it was nice to hear that everything is vulnerable. I was
thinking if we should sell all our IT equipments, fire all our colleagues (you know, to prevent
social engineering), and move to the South Americas to herd llamas or sheep, so the only danger
would be some lurking pumas or jaguars. Or I simply leave my old background image on my desktop,
from the well-known game, which says: Trust is a weakness.
Anyways, the conference was really nice. We heard about the weaknesses of Android, Oracle, and
even FireWire. They showed some demos about everything, exploited some free and commercial
software with no problem at all. We have seen how much power the virtualisation admin has
(although I think it can be prevented, but Im not sure yet). However, in the end, we could see
that the Cloud is secure (or at least it can be, in a few months or so), so Im not totally
pessimistic. See you next time at Hacktivity!

View File

@@ -0,0 +1,75 @@
Gentoo hardened desktop with GNOME 3 Round one
################################################
:date: 2011-05-12T20:32:41Z
:url: blog/2011/5/12/gentoo-hardened-desktop-with-gnome-3-round-one.html
:save_as: blog/2011/5/12/gentoo-hardened-desktop-with-gnome-3-round-one.html
:category: blog
:tags: gentoo,gnome3,selinux
:author: Gergely Polonkai
:status: published
After having some hard times with Ubuntu (upgrading from 10.10 to 11.04), I decided to switch back
to my old friend, Gentoo. As Im currently learning about Linux hardening, I decided to use the
new SELinux profile, which supports the v2 reference policy.
Installation was pretty easy, using the `Gentoo x86 Handbook
<http://www.gentoo.org/doc/hu/handbook/handbook-x86.xml>`_. This profile automatically turns on
the ``USE=selinux`` flag (so does the old SELinux profile), but deprecated ``FEATURE=loadpolicy``
(which is turned on by the profile, so portage will complain about it until you disable it in
``/etc/make.conf``).
For the kernel, I chose ``hardened-sources-2.6.37-r7``. This seems to be recent enough for my
security testing needs. I turned on both SELinux, PaX and grsecurity. So far, I have no problem
with it, but I dont have X installed yet, which will screw up things for sure.
After having those hard times with Ubuntu mentioned before, I decided not to install Grub2 yet, as
it renders things unusable (eg. my Windows 7 installation, which I sometimes need at the office).
So I installed Grub 0.97 (this is the only version marked as stable, as I remember), touched
``/.autorelabel``, and reboot.
My first mistake was using an UUID as the root device on the kernel parameter list (I dont want
to list all the small mistakes like forgetting to include to correct SATA driver from my kernel
and such). Maybe I was lame, but after including ``/dev/sda5`` instead of the UUID thing, it
worked like…
Well, charm would not be the good word. For example, I forgot to install the ``lvm2`` package, so
nothing was mounted except my root partition. After I installed it with the install CD, I assumed
everything will be all right, but I was wrong.
``udev`` and LVM is a critical point in a hardened environment. ``udev`` itself doesnt want to
work without the ``CONFIG_DEVFS_TEMPFS=y`` kernel option, so I also had to change that. It seemed
that it can be done without the install CD, as it compiled the kernel with no problems. However,
when it reached the point when it compresses the kernel with gzip, it stopped with a ``Permission
denied`` message (although it was running with root privileges).
The most beautiful thing in the hardened environment with Mandatory Access Control enabled is that
root is not a real power user any more by default. You can get this kind of messages many times.
There are many tools to debug these, I will talk about these later.
So, my ``gzip`` needed a fix. After digging a bit on the Internet, I found that the guilty thing
is text relocation, which can be corrected if ``gzip`` is compiled with PIC enabled. Thus, I
turned on ``USE=pic`` flag globally, and tried to remerge gzip. Of course it failed, as it had to
use gzip to unpack the gzip sources. So it did when I tried to install the PaX tools and
``gradm`` to turn these checks off. The install CD came to the rescue again, with which I
successfully recompiled gzip, and with this new gzip, I compressed my new kernel, with which udev
started successfully. So far, so good, lets try to reboot!
Damn, LVM is still not working. So I decided to finally consult the Gentoo hardened guide. It
says that the LVM startup scripts under ``/lib/rcscripts/…`` must be modified, so LVM will put its
lock files under ``/etc/lvm/lock`` instead of ``/dev/.lvm``. After this step and a reboot, LVM
worked fine (finally).
The next thing was the file system labelling. SELinux should automatically relabel the entire
file system at boot time whenever it finds the ``/.autorelabel`` file. Well, in my case it didnt
happen. After checking the `Gentoo Hardening <http://wiki.gentoo.org/wiki/Hardened_Gentoo>`_
docs, I realised that the ``rlpkg`` program does exactly the same (as far as I know, it is
designed specifically for Gentoo). So I ran ``rlpkg``, and was kind of shocked. It says it will
relabel ext2, ext3, xfs and JFS partitions. Oh great, no ext4 support? Well, consulting the
forums and adding some extra lines to ``/etc/portage/package.keywords`` solved the problem
(``rlpkg`` and some dependencies had to have the ``~x86`` keyword set). Thus, ``rlpkg``
relabelled my file systems (I checked some directories with ``ls -lZ``, it seemed good for me).
Now it seems that everything is working fine, except the tons of audit messages. Tomorrow I will
check them with ``audit2why`` or ``audit2allow`` to see if it is related with my SELinux lameness,
or with a bug in the policy included with Gentoo.

View File

@@ -0,0 +1,32 @@
Zabbix performance tip
######################
:date: 2011-05-13T19:03:31Z
:category: blog
:tags: zabbix,monitoring
:url: blog/2011/5/13/zabbix-performance-tip.html
:save_as: blog/2011/5/13/zabbix-performance-tip.html
:status: published
:author: Gergely Polonkai
Recently I have switched from `MRTG <http://oss.oetiker.ch/mrtg/>`_ + `Cacti
<http://www.cacti.net/>`_ + `Nagios <http://www.nagios.org/>`_ + `Gnokii
<http://www.gnokii.org/>`_ to `Zabbix <http://www.zabbix.com/>`_, and I must say Im more than
satisfied with it. It can do anything the former tools did, and much more. First of all, it can
do the same monitoring as Nagios did, but it does much more fine. It can check several parameters
within one request, so network traffic is kept down. Also, its web front-end can generate any
kinds of graphs from the collected data, which took Cacti away. Also, it can do SNMP queries
(v1-v3), so querying my switches port states and traffic made easy, taking MRTG out of the
picture (I know Cacti can do it either, it had historical reasons we had both tools installed).
And the best part: it can send SMS messages via a GSM modem natively, while Nagios had to use
Gnokii. The trade-off is, I had to install Zabbix agent on all my monitored machines, but I think
it worths the price. I even have had to install NRPE to monitor some parameters, which can be a
pain on Windows hosts, while Zabbix natively supports Windows, Linux and Mac OS/X.
So I only had to create a MySQL database (which I already had for NOD32 central management), and
install Zabbix server. Everything went fine, until I reached about 1300 monitored parameters.
MySQL seemed to be a bit slow on disk writes, so my Zabbix “queue” filled up in no time. After
reading some forums, I decided to switch to PostgreSQL instead. Now it works like charm, even
with the default Debian settings. However, I will have to add several more parameters, and my
boss wants as many graphs as you can imagine, so Im more than sure that I will have to fine tune
my database later.

View File

@@ -0,0 +1,26 @@
Gentoo hardened desktop with GNOME 3 Round two
################################################
:date: 2011-05-18T10:28:14Z
:category: blog
:tags: gentoo,gnome3,selinux
:url: blog/2011/5/18/gentoo-hardened-desktop-with-gnome-3-round-two.html
:save_as: blog/2011/5/18/gentoo-hardened-desktop-with-gnome-3-round-two.html
:status: published
:author: Gergely Polonkai
After several hours of ``package.keywords``/``package.use`` editing and package compiling, I
managed to install GNOME 3 on my notebook. Well, I mean, the GNOME 3 packages. Unfortunately the
``fglrx`` driver didnt seem to recognise my ATI Mobility M56P card, and the open source driver
didnt want to give me GLX support. When I finally found some clues on what should I do, I had to
use my notebook for work, so I installed Fedora 14 on it. Then I realised that GNOME 3 is already
included in Rawhide (Fedora 15), so I quickly downloaded and installed that instead. Now I have
to keep this machine in a working state for a few days, so I will learn SELinux stuff in its
native environment.
When I installed Fedora 14, the first AVC message popped up after about ten minutes. That was a
good thing, as I wanted to see ``setroubleshoot`` in action. However, in Fedora 15, the AVC
bubbles didnt show up even after a day. I raised my left eyebrow and said thats impossible,
SELinux must be disabled. And its not! Its even in enforcing mode! And it works just fine. I
like it, and I hope I will be able to get the same results with Gentoo if I can get back to
testing…

View File

@@ -0,0 +1,34 @@
Citrix XenServer 5.5 vs. Debian 5.0 upgrade to 6.0
##################################################
:date: 2011-05-27T17:33:41Z
:category: blog
:tags: citrix-xenserver,debian
:url: blog/2011/5/27/citrix-xenserver-vs-debian-5-0-upgrade-to-6-0.html
:save_as: blog/2011/5/27/citrix-xenserver-vs-debian-5-0-upgrade-to-6-0.html
:status: published
:author: Gergely Polonkai
Few weeks ago Ive upgraded two of our Debian based application servers from 5.0 to 6.0.
Everything went fine, as the upgraded packages worked well with the 4.2 JBoss instances. For the
new kernel we needed a reboot, but as the network had to be rebuilt, I postponed this reboot until
the network changes. With the network, everything went fine again, we successfully migrated our
mail servers behind a firewall. Also the Xen server (5.5.0, upgrade to 5.6 still has to wait for
a week or so) revolted well with some storage disks added. But the application servers remained
silent…
After checking the console, I realised that they dont have an active console. And when I tried
to manually start them, XenServer refused with a message regarding ``pygrub``.
To understand the problem, I had to understand how XenServer boots Debian. It reads the
``grub.conf`` on the first partitions root or ``/boot`` directory, and starts the first option,
without asking (correct me, if Im mistaken somewhere). However, this ``pygrub`` thing can not
parse the new, grub2 config. This is kinda frustrating.
For the first step, I quickly installed a new Debian 5.0 system from my template. Then I attached
the disks of the faulty virtual machine, and mounted all its partitions. This way I could reach
my faulty 6.0 system with a chroot shell, from which I could install the ``grub-legacy`` package
instead of grub, install the necessary kernel and XenServer tools (which were missing from both
machines somehow), then halt the rescue system, and start up the original instance.
Next week I will do an upgrade on the XenServer to 5.6.1. I hope no such problems will occur.

View File

@@ -0,0 +1,23 @@
Oracle Database “incompatible” with Oracle Linux?
#################################################
:date: 2011-05-27T17:53:31Z
:category: blog
:tags: linux,oracle
:url: blog/2011/5/27/oracle-database-incompatible-with-oracle-linux.html
:save_as: blog/2011/5/27/oracle-database-incompatible-with-oracle-linux.html
:status: published
:author: Gergely Polonkai
Today I gave a shot to install `Oracle Linux
<http://www.oracle.com/us/technologies/linux/overview/index.html>`_. I thought I could easily
install an Oracle DBA on it. Well, I was naive.
As only the 5.2 version is supported by XenServer 5.5, I downloaded that version of Oracle Linux.
Installing it was surprisingly fast and easy, it asked almost nothing, and booted without any
problems.
After this came the DBA, 10.2, which bloated an error message in my face saying that this is an
unsupported version of Linux. Bah.
Is it only me, or is it really strange that Oracle doesnt support their own distro?

View File

@@ -0,0 +1,29 @@
Proxy only non-existing files with mod_proxy and mod_rewrite
############################################################
:date: 2011-06-10T14:20:43Z
:category: blog
:tags: apache
:url: blog/2011/6/10/proxy-only-non-existing-files-with-mod-proxy-and-mod-rewrite.html
:save_as: blog/2011/6/10/proxy-only-non-existing-files-with-mod-proxy-and-mod-rewrite.html
:status: published
:author: Gergely Polonkai
Today I got an interesting task. I had to upload some pdf documents to a site. The domain is
ours, but we dont have access to the application server that is hosting the page yet. Until we
get it in our hands, I did a trick.
I enabled `mod_rewrite`, `mod_proxy` and `mod_proxy_http`, then added the following lines to my
apache config:
.. code-block:: apache
RewriteEngine on
RewriteRule ^/$ http://172.16.72.131:8080/ [QSA,L,P]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*) http://172.16.72.131:8080/$1 [QSA,L,P]
Order allow,deny
Allow from all
Im not totally sure its actually secure, but it works for now.

View File

@@ -0,0 +1,26 @@
Inverse of `sort`
#################
:date: 2011-09-18T14:57:31Z
:category: blog
:tags: linux,command-line
:url: blog/2011/9/18/inverse-of-sort.html
:save_as: blog/2011/9/18/inverse-of-sort.html
:status: published
:author: Gergely Polonkai
Im using \*NIX systems for about 14 years now, but it can still show me new things. Today I had
to generate a bunch of random names. Ive create a small perl script which generates permutations
of some usual Hungarian first and last names, occasionally prefixing it with a Dr. title or
using double first names. For some reasons I forgot to include uniqueness check in the script.
When I ran it in the command line, I realized the mistake, so I appended ``| sort | uniq`` to the
command line. So I had around 200 unique names, but in alphabetical order, which was awful for my
final goal. Thus, I tried shell commands like ``rand`` to create a random order, and when many of
my tries failed, the idea popped in my mind (not being a native English speaker): “I dont have to
create »random order«, but »shuffle the list«. So I started typing ``shu``, pressed Tab in the
Bash shell, and voilà! ``shuf`` is the winner, it does just exactly what I need:
**NAME**
shuf - generate random permutations
Thank you, Linux Core Utils! :)

View File

@@ -0,0 +1,14 @@
Why you should always test your software with production data
#############################################################
:date: 2011-12-11T12:14:51Z
:category: blog
:tags: development,testing,ranting
:url: blog/2011/12/11/why-you-should-always-test-your-software-with-production-data.html
:save_as: blog/2011/12/11/why-you-should-always-test-your-software-with-production-data.html
:status: published
:author: Gergely Polonkai
Im writing a software for my company in PHP, using the Symfony 2 framework. Ive finished all
the work, created some sample data, it loaded perfectly. Now I put the whole thing into
production and tried to upload the production data into it. Guess what… it didnt load.

View File

@@ -0,0 +1,25 @@
PHP 5.4 released
################
:date: 2012-03-20T13:31:12Z
:category: blog
:tags: php
:url: blog/2012/3/20/php-5-4-released.html
:save_as: blog/2012/3/20/php-5-4-released.html
:status: published
:author: Gergely Polonkai
After a long time of waiting, PHP announced 5.4 release on 1 March (also, today they announced
that they finally migrate to Git, which is sweet from my point of view, but it doesnt really
matter).
About a year ago we became very agressive towards a developer who created our internal e-learning
system. Their database was very insecure, and they didnt really follow industry standards in
many ways. Thus, we forced them to move from Windows + Apache 2.0 + PHP 5.2 + MySQL 4.0 to Debian
Linux 6.0 + Apache 2.2 + PHP 5.3 + MySQL 5.1. It was fun (well, from our point of view), as their
coders… well… they are not so good. The code that ran “smoothly” on the old system failed at many
points on the new one. So they code and code, and write more code. And they still didnt finish.
And now 5.4 is here. Okay, I know it will take some time to get into the Debian repositories, but
its here. And they removed ``register_globals``, which will kill that funny code again at so
many points that they will soon get to rewrite the whole code to make it work. And I just sit
here in my so-much-comfortable chair, and laugh. Am I evil?

View File

@@ -0,0 +1,29 @@
Fast world, fast updates
########################
:date: 2012-03-27T06:18:43Z
:category: blog
:tags: linux
:url: blog/2012/3/27/fast-world-fast-updates.html
:save_as: blog/2012/3/27/fast-world-fast-updates.html
:status: published
:author: Gergely Polonkai
We live in a fast world, thats for sure. When I first heard about Ubuntu Linux and their goals,
I was happy: they gave a Debian to everyone, but in different clothes. It had fresh software in
it, and even they gave support of a kind. It was easy to install and use, even if one had no
Linux experience before. So people liked it. Ive even installed it on some of my servers
because of the new package versions that came more often. Thus I got an up to date system.
However, it had a price. After a while, security updates came more and more often, and when I had
a new critical update every two or three days, Ive decided to move back to Debian. Fortunately I
did this at the time of a new release, so I didnt really loose any features.
After a few years passed, even Debian is heading this very same way. But as I see, the cause is
not the same. It seems that upstream software is hitting these bugs, and even the Debian guys
dont have the time to check for them. At the time of a GNOME version bump (yes, GNOME 3 is a
really big one for the UN\*X-like OSes), when hundreds of packages need to be checked, security
bugs show off more often. On the other hand however, Debian is releasing a new security update
every day (I had one on each of the last three days). This, of course, is good from one point of
view as we get a system that is more secure, but most administrators dont have maintenance
windows this often. I can think of some alternatives like Fedora, but do I really have to change?
Dear fellow developers, please code more carefully instead!

View File

@@ -0,0 +1,23 @@
Wordpress madness
#################
:date: 2012-06-14T06:40:12Z
:category: blog
:tags: wordpress,ranting
:url: blog/2012/6/14/wordpress-madness.html
:save_as: blog/2012/6/14/wordpress-madness.html
:status: published
:author: Gergely Polonkai
Im a bit fed up that I had to install `MySQL <http://www.mysql.com/>`_ on my server to have
`Wordpress <http://wordpress.org/>`_ working, so Ive Googled a bit to find a solution for my
pain. I found `this <http://codex.wordpress.org/Using_Alternative_Databases>`_. I dont know
when this post was written, but I think its a bit out of date. I mean come on, PDO is the part
of PHP for ages now, and they say adding a DBAL to the dependencies would be a project as large as
(or larger than) WP itself. Well, yes, but PHP is already a dependency, isnt it? Remove it
guys, its too large!
Okay, to be serious… Having a heavily MySQL dependent codebase is a bad thing in my opinion, and
changing it is no easy task. But once it is done, it would be a childs play to keep it up to
date, and to port WP to other database backends. And it would be more than enough to call it 4.0,
and raising version numbers fast is a must nowadays (right, Firefox and Linux Kernel guys?)

View File

@@ -0,0 +1,25 @@
SSH login FAILed on Red Had Enterprise Linux 6.2
################################################
:date: 2012-06-18T18:28:45Z
:category: blog
:tags: linux,selinux,ssh,red-hat
:url: blog/2012/6/18/ssh-login-failed-on-red-hat-enterprise-linux-6-2.html
:save_as: blog/2012/6/18/ssh-login-failed-on-red-hat-enterprise-linux-6-2.html
:status: published
:author: Gergely Polonkai
Now this was a mistake I should not have done…
About a month ago I have moved my AWS EC2 machine from Amazon Linux to RHEL 6.2. This was good.
I have moved all my files and stuff, recreated my own user, everything was just fine. Then I
copied my `gitosis <https://github.com/tv42/gitosis>`_ account (user ``git`` and its home
directory). Then I tried to log in. It failed. I was blaming OpenSSH for a week or so, changed
the config file in several ways, tried to change the permissions on ``~git/.ssh/*``, but still
nothing. Permission were denied, I was unable to push any of my development changes. Now after a
long time of trying, I coincidently ``tail -f``-ed ``/var/log/audit/audit.log`` (wanted to open
``auth.log`` instead) and that was my first good point. It told me that ``sshd`` was unable to
read ``~git/.ssh/authorized_keys``, which gave me the idea to run ``restorecon`` on ``/home/git``.
It solved the problem.
All hail SELinux and RBAC!

View File

@@ -0,0 +1,31 @@
Upgrades requiring a reboot on Linux? At last!
##############################################
:date: 2012-06-22T20:04:51Z
:category: blog
:tags: linux
:url: blog/2012/6/22/upgrades-requiring-a-reboot-on-linux-at-last.html
:save_as: blog/2012/6/22/upgrades-requiring-a-reboot-on-linux-at-last.html
:status: published
:author: Gergely Polonkai
Ive recently received an article on Google+ about Fedoras new idea: package upgrades that
require a reboot. The article said that Linux guys have lost their primary adoo: “Haha! I dont
have to reboot my system to install system upgrades!” My answer was always this: “Well, actually
you should…”
I think this can be a great idea if distros implement it well. PackageKit was a good first step
on this road. That software could easily solve such an issue. However, it is sooo easy to do it
wrong. The kernel, of course, can not be upgraded online (or could it be? I have some theories on
this subject, wonder if it can be implemented…), but other packages are much different. From the
users point of view the best would be if the packages would be upgraded in the background
seemlessly. E.g. PackageKit should check if the given executable is running. If not, it should
upgrade it, while notifying the user like “Hey dude, dont start Anjuta now, Im upgrading it!”,
or simply denying to start it. Libraries are a bit different, as PackageKit should check if any
running executables are using the library. Meanwhile, PK should also keep a notification
somewhere telling the users that some packages could be upgraded, but without stopping
this-and-that, it can not be done.
I know these things are easier said than done. But I think (a) users should tell such ideas to
the developers and (b) developers (mostly large companies, like Microsoft or Apple) should listen
to them, and at least think of these ideas. Some users are not as stupid as they think…

View File

@@ -0,0 +1,67 @@
Some thoughts about that dead Linux Desktop
###########################################
:date: 2012-09-05T09:01:31Z
:category: blog
:tags: linux,ranting
:url: blog/2012/9/5/some-thoughts-about-that-dead-linux-desktop.html
:save_as: blog/2012/9/5/some-thoughts-about-that-dead-linux-desktop.html
:status: published
:author: Gergely Polonkai
There were some arguments in the near past on `What Killed the Linux Desktop
<http://tirania.org/blog/archive/2012/Aug-29.html>`_. After reading many replies, like `Linus
Torvaldss
<http://www.zdnet.com/linus-torvalds-on-the-linux-desktops-popularity-problems-7000003641/>`_, I
have my own thoughts, too.
I know my place in the world, especially in the online community. Im a Linux user for about 15
years and a Linux administrator for 10 years now, beginning with WindowMaker and something that I
remember as GNOME without a version number. I have committed some minor code chunks and
translations in some minor projects, so Im not really into it from the “write” side (well, until
now, since I have began to write this blog, and much more, but dont give a penny for my words
until you see it).
Im using Linux since 2.2 and GNOME since 1.whatever. Its nice that a program compiled years ago
still runs on todays Linux kernel, especially if you see old DOS/Windows software failing to
start on a new Windows 7 machine. I understand Linus point that breaking external APIs is bad,
and I think it can work well on the kernels level. But the desktop level is much different. As
the Linux Desktop has such competitors (like OS/X and Windows Aero and Metro), they have to give
something new to the users almost every year to keep up with them. Eye candies are a must (yes,
of course my techy fellows, they are worthless, but users *need* it), and they can not be created
without extending APIs. And the old API… well, it fades away fast. I dont really understand
however, why they have to totally disappear, like `GTK_DIALOG_NO_SEPARATOR
<http://developer.gnome.org/gtk/stable/GtkDialog.html#GtkDialogFlags>`_ in Gtk+3. It could be
replaced with a 0 value (e.g: it wont do anything). This way my old Gtk+2 program could compile
with Gtk+3 nicely. Also, there could be a small software that goes through your source code and
warn you about such deprecated (and no-doer but still working) things. Porting applications
between Gtk+ (and thus, GNOME) versions became a real pain, which makes less enthusiast
programmers stop developing for Linux. Since Im a GNOME guy for years, I can tell nothing about
Qt and KDE, but for the GNOME guys, this is a bad thing. As of alternatives, there is Java. No,
wait… it turned out recently that `it has several security bugs
<http://www.theregister.co.uk/2012/08/31/critical_flaw_found_in_patched_java>`_. Also its not
that multiplatform as they say (I cant find the article on that at the moment, but I have proof).
Also, the JVMs out there eat up so much resources, which makes it a bit hard and expensive to use.
Also, I see another problem: those blasted package managers. RPM, DPKG, Portage, whatever. What
the hell? Why are there so many? Why do developers reinvent the wheel? The nave is too small or
there are to few spokes? Come on… we live in an open source world! Contribute to the one and
only package manager (which one is that I dont actually care)! Im sure the two (three, many)
bunches of develoeprs could make a deal. Thus, it could become better and “outsider” companies
would be happier to distribute their software for Linux platforms.
And now that we get to the big companies. I dont really understand them. nVidia and ATI made
their own closed source drivers for Linux. Some other hardware vendors also write Linux drivers,
and as the kernel API doesnt really change, they will work for a long time. But what about
desktop application vendors? Well, they try to stick to a desktop environment or two, and if they
change too frequently, they stop developing for Linux, like Skype did (OK, maybe Skype has other
reasons, but you see my point). But why? The main part for Linux programs is the Linux kernel
and the basic userland like libc/stdlib++. If you write graphical software, it will have to use
X-Windows. Yes, its much different in many ways, mostly because they have a… well… pretty ugly
design by default. But still, its the same on every Linux distributions, as it became somewhat
an industry standard, as it was already on the market back in the old UN\*X days. The protocol
itself changed just like the Linux kernel: almost no change at all, just some new features.
So what kills the Linux desktop in my opinion is these constant wars inside, and the lack of
support from the outside. Open Source is good, but until these (mostly the first) problems are
not resolved, Linux Desktop can do nothing on the market. Its a downward spiral hard to escape.

View File

@@ -0,0 +1,73 @@
How to start becoming a web developer
#####################################
:date: 2012-09-07T18:12:12Z
:category: blog
:tags: development,technology
:url: blog/2012/9/7/how-to-start-becoming-a-web-developer.html
:save_as: blog/2012/9/7/how-to-start-becoming-a-web-developer.html
:status: published
:author: Gergely Polonkai
A friend of mine asked me today how to become a web developer. It took me a while, but I made up
a checklist. Its short, but its enough for the first steps.
First of all, learn English
===========================
Well, if you read this, maybe this was a bad first point…
Choose a language and stick to it!
==================================
For the UN\*X/Linux line, there is PHP. Its free, easy to learn, and has many free tools and
documentations available. It can be used in a functional or an object-oriented way.
C# is another good way to start, but for the Windows line. Its fully object oriented, and the
web is full of tutorials, how-tos and other resources.
Learn the basics of the system you are working on
=================================================
To become a good developer, learn at least the basics of the system you are working on. Basic
commands can always come in handy. Debugging (yes, you will do tons of bugs for sure) can become
much easier if you know the huge set of tools provided by your OS. You should also try to develop
in the chosen environment. Chose PHP? Get a Linux desktop! ASP.NET? Get a Windows. Everything
will be much easier!
Learn the basics of the web server you are using
================================================
PHP can run on `Apache <http://httpd.apache.org/>`_ (as a module), or any CGI-capable webserver,
like `lighttpd <http://www.lighttpd.net/>`_ or `nginx <http://nginx.org/>`_ (well, it can also run
on IIS, but trust me: you dont want that). ASP.NET is designed for IIS, and although some
scripts can be run under a mono-capable server, it should still stay there.
Whichever you choose, learn the basics! How to start and stop the service,
basic configuration methods, modules/extensions, and so on. Its more than sure
that you will face some issues while developing, so it can never hurt.
Keep your versions under control
================================
Version control is critical nowadays. It gives you a basic backup solution, can come in handy
with debugging, and if you ever want to work in a team, you will badly need it.
Subversion is a bit out of date now, and its kind of hard to set up.
Git is no easy. You will have to learn a lot of stuff, but basicly its just another version
control system. Just choose if you want to stick to merge-then-commit or rebase-then-commit, get
a client, and get on the run.
Microsofts Team Foundation is another good way if you are working in a team. It provides several
other features besides version controlling, and is well integrated into Visual Studio, which is
highly recommended for Windows based development.
Choose an environment to work in
================================
There are so many good tools out there. You should choose according to the language and OS on
what you are working on. `Zend Studio <http://www.zend.com/en/products/studio>`_ or `Netbeans
<https://netbeans.org/>`_ are both good tools for PHP development, while `Visual Studio
<http://www.visualstudio.com/>`_ is a best buy for Windows development. Both of these have many
ups and downs, but once you get in touch with their deeper parts, you will like them.

View File

@@ -0,0 +1,17 @@
Do-Not-Track in IE10 vs. Apache
###############################
:date: 2012-09-10 20:22:32Z
:category: blog
:tags: apache,technology
:url: blog/2012/9/10/do-not-track-in-ie10-vs-apache.html
:save_as: blog/2012/9/10/do-not-track-in-ie10-vs-apache.html
:status: published
:author: Gergely Polonkai
`Apache developer decided not to accept Do-Not-Track headers from IE10 users
<http://arstechnica.com/security/2012/09/apache-webserver-updated-to-ignore-do-not-track-settings-in-ie-10/>`_,
because its enabled by default. So… if I install a plugin that hides the fact from the web
server that Im using IE10, I become eligible of using it. But if I do this, I simply became
eligible because I consciously installed that addon, so I could actually use it without hiding the
fact. Sorry if Im a bit Philosoraptorish…

View File

@@ -0,0 +1,74 @@
Symfony 2 Create role- and class-based ACLs with your roles coming from the ORM
#################################################################################
:date: 2012-09-16T18:39:25Z
:category: blog
:tags: php,symfony
:url: blog/2012/9/16/symfony-2-create-role-and-class-based-acls-with-your-roles-coming-from-the-orm.html
:save_as: blog/2012/9/16/symfony-2-create-role-and-class-based-acls-with-your-roles-coming-from-the-orm.html
:status: published
:author: Gergely Polonkai
During the last weeks I had some serious issues with one of my private Symfony 2 projects. One of
my goals was to create a dynamic security system, e.g my administrators wanted to create roles,
and grant these roles access to different object types (classes) and/or objects.
So I have created a ``User`` entity, which implements ``UserInterface`` and
``AdvancedUserInterface``, the latter for the possibility to enable/disable accounts and such. It
had a ``$roles`` property, which was a ``ManyToMany`` relation to the ``Role`` entity, which
implemented ``RoleInterface``. Also I have created my own role hierarchy service that implements
``RoleHierarchyInterface``.
So far so good, first tests. It soon turned out that if ``User::getRoles()`` returns a
``DoctrineCollection`` as it does by default, then the standard
.. code-block:: php
<?php
$this->get('security.context')->isGranted('ROLE_ADMIN');
doesnt work. I know, it should not be hard coded, as my roles and permission tables are dynamic,
I have just tested. So I fixed my ``User`` entity so ``getRoles()`` returns an array of ``Role``
objects instead of the ``DoctrineCollection``. Also I implemented a ``getRolesCollection()``
method to return the original collection, but I think it will never be used.
After that, I had to implement some more features so I put this task away. Then, I tried to
create my first ACL.
.. code-block:: php
<?php
$securityIdentity = new RoleSecurityIdentity('ROLE_ADMIN');
$objectIdentity = new ObjectIdentity('newsClass', 'Acme\\DemoBundle\\Entity\\News');
$acl = $aclProvider->createAcl($objectIdentity);
$acl->insertClassAce($securityIdentity, MaskBuilder::MASK_OWNER);
$aclProvider->updateAcl($acl);
I was about to check if the user who is logged in has an ``OWNER`` permission on the ``User``
class.
.. code-block:: php
<?php
$this->objectIdentity = new ObjectIdentity(self::OBJECT_ID, self::OBJECT_FQCN);
if ($this->securityContext->isGranted('OWNER', $this->objectIdentity) === false) {
throw new AccessDeniedException('You dont have the required permissions!');
}
The ACL was defined based on a role, so everyone who had the ``ROLE_ADMIN`` role should gain
access to the user listing page. But they didnt. It took several weeks to find the cause, I
have put it on `stackoverflow
<http://stackoverflow.com/questions/12057795/symfony-2-1-this-getsecurity-context-isgrantedrole-admin-returns-fa>`_
and the Symfony Google Group, but no usable answers.
Then I went off for debugging. Setting up NetBeans for xdebug-based PHP debugging was real fun
under Fedora, but thats another story. After a while I have found that Symfonys basic access
decision manager checks for ``$role->getRole()`` only if ``$role`` is an instance of
``Symfony\Component\Security\Core\Role\Role``, instead of checking if the object implements
``Symfony\Component\Security\Core\Role\RoleInterface``. So Ive checked if the bug is already
reported. It turned out that it was, and my solution was available in a specific commit about a
year ago, but as `Johannes Schmitt commented, it would introduce a security issue
<https://github.com/symfony/symfony/commit/af70ac8d777873c49347ac828a817a400006cbea>`_, so it was
reverted. Unfortunately neither Johannes Schmitt, nor Fabien Potencier (nor anyone else) could (or
wanted) to tell about this issue. So the final (and somewhat hack-like) solution was to extend
``Symfony\Component\Security\Core\Role\Role``. And boom! It worked.

View File

@@ -0,0 +1,36 @@
SmsGateway and SmsSender
########################
:date: 2012-10-07T00:10:26Z
:category: blog
:tags: development,php,symfony
:url: blog/2012/10/7/smsgateway-and-smssender.html
:save_as: blog/2012/10/7/smsgateway-and-smssender.html
:status: published
:author: Gergely Polonkai
I have just uploaded my SmsGateway, SmsSender and SmsSenderBundle packages to `GitHub
<http://github.com/gergelypolonkai>`_ and `Packagist <http://packagist.org>`_. I hope some of you
will find it useful.
* SmsGateway
* `SmsGateway on GitHub`_
* `SmsGateway on Packagist`_
* SmsSender
* `SmsSender on GitHub`_
* `SmsSender on Packagist`_
* SmsSenderBundle
* `SmsSenderBundle on GitHub`_
* `SmsSenderBundle on Packagist`_
.. _SmsGateway on GitHub: https://github.com/gergelypolonkai/smsgateway
.. _SmsGateway on Packagist: https://packagist.org/packages/gergelypolonkai/smsgateway
.. _SmsSender on GitHub: https://github.com/gergelypolonkai/smssender
.. _SmsSender on Packagist: https://packagist.org/packages/gergelypolonkai/smssender
.. _SmsSenderBundle on GitHub: https://github.com/gergelypolonkai/smssender-bundle
.. _SmsSenderBundle on Packagist: https://packagist.org/packages/gergelypolonkai/smssender-bundle

View File

@@ -0,0 +1,22 @@
Changing the session cookies name in Symfony 2
###############################################
:date: 2012-10-13T12:49:28Z
:category: blog
:tags: symfony,development
:url: blog/2012/10/13/changing-the-session-cookie-s-name-in-symfony-2.html
:save_as: blog/2012/10/13/changing-the-session-cookie-s-name-in-symfony-2.html
:status: published
:author: Gergely Polonkai
I have a development server, on which I have several Symfony 2.x projects under the same hostname
in different directories. Now Im facing a funny problem which is caused by that the cookies
Symfony places for each of my projects have the same name.
To change this, you will have to modify the ``config.yml`` file like this:
.. code-block:: yaml
session:
name: SiteSpecificSessionName
lifetime: 3600

View File

@@ -0,0 +1,52 @@
Symfony 2 Configuration Array of associative arrays
#####################################################
:date: 2012-12-20T12:03:23Z
:category: blog
:tags: php,symfony
:url: blog/2012/12/20/symfony-2-configuration-array-of-associative-arrays.html
:save_as: blog/2012/12/20/symfony-2-configuration-array-of-associative-arrays.html
:status: published
:author: Gergely Polonkai
Few days ago I have struggled with a problem using Symfony2 configuration. I
wanted to add the following kind of configuration to ``config.yml``:
.. code-block:: yaml
acme_demo:
transitions:
- { hc_cba: 180 }
- { cba_hc: -1 }
The problem was that the stuff under ``transitions`` is dynamic, so those ``hc_cba`` and
``cba_hc`` tags can be pretty much anything. After hitting many errors, I came to the solution:
.. code-block:: php
<?php
$rootNode
->children()
->arrayNode('state_machine')
->requiresAtLeastOneElement()
->beforeNormalization()
->ifArray()
->then(function($values) {
$ret = array();
foreach ($values as $value) {
foreach ($value as $transition => $time) {
$ret[] = array('transition' => $transition, 'time' => e);
}
}
return $ret;
})
->end()
->prototype('array')
->children()
->scalarNode('transition')->end()
->scalarNode('time')->end()
->end()
->end()
->end()
->end()
;

View File

@@ -0,0 +1,13 @@
Development man pages on Fedora
###############################
:date: 2013-01-05T18:20:41Z
:category: blog
:tags: development,fedora
:url: blog/2013/1/5/development-man-pages-on-fedora.html
:save_as: blog/2013/1/5/development-man-pages-on-fedora.html
:status: published
:author: Gergely Polonkai
If you use Fedora (like me), and cant find the development manual pages for e.g. ``printf(3)``
(like me), just ``yum install man-pages`` (like me).

View File

@@ -0,0 +1,99 @@
Registering an enum type in GLibs type system
##############################################
:date: 2013-01-06T02:34:03Z
:category: blog
:tags: c,development,glib
:url: blog/2013/1/6/registering-an-enum-type-in-glib-s-type-system.html
:save_as: blog/2013/1/6/registering-an-enum-type-in-glib-s-type-system.html
:status: published
:author: Gergely Polonkai
I faced a problem in my `GLib <https://developer.gnome.org/glib/>`_ self-teaching project, `wMUD
<https://github.com/gergelypolonkai/wmud>`_ today. I wanted to register a signal for a
``GObject``, whose handler should accept two ``enum`` parameters for which I had to register a new
``GEnum`` type in the ``GObject`` type system. However, the `documentation on this feature
<https://developer.gnome.org/gobject/unstable/gtype-non-instantiable.html>`_ (thanks for pointing
out goes to `hashem` on ``#gnome-hackers``) is not… uhm… obvious. Making the long story short, I
have checked with the ``GIO`` sources for an example, and using that, I have created this small,
working chunk:
.. code-block:: c
#ifndef __WMUD_CLIENT_STATE_H__
#define __WMUD_CLIENT_STATE_H__
#include <glib-object.h>
/**
* WmudClientState:
* @WMUD_CLIENT_STATE_FRESH: Client is newly connected. Waiting for a login
* player name
* @WMUD_CLIENT_STATE_PASSWAIT: Login player name is entered, waiting for a
* login password
* @WMUD_CLIENT_STATE_MENU: Authentication was successful, player is now in the
* main game menu
* @WMUD_CLIENT_STATE_INGAME: Character login was successful, player is now
* in-game
* @WMUD_CLIENT_STATE_YESNO: Player was asked a yes/no question, and we are
* waiting for the answer. client.yesNoCallback MUST be set at this point!
* TODO: if wmudClient had a prevState field, and there would be some hooks
* that are called before and after the client enters a new state, this
* could be a three-state stuff, in which the player can enter e.g ? as
* the answer, so they would be presented with the question again.
* @WMUD_CLIENT_STATE_REGISTERING: Registering a new player. Waiting for the
* e-mail address to be given
* @WMUD_CLIENT_STATE_REGEMAIL_CONFIRM: E-mail address entered séms valid,
* waiting for confirmation
*
* Game client states.
*/
typedef enum {
WMUD_CLIENT_STATE_FRESH,
WMUD_CLIENT_STATE_PASSWAIT,
WMUD_CLIENT_STATE_MENU,
WMUD_CLIENT_STATE_INGAME,
WMUD_CLIENT_STATE_YESNO,
WMUD_CLIENT_STATE_REGISTERING,
WMUD_CLIENT_STATE_REGEMAIL_CONFIRM
} WmudClientState;
GType wmud_client_state_get_type (void) G_GNUC_CONST;
#define WMUD_TYPE_CLIENT_STATE (wmud_client_state_get_type())
#endif /* __WMUD_CLIENT_STATE_H__ */
.. code-block:: c
#include "wmudclientstate.h"
GType
wmud_client_state_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter(&g_define_type_id__volatile)) {
static const GEnumValue values[] = {
{ WMUD_CLIENT_STATE_FRESH, "WMUD_CLIENT_STATE_FRESH", "fresh" },
{ WMUD_CLIENT_STATE_PASSWAIT, "WMUD_CLIENT_STATE_PASSWAIT", "passwait" },
{ WMUD_CLIENT_STATE_MENU, "WMUD_CLIENT_STATE_MENU", "menu" },
{ WMUD_CLIENT_STATE_INGAME, "WMUD_CLIENT_STATE_INGAME", "ingame" },
{ WMUD_CLIENT_STATE_YESNO, "WMUD_CLIENT_STATE_YESNO", "yesno" },
{ WMUD_CLIENT_STATE_REGISTERING, "WMUD_CLIENT_STATE_REGISTERING", "registering" },
{ WMUD_CLIENT_STATE_REGEMAIL_CONFIRM, "WMUD_CLIENT_STATE_REGEMAIL_CONFIRM", "regemail-confirm" },
{ 0, NULL, NULL }
};
GType g_define_type_id = g_enum_register_static(g_intern_static_string("WmudClientState"), values);
g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
Still, it can be made more perfect by using the `glib-mkenums
<http://developer.gnome.org/gobject/stable/glib-mkenums.html>`_ tool. I will read through the
GLib Makefiles tomorrow for some hints on this.
Edit: you can find the glib-mkenums solution `here
<{filename}2014-08-16-registering-an-enum-type-in-glib-glib-mkenums-magic.rst>`_.

View File

@@ -0,0 +1,16 @@
git rm --cached madness
#######################
:date: 2013-01-14T21:38:00Z
:category: blog
:tags: development,git
:url: blog/2013/1/14/git-rm-cached-madness.html
:save_as: blog/2013/1/14/git-rm-cached-madness.html
:status: published
:author: Gergely Polonkai
I have recently learned about ``git rm --cached``. Its a very good tool, as it removes a file
from tracking, without removing your local copy of it. However, be warned that if you use ``git
pull`` in another working copy, the file will be removed from there! If you accidentally put the
configuration of a production project, and remove it on your dev machine, it can cause a lot of
trouble ;)

View File

@@ -0,0 +1,53 @@
JMS\\DiExtraBundles GrepPatternFinder grep exits with status code 2 on Fedora 18
###################################################################################
:date: 2013-01-17T00:32:12Z
:category: blog
:tags: fedora,selinux,symfony
:url: blog/2013/1/17/jms-diextrabundle-s-greppatternfinder-grep-exits-with-status-code-2-on-fedora-18.html
:save_as: blog/2013/1/17/jms-diextrabundle-s-greppatternfinder-grep-exits-with-status-code-2-on-fedora-18.html
:status: published
:author: Gergely Polonkai
Yesterday Ive upgraded my development machines from Fedora 17 to Fedora
18. Although it went well, my `Symfony <http://symfony.com/>`_ projects stopped working with a
message like this:
.. code-block:: log
RuntimeException: Command "/usr/bin/grep --fixed-strings --directories=recurse --devices=skip --files-with-matches --with-filename --color=never --include=*.php 'JMS\DiExtraBundle\Annotation'
'/var/www/html/gergelypolonkaiweb/app/../src'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/monolog-bundle/Symfony/Bundle/MonologBundle'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/assetic-bundle/Symfony/Bundle/AsseticBundle'
'/var/www/html/gergelypolonkaiweb/vendor/doctrine/doctrine-bundle/Doctrine/Bundle/DoctrineBundle'
'/var/www/html/gergelypolonkaiweb/vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle'
'/var/www/html/gergelypolonkaiweb/vendor/jms/aop-bundle/JMS/AopBundle'
'/var/www/html/gergelypolonkaiweb/vendor/jms/security-extra-bundle/JMS/SecurityExtraBundle'
'/var/www/html/gergelypolonkaiweb/vendor/doctrine/doctrine-migrations-bundle/Doctrine/Bundle/MigrationsBundle'
'/var/www/html/gergelypolonkaiweb/vendor/friendsofsymfony/jsrouting-bundle/FOS/JsRoutingBundle'
'/var/www/html/gergelypolonkaiweb/vendor/avalanche123/imagine-bundle/Avalanche/Bundle/ImagineBundle'
'/var/www/html/gergelypolonkaiweb/vendor/genemu/form-bundle/Genemu/Bundle/FormBundle'
'/var/www/html/gergelypolonkaiweb/src/GergelyPolonkai/FrontBundle'
'/var/www/html/gergelypolonkaiweb/src/GergelyPolonkai/GeshiBundle'
'/var/www/html/gergelypolonkaiweb/vendor/symfony/symfony/src/Symfony/Bundle/WebProfilerBundle'
'/var/www/html/gergelypolonkaiweb/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle'
'/var/www/html/gergelypolonkaiweb/vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle'" exited with non-successful status code "2".
After getting through my logs and such, Ive finally found out that the new SELinux policy is
causing the trouble together with git. Eventually, my ``.git/logs`` directory is tagged as
``unconfined_u:object_r:httpd_log_t:s0``. ``httpd_log_t`` type is not readable by the
``system_u:system_r:httpd_t:s0`` user, which makes ``/usr/bin/grep`` throw an access denied error.
To fix this, I needed to do
.. code-block:: shell
semanage fcontext -a -t httpd_sys_content_t '/var/www(/.*)?/\.git/logs(/.*)?'
as root. This makes ``.git`` directories readable for the httpd process, thus, for ``grep``. The
optimal solution would be to tell ``GrepPatternFinder`` to ignore version control stuff, so the
``httpd`` process would have no access to them at all. Also, in production, removing the ``.git``
or ``.svn`` directories could be a good idea.

View File

@@ -0,0 +1,33 @@
mount: device or resource busy after enabling multipath
#######################################################
:date: 2013-02-19T23:09:05Z
:category: blog
:tags: linux,heartbeat-cluster
:url: blog/2013/2/19/mount-device-or-resource-busy-after-enabling-multipath.html
:save_as: blog/2013/2/19/mount-device-or-resource-busy-after-enabling-multipath.html
:status: published
:author: Gergely Polonkai
We have a heartbeat cluster with two nodes. It has been running for several months without
problems. The shared storage is on an IBM DS3400, on which we have a large volume formatted with
ext4.
Today I decided to reboot the active node for security reasons. So Ive switched to the passive
node, which failed at the first step: it was unable to mount the storage (``/dev/sda1``). After
whining for a few moments, I tried to mount it by hand, which told me
.. code-block:: log
/dev/sda1 already mounted or /data is busy
Ive quickly made sure that none of that was true. After checking this-and-that, it turned out
that the passive node had ``multipathd`` running, so I looked under ``/dev/mapper``, and found two
symlinks there, ``<long-long WWN>`` and ``<long-long WWN>-part1``. As the partition table and the
disk size was the same as on ``/dev/sda``, I tried to
.. code-block:: shell
mount /dev/<long-long WWN>-part1 /data
and voilà! It worked like charm!

View File

@@ -0,0 +1,23 @@
Why I stopped using annotation based routing in Symfony today
#############################################################
:date: 2013-02-27T23:10:24Z
:category: blog
:tags: development,symfony
:url: blog/2013/2/27/why-i-stopped-using-annotation-based-routing-in-symfony-today.html
:save_as: blog/2013/2/27/why-i-stopped-using-annotation-based-routing-in-symfony-today.html
:status: published
:author: Gergely Polonkai
I have read several opinions about routing configuration in Symfony. I stayed with annotation
based routing as it was convinient for me to see the URL right above the controller action. This
was because by just checking the URL, I remembered the controlling code, as they always were fresh
ones. Well, until today.
I had to take a look into an old (Sf 2.0, last commit was about 3 months ago) project of mine. In
the same run Ive upgraded the whole project to 2.2 (it was a fast one, thanks for `JMikola@GitHub
<https://github.com/jmikola>`_ for the quick reply on my issue with `JmikolaJsAssetsHelperBundle
<https://github.com/jmikola/JmikolaJsAssetsHelperBundle>`_ again!). After that I went on to the
requested change. Now, finding a route in about 40 controller files spread between 3 bundles can
really be a pain! So Ive finished with annotation based routing. Its still a nice feature,
its simply not for me.

View File

@@ -0,0 +1,41 @@
Fedora cant change Active Directory password via kpasswd
#########################################################
:date: 2013-03-05T08:55:04Z
:category: blog
:tags: fedora,kerberos,active-directory
:url: blog/2013/3/5/fedora-can-t-change-active-directory-password-via-kpasswd.html
:save_as: blog/2013/3/5/fedora-can-t-change-active-directory-password-via-kpasswd.html
:status: published
:author: Gergely Polonkai
I wanted to change my AD password today. As the AD is actually a Kerberos server, I was pretty
sure that ``kpasswd`` will do the trick. However, ``kpasswd`` output looked like this:
.. code-block:: output
$ kpasswd
Password for polonkai.gergely@EXAMPLE.LOCAL:
Enter new password:
Enter it again:
kpasswd: Cannot find KDC for requested realm changing password
Ive checked ``kinit`` and ``klist``, everything looked fine. After a while it came
to my mind that password changing is done through the kadmin server, not
through the KDC. It seems that when I set up the Active Directory membership,
the ``admin_server`` directive is not get written to ``krb5.conf``. So all I had to
do was to put
.. code-block:: conf
admin_server = ad.example.local
in that file, and voilà!
.. code-block:: output
$ kpasswd
Password for polonkai.gergely@EXAMPLE.LOCAL:
Enter new password:
Enter it again:
Password changed.

View File

@@ -0,0 +1,25 @@
Haversine in MySQL
##################
:date: 2013-03-05T12:49:28Z
:category: blog
:tags: mysql,development
:url: blog/2013/3/5/haversine-in-mysql.html
:save_as: blog/2013/3/5/haversine-in-mysql.html
:status: published
:author: Gergely Polonkai
Just insert it in your database, feed them two Google coordinates, and you get the distance in
kilometres. If you happen to need it in miles, change the constant ``12756.200`` in the
``RETURN`` row to ``7922.6`` instead.
.. code-block:: sql
DELIMITER $$
CREATE FUNCTION `haversine` (lng1 FLOAT, lat1 FLOAT, lng2 FLOAT, lat2 FLOAT)
RETURNS float NO SQL DETERMINISTIC
BEGIN
SET @a = ABS(POWER(SIN(RADIANS(lat1 - lat2)) / 2, 2) + COS(RADIANS(lat1)) * COS(RADIANS(lat2)) * POWER(SIN(RADIANS(lng1 - lng2)) / 2, 2));
RETURN 12756.200 * ATAN2(SQRT(@a), SQRT(1 - @a));
END$$

View File

@@ -0,0 +1,25 @@
Dvorak and me
#############
:date: 2013-03-13T21:20:13Z
:category: blog
:tags: linux
:url: blog/2013/3/13/dvorak-and-me.html
:save_as: blog/2013/3/13/dvorak-and-me.html
:status: published
:author: Gergely Polonkai
A few months ago I have decided to switch to the Dvorak layout. After using QWERTY (well, QWERTZ,
to be precise) for almost 17 years, it was a hard decision, but now I think it worthed the try. I
started with the UK (Dvorak with UK punctuation) layout, and in about four weeks, Ive almost
reached my original typing speed. Today I have modified the Hungarian xkb definitions file to add
the Hungarian accended letters like ű to the layout, so I dont have to use dead keys anymore
(which apparently turned out to be a problem, as the Linux version of Java doesnt support dead
keys at all).
Best thing is, as I never learned proper 10-finger typing, but learned Dvorak that way, I can
switch between QWERTY and Dvorak more or less painlessly (about 10 minutes of confusion, so to
say).
Conclusion: I dont know yet if this was actually a good decision, but it wasnt bad, after all.
But seeing peoples faces when they try to type on my machine totally worths it.

View File

@@ -0,0 +1,25 @@
Renaming a Symfony 2 bundle
###########################
:date: 2013-04-09T22:29:48Z
:category: blog
:tags: development,symfony
:url: blog/2013/4/9/renaming-a-symfony-2-bundle.html
:save_as: blog/2013/4/9/renaming-a-symfony-2-bundle.html
:status: published
:author: Gergely Polonkai
Today Ive realised that the name I gave to one of my Symfony 2 bundles should be something else.
To rename a bundle, one must do four things (at least).
1. Change the namespace from ``Vendor\OldBundle`` to ``Vendor\NewBundle`` in every PHP class
(sounds like pain? It is…)
2. Change the name of files and classes. Some files under ``src/Vendor/OldBundle`` (and the
classes in them) contain the name of the bundle, like
``OldBundle/DependencyInjection/VendorOldBundleExtension.php`` and
``OldBundle/VendorOldBundle.php``. You should rename them, or Symfony wont find the classes
defined in them! When done, rename the whole bundle directory either.
3. Change the configuration files accordingly, including ``AppKernel.php``. These config files
are usually ``routing.yml``, ``services.yml``, and in some cases, ``config.yml``.
4. Change the references in other parts of your code. A ``grep -r OldBundle .`` will usually
help…

View File

@@ -0,0 +1,107 @@
Installing OTRS in Fedora 18 with SELinux enabled
#################################################
:date: 2013-05-06T06:01:52Z
:category: blog
:tags: fedora,selinux,otrs
:url: blog/2013/5/6/installing-otrs-in-fedora-18-with-selinux-enabled.html
:save_as: blog/2013/5/6/installing-otrs-in-fedora-18-with-selinux-enabled.html
:status: published
:author: Gergely Polonkai
Ive read somewhere in an OTRS installation howto that if you want to install OTRS, you will have
to disable SELinux. Well, I wont.
During the last few months, I have been using Fedora 18 with SELinux on all of my desktop machines
and on my notebook, and I had no problems at all. Meanwhile I got familiar with SELinux itself,
and got used to solving problems caused by it. So I started ``tail -f /var/log/httpd/error_log``
in one terminal (to see if something Apache related thing appears), ``tail -f
/var/log/audit/audit.log`` in another (to see errors caused by SELinux), opened the admin manual
at the installation chapter, took a deep breath, and went on.
Throughout this article, I will refer to OTRS 3.2.6 as OTRS and Fedora 18 (with only “stock”
repositories) as Fedora. I assume that you have already installed OTRS in a non-SELinux
environment before, and that you have at least some basic knowledge about SELinux, MAC, RBAC, and
all the like. Im installing OTRS in ``/opt/otrs``, so if you install it somewhere else, you will
have to modify the paths below. Also, if you happen to install under ``/var/www`` (I wouldnt
recommend it), that directory already has the ``httpd_sys_content_t`` type, so you wont have to
set it explicitly.
As the first step I have unpacked the archive to ``/opt/otrs``. This directory is the OTRS
default, many config files have it hardcoded, and changing it is no easy task.
Running ``otrs.CheckModules.pl`` gave me a list of missing perl modules. Red Hat and Fedora makes
it easy to install these, as you dont have to know the RPM package name, just the perl module
name:
.. code-block:: shell
yum install 'perl(Crypt::SSLeay)' \
'perl(DBD::Pg)' \
'perl(GD)' \
'perl(JSON::XS)' \
'perl(GD::Text)' \
'perl(GD::Graph)' \
'perl(Mail::IMAPClient)' \
'perl(Net::DNS)' \
'perl(PDF::API2)' \
'perl(Text::CSV_XS)' \
'perl(YAML::XS)'
I also needed to install ``mod_perl``. Although ``otrs.CheckModules.pl`` didnt mention it, the
default settings use syslog as the logging module, so unless you change it in ``Config.pm``, you
will also need to install ``'perl(Unix::Syslog)'``, either.
The default SELinux policy doesnt permit any network connection to be initiated by Apache httpd.
As OTRS needs to connect to its database, you need to enable it explicitly. In older
distributions, the ``httpd_can_network_connect`` was the SELinux boolean for this, but recent
installations also have a ``httpd_can_network_connect_db`` flag. As far as I know, this enables
all network connections to the well-known database servers default port, but I will have to check
for it. For me, with a MySQL listening on its standard port, the ``setsebool
httpd_can_network_connect_db=1`` command just did it.
With SELinux enabled, Apache wont be able to read anything thats not marked with the
``httpd_sys_content_t`` type, nor write anywhere without the ``httpd_sys_rw_content_t`` type. The
trivial, quick and dirty solution is to label all the files as ``httpd_sys_rw_content_t``, and let
everything go. However, the goal of SELinux is just the opposite of this: grant access only to
what is really needed. After many trial-and-error steps, it finally turned out that for OTRS to
work correctly, you must set
* ``httpd_sys_content_t``
* on ``/opt/otrs/var/httpd/htdocs``
* ``httpd_script_exec_t``
* on ``/opt/otrs/bin/cgi-bin``
* ``httpd_sys_rw_content_t``
* on ``/opt/otrs/Kernel``
* on ``/opt/otrs/var/sessions``
* on ``/opt/otrs/var/log`` (unless you use syslog for logging)
* on ``/opt/otrs/var/packages`` (this is used only when you download an .opm package)
* on ``/opt/otrs/var/stats``
* on ``/opt/otrs/var/tmp``
* on ``/opt/otrs/bin`` (I wonder why this is required, though)
To do this, use the following command:
.. code-block:: sh
semanage fcontext -a -t <context> <directory regex>
Where ``<directory regex>`` is something like ``/opt/otrs/Kernel(/.*)?``. When this is done, all
you have to do is running ``restorecon -vR /opt/otrs`` so it will relabel everything with the
correct types (you can omit ``-v``, I just like to see what my software do).
The last thing I faced is that Fedora is more restrictive on reading directories other than
``/var/www``. It has a ``Require all denied`` on ``<Directory />``, and a ``Require all granted``
on ``<Directory /var/www>``, so ``/opt/otrs/var/httpd/htdocs`` will throw a ``403 Forbidden
(client denied by server configuration)`` error. To get rid of this, I had to modify
``scripts/apache2-httpd.include.conf`` and add ``Require all granted`` to both the ``cgi-bin`` and
``htdocs`` directories.
As I will have to use OTRS in a production environment soon with SELinux enabled, it is more than
sure that this list will change in the near future. As there are no official documentation on
this (I havent find one yet), I have to do it with the trial-and-error way, so be patient!

View File

@@ -0,0 +1,25 @@
SWE-GLib final release
######################
:date: 2013-09-16T21:37:17Z
:category: blog
:tags: development,astrology
:url: blog/2013/9/16/swe-glib-final-release.html
:save_as: blog/2013/9/16/swe-glib-final-release.html
:status: published
:author: Gergely Polonkai
Few of you may know that Im interested in astrology. About two months ago I have decided to
create an astrologers software for the GNOME desktop. Since then, I have contacted Jean-André
Santoni, who created a software called `Astrognome <https://code.google.com/p/astrognome/>`_ some
years ago. We exchanged some e-mails, and after several weeks of coding, Im proud to present
`SWE-GLib <https://github.com/gergelypolonkai/swe-glib>`_ 1.0.1. This is “just” a library which
wraps `Swiss Ephemeris <http://www.astro.com/swisseph/>`_, creating a nice GLib-ish interface
around it. See the project page and the built-in GTK-Doc document for more information.
The astrologers software Im writing will be Astrognome (you can check the `GitHub repository
<https://github.com/gergelypolonkai/astrognome>`_ already, thanks for Jean-André for letting me
use the name). It is currently in pre-alpha status, but already utilizes SWE-GLib (it just cant
display the results yet). If you happen to be interested in astrology and/or Astrognome, fork the
repository and contribute! You can also contact me (or open an enhancement issue on GitHub) if
you have any ideas.

View File

@@ -0,0 +1,22 @@
From Symfony to Django in two days
##################################
:date: 2013-09-24T14:05:22Z
:category: blog
:tags: development,symfony,django
:url: blog/2013/9/24/from-symfony-to-django-in-two-days.html
:save_as: blog/2013/9/24/from-symfony-to-django-in-two-days.html
:status: published
:author: Gergely Polonkai
I was a Python hater for a long time, although I cant really tell why. It didnt fit in my mind,
maybe. I was programming in BASIC, Pascal (none of these would come to my mind now, though), C,
PHP, Perl, JavaScript, and different shell “languages” like awk, sed or bash.
After I could not fit my next Symfony app on my cloud server (it is pretty low on storage), I have
decided to move slowly to Django. My first task was simple: transition my web page (this one)
from PHP + Symfony 2 to Python + Django. The results: the “static” pages are already working, the
blog listing is almost ready (some styling issues are still around), only tagging remains. And
this is after about 6 hours of work. Oh, and the admin site is included with Django, so I dont
have to port that. I have also decided to finally integrate a comment feature in the Django
version.

View File

@@ -0,0 +1,25 @@
First impressions of Windows 8
##############################
:date: 2013-11-05T08:14:50Z
:category: blog
:tags: windows
:url: blog/2013/11/5/first-impressions-of-windows-8.html
:save_as: blog/2013/11/5/first-impressions-of-windows-8.html
:status: published
:author: Gergely Polonkai
Many of you may know my commitment to Linux and Open Source Software. But this doesnt mean I
hate proprietary software like many others do. I think everything has its own place in the world,
and this goes for software as well.
A few days ago I got my hands on a new notebook, thanks to my company. It was shipped with
Windows 8 by default, and although I installed Fedora 19 in an instant (which went smoothlessly,
even with Secure Boot enabled), Ive decided to give a try to this new Windows Version.
Being a heavy Windows 7 user, my first thought was “What the hell is this?” But in a day, I got
totally used to it. I dont miss the Start button at all. The applications already installed
were almost enough for me (I still need Office. Maybe Ill also enroll for Office 365 later…),
and the games are great and beautiful too. So overall, this new version may be totally different
(by the looks), but it seems almost the same Windows as we know it. So if you dont freak out by
touching something new, go give it a try: dont instant-remove 8 in favour of 7!

View File

@@ -0,0 +1,60 @@
List Git branches and their remote tracking branches side by side
#################################################################
:date: 2014-07-18T21:46:45Z
:category: blog
:tags: git
:url: blog/2014/7/18/list-git-branches-and-their-remote-tracking-branches-side-by-side.html
:save_as: blog/2014/7/18/list-git-branches-and-their-remote-tracking-branches-side-by-side.html
:status: published
:author: Gergely Polonkai
I had a hard time following my own branches in a project. They got pretty numerous, and I wasnt
sure if I pushed them to ``origin`` at all. ``git branch -a`` can list all the branches,
including remote ones, but, as my list grew too big, it was impossible to follow it any more.
Thus, I have created a small script called ``git-branches-with-remotes``, which does the work for
me. Its only requirements are git (of course), and the ``column`` command, which is pretty
obviously present on every POSIX compliant systems (even OSX).
.. code-block:: shell
#! /bin/sh
COLUMN=`which column 2> /dev/null`
if test -z $COLUMN
then
echo "\`column' is not found in PATH. Cannot continue."
exit 1
fi
current_branch=`git rev-parse --abbrev-ref HEAD`
for branch in $(git for-each-ref --shell --format='%(refname)' refs/heads | sed -e s/^\'refs\\/heads\\/// -e s/\'$//)
do
remote=`git config branch.$branch.remote`
merge=`git config branch.$branch.merge | sed -e 's/^refs\/heads\///'`
[ x"$current_branch" == x"$branch" ] && echo -n '*'
echo -n "$branch"
if ! test -z $merge
then
echo -en "\t"
echo -n $remote
echo -n /
echo -n $merge
fi
echo
done | $COLUMN -t
I just put it in my path, and ``git branches-with-remotes`` does the work!
Edit (16 August): I have added some code to mark the current branch (if any) with an asterisk.
Also, I have put this script `in a gist
<https://gist.github.com/gergelypolonkai/8af6a3e86b57dd4c250e>`_.
Edit (26 February, 2015): It turns out that ``git branch -vv`` shows the same information and some
more: it also shows if the branches are diverged, and the first line of the last commits message.

View File

@@ -0,0 +1,148 @@
Registering an enum type in GLib, glib-mkenums magic
####################################################
:date: 2014-08-16T15:10:54Z
:category: blog
:tags: development,c,glib
:url: blog/2014/8/16/registering-an-enum-type-in-glib-glib-mkenums-magic.html
:save_as: blog/2014/8/16/registering-an-enum-type-in-glib-glib-mkenums-magic.html
:status: published
:author: Gergely Polonkai
In `this post <{filename}2013-01-06-registering-an-enum-type-in-glib-s-type-system.rst>`_ I said I
will get through the GLib Makefiles to add an enum type to GLib in a more sophisticated way.
In my other project, `SWE-GLib <https://github.com/gergelypolonkai/swe-glib>`_ I already used this
method. The following two rules in ``Makefile.am`` create ``gswe-enumtypes.h`` and
``gswe-enumtypes.c``.
.. code-block:: makefile
gswe_enum_headers = headers-that-contain-enums.h
gswe-enumtypes.h: $(gswe_enum_headers) gswe-enumtypes.h.template
$(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
gswe-enumtypes.h.tmp && mv gswe-enumtypes.h.tmp gswe-enumtypes.h
gswe-enumtypes.c: $(gswe_enum_headers) gswe-enumtypes.h gswe-enumtypes.c.template
$(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
gswe-enumtypes.c.tmp && mv gswe-enumtypes.c.tmp gswe-enumtypes.c
``$(GLIB_MKENUMS)`` is set in ``configure`` using
.. code-block:: m4
AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums])
This approach requires the GNU Autotools (you can get rid of it by changing ``$(GLIB_MKENUMS)`` to
the path to ``glib-mkenums`` binary), and two template files, one for the header and one for the
code. ``$(gswe_enum_headers)`` contains a list of all the header files that have enum types
defined throughout the project.
.. code-block:: c
/*** BEGIN file-header ***/
/* gswe-enumtypes.h - Enumeration types for SWE-GLib
*
* Copyright © 2013 Gergely Polonkai
*
* SWE-GLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* SWE-GLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSWE_ENUM_TYPES_H__
#define __GSWE_ENUM_TYPES_H__
#include <glib-object.h>
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
#include "@filename@"
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type(void);
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/
/*** BEGIN file-tail ***/
#endif /* __GSWE_ENUM_TYPES_H__ */
/*** END file-tail ***/
.. code-block:: c
/*** BEGIN file-header ***/
/* gswe-enumtypes.c - Enumeration types for SWE-GLib
*
* Copyright © 2013 Gergely Polonkai
*
* SWE-GLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* SWE-GLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "swe-glib.h"
#include "gswe-enumtypes.h"
#include "@filename@"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type(void)
{
static volatile gsize g_define_type_id__volatile = 0;
gswe_init();
if (g_once_init_enter(&g;_define_type_id__volatile)) {
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{
@VALUENAME@,
"@VALUENAME@",
"@valuenick@"
},
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_define_type_id = g_@type@_register_static(
g_intern_static_string("@EnumName@"),
values
);
g_once_init_leave(&g;_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/*** END value-tail ***/

View File

@@ -0,0 +1,14 @@
NyanMacs
########
:date: 2014-09-17T12:45:42Z
:category: blog
:tags: emacs
:url: blog/2014/9/17/nyanmacs.html
:save_as: blog/2014/9/17/nyanmacs.html
:status: published
:author: Gergely Polonkai
I was a Vi/ViM user for years. For several reasons I had to change to Emacs now and then. And
then, I found `this <https://github.com/TeMPOraL/nyan-mode/>`_. I surrender. Emacs is just
better. (And this addon is working even in plain text mode without graphics)

View File

@@ -0,0 +1,40 @@
Rounding numbers to N decimals in Emacs
#######################################
:date: 2014-10-07T10:28:50Z
:category: blog
:tags: emacs,development
:url: blog/2014/10/7/rounding-numbers-to-n-decimals-in-emacs.html
:save_as: blog/2014/10/7/rounding-numbers-to-n-decimals-in-emacs.html
:status: published
:author: Gergely Polonkai
I have recently faced a problem, where I had a bunch of SVG files with a large amount of fraction
numbers in the path definitions. These images were displayed in small size, so this amount of
precision was irrelevant, and these numbers took almost half of my SVG images size. So I created
an Elisp defun to round these numbers to 2 decimals:
.. code-block:: lisp
(defun get-number-at-point ()
(interactive)
(skip-chars-backward "0123456789.-")
(or (looking-at "[0123456789.-]+")
(error "No number at point"))
(string-to-number (match-string 0)))
(defun round-number-at-point-to-decimals (decimal-count)
(interactive "NDecimal count: ")
(let ((mult (expt 10 decimal-count)))
(replace-match (number-to-string
(/
(fround
(*
mult
(get-number-at-point)))
mult)))))
This finds the first digit of the number under point (the cursor), and reduces its digits to the
given amount (or the number given with :kbd:`C-u`). It has some drawbacks, though, as it cannot
handle exponential forms (e.g. ``1e-1234``), but these were rare in my case, and its hard to
iterate through all numbers. I will come over this latter problem soon(ish).

View File

@@ -0,0 +1,44 @@
Using Git bisect to find the first good commit
##############################################
:date: 2015-02-26T10:42:56Z
:category: blog
:tags: git
:url: blog/2015/2/26/using-git-bisect-to-find-the-first-good-commit.html
:save_as: blog/2015/2/26/using-git-bisect-to-find-the-first-good-commit.html
:status: published
:author: Gergely Polonkai
Few months ago we “implemented” a bug in our software, which was released to the customers. We
continued development for two weeks when the first customer ticket arrived about the bug. We
successfully reproduced it with the customers version, but not with the development sources; it
turned out that one of the developers unconsciously fixed the bug. The devs spent some hours
finding where the fix lied before coming to me like “There is ``git-bisect`` which we can use to
find the commit where we messed up things. Is there a way to find where we fixed it?”
For those who dont know this feature, you have to mark a known “good” and “bad” commit, then
git-bisect will go through the commits between this two, present you the corresponding snapshots,
and you have to mark each of them as “good” or “bad”. At the end, you will get a commit hash
where the bug first occured.
As it turned out, our developers problem rooted in the naming convention of git-bisect: they
assumed that the “good” commit must be a working one, while a “bad” one must be the buggy. In
this case, we did the following:
The commit with the customers release tag was marked as good (even though this had the bug), and
the latest commit on our development branch was marked as “bad” (even though the bug was fixed by
then). Now with every snapshot presented by git-bisect we had to do the opposite what you usually
do: mark commits still having the bug as “good”, and commits that dont as “bad”. At the end, we
had the hash of the commit that fixed the bug (among some other things; luckily, the developer who
pushed that commit had a workflow that introduced a lot of cherry-picking and squashing before the
push, so he could easily find the bit that actually fixed the problem in his local repository with
the same technique).
`This StackOverflow answer <http://stackoverflow.com/a/17153598/1305139>`_ suggests the very same,
but with some aliases:
.. code-block:: dosini
[alias]
bisect-fixed = bisect bad
bisect-unfixed = bisect good

View File

@@ -0,0 +1,19 @@
Good bye, Digital Ocean! Hello again, GitHub!
#############################################
:date: 2015-04-25T21:18:56Z
:category: blog
:url: blog/2015/4/25/good-bye-digital-ocean-hello-again-github.html
:save_as: blog/2015/4/25/good-bye-digital-ocean-hello-again-github.html
:status: published
:author: Gergely Polonkai
Few years ago I have signed up for a `Digital Ocean <https://www.digitalocean.com/>`_ account. I
used one single droplet for my private needs, like hosting my private Git repositories and my
blog. However, as I didnt host anything else there except my blog, I decided to shut it down.
From now on, my blog is on `GitHub Pages <https://pages.github.com/>`_, as it provides just
everything I need (except automatically converting my resume to PDF. But I can live without
that.)
Im really sorry, Digital Ocean Guys, your hosting is awesome and Ill keep recommending you to
others, but paying for a droplet for one single blog is overkill.

View File

@@ -0,0 +1,60 @@
Cross browser border-radius SASS mixin with varargs
###################################################
:date: 2015-04-27T22:59:56Z
:category: blog
:tags: css,sass
:url: blog/2015/4/28/cross-browser-border-radius-sass-mixin-with-varargs.html
:save_as: blog/2015/4/28/cross-browser-border-radius-sass-mixin-with-varargs.html
:status: published
:author: Gergely Polonkai
Few days ago I needed to create style sheets with many rounded boxes, where different corners had
to be rounded differently (think about Bootstraps `button groups
<http://getbootstrap.com/components/#btn-groups>`_).
CSS has this nifty shorthand to specify border width in one line, like with ``border-width: 1px
2px 3px 4px``, but it lacks the same for ``border-radius``. So I decided to create something
similar using `Sass mixins <http://sass-lang.com/guide#topic-6>`_ with dynamic parameters.
Another nice feature you get using the ``border-width`` shorthand is that you can specify less
than four parameters, and the values will be applied on different sides of your box, so in the end
all side will have the whole ``border-width`` set.
I wanted to achieve the same for my ``border-radius`` mixin, although I
could not start specifically with the `top` side. I decided to go with
the top right corner for the first parameter, while trying to keep a
sane repeating pattern. Here is the result:
.. code-block:: sass
=border-width($t, $r: $t, $b: $t, $l: $r)
border-top-width: $t
border-right-width: $r
border-bottom-width: $b
border-left-width: $l
=border-top-right-radius($value)
border-top-right-radius: $value
-moz-border-top-right-radius: $value
-webkit-border-top-right-radius: $value
=border-top-left-radius($value)
border-top-left-radius: $value
-moz-border-top-left-radius: $value
-webkit-border-top-left-radius: $value
=border-bottom-right-radius($value)
border-bottom-right-radius: $value
-moz-border-bottom-right-radius: $value
-webkit-border-bottom-right-radius: $value
=border-bottom-left-radius($value)
border-bottom-left-radius: $value
-moz-border-bottom-left-radius: $value
-webkit-border-bottom-left-radius: $value
=border-radius($tr, $br: $tr, $bl: $br, $tl: $tr)
+border-top-right-radius($tr)
+border-bottom-right-radius($br)
+border-bottom-left-radius($bl)
+border-top-left-radius($tl)

View File

@@ -0,0 +1,154 @@
@ParamConverter à la Django
###########################
:date: 2015-06-07T18:14:32Z
:category: blog
:tags: python,django
:url: 2015/06/07/paramconverter-a-la-django/
:save_as: 2015/06/07/paramconverter-a-la-django/index.html
:status: published
:author: Gergely Polonkai
One thing I really miss from `Django <https://www.djangoproject.com/>`_ is `Symfony
<http://symfony.com/>`_s `@ParamConverter
<http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html>`_. It
made my life so much easier while developing with Symfony. In Django, of course, there is
`get_object_or_404
<https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#get-object-or-404>`_ but, for
example, in one of my projects I had a view that had to resolve 6(!) objects from the URL, and
writing ``get_object_or_404`` six times is not what a programmer likes to do (yes, this view had a
refactor later on). A quick Google search gave me one `usable result
<http://openclassrooms.com/forum/sujet/middleware-django-genre-paramconverter-doctrine>`_ (in
French), but it was very generalized that I cannot always use. Also, it was using a middleware,
which may introduce performance issues sometimes :sup:`[citation needed]`. So I decided to go
with decorators, and at the end, I came up with this:
.. code-block:: python
import re
from django.shortcuts import get_object_or_404
from django.db import models
def convert_params(*params_to_convert, **options):
"""
Convert parameters to objects. Each parameter to this decorator
must be a model instance (subclass of django.db.models.Model) or a
tuple with the following members:
* model: a Model subclass
* param_name: the name of the parameter that holds the value to be
matched. If not exists, or is None, the models class name will
be converted from ModelName to model_name form, suffixed with
"_id". E.g. for MyModel, the default will be my_model_id
* the field name against which the value in param_name will be
matched. If not exists or is None, the default will be "id"
* obj_param_name: the name of the parameter that will hold the
resolved object. If not exists or None, the default value will
be the models class name converted from ModelName to model_name
form, e.g. for MyModel, the default value will be my_model.
The values are resolved with get_object_or_404, so if the given
object doesnt exist, it will redirect to a 404 page. If you want
to allow non-existing models, pass prevent_404=True as a keyword
argument.
"""
prevent_404 = options.pop('prevent_404', False)
def is_model(m):
return issubclass(type(m), models.base.ModelBase)
if len(params_to_convert) == 0:
raise ValueError("Must pass at least one parameter spec!")
if (
len(params_to_convert) == 1 and \
hasattr(params_to_convert[0], '__call__') and \
not is_model(params_to_convert[0])):
raise ValueError("This decorator must have arguments!")
def convert_params_decorator(func):
def wrapper(*args, **kwargs):
converted_params = ()
for pspec in params_to_convert:
# If the current pspec is not a tuple, lets assume
# its a model class
if not isinstance(pspec, tuple):
pspec = (pspec,)
# First, and the only required element in the
# parameters is the model name which this object
# belongs to
model = pspec[0]
if not is_model(model):
raise ValueError(
"First value in pspec must be a Model subclass!")
# We will calculate these soon…
param_name = None
calc_obj_name = re.sub(
'([a-z0-9])([A-Z])',
r'\1_\2',
re.sub(
'(.)([A-Z][a-z]+)',
r'\1_\2',
model.__name__)).lower()
obj_field_name = None
# The second element, if not None, is the keyword
# parameter name that holds the value to convert
if len(pspec) < 2 or pspec[1] is None:
param_name = calc_obj_name + '_id'
else:
param_name = pspec[1]
if param_name in converted_params:
raise ValueError('%s is already converted' % param_name)
converted_params += (param_name,)
field_value = kwargs.pop(param_name)
# The third element is the field name which must be
# equal to the specified value. If it doesnt exist or
# None, it defaults to 'id'
if (len(pspec) < 3) or pspec[2] is None:
obj_field_name = 'id'
else:
obj_field_name = pspec[2]
# The fourth element is the parameter name for the
# object. If the parameter already exists, we consider
# it an error
if (len(pspec) < 4) or pspec[3] is None:
obj_param_name = calc_obj_name
else:
obj_param_name = pspec[3]
if obj_param_name in kwargs:
raise KeyError(
"'%s' already exists as a parameter" % obj_param_name)
filter_kwargs = {obj_field_name: field_value}
if (prevent_404):
kwargs[obj_param_name] = model.objects.filter(
**filter_kwargs).first()
else:
kwargs[obj_param_name] = get_object_or_404(
model,
**filter_kwargs)
return func(*args, **kwargs)
return wrapper
return convert_params_decorator
Now I can decorate my views, either class or function based, with ``@convert_params(User,
(Article, 'aid'), (Paragraph, None, 'pid'), (AnotherObject, None, None, 'obj'))`` and all the
magic happens in the background. The ``user_id`` parameter passed to my function will be popped
off, and be resolved against the ``User`` model by using the ``id`` field; the result is put in
the new ``user`` parameter. For Article, the ``aid`` parameter will be matched against the ``id``
field of the ``Article`` model putting the result into ``article``, and finally, the
``another_object_id`` will be matched against the ``id`` field of the ``AnotherObject`` model, but
in this case, the result is passed to the original function as ``obj``.

View File

@@ -0,0 +1,17 @@
F/OSS Fail meter
################
:date: 2015-08-19T10:12:19Z
:category: blog
:tags: development
:url: 2015/08/19/foss-failmeter/
:save_as: 2015/08/19/foss-failmeter/index.html
:status: published
:author: Gergely Polonkai
I have recently bumped into `this article <http://spot.livejournal.com/308370.html>`_. Naturally,
I quickly calculated the FAIL metrics for all my projects (most of them are pretty high). To ease
calculation, I made up a `small page <{static}../failmeter/index.html>`_ based on this list
(although I have divided the points by 5; I really dont understand why spot is using such big
points if all of them can be divided by 5). Feel free to use it, and if you have any
recommendations (point additions/removal, new categories, etc.), leave me a comment!

View File

@@ -0,0 +1,201 @@
How my e-mail gets to that other guy?
#####################################
:date: 2015-08-27T21:47:19Z
:category: blog
:tags: technology
:url: 2015/08/27/how-my-email-gets-to-that-other-guy/
:save_as: 2015/08/27/how-my-email-gets-to-that-other-guy/index.html
:status: published
:author: Gergely Polonkai
A friend of mine asked me how it is possible that she pushes buttons on her keyboard and mouse,
and in an instant her peer reads the text she had in her mind. This is a step-by-step
introduction of what happens in-between.
From your mind to your computer
===============================
When you decide to write an e-mail to an acquaintance of yours, you open up your mailing software
(this document doesnt cover using mail applications you access through your browsers, just plain
old Thunderbird, Outlook or similar programs. However, it gets the same after the mail left your
computer), and press the “New Mail” button. What happens during this process is not covered in
this article, but feel free to ask me in a comment! Now that you have your Mail User Agent (MUA)
up and running, you begin typing.
When you press a button on your keyboard or mouse, a bunch of bits gets through the wire (or
through air, if you went wireless) and get into your computer. I guess you learned about Morse
during school; imagine two `Morse operators
<http://www.uscupstate.edu/academics/education/aam/lessons/susan_sawyer/morse%20code.jpg>`_, one
in your keyboard/mouse, and one in your computer. Whenever you press a key, that tiny creature
sends a series of short and long beeps (called 0 or 1 bits, respectively) to the operator in your
computer (fun fact: have you ever seen someone typing at an amazing speed of 5 key presses per
second? Now imagine that whenever that guy presses a key on their keyboard, that tiny little
Morse operator pressing his button 16 times for each key press, with perfect timing so that the
receiving operator can decide if that was a short or long beep.)
Now that the code got to the operator inside the machine, its up to him to decode it. The funny
thing about keyboards and computers is that the computer doesnt receive the message “Letter Q was
pressed”, but instead “The second button on the second row was pressed” (a number called scan
code). At this time the operator decodes this information (in this example it is most likely this
Morse code: ``···-···· -··-····``) and checks one of his tables titled “Current Keyboard Layout.”
It says this specific key corresponds to letter Q, so it forwards this information (I mean the
letter; after this step your computer doesnt care which plastic slab you hit, just the letter
Q) to your MUA, inserts it into the mail in its memory, then displaying it happily (more about
this step later).
When you finish your letter you press the send button of your MUA. First it converts all the
pretty letters and pictures to something a computer can understand (yes, those Morse codes, or
more precisely, zeros and ones, again). Then it adds loads of meta data, like your name and
e-mail address, the current date and time including the time zone and pass it to the sending parts
of the MUA so the next step can begin.
IP addresses, DNS and protocols
===============================
The Internet is a huge amount of computers connected with each other, all of them having at least
one address called IP address that looks something like this: ``123.234.112.221``. These are four
numbers between 0 and 255 inclusive, separated by dots. This makes it possible to have
4,294,967,296 computers. With the rules of address assignment added, this is actually reduced to
3,702,258,432; a huge number, still, but it is not enough, as in the era of the Internet of Things
everything is interconnected, up to and possibly including your toaster. Thus, we are slowly
transitioning to a new addressing scheme that looks like this:
``1234:5678:90ab:dead:beef:9876:5432:1234``. This gives an enormous amount of
340,282,366,920,938,463,463,374,607,431,768,211,456 addresses, with only
4,325,185,976,917,036,918,000,125,705,034,137,602 of them being reserved, which gives us only a
petty 335,957,180,944,021,426,545,374,481,726,734,073,854 available.
Imagine a large city with `that many buildings
<http://www.digitallifeplus.com/wp-content/uploads/2012/07/new-york-city-aerial-5.jpg>`_, all of
them having only a number: their IP address. No street names, no company names, no nothing. But
people tend to be bad at memorizing numbers, so they started to give these buildings names. For
example there is a house with the number ``216.58.209.165``, but between each other, people call
it ``gmail.com``. Much better, isnt it? Unfortunately, when computers talk, they only
understand numbers so we have to provide them just that.
As remembering this huge number of addresses is a bit inconvenient, we created Domain Name
Service, or DNS for short. A “domain name” usually (but not always) consist of two strings of
letters, separated by dots (e.g. polonkai.eu, gmail.com, my-very-long-domain.co.uk, etc.), and a
hostname is a domain name occasionally prefixed with something (e.g. **www**.gmail.com,
**my-server**.my-very-long-domain.co.uk, etc.) One of the main jobs of DNS is to keep record of
hostname/address pairs. When you enter ``gmail.com`` (which happens to be both a domain name and a
hostname) in your browsers address bar, your computer asks the DNS service if it knows the actual
address of the building that people call ``gmail.com``. If it does, it will happily tell your
computer the number of that building.
Another DNS job is to store some meta data about these domain names. For such meta data there are
record types, one of these types being the Mail eXchanger, or MX. This record of a domain tells
the world who is handling incoming mails for the specified domain. For ``gmail.com`` this is
``gmail-smtp-in.l.google.com`` (among others; there can be multiple records of the same type, in
which case they usually have priorities, too.)
One more rule: when two computers talk to each other they use so called protocols. These
protocols define a set of rules on how they should communicate; this includes message formatting,
special code words and such.
From your computer to the mail server
=====================================
Your MUA has two settings called SMTP server address SMTP port number (see about that later).
SMTP stands for Simple Mail Transfer Protocol, and defines the rules on how your MUA, or another
mail handling computer should communicate with a mail handling computer when *sending* mail. Most
probably your Internet Service Provider gave you an SMTP server name, like ``smtp.aol.com`` and a
port number like ``587``.
When you hit that send button of yours, your computer will check with the DNS service for the
address of the SMTP server, which, for ``smtp.aol.com``, is ``64.12.88.133``. The computer puts
this name/address pair into its memory, so it doesnt have to ask the DNS again (this technique is
called caching and is widely used wherever time consuming operations happen).
Then it will send your message to the given port number of this newly fetched address. If you
imagined computers as office buildings, you can imagine port numbers as departments and there can
be 65535 of them in one building. The port number of SMTP is usually 25, 465 or 587 depending on
many things we dont cover here. Your MUA prepares your letter, adding your e-mail address and
the recipients, together with other information that may be useful for transferring your mail.
It then puts this well formatted message in an envelope and writes “to building ``64.12.88.133``,
dept. ``587``”, and puts it on the wire so it gets there (if the wire is broken, the building does
not exist or there is no such department, you will get an error message from your MUA). Your
address and the recipients address are inside the envelope; other than the MUA, your own computer
is not concerned about it.
The mailing department (or instead lets call it the Mail Transfer Agent, A.K.A. MTA) now opens
this envelope and reads the letter. All of it, letter by letter, checking if your MUA formatted
it well. More than probably it also runs your message through several filters to decide if you
are a bad guy sending some unwanted letter (also known as spam), but most importantly it fetches
the recipients address. It is possible, e.g. when you send an e-mail within the same
organization, that the recipients address is handled by this very same computer. In this case
the MTA puts the mail to the recipients mailbox and the next step is skipped.
From one server to another
==========================
Naturally, it is possible to send an e-mail from one company to another, so these MTAs dont just
wait for e-mails from you, but also communicate with each other. When you send a letter from your
``example@aol.com`` address to me at ``gergely@polonkai.eu``, this is what happens.
In this case, the MTA that initially received the e-mail from you (which happened to be your
Internet Service Providers SMTP server) turns to the DNS again. It will ask for the MX record of
the domain name specified by the e-mail address, (the part after the ``@`` character, in my case,
``polonkai.eu``), because the server mentioned that must be contacted, so they can deliver your
mail for me. My domain is configured so its primary MX record is ``aspmx.l.google.com`` and the
secondary is ``alt1.aspmx.l.google.com`` (and 5 more. Google likes to play it safe.) The MTA
then gets the first server name, asks the DNS for its address, and tries to send a message to the
``173.194.67.27`` (the address of ``aspmx.l.google.com``), same department. But unlike your MUA,
MTAs dont have a pre-defined port number for other MTAs (although there can be exceptions).
Instead, they use well-known port numbers, ``465`` and ``25``. If the MTA on that server cannot
be contacted for any reason, it tries the next one on the list of MX records. If none of the
servers can be contacted, it will retry based on a set of rules defined by the administrators,
which usually means it will retry after 1, 4, 24 and 48 hours. If there is still no answer after
that many attempts, you will get an error message back, in the form of an e-mail sent directly by
the SMTP server.
Once the other MTA could be contacted, your message is sent there. The original envelope you used
is discarded, and a new one is used with the address and dept. number (port) of the receiving MTA.
Also, your message gets altered a little bit, as most MTAs are kind enough (ie. not sneaky) to add
a clause to your message stating “the MTA at <organization> has checked and forwarded this
message.”
It is possible, though not likely, that your message gets through more than two MTAs (one at your
ISP and one at the receivers) before arriving to its destination. At the end, an MTA will say
that “OK, this recipient address is handled by me”, your message stops and stays there, put in
your peers mailbox.
The mailbox
-----------
Now that the MTA has passed your mail to the mailbox team (I call it a team instead of department
because the tasks described here are usually handled by the MTA, too), it reads it. (Pesky little
guys these mail handling departments, arent they?) If the mailbox has some filtering rules, like
“if XY sends me a letter, mark it as important” or “if the letter has a specific word in its
subject, put it in the XY folder”, it executes them, but the main point is to land the message in
the actual post box of the recipient.
From the post box to the recipients computer
============================================
When the recipient opens their MUA, it will look to a setting usually called “Incoming mail
server”. Just like the SMTP server, it has a name and port number, along with a server type.
This type can vary from provider to provider, and is usually one of POP3 (pretty old protocol,
doesnt even support folders on its own), IMAP (a newer one, with folders and message flags like
“important”), MAPI (a dialect of IMAP, created by Microsoft as far as I know), or plain old mbox
files on the receiving computer (this last option is pretty rare nowadays, so I dont cover this
option. Also, if you use these, you most probably dont really need this article to understand
how these things work.) This latter setting defines the protocol, telling your MUA how to “speak”
to the post box.
So your MUA turns to the DNS once more to get the address of your incoming mail server and
contacts it, using the protocol set by the server type. At the end, the recipients computer will
receive a bunch of envelopes including the one that contains your message. The MUA opens them one
by one and reads them, making a list ordered by their sender or subject, or the date of sending.
From the recipients comupter to their eyes
===========================================
When the recipient then clicks on one of these mails, the MUA will fetch all the relevant bits
like the sender, the subject line, the date of sending and the contents itself and sends it to the
“printing” department (I use quotes as they dont really print your mail on paper, they just
convert it to a nice image so the recipient can see it. This is sometimes referred to as a
rendering engine). Based on a bunch of rules they pretty-print it and send it to your display as
a new series of Morse codes. Your display then decides how it will present it to the user: draw
the pretty pictures if it is a computer screen, or just raise and lower some hard dots that
represents letters on a Braille terminal.

View File

@@ -0,0 +1,131 @@
Emacs: Implement a GObjects virtual function
#############################################
:date: 2016-01-13T13:31:12Z
:category: blog
:tags: c,development,emacs
:url: 2016/01/13/emacs-implement-a-gobject-s-virtual-function/
:save_as: 2016/01/13/emacs-implement-a-gobject-s-virtual-function/index.html
:status: published
:author: "Gergely Polonkai"
I have recently started creating a GLib implementation of the Matrix.org API. For that, I have
created a GObject interface, MatrixAPI, which has as many virtual functions as API calls (which is
a lot, and expanding). This way I ended up with the following scenario.
In ``matrix-api.h`` I had a struct like this, with a lot more elements:
.. code-block:: c
typedef struct {
void (*initial_sync)(MatrixAPI *api,
MatrixAPICallback callback,
gpointer user_data,
GError **error);
void (*sync)(MatrixAPI *api,
MatrixAPICallback callback,
gpointer user_data,
GError **error);
And in ``matrix-http-api.c``, which implements ``MatrixAPI``, I have a function like this (again,
with a lot more elements):
.. code-block:: c
static void
matrix_http_api_matrix_api_init(GObjectInterface *iface)
{
iface->initial_sync = i_initial_sync;
iface->sync = i_sync;
}
And every time I wanted to implement a new function from the vtable, I had to copy the prototype,
and add an ``iface->foo_bar = i_foo_bar`` line and an actual function header for ``i_foo_bar``
with the same parameters. Thats a cumbersome job for more than 40 function headers. But Emacs
comes to the rescue!
.. code-block:: lisp
(require 'thingatpt)
(defun get-point(symbol &optional arg)
"Get point, optionally running a command beforehand"
(funcall symbol arg)
(point))
(defun copy-symbol-at-point()
"Copy the symbol under point"
(interactive)
(save-excursion
(let ((beg (get-point 'beginning-of-thing 'symbol))
(end (get-point 'end-of-thing 'symbol)))
(copy-region-as-kill beg end))))
(defun implement-gobject-vfunc()
"Change a vtable line of a GObject interface to an implementation line like:
void (*my_iface_func)(type1 param1, type2 param2, ...);
to
iface->my_iface_func = i_my_iface_func;"
(interactive)
(save-excursion
(let ((beg ((lambda()
(search-forward "(*")
(point))))
(end ((lambda()
(back-to-indentation)
(point)))))
(kill-region beg end))
(copy-symbol-at-point)
(insert "iface->")
(end-of-thing 'symbol)
(delete-char 1)
(let ((beg (point))
(end ((lambda()
(find-list-end)
(point)))))
(kill-region beg end))
(insert " = i_")
(yank 2))
(next-line)
(beginning-of-line))
(defun implement-gobject-vfunc-prototype()
"Change a vtable line of a GObject interface to an implementation prototype line like:
void (*my_iface_func)(type1 param1, type2 param2, ...);
to
static void
i_my_iface_func(type1 param1, type2 param2, ...)"
(interactive)
(let ((beg ((lambda()
(back-to-indentation)
(point))))
(end ((lambda()
(beginning-of-line)
(point)))))
(kill-region beg end))
(insert "static ")
(search-forward "(*")
(delete-char -3)
(newline)
(insert "i_")
(end-of-thing 'symbol)
(delete-char 1)
(let ((beg (point))
(end ((lambda()
(find-list-end)
(point)))))
(indent-region beg end))
(delete-char 1))
Now all I have to do is to copy the whole vtable entry into ``matrix_http_api_matrix_api_init()``,
execute :kbd:`M-x implement-gobject-vfunc`, then put the same vtable entry somewhere before the
interface init function, and execute :kbd:`M-x implement-gobject-vfunc-prototype`.

View File

@@ -0,0 +1,32 @@
Vala interface madness
######################
:date: 2016-02-26T13:07:52Z
:category: blog
:tags: vala,development
:url: 2016/02/26/vala-interface-madness/
:save_as: 2016/02/26/vala-interface-madness/index.html
:status: published
:author: "Gergely Polonkai"
Although I have just started making it in C, I decided to move my Matrix GLib SDK to Vala. First
to learn a new language, and second because it is much easier to write GObject based stuff with
it.
For the first step I created a ``.vapi`` file from my existing sources, so the whole SDK prototype
was available for me in Vala.
I had a ``MatrixEvent`` class that implemented the ``GInitable`` interface, and many others were
subclassed ``MatrixEvent``. For some reason I dont remember, I created the following header for
one of the event classes:
.. code-block:: vala
public class MatrixPresenceEvent : GLib.Object, GLib.Initable {
This is nice and everything, but as I didnt create an ``init()`` method for
``MatrixPresenceEvent``, it tried to use the one from the parent class and somehow got into an
infinite loop. The Vala transformer (``valac``), however, doesnt mention this.
Lessons learned: if you implement an interface on a subclass that is implemented by the parent
dont forget to add the necessary functions to the subclass.

View File

@@ -0,0 +1,38 @@
Emacs package to generate GObject boilerplate
#############################################
:date: 2016-09-28T15:40:15Z
:category: blog
:tags: gnome,development
:url: 2016/09/28/emacs-package-to-generate-gobject-boilerplate/
:save_as: 2016/09/28/emacs-package-to-generate-gobject-boilerplate/index.html
:status: published
:author: Gergely Polonkai
Before I started using Vala (and sometimes even after that) I often needed to generate new classes
based on `GObject <https://developer.gnome.org/gobject/stable/>`_.
If you have ever worked with GObject in C, you know how tedious it can be. You need a pretty long
boilerplate just to register your class, and, if you want to be introspectable (and readable,
actually), your function names can grow really long.
To overcome this problem back in my ViM days, I used template files, where I could replace class
prefixes and names with a few keyboard macros. As I never really dug into ViM scripting other
than using some plugins, I never got farther than that. `Then came Emacs
<{filename}2014-09-17-nyanmacs.rst>`_.
I use Emacs for about two years now very extensively, up to and including GLib-based development.
I tried the template approach, but it felt to be a really poor experience, especially given that I
made my feet wet with Emacs Lisp. So I dug deeper, and created a package for that.
.. image:: {static}../images/screenshot-gobgen.png
:alt: A screenshot of GobGen in action
GobGen has its own buffer with some widgets, a bit similar to ``customize``. You can enter the
name of your new object and its parent, specify some settings. Then you press Generate, and you
are presented with two new buffers, one for the ``.c`` and another for the ``.h`` boilerplate.
There are a lot of things to do, actually. There is already an open issue for creating a major
mode for this buffer, and there are some minor switches Id like to add, but it is already usable.
You can grab it from `MELPA <https://melpa.org/#/gobgen>`_ (my first package there; woo!) or from
my `GitHub account <https://github.com/gergelypolonkai/gobgen.el>`_.

View File

@@ -0,0 +1,63 @@
git-merge stages
################
:date: 2016-10-04T12:46:00Z
:category: blog
:tags: git
:url: 2016/10/04/git-merge-stages/
:save_as: 2016/10/04/git-merge-stages/index.html
:status: published
:author: Gergely Polonkai
This was a mail to my companys internal Git mailing list, after I realised many colleagues cant
wrap their heads around merge conflicts.
Hello all,
I just saw this on the `git-users <https://groups.google.com/forum/#!forum/git-users>`_ list
and thought it could help you when you bump into a merge conflict. It is an excerpt from a
mail by Konstantin Khomoutov (one of the main contributors on the list), with a few
modifications of mine. Happy debugging :)
When a merge conflict is detected for a file, Git:
1. Updates the entry for that file in the index to make it contain
several so-called “stages”:
* `0`: “Ours” version that one which was there in this index entry
before we begun to merge. At the beginning of the conflict, like
right after the `git merge` or `git rebase` command this wont
exist (unless you had the file in the index, which you didnt, did
you?). When you resolve the conflict and use `git add
my/conflicting/file.cc`, this will be the version added to the
staging area (index), thus, the resolution of the conflict.
* `1`: The version from the common ancestor commit, ie. the version
of the file both of you modified.
* `2`: The version from `HEAD`. During a merge, this is the current
branch. During a rebase, this is the branch or commit you are
rebasing onto, which usually will be `origin/develop`).
* `3`: The version being merged, or the commit you are rebasing.
2. Updates the file in the work tree to contain conflict markers and
the conflicting chunks of text between them (and the text from the
common ancestor if the `diff3` style of conflict markers was set).
Now you can use the numbers in point 1 to access the different stages
of the conflicting file. For example, to see the common ancestor (the
version both of you modified), use
.. code-block:: shell
git show :1:my/conflicting/file.cc
Or, to see the difference between the two conflicting versions, try
.. code-block:: shell
git diff :2:my/conflicting/file.cc :3:my/conflicting/file.cc
**Note** that you cant use the ``:0:`` stage *before* you stage your resolution with ``git
add``, and you cant use the ``:2:`` and ``:3:`` stages *after* you staged the resolution.
Fun fact: behind the scenes, these are the files (*revisions*) ``git mergetool`` accesses when
it presents you the conflict visually.

View File

@@ -0,0 +1,76 @@
How I started with Emacs
########################
:date: 2016-11-03T09:58:41Z
:category: blog
:tags: emacs
:url: 2016/11/03/how-i-started-with-emacs/
:save_as: 2016/11/03/how-i-started-with-emacs/index.html
:status: published
:author: Gergely Polonkai
Sacha Chua has a nice `Emacs chat intro <http://sachachua.com/blog/2013/04/emacs-chat-intro/>`_
article back from 2013. I write this post half because she asks there about my (OK, anyones)
first Emacs moments, and half because I plan to do it for months now.
I wanted to start using Emacs 6(ish) years ago, and I was like “:kbd:`C-x` what”? (Note that back
around 1998, I was among the people who exited ``vi`` by killing it from another terminal after a
bunch of tries & fails like `these <http://osxdaily.com/2014/06/12/how-to-quit-vim/>`_.)
I tried to come back to Emacs a lot of times. And I mean a *lot*, about every two months. I
suddenly learned what these cryptic key chord descriptions mean (``C`` is for :kbd:`Control` and
``M`` is for :kbd:`Meta`, which is actually :kbd:`Alt`), but somehow it didnt *click*. I
remained a ViM power user with a huge pile of 3:sup:`rd` party plugins. Then `I found Nyan-macs
<{filename}2014-09-17-nyanmacs.rst>`_), which converted me to Emacs, and it is final now. Many of
my friends thought Im just kidding this being the cause, but Im not. Im a huge fan of Nyan cat
(did you know there is even a site called `nyan.cat <http://nyan.cat/>`_?) and since then I have
it in my mode line:
.. image:: {static}../images/nyan-modeline.png
:alt: Nyan modeline
…in my ``eshell`` prompt:
.. image:: {static}../images/nyan-eshell.png
:alt: eshell prompt with a Nyan cat
…and I also `zone out <https://www.emacswiki.org/emacs/ZoneMode>`_ with Nyan cat:
.. image:: {static}../images/nyan-zone.png
:alt: a text-based animation with Nyan cat
Now on to more serious stuff. After browsing through all the packages provided by `ELPA
<http://elpa.gnu.org/>`_, I found tons of useful (and sometimes, less useful) packages, like `Helm
<https://github.com/emacs-helm/helm/wiki>`_, `company <http://company-mode.github.io/>`_, `gtags
<https://www.emacswiki.org/emacs/GnuGlobal>`_ (which introduced me to GNU Global, removing
Exuberant ctags from my life), `magit <https://magit.vc/>`_, `Projectile
<http://batsov.com/projectile/>`_, and `Org <http://orgmode.org/>`_ (OK, its actually part of
Emacs for a while, but still). I still use these few, but in a month or two, I started to
`version control <https://github.com/gergelypolonkai/my-emacs-d>`_ my ``.emacs.d`` directory, so I
can easily transfer it between my home and work machine (and for a few weeks now, even to my
phone: Im using Termux on Android). Then, over these two years I wrote some packages like
`GobGen <https://github.com/gergelypolonkai/gobgen.el>`_, and a small addon for Calendar providing
`Hungarian holidays <https://github.com/gergelypolonkai/hungarian-holidays>`_, and I found a lot
more (in no particular order):
* `git-gutter <https://github.com/syohex/emacs-git-gutter>`_
* `multiple-cursors <https://github.com/magnars/multiple-cursors.el>`_
* `origami <https://github.com/gregsexton/origami.el>`_
* `ace-window <https://github.com/abo-abo/ace-window>`_
* `avy <https://github.com/abo-abo/avy>`_
* `beacon <https://github.com/Malabarba/beacon>`_
…and a lot more.
What is more important (to me) is that I started using the `use-package
<https://github.com/jwiegley/use-package>`_ package, which can automatically download packages
that are not installed on my current local system. Together with `auto-package-update
<https://github.com/rranelli/auto-package-update.el>`_, it is *very* practical.
In addition, I started to follow the blogs of a bunch of Emacs users/gurus. Ive already
mentioned `Sacha Chua <http://sachachua.com/>`_. Shes a charming, cheerful person, writing a lot
about Emacs and project management (among other things). Another one is `Bozhidar Batsov
<http://batsov.com/>`_, who, among other things, had an initiate to lay down the foundation of a
`common Elisp coding style <https://github.com/bbatsov/emacs-lisp-style-guide>`_. Another
favourite of mine is `Endless Parentheses <http://endlessparentheses.com/>`_, whence I got a lot
of ideas.

View File

@@ -0,0 +1,38 @@
Edit file as another user in Emacs
##################################
:date: 2016-11-10T08:57:12Z
:category: blog
:tags: development,emacs
:url: 2016/11/10/edit-file-as-other-user-in-emacs/
:save_as: 2016/11/10/edit-file-as-other-user-in-emacs/index.html
:status: published
:author: Gergely Polonkai
I have recently found `this article <http://emacsredux.com/blog/2013/04/21/edit-files-as-root/>`_
by Bozhidar Batsov on opening the current file as root. I barely use `tramp
<https://www.gnu.org/software/tramp/>`_ for sudo access, but when I do, I almost never use root as
the target user. So I decided to fix it for my needs.
.. code-block:: lisp
(defun open-this-file-as-other-user (user)
"Edit current file as USER, using `tramp' and `sudo'. If the current
buffer is not visiting a file, prompt for a file name."
(interactive "sEdit as user (default: root): ")
(when (string= "" user)
(setq user "root"))
(let* ((filename (or buffer-file-name
(read-file-name (format "Find file (as %s): "
user))))
(tramp-path (concat (format "/sudo:%s@localhost:" user) filename)))
(if buffer-file-name
(find-alternate-file tramp-path)
(find-file tramp-path))))
If the user is not specified, the default is still root. Also, if the current buffer is not
visiting a file, I prompt for a filename. As Im not an ``ido`` user, I didnt bother calling
``ido-read-file-name``; `helm <https://github.com/emacs-helm/helm/wiki>`_ overrides
``read-file-name`` for me anyway.
Unlike Bozhidar, I barely use this feature, so I didnt bind this to a key.

View File

@@ -0,0 +1,46 @@
Get account data programatically from id-manager
################################################
:date: 2016-11-18T12:43:13Z
:category: blog
:tags: emacs
:url: 2016/11/18/get-passwords-from-id-manager/
:save_as: 2016/11/18/get-passwords-from-id-manager/index.html
:status: published
:author: Gergely Polonkai
I recently started using `id-manager <https://github.com/kiwanami/emacs-id-manager>`_. It is a
nice little package that can store your passwords, encrypting them with GPG. My original reason
was to store my GitHub access token for `github-notifier
<https://github.com/xuchunyang/github-notifier.el>`_, but it soon turned out, its not *that*
easy.
``id-manager`` is a nice package when it comes to storing your password and retrieving them for
your own eyes. But it cannot retrieve account data programatically. Taking a look into its
source code, I came up with this solution:
.. code-block:: lisp
(defun gpolonkai/idm-record-get-field (record field)
"Get FIELD of an id-manager RECORD."
(let ((funcname (intern (concat "idm-record-" (symbol-name field)))))
(when (fboundp funcname)
(funcall funcname record))))
(defun gpolonkai/idm-get-field-for-account (account field)
"Get id-manager password for ACCOUNT."
(let ((db (idm-load-db))
(lookup-record nil))
(dolist (record (funcall db 'get-all-records) password)
(when (string= account (idm-record-name record))
(setq lookup-record (gpolonkai/idm-record-get-field record field))))
lookup-record))
(defmacro gpolonkai/idm-get-password-for-account (account)
`(gpolonkai/idm-get-field-for-account ,account 'password))
(defmacro gpolonkai/idm-get-id-for-account (account)
`(gpolonkai/idm-get-field-for-account ,account 'account-id))
I currently need only the account ID (ie. the username) and the password, but its pretty easy to
add a macro to get the ``memo`` or ``update-time`` fields, too.

View File

@@ -0,0 +1,80 @@
Add Python docstring to the beginning of anything in Emacs
##########################################################
:date: 2016-11-30T07:52:37Z
:category: blog
:tags: development,python,emacs
:url: 2016/11/30/add-python-docstring-to-the-beginning-of-anything/
:save_as: 2016/11/30/add-python-docstring-to-the-beginning-of-anything/index.html
:status: published
:author: Gergely Polonkai
Now that I write Python code for a living, I write a lot of functions, classes, and modules. What
I still tend to forget, and also find tedious, is adding docstrings. Unlike many developers,
writing documentation is not an enemy of mine, but it usually comes to my mind when I finish
implementation. The procedure, roughly, is this:
* Decide where I am (in a function, in a class but not in one of its methods, or not inside such a
block at all)
* Go to the beginning of the thing
* Insert ``"""``
* Leave a blank line
* Insert ``"""``
One of my mottos is if something takes more than one step and you have to do it more than twice,
you should automate it after the first time. This puts a small(ish) overhead on the second
invocation (when you implement the automation), but it usually worth the time.
Since I use Emacs for pretty much everything coding-related (and many more, but thats the topic
of a different post), I wrote a small function to do it for me.
.. code-block:: lisp
(defun gpolonkai/prog-in-string-p ()
"Return `t' if point is inside a string."
(nth 3 (syntax-ppss)))
(defun gpolonkai/prog-in-comment-p ()
"Return `t' if point is inside a comment."
(nth 4 (syntax-ppss)))
(defun gpolonkai/python-add-docstring ()
"Add a Python docstring to the current thing. If point is
inside a function, add docstring to that. If point is in a
class, add docstring to that. If neither, add docstring to the
beginning of the file."
(interactive)
(save-restriction
(widen)
(beginning-of-defun)
(if (not (looking-at-p "\\(def\\|class\\) "))
(progn
(goto-char (point-min))
(back-to-indentation)
(forward-char)
(while (gpolonkai/prog-in-comment-p)
(forward-line)
(back-to-indentation)
(forward-char)))
(search-forward ":")
(while (or (gpolonkai/prog-in-string-p)
(gpolonkai/prog-in-comment-p))
(search-forward ":")))
(if (eq 1 (count-lines 1 (point)))
(open-line-above)
(open-line-below))
(insert "\"\"\"")
(open-line-below)
(insert "\"\"\"")
(open-line-above)))
There are still a lot of things to improve:
* it always inserts double quotes (althoug I couldnt show a use-case when single quotes are
preferred)
* it doesnt check for an existing docstring, just happily inserts a new one (leaving the old one
alone, but generating a syntax error this way)
* it would also be nice if I could jump to the beginning of a file even from a class method. I
guess I will use prefix keys for that, but Im not sure yet.
You can bet I will implement these features, so check back soon for an updated version!

View File

@@ -0,0 +1,40 @@
Slugify in Python 3
###################
:date: 2016-12-08T12:54:19Z
:category: blog
:tags: development,python
:url: 2016/12/08/slugify-in-python3/
:save_as: 2016/12/08/slugify-in-python3/index.html
:status: published
:author: Gergely Polonkai
Today I needed a function to create a slug (an ASCII-only representation of a string). I went
Googling a bit, and found an excellend `Flask snippet <http://flask.pocoo.org/snippets/5/>`_.
Problem is, it is designed for Python 2, so I came up with a Python 3 version.
.. code-block:: python
import re
from unicodedata import normalize
_punctuation_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
def slugify(text, delim='-'):
"""
Generate an ASCII-only slug.
"""
result = []
for word in _punctuation_re.split(text.lower()):
word = normalize('NFKD', word) \
.encode('ascii', 'ignore') \
.decode('utf-8')
if word:
result.append(word)
return delim.join(result)
As I dont really like the transliteration done in the first example (e.g. converting ü to ue), I
went with the second example.

View File

@@ -0,0 +1,246 @@
Finding non-translated strings in Python code
#############################################
:date: 2016-12-22T09:35:11Z
:category: blog
:tags: development,python
:url: 2016/12/22/finding-non-translated-strings-in-python-code/
:save_as: 2016/12/22/finding-non-translated-strings-in-python-code/index.html
:status: published
:author: Gergely Polonkai
When creating multilingual software, be it on the web, mobile, or desktop, you will eventually
fail to mark strings as translatable. I know, I know, we developers are superhuman and never do
that, but somehow I stopped trusting myself recently, so I came up with an idea.
Right now I assist in the creation of a multilingual site/web application, where a small part of
the strings come from the Python code instead of HTML templates. Call it bad practice if you
like, but I could not find a better way yet.
As a start, I tried to parse the source files with simple regular expressions, so I could find
anything between quotation marks or apostrophes. This attempt quickly failed with strings that
had such characters inside, escaped or not; my regexps became so complex I lost all hope. Then
the magic word “lexer” came to mind.
While searching for ready made Python lexers, I bumped into the awesome ``ast`` module. AST
stands for Abstract Syntax Tree, and this module does that: parses a Python file and returns a
tree of nodes. For walking through these nodes there is a ``NodeVisitor`` class (among other
means), which is meant to be subclassed. You add a bunch of ``visitN`` methods (where ``N`` is an
``ast`` class name like ``Str`` or ``Call``), instantiate it, and call its ``visit()`` method with
the root node. For example, the ``visitStr()`` method will be invoked for every string it finds.
How does it work?
=================
Before getting into the details, lets me present you the code I made:
.. code-block:: python
import ast
import gettext
from gettext import gettext as _
import sys
def get_func_name(node):
cls = node.__class__.__name__
if cls == 'Call':
return get_func_name(node.func)
elif cls == 'Attribute':
return '{}.{}'.format(
get_func_name(node.value),
node.attr)
elif cls == 'Name':
return get_func_name(node.id)
elif cls == 'str':
return node
elif cls == 'Str':
return "<String literal>"
elif cls == 'Subscript':
return '{}[{}]'.format(get_func_name(node.value),
get_func_name(node.slice))
elif cls == 'Index':
return get_func_name(node.value)
else:
print('ERROR: Unknown class: {}'.format(cls))
class ShowStrings(ast.NodeVisitor):
TRANSLATION_FUNCTIONS = [
'_', # gettext.gettext is often imported under this name
'gettext',
'gettext.gettext',
# FIXME: this list is pretty much incomplete
]
UNTRANSLATED = 'untranslated 9'
def __init__(self, filename=None):
super(ShowStrings, self).__init__()
self.in_call = []
self.filename = filename or '<parsed string>'
def visit_with_trace(self, node, func):
self.in_call.append((func, node.lineno, node.col_offset))
self.visit(node)
self.in_call.pop()
def visit_Str(self, node):
# TODO: make it possible to ignore untranslated strings
# TODO: make this ignore docstrings
# if we are not in a translator function, issue a warning
if not self.in_call or \
self.in_call[-1][0] not in self.TRANSLATION_FUNCTIONS:
try:
funcname = self.in_call[-1][0]
except IndexError:
funcname = None
funcall_msg = "outside a function call" if funcname is None \
else "inside a call to {funcname}".format(
funcname=funcname)
print("WARNING: Untranslated string found at "
"{filename}:{line}:{col} {funcall_msg}".format(
filename=self.filename,
line=node.lineno,
col=node.col_offset,
funcall_msg=funcall_msg))
def visit_Call(self, node):
# if we are in a translator function, issue a warninc
if self.in_call and self.in_call[-1][0] in self.TRANSLATION_FUNCTIONS:
print("WARNING: function call within a translation function at "
"{filename}:{line}:{col}".format(filename=self.filename,
line=node.lineno,
col=node.col_offset))
funcname = get_func_name(node)
for arg in node.args:
self.visit_with_trace(arg, funcname)
for kwarg in node.keywords:
self.visit_with_trace(kwarg.value, funcname)
def generic_visit(self, node):
# if we are inside a translator function, issue a warning
if self.in_call and self.in_call[-1][0] in self.TRANSLATION_FUNCTIONS:
# Some ast nodes, like Add dont have position information
if hasattr(node, 'lineno'):
print("WARNING: something not a string ({klass}) found in a "
"translation function at {filename}:{line}:{col}".format(
filename=self.filename,
klass=node.__class__.__name__,
line=node.lineno,
col=node.col_offset))
else:
print("WARNING: something not a string ({klass}) found in a "
"translation function. Position unknown; function call "
"is at {filename}:{line}:{col}".format(
filename=self.filename,
klass=node.__class__.__name__,
line=self.in_call[-1][1],
col=self.in_call[-1][2]))
super(ShowStrings, self).generic_visit(node)
def tst(*args, **kwargs):
pass
def actual_tests():
_('translated 1')
tst(_('translated 2'))
tst(gettext.gettext('translated 3'))
tst(_('translated 4') + 'native 1')
tst('native 2'
'native 3')
tst(_('native 4' + 'native 5'))
tst('native 6', b='native 7')
tst(_(tst('hello!')))
if __name__ == '__main__':
try:
filename = sys.argv[1]
except IndexError:
filename = __file__
print("INFO: No filename specified, checking myself.")
with open(filename, 'r') as f:
code = f.read()
root = ast.parse(code)
show_strings = ShowStrings(filename=filename)
show_strings.visit(root)
The class initialization does two things: creates an empty ``in_call`` list (this will hold our
primitive backtrace), and saves the filename, if provided.
``visitCall``, again, has two tasks. First, it checks if we are inside a translation function.
If so, it reports the fact that we are translating something that is not a raw string. Although
it is not necessarily a bad thing, I consider it bad practice as it may result in undefined
behaviour.
Its second task is to walk through the positional and keyword arguments of the function call. For
each argument it calls the ``visit_with_trace()`` method.
This method updates the ``in_call`` property with the current function name and the position of
the call. This latter is needed because ``ast`` doesnt store position information for every node
(operators are a notable example). Then it simply visits the argument node, which is needed
because ``NodeVisitor.visit()`` is not recursive. When the visit is done (which, with really
deeply nested calls like ``visit(this(call(iff(you(dare)))))`` will be recursive), the current
function name is removed from ``in_call``, so subsequent calls on the same level see the same
“backtrace”.
The ``generic_visit()`` method is called for every node that doesnt have a named visitor (like
``visitCall`` or ``visitStr``. For the same reason we generate a warning in ``visitCall``, we do
the same here. If there is anything but a raw string inside a translation function call,
developers should know about it.
The last and I think the most important method is ``visitStr``. All it does is checking the last
element of the ``in_call`` list, and generates a warning if a raw string is found somewhere that
is not inside a translation function call.
For accurate reports, there is a ``get_func_name()`` function that takes an ``ast`` node as an
argument. As function call can be anything from actual functions to object methods, this goes all
down the nodes properties, and recursively reconstructs the name of the actual function.
Finally, there are some test functions in this code. ``tst`` and
``actual_tests`` are there so if I run a self-check on this script, it will
find these strings and report all the untranslated strings and all the
potential problems like the string concatenation.
Drawbacks
=========
There are several drawbacks here. First, translation function names are built in, to the
``TRANSLATION_FUNCTIONS`` property of the ``ShowString`` class. You must change this if you use
other translation functions like ``dngettext``, or if you use a translation library other than
``gettext``.
Second, it cannot ignore untranslated strings right now. It would be great if a pragma like
``flake8``s ``# noqa`` or ``coverage.py``s ``# pragma: no cover`` could be added. However,
``ast`` doesnt parse comment blocks, so this proves to be challenging.
Third, it reports docstrings as untranslated. Clearly, this is wrong, as docstrings generally
dont have to be translated. Ignoring them, again, is a nice challenge I couldnt yet overcome.
The ``get_func_name()`` helper is everything but done. As long as I cannot remove that final
``else`` clause, there may be error reports. If that happens, the reported class should be
treated in a new ``elif`` branch.
Finally (and the most easily fixed), the warnings are simply printed on the console. It is nice,
but it should be optional; the problems identified should be stored so the caller can obtain it as
an array.
Bottom line
===========
Finding strings in Python sources is not as hard as I imagined. It was fun to learn using the
``ast`` module, and it does a great job. Once I can overcome the drawbacks above, this script
will be a fantastic piece of code that can assist me in my future tasks.

View File

@@ -0,0 +1,39 @@
Rename automatically named foreign keys with Alembic
####################################################
:date: 2017-01-02T09:41:23Z
:category: blog
:tags: mysql,development,flask,python
:url: 2017/01/02/rename-automatically-named-foreign-keys-with-alembic/
:save_as: 2017/01/02/rename-automatically-named-foreign-keys-with-alembic/index.html
:status: published
:author: Gergely Polonkai
I have recently messed up my Alembic migrations while modifying my SQLAlchemy models. To start
with, I didnt update the auto-generated migration files to name the indexes/foreign keys a name,
so Alembic used its own naming scheme. This is not an actual problem until you have to modify
columns that have such constraints. I have since fixed this problem, but first I had to find
which column references what (I had no indexes other than primary key back then, so I could go
with foreign keys only). Here is a query I put together, mostly using `this article
<http://www.binarytides.com/list-foreign-keys-in-mysql/>`_.
.. code-block:: sql
SELECT constraint_name,
CONCAT(table_name, '.', column_name) AS 'foreign key',
CONCAT(referenced_table_name, '.', referenced_column_name) AS 'references'
FROM information_schema.key_column_usage
WHERE referenced_table_name IS NOT NULL AND
table_schema = 'my_app';
Now I could easily drop such constraints using
.. code-block:: python
alembic.op.drop_constraint('users_ibfk1', 'users', type_='foreignkey')
and recreate them with
.. code-block:: python
alembic.op.create_foreign_key('fk_user_client', 'users', 'clients', ['client_id'], ['id'])

View File

@@ -0,0 +1,85 @@
Category-based logging with Flask
#################################
:date: 2017-03-26T22:00:52Z
:category: blog
:tags: development,python,flask
:url: 2017/03/27/category-based-logging-with-flask/
:save_as: 2017/03/27/category-based-logging-with-flask/index.html
:status: published
:author: Gergely Polonkai
Im in a team who are developing a Flask-based web application, which uses logging extensively.
For a while now it spews out a lot of lines so the need arose to index them in ElasticSearch, and
more importantly, to search through them for auditing purposes. This latter user story brought up
one more question: why dont we categorize our log messages? I quickly came up with an extended
log format (``[auth]`` is the new category name):
.. code-block:: log
[2017-01-14 00:55:42,554] [8286] [INFO] [auth] invalid password for john@example.com [at __init__.py:12, in function utils.validate_login]
Here, ``[auth]`` is the category name. In the ideal solution, all Id have to
do is adding ``%(category)s`` to my formatter, and I could call
.. code-block:: python
app.logger.info(message, extra={'auth': 'invalid password'})
to achieve this output. Unfortunately, ``Flask.logger`` (and, in the background, the ``logging``
module) is not that easy to tame.
As it turns out, a Flask applications ``logger`` property is a subclass of ``logging.Logger``, so
my first idea was to monkey patch that class. When the apps logger is initialised, it subclasses
``logging.Logger`` and tweaks the log level so it goes down to ``logging.DEBUG`` if the app is
running in debug mode. This is done by using a different logger class depending on the app
config. Fortunately it doesnt directly subclass ``logging.Logger``; it calls
``logging.getLoggerClass()`` to find which class it should extend. To achieve my goals, all I had
to do is to subclass the original logger class, and pass it to ``logging.setLoggerClass()``
*before* I initialise my app, and I have a fail-safe(ish) solution. So far so good, on to the
extra category parameter.
Now if you add a new variable to the formatter like my new ``%(category)s``, you get a nifty
``KeyError`` saying there is no ``category`` in the format expansion dictionary. If you add
``category='auth'`` to the ``app.logger.info()`` calls and its cousins, its fine, because these
methods use the magic ``**kwarg`` argument to swallow it. Everything goes well until control
arrives to the ``_log()`` method: it complains about that extra ``category`` keyword argument.
Taking a peek at Pythons internals, I found two things: ``info()`, `error()``, and co. pass
``*args`` and ``**kwargs`` to ``_log()`` unmodified, and the ``_log()`` method doesnt have
``**kwargs`` present in its definition to swallow it. A little doc reading later I found that if
I want to pass extra arguments for such a formatter, I should do it via the ``extra`` keyword
argument to ``_log()``. A call like ``app.logger.info('invalid password', extra={'category':
'auth'})`` solved the problem. Now *that* is tedious.
My first idea was to override all the standard logging methods like ``info()`` and ``error()``,
and handle ``category`` there. But this resulted in lots of repeating code. I changed the
specification a bit, so my calls would look like ``info('message', category='auth)`` instead of
the original plan of ``info('auth', 'message')``: as the logging methods pass all keyword
arguments to ``_log()``, I can handle it there. So at the end, my new logger class only patches
``_log()``, by picking out ``category`` from the kwarg list, and inserting it to ``extra`` before
calling ``super``.
As you can see, this is a bit ugly solution. It requires me, the app
author, to know about Flasks internals (that I can set my own logging class
before the app is created, and so the app will use it.) This means if Flask
developers change the way how logging is done, I have to adapt and find a
workaround for the new version (well, unless they let me directly set the
logging class. That would make it easy.)
What is worse, I must know about Python internals. I know the ``extra`` kwarg is documented well
(I just failed to notice), but this made adding a new formatter variable so hard. Python version
doesnt change as often as Flask version in this project, and I think the standard library wont
really change until 4.0, so I dont think my tampering with a “protected” method will cause any
trouble in the future. Still, this makes me feel a bit uneasy.
All the above can be circumvented if this class, and the whole solution have some tests. As my
class uses the same method as Flask (use ``logging.getLoggerClass()`` as a base class instead of
using ``logging.Logger()`` directly), if the base logger class changes in Python or in the running
environment, my app wont care. By checking if the app logger can use my special ``category``
variable (ie. it doesnt raise an exception *and* the category actually gets into the log output),
I made sure my class is used as a base in Flask, so if they change the way they construct
``app.logger``, I will know about it when I first run my tests after upgrading Flask.
If you are interested in such functionality (and more), you can grab it from `GitHub
<https://github.com/gergelypolonkai/flask-logging-extras>`_, or via `PyPI
<https://pypi.python.org/pypi/Flask-Logging-Extras/>`_.

View File

@@ -0,0 +1,29 @@
Add SysAdmin day to Emacs Calendar
##################################
:date: 2017-10-02T09:37:52Z
:category: blog
:tags: emacs
:url: 2017/10/02/add-sysadmin-day-to-emacs-calendar/
:save_as: 2017/10/02/add-sysadmin-day-to-emacs-calendar/index.html
:status: published
:author: Gergely Polonkai
Im a SysAdmin since 1998. Maybe a bit earlier, if you count managing our home computer. This
means `SysAdmin Day <http://sysadminday.com/>`_ is also celebrating me. However, my Emacs
Calendar doesnt show it for some reason.
The solution is pretty easy:
.. code-block:: lisp
(add-to-list 'holiday-other-holidays '(holiday-float 7 5 -1 "SysAdmin Day") t)
Now invoke :kbd:`M-x holidays-list` for any year, choosing “Other” as the category, and there you
go:
.. code-block:: log
Friday, July 28, 2017: SysAdmin Day

View File

@@ -0,0 +1,54 @@
Please welcome Calendar.social
##############################
:date: 2018-06-26T05:36:00Z
:category: blog
:tags: development
:url: 2018/06/26/please-welcome-calendar-social/
:save_as: 2018/06/26/please-welcome-calendar-social/index.html
:status: published
:author: Gergely Polonkai
I started looking at decentralised/federated tools some years ago, but other than Matrix I didnt
use any of them until recently. Then this February I joined the Fediverse (federated universe) by
spinning up my own `Mastodon <https://joinmastodon.org/>`_ instance. Im not going to lie, this
place is pure awesome. I follow only 53 people but unlike on Twitter or Facebook, I cant just
scroll through my timeline; I have to read them all. These 53 accounts are real persons over the
Internet with meaningful posts. I could never find this on the noisy Twitter or Facebook timeline
during the last 10 or so years.
Bragging aside, and given my strive for learning, I wanted to give back something to this
community. I thought about an image sharing platform where people can share their photo albums
with each other, but I realised Im not that good at image handling. So I decided to make a
calendar instead.
My app, creatively codenamed Calendar.social, aims to be a calendar service similar to Google
Calendar (and, obviously, any calendar app you can find out there) but instead of using emails, it
will use ActivityPub to share all the details (although I might add e-mail support sooner or
later.)
I have a *lot* on my mind about what this tool should/could do when its done. In no particular
order, heres a list of them:
* events that can be private (only you and the (optional) guests see them), or public (anyone can
see them). They will have all the usual fields like start/end time, location, and maybe an icon
and a cover photo
* multiple calendars you would expect from a calendar app. This way you can separate your
birthday reminders from the dentist appointments
* event sharing over ActivityPub and other channels (to be decided, but I think you can take email
and maybe Matrix for granted.)
* full calendar sharing. The other party can get access from a very basic free/busy level to full
write access (which might be a good idea for family or company wide calendars.)
* Holiday calendars that store national/bank holidays. Users can subscribe to them to see the
holidays of a given country/area, and optionally set them as busy (on holiday weekdays) or free
(on weekends that are actually workdays for some reason.)
* Reminders! Because you obviously dont want to forget the birthday of your significant other,
your anniversary, or your barber appointment.
* All this developed with time zones, localisation, and accessibility in mind.
That, and anything more that comes to my mind.
You can follow the development `here <https://gitea.polonkai.eu/gergely/calendar-social>`_. Also,
feel free to ping me with your ideas on my `Mastodon account <https://social.polonkai.eu/@gergely>`_, `Matrix
<https://matrix.to/#/@gergely:polonkai.eu>`_, or any other channels you can find under the
“Contact me” menu.

View File

@@ -0,0 +1,37 @@
Recurring events are hard
#########################
:date: 2018-07-19T13:22:00Z
:category: blog
:tags: development
:url: 2018/07/19/recurring-events/
:save_as: 2018/07/19/recurring-events/index.html
:status: published
:author: Gergely Polonkai
It was almost a month ago when I `announced
<{filename}2018-06-26-please-welcome-calendar-social.rst>`_ the development of Calendar.social.
Since then Im over some interesting and some less interesting stuff; (web) development, after
all, is just a recurrence of patterns. Speaking of recurrence, I arrived to a really interesting
topic: recurring events.
My initial thought was like “oh, thats easy! Lets insert all future occurences as a separate
``Event`` object, linking to the original one for the details. That makes handling exceptions
easy, as I just have to update/delete that specific instance.” Well, not really. I mean, an
event repeating daily *forever* would fill up the database quickly, isnt it? Thats when I
decided to look how other projects do it.
As it turns out, my first thought is about the same as everyone else has their mind, with about
the same reasons. Then, they usually turn down the idea just like I did. And instead, they
implement recurrence patterns and exception patterns.
My favourite is `this article
<https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md>`_ so far. The author
suggests to use the recurrence patterns specced by `RFC2445
<http://www.ietf.org/rfc/rfc2445.txt>`_ (the spec for the iCalendar format). The interesting part
in this solution is how to query recurring events: you simply store the timestamp of the last
occurence of the events (or, if the event repeats forever, the greatest timestamp your database
supports.)
Choosing the maximum date seemed to be the tricky one, but it turned out both Python and popular
SQL backends support dates up to the end of year 9999.

View File

@@ -0,0 +1,220 @@
Check if the last Git commit has test coverage
##############################################
:date: 2018-07-26T12:49:52Z
:category: blog
:tags: python,development,testing
:url: 2018/07/26/check-if-last-git-commit-has-test-coverage/
:save_as: 2018/07/26/check-if-last-git-commit-has-test-coverage/index.html
:status: published
:author: Gergely Polonkai
I use Python at work and for private projects. I also aim to write tests for my code, especially
recently. And as I usually dont start from 100% code coverage (TDD is not my game), I at least
want to know if the code I just wrote have full coverage.
The trick is to collect all the lines that changed, and all the lines that has no coverage. Then
compare the two, and you have the uncovered lines that changed!
Getting the list of changed lines
=================================
Recently, I bumped into
`this article <https://adam.younglogic.com/2018/07/testing-patch-has-test/>`_. It is a great awk
script that lists the lines that changed in the latest commit. I have really no problem with awk,
but Im pretty sure it can be done in Python, as that is my main language nowadays.
.. code-block:: python
def get_changed_lines():
"""Get the line numbers that changed in the last commit
"""
git_output = subprocess.check_output('git show', shell=True).decode('utf-8')
current_file = None
lines = {}
left = 0
right = 0
for line in git_output.split('\n'):
match = re.match(r'^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@', line)
if match:
left = int(match.groups()[0])
right = int(match.groups()[1])
continue
if re.match(r'^\+\+\+', line):
current_file = line[6:]
continue
if re.match(r'^-', line):
left += 1
continue
if re.match(r'^[+]', line):
# Save this line number as changed
lines.setdefault(current_file, [])
lines[current_file].append(right)
right += 1
continue
left += 1
right += 1
return lines
OK, not as short as the awk script, but works just fine.
Getting the uncovered lines
===========================
Coverage.py can list the uncovered lines with ``coverage report --show-missing``. For
Calendar.social, this looks something like this:
.. code-block:: log
Name Stmts Miss Cover Missing
----------------------------------------------------------------------
calsocial/__init__.py 173 62 64% 44, 138-148, 200, 239-253, 261-280, 288-295, 308-309, 324-346, 354-363
calsocial/__main__.py 3 3 0% 4-9
calsocial/account.py 108 51 53% 85-97, 105-112, 125, 130-137, 148-160, 169-175, 184-200, 209-212, 221-234
calsocial/app_state.py 10 0 100%
calsocial/cache.py 73 11 85% 65-70, 98, 113, 124, 137, 156-159
calsocial/calendar_system/__init__.py 10 3 70% 32, 41, 48
calsocial/calendar_system/gregorian.py 77 0 100%
calsocial/config_development.py 11 11 0% 4-17
calsocial/config_testing.py 12 0 100%
calsocial/forms.py 198 83 58% 49, 59, 90, 136-146, 153, 161-169, 188-195, 198-206, 209-212, 228-232, 238-244, 252-253, 263-267, 273-277, 317-336, 339-342, 352-354, 362-374, 401-413
calsocial/models.py 372 92 75% 49-51, 103-106, 177, 180-188, 191-200, 203, 242-248, 257-268, 289, 307, 349, 352-359, 378, 392, 404-409, 416, 444, 447, 492-496, 503, 510, 516, 522, 525, 528, 535-537, 545-551, 572, 606-617, 620, 652, 655, 660, 700, 746-748, 762-767, 774-783, 899, 929, 932
calsocial/security.py 15 3 80% 36, 56-58
calsocial/utils.py 42 5 88% 45-48, 52-53
----------------------------------------------------------------------
TOTAL 1104 324 71%
All we have to do is converting these ranges into a list of numbers, and compare it with the
result of the previous function:
.. code-block:: python
def get_uncovered_lines(changed_lines):
"""Get the full list of lines that has not been covered by tests
"""
column_widths = []
uncovered_lines = {}
for line in sys.stdin:
line = line.strip()
if line.startswith('---'):
continue
if line.startswith('Name '):
match = re.match(r'^(Name +)(Stmts +)(Miss +)(Cover +)Missing$', line)
assert match
column_widths = [len(col) for col in match.groups()]
continue
name = [
line[sum(column_widths[0:idx]):sum(column_widths[0:idx]) + width].strip()
for idx, width in enumerate(column_widths)][0]
missing = line[sum(column_widths):].strip()
for value in missing.split(', '):
if not value:
continue
try:
number = int(value)
except ValueError:
first, last = value.split('-')
lines = range(int(first), int(last) + 1)
else:
lines = range(number, number + 1)
for lineno in lines:
if name in changed_lines and lineno not in changed_lines[name]:
uncovered_lines.setdefault(name, [])
uncovered_lines[name].append(lineno)
return uncovered_lines
At the end we have a dictionary that has filenames as keys, and a list of changed but uncovered
lines.
Converting back to ranges
=========================
To make the final result more readable, lets convert them back to a nice ``from_line-to_line``
range list first:
.. code-block:: python
def line_numbers_to_ranges():
"""List the lines that has not been covered
"""
changed_lines = get_changed_lines()
uncovered_lines = get_uncovered_lines(changed_lines)
line_list = []
for filename, lines in uncovered_lines.items():
lines = sorted(lines)
last_value = None
ranges = []
for lineno in lines:
if last_value and last_value + 1 == lineno:
ranges[-1].append(lineno)
else:
ranges.append([lineno])
last_value = lineno
range_list = []
for range_ in ranges:
first = range_.pop(0)
if range_:
range_list.append(f'{first}-{range_[-1]}')
else:
range_list.append(str(first))
line_list.append((filename, ', '.join(range_list)))
return line_list
Printing the result
===================
Now all that is left is to print the result on the screen in a format digestable by a human being:
.. code-block:: python
def tabular_print(uncovered_lines):
"""Print the list of uncovered lines on the screen in a tabbed format
"""
max_filename_len = max(len(data[0]) for data in uncovered_lines)
for filename, lines in uncovered_lines:
print(filename.ljust(max_filename_len + 2) + lines)
And we are done.
Conclusion
==========
This task never seemed hard to accomplish, but somehow I never put enough energy into it to make
it happen. Kudos to Adam Young doing some legwork for me!

View File

@@ -0,0 +1,12 @@
cut-at-ten
##########
:status: draft
:author: Gergely Polonkai
:date: 2019-11-03T07:21Z
.. code-block:: lisp
(defun cut-at-ten ()
(while (re-search-forward "," (save-excursion (end-of-line) (point)) t 10)
(newline-and-indent)))

View File

@@ -0,0 +1,15 @@
GtkActionable in action
#######################
:status: draft
:author: "Gergely Polonkai"
:date: 2017-09-17T00:00Z
I have seen several people (including myself) struggling with disabling/enabling menu items,
toolbar buttons and similar UI interfaces based on different conditions. It gets even worse if
there are multiple representations of the same action in the same application, e.g. a menu item
and a toolbar button exists for the same action. But with GTK+ 3.4, we have GtkAction, which is
exactly for this kind of situations.
.. include:: ../files/gtk-actionable-test.glade
:code: xml

View File

@@ -0,0 +1,14 @@
Measuring code coverage with codecov for libtool projects
#########################################################
:author: Gergely Polonkai
:status: draft
:date: 2017-09-17T02:00Z
I have recently found `codecov <https://codecov.io/>`_; they offer free services for public GitHub
projects. As I have recently started writing tests for my SWE-GLib project, I decided to give it
a go. Things are not this easy if you use GNU Autotools and libtool, though…
The problem here is that these tools generate output under ``src/.libs/`` (given that your sources
are under ``src/``) and ``gcov`` has hard times finding the coverage data files. Well, at least
in the codecov environment, it works fine on my machine.

View File

@@ -0,0 +1,55 @@
Programming, as I see it
########################
:category: blog
:status: draft
:author: Gergely Polonkai
:date: 2017-09-17T02:00Z
since my age of around 11, i write code. i began with basic, which is, well, the most basic
language i have ever seen. simply writing ``10 print "hello world!"`` does the job (with assembly
it would be tens of lines as i recall). then i moved to pascal, then delphi (which is basically
the same thing). the next step was a bit longer, as i started learning more languages after this,
like perl (for dynamic web pages), c (for desktop applications), tcl (for eggdrop programming.
yes, i might have been a weird kid), php (again, for dynamic web pages. it was becoming
mainstream back then).
many of my classmates looked down on me, as they thought i was a geek (hell i was, but i wouldnt
have confessed it then), and called me a nerd. for a few months maybe i was depressed, but after
that i realised that this is the thing i want to do in my life, this is the thing im good at.
Most people I ask why dont they code say “its too hard”. Ive attended some courses (both
online and offline, and I was like “Whoa! Coding is extremely hard! What the hell! I will never
learn it!”, but right after the course I realised that everything is just fine, I can still write
programs, and its eeeeasy. So then, whats the problem?
After looking through many course papers, I found that most teachers do it totally wrong. A
programming language is just that: a language. You dont start learning Spanish by going into a
classic literature conference in Madrid and doing a speech, but learn the basic vocabulary and
grammar. The same goes for coding. You learn the vocabulary (the basic commands or keywords) and
grammar (syntax). I had several ideas how this could be taught, just didnt have the background
to do it.
The idea of teaching programming lingers in my head for years now, and a few days ago, Ive bumped
into `this video <https://www.youtube.com/watch?v=dU1xS07N-FA>`_. So it seems that technology
superstars like Bill Gates and Mark Zuckerberg wants to do the same. Maybe they dont have enough
high quality coders at hand. Well of course, if teachers make it awfully hard to learn it! So a
bunch of guys sat together and created `code.org <http://www.code.org/>`_ to achieve my old dream.
I like the idea. And although I have almost no visitor on this blog of mine, allow me to give you
a few points on how I see programming.
Great learning process
======================
When you write programs, especially during the first years, you adapt a new way of thinking and
learning. If you learn it as an adult, it can be a bit of a pain, but as a child, its easy as
learning how the wheels of those little cars spin).
A job
=====
Art
===
Magic
=====

View File

@@ -0,0 +1,315 @@
Writing a GNOME Shell extension
###############################
:date: 2017-09-17T03:00Z
I could not find a good tutorial on how to write a GNOME Shell extension. There is a so called
step by step `instruction list
<https://wiki.gnome.org/Projects/GnomeShell/Extensions/StepByStepTutorial>`_ on how to do it, but
it has its flaws, including grammar and clearance. As I wanted to create an extension for my SWE
GLib library to display the current position of some planets, I dug into existing (and working)
extensions source code and made up something. Comments welcome!
---
GNOME Shell extensions are written in JavaScript and are interpreted by `GJS
<https://wiki.gnome.org/action/show/Projects/Gjs>`_. Using introspected libraries from JavaScript
is not a problem for me (see SWE GLibs `Javascript example
<https://github.com/gergelypolonkai/swe-glib/blob/master/examples/basic.js>`_; its not beautiful,
but its working), but wrapping your head around the Shells concept can take some time.
The Shell is a Clutter stage, and all the buttons (including the top-right “Activities” button)
are actors on this stage. You can add practically anything to the Shell panel that you can add to
a Clutter stage.
The other thing to remember is the lifecycle of a Shell extension. After calling ``init()``, there
are two ways forward: you either use a so called extension controller, or plain old JavaScript
functions ``enable()`` and ``disable()``; I will go on with the former method for reasons
discussed later.
If you are fine with the ``enable()``/``disable()`` function version, you can ease your job with
the following command:
.. code-block:: shell
gnome-shell-extension-tool --create-extension
This will ask you a few parameters and create the necessary files for you. On what these
parameters should look like, please come with me to the next section.
Placement and naming
====================
Extensions reside under ``$HOME/.local/share/gnome-shell/extensions``, where each of them have its
own directory. The directory name has to be unique, of course; to achieve this, they are usually
the same as the UUID of the extension.
The UUID is a string of alphanumeric characters, with some extras added. Generally, it should
match this regular expression: ``^[-a-zA-Z0-9@._]+$``. The convention is to use the form
``extension-name@author-id``, e.g. ``Planets@gergely.polonkai.eu``. Please see `this link
<https://wiki.gnome.org/Projects/GnomeShell/Extensions/UUIDGuidelines>`_ for some more information
about this.
Anatomy of an extension
=======================
Extensions consist of two main parts, ``metadata.json`` and ``extension.js``.
The ``metadata.json`` file contains compatibility information and, well, some meta data:
.. code-block:: json
{
"shell-version": ["3.18"],
"uuid": "planets@gergely.polonkai.eu",
"name": "Planets",
"description": "Display current planet positions"
}
Here, ``shell-version`` must contain all versions of GNOME Shell that is known to load and display
your extension correctly. You can insert minor versions here, like I did, or exact version
numbers, like ``3.18.1``.
In the ``extension.js`` file, which contains the actual extension code, the only thing you
actually need is an ``init()`` function:
.. code-block:: javascript
function init(extensionMeta) {
// Do whatever it takes to initialize your extension, like initializing the translations.
// However, never do any widget magic here yet.
// Then return the controller object
return new ExtensionController(extensionMeta);
}
Extension controller
====================
So far so good, but what is this extension controller thing? It is an object which is capable of
managing your GNOME Shell extension. Whenever the extension is loaded, its ``enable()`` method is
called; when the extension is unloaded, you guessed it, the ``disable()`` method gets called.
.. code-block:: javascript
function ExtensionController(extensionMeta) {
return {
extensionMeta: extensionMeta,
extension: null,
enable: function() {
this.extension = new PlanetsExtension(this.extensionMeta);
Main.panel.addToStatusArea("planets", this.extension, 0, "right");
},
disable: function() {
this.extension.actor.destroy();
this.extension.destroy();
this.extension = null;
}
}
}
This controller will create a new instance of the ``PlanetsExtension`` class and add it to the
panels right side when loaded. Upon unloading, the extensions actor gets destroyed (which, as
you will see later, gets created behind the scenes, not directly by us), together with the
extension itself. Also, for safety measures, the extension is set to ``null``.
The extension
=============
The extension is a bit more tricky, as, for convenience reasons, it should extend an existing
panel widget type.
.. code-block:: javascript
function PlanetsExtension(extensionMeta) {
this._init(extensionMeta);
}
PlanetsExtension.prototype = {
__proto__ = PanelMenu.Button.prototype,
_init: function(extensionMeta) {
PanelMenu.Button.prototype._init.call(this, 0.0);
this.extensionMeta = extensionMeta;
this.panelContainer = new St.BoxLayout({style_class: 'panel-box'});
this.actor.add_actor(this.panelContainer);
this.actor.add_style_class_name('panel-status-button');
this.panelLabel = new St.Label({
text: 'Loading',
y_align: Clutter.ActorAlign.CENTER
});
this.panelContainer.add(this.panelLabel);
}
};
Here we extend the ``Button`` class of ``panelMenu``, so we will be able to do some action upon
activate.
The only parameter passed to the parents ``_init()`` function is ``menuAlignment``, with the
value ``0.0``, which is used to position the menu arrow. (*Note: I cannot find any documentation
on this, but it seems that with the value ``0.0``, a menu arrow is not added.*)
The extension class in its current form is capable of creating the actual panel button displaying
the text “Loading” in its center.
Loading up the extension
========================
Now with all the necessary import lines added:
.. code-block:: javascript
// The PanelMenu module that contains Button
const PanelMenu = imports.ui.panelMenu;
// The St class that contains lots of UI functions
const St = imports.gi.St;
// Clutter, which is used for displaying everything
const Clutter = imports.gi.Clutter;
As soon as this file is ready, you can restart your Shell (press :kbd:`Alt-F2` and enter the
command ``r``), and load the extension with e.g. the GNOME Tweak Tool. You will see the Planets
button on the right. This little label showing the static text “Planets”, however, is pretty
boring, so lets add some action.
Adding some periodical change
=============================
Since the planets position continuously change, we should update our widget every minute or
so. Lets patch our ``_init()`` a bit:
.. code-block:: javascript
this.last_update = 0;
MainLoop.timeout_add(1, Lang.bind(this, function() {
this.last_update++;
this.panelLabel.set_text("Update_count: " + this.last_update);
}))
This, of course, needs a new import line for ``MainLoop`` to become available:
.. code-block:: javascript
const MainLoop = imports.mainloop;
const Lang = imports.lang;
Now if you restart your Shell, your brand new extension will increase
its counter every second. This, however, presents some problems.
SWE GLib queries can sometimes be expensive, both in CPU and disk operations, so updating our
widget every second may present problems. Also, planets dont go **that** fast. We may update
our timeout value from ``1`` to ``60`` or something, but why dont just give our user a chance to
set it?
Introducing settings
====================
Getting settings from ``GSettings`` is barely straightforward, especially for software installed
in a non-GNOME directory (which includes extensions). To make our lives easier, I copied over a
`convenience library
<https://github.com/projecthamster/shell-extension/blob/master/convenience.js>`_ from the `Hamster
project <https://projecthamster.wordpress.com/>`_s extension, originally written by Giovanni
Campagna. The relevant function here is ``getSettings()``:
.. code-block:: javascript
/**
* getSettings:
* @schema: (optional): the GSettings schema id
*
* Builds and return a GSettings schema for @schema, using schema files
* in extensionsdir/schemas. If @schema is not provided, it is taken from
* metadata['settings-schema'].
*/
function getSettings(schema) {
let extension = ExtensionUtils.getCurrentExtension();
schema = schema || extension.metadata['settings-schema'];
const GioSSS = Gio.SettingsSchemaSource;
// check if this extension was built with "make zip-file", and thus
// has the schema files in a subfolder
// otherwise assume that extension has been installed in the
// same prefix as gnome-shell (and therefore schemas are available
// in the standard folders)
let schemaDir = extension.dir.get_child('schemas');
let schemaSource;
if (schemaDir.query_exists(null))
schemaSource = GioSSS.new_from_directory(schemaDir.get_path(),
GioSSS.get_default(),
false);
else
schemaSource = GioSSS.get_default();
let schemaObj = schemaSource.lookup(schema, true);
if (!schemaObj)
throw new Error('Schema ' + schema + ' could not be found for extension '
+ extension.metadata.uuid + '. Please check your installation.');
return new Gio.Settings({ settings_schema: schemaObj });
}
You can either incorporate this function into your ``extension.js`` file, or just use
``convenience.js`` file like I (and the Hamster applet) did and import it:
.. code-block:: javascript
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension;
const Convenience = Me.imports.convenience;
Now lets create the settings definition. GSettings schema files are XML files. We want to add
only one settings for now, the refresh interval.
.. code-block:: xml
<?xml version="1.0" encoding="utf-8"?>
<schemalist>
<schema id="org.gnome.shell.extensions.planets" path="/org/gnome/shell/extensions/planets/">
<key name="refresh-interval" type="i">
<default>30</default>
<summary>Refresh interval of planet data</summary>
<description>Interval in seconds. Sets how often the planet positions are recalculated. Setting this too low (e.g. below 30) may raise performance issues.</description>
</key>
</schema>
</schemalist>
you need to compile these settings with
.. code-block:: shell
glib-compile-schemas --strict schemas/
Now lets utilize this new setting. In the extensions ``_init()`` function, add the following
line:
.. code-block:: javascript
this._settings = Convenience.getSettings();
And, for ``getSettings()`` to work correctly, we also need to extend our ``metadata.json`` file:
.. code-block:: json
"settings-schema": "planets"
After another restart (please, GNOME guys, add an option to reload extensions!), your brand new
widget will refresh every 30 seconds.
Displaying the planet positions
===============================
The settings panel
==================
Start an application
====================

View File

@@ -0,0 +1,54 @@
Lessons you learn while writing an SDK
######################################
:tags: development
:author: Gergely Polonkai
:date: 2017-09-17T01:00Z
In the last few months Ive been working on a GLib based SDK for client applications that want to
communicate with a Matrix.org homeserver.
For whoever doesnt know it, Matrix is a decentralized network of servers (Homeservers). Clients
can connect to them via HTTP and send messages (events, in Matrix terminology) to each other.
They are called events because these messages can be pretty much anything from instant messages
through automated notifications to files or, well, actual events (such as a vCalendar); anything
that you can serialize to JSON can go through this network.
My original intention was to integrate Matrix based chat into Telepathy, a DBus based messaging
framework used by e.g. the GNOME desktop (more specifically Empathy, GNOME's chat client.) After
announcing my plans among the Matrix devs, I quickly learned some things:
1. they are more than open to any development ideas
2. they really wanted to see this working
3. they would have been happy if there were a GLib or Qt based SDK
With my (far from complete) knowledge in GLib I decided to move on with this last point, hoping
that it will help me much when I finally implement the Telepathy plugin.
Matrix devs are open minded
===========================
What I learned very quickly is that Matrix devs are very open minded folks from different parts of
the world. They are all individuals with their own ideas, experiences and quirks, yet, when it
comes to that, they steer towards their goals as a community. Thus, getting additional
information from them while reading the spec was super easy.
The specification is easy to understand
=======================================
Except when it is not. For these cases, see the previous point.
Jokes aside, anyone who worked with communications protocols or JSON APIs before can get along
with it fast. The endpoints are all documented, and if something is unclear, they are happy to
help (especially if you patch up the spec afterwards.)
Copying the SDK for a different language is not (always) what you want
======================================================================
I started my SDK in C, trying to mimic the Python SDK. This was a double fail: the Python SDK was
a volatile WiP, and C and Python are fundamentally different.
During the upcoming weeks this became clear and I switched to the Vala language. It is much
easier to write GObject based stuff in Vala, although I had to fall back to C to get some features
working. I also planned and implemented a more object oriented API, which is easier to use in the
GObject world.

View File

@@ -0,0 +1,12 @@
body {
padding-top: 80px;
}
.fail:hover {
background-color: #eee;
}
.progress {
margin-bottom: 0;
background-color: #cacaca;
}

View File

@@ -0,0 +1,186 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>F/OSS Fail meter</title>
<meta name="date" content="2015-08-14T12:23:34Z">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<link rel="stylesheet" href="css/failmeter.css" type="text/css">
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha256-Sk3nkD6mLTMOF0EOpNtsIry+s1CsaqQC1rVLTAy+0yc= sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
<script src="js/failmeter.js"></script>
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand">Fail meter for F/OSS projects</a>
</div>
<div class="navbar-text" id="failtext"></div>
<p class="navbar-text navbar-right">
Based on <a href="http://spot.livejournal.com/308370.html" class="navbar-link">this article</a>
</p>
</div>
<div class="progress">
<div id="failmeter" class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span id="points">0</span>
</div>
</div>
</nav>
<div class="container">
<h2>Size</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="1">The source code is more than 100 MB.</li>
<li class="list-group-item fail" data-points="1">If the source code also exceeds 100 MB when it is compressed</li>
</ul>
<h2>Source Control</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="2">There is no publicly available source control (e.g. cvs, svn, bzr, git)</li>
<li class="list-group-item">There is publicly available source control, but:
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="1">There is no web viewer for it</li>
<li class="list-group-item fail" data-points="1">There is no documentation on how to use it for new users</li>
<li class="list-group-item fail" data-points="6">You've written your own source control for this code</li>
<li class="list-group-item fail" data-points="10">You don't actually use the existing source control</li>
</ul>
</li>
</ul>
<h2>Building From Source</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="4">There is no documentation on how to build from source</li>
<li class="list-group-item fail" data-points="2">Documentation exists on how to build from source, but it doesn't work</li>
<li class="list-group-item">Your source is configured…
<ul class="list-group fail-list choose-one">
<li class="list-group-item fail" data-points="2">…with a handwritten shell script</li>
<li class="list-group-item fail" data-points="4">…by editing flat text config files</li>
<li class="list-group-item fail" data-points="6">…by editing code header files manually</li>
<li class="list-group-item fail" data-points="10">Your source isn't configurable</li>
</ul>
</li>
<li class="list-group-item">You source builds with…
<ul class="list-group fail-list choose-one">
<li class="list-group-item fail" data-points="2">…something that isn't GNU Make</li>
<li class="list-group-item fail" data-points="10">…a third-party proprietary build tools</li>
<li class="list-group-item fail" data-points="20">…something you wrote for this code</li>
</ul>
</li>
</ul>
<h2>Bundling</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="4">Your source only comes with other code projects that it depends on</li>
<li class="list-group-item fail" data-points="2">Your source code cannot be built without first building the bundled code bits</li>
<li class="list-group-item fail" data-points="8">You have modified those other bundled code bits</li>
</ul>
<h2>Libraries</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="4">Your code only builds static libraries</li>
<li class="list-group-item fail" data-points="4">Your code can build shared libraries, but only unversioned ones</li>
<li class="list-group-item fail" data-points="4">Your source does not try to use system libraries if present</li>
</ul>
<h2>System Install</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="2">Your code tries to install into /opt or /usr/local without explicitly telling it to do so</li>
<li class="list-group-item fail" data-points="4">Your code has no "make install"</li>
<li class="list-group-item fail" data-points="6">Your code doesn't work outside of the source directory</li>
</ul>
<h2>Code Oddities</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="1">Your code uses Windows line breaks ("DOS format" files)</li>
<li class="list-group-item fail" data-points="4">Your code depends on specific compiler feature functionality</li>
<li class="list-group-item fail" data-points="10">Your code depends on specific compiler bugs</li>
<li class="list-group-item fail" data-points="20">Your code depends on Microsoft Visual Anything</li>
</ul>
<h2>Communication</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="1">Your project does not announce releases on a mailing list</li>
<li class="list-group-item fail" data-points="2">Your project does not have a mailing list</li>
<li class="list-group-item fail" data-points="4">Your project does not have a bug tracker</li>
<li class="list-group-item fail" data-points="10">Your project does not have a website</li>
<li class="list-group-item fail" data-points="20">Your project is sourceforge vaporware</li>
</ul>
<h2>Releases</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="2">Your project does not do sanely versioned releases (Major, Minor)</li>
<li class="list-group-item fail" data-points="4">Your project does not do versioned releases</li>
<li class="list-group-item fail" data-points="10">Your project does not do releases</li>
<li class="list-group-item fail" data-points="20">Your project only does releases as attachments in web forum posts</li>
<li class="list-group-item">Your releases are <em>only</em> in
<ul class="list-group choose-one">
<li class="list-group-item fail" data-points="1">.zip format</li>
<li class="list-group-item fail" data-points="2">OSX .zip format</li>
<li class="list-group-item fail" data-points="4">.rar format</li>
<li class="list-group-item fail" data-points="10">.arj format</li>
<li class="list-group-item fail" data-points="20">an encapsulation format that you invented</li>
</ul>
</li>
<li class="list-group-item fail" data-points="2">Your release does not unpack into a versioned top-level directory (e.g. <code>glibc-2.4.2/</code>)</li>
<li class="list-group-item fail" data-points="5">Your release does not unpack into a top-level directory (e.g. <code>glibc/</code>)</li>
<li class="list-group-item fail" data-points="10">Your release unpacks into an absurd number of directories (e.g. <code>home/johndoe/glibc-svn/tarball/glibc/src/</code>)</li>
</ul>
<h2>History</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="2">Your code is a fork of another project</li>
<li class="list-group-item fail" data-points="10">Your primary developers were not involved with the parent project</li>
<li class="list-group-item">Until open sourcing it, your code was proprietary for:
<ul class="list-group choose-one">
<li class="list-group-item fail" data-points="2">1-2 years</li>
<li class="list-group-item fail" data-points="4">3-5 years</li>
<li class="list-group-item fail" data-points="6">6-10 years</li>
<li class="list-group-item fail" data-points="10">10+ years</li>
</ul>
</li>
</ul>
<h2>Licensing</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="2">Your code does not have per-file licensing</li>
<li class="list-group-item fail" data-points="4">Your code contains inherent license incompatibilities</li>
<li class="list-group-item fail" data-points="6">Your code does not have any notice of licensing intent</li>
<li class="list-group-item fail" data-points="10">Your code doesn't include a copy of the license text</li>
<li class="list-group-item fail" data-points="20">Your code doesn't have a license</li>
</ul>
<h2>Documentation</h2>
<ul class="fail-list list-group">
<li class="list-group-item fail" data-points="2">Your code doesn't have a changelog</li>
<li class="list-group-item fail" data-points="4">Your code doesn't have any documentation</li>
<li class="list-group-item fail" data-points="6">Your website doesn't have any documentation</li>
</ul>
<script>
append_point_values();
calc_max_points();
update_points();
$('.fail').click(function() {
parent = $(this).parent();
if (parent.hasClass('choose-one')) {
newState = !$(this).hasClass('active');
parent.children().removeClass('active');
if (newState) {
$(this).addClass('active');
} else {
$(this).removeClass('active');
}
} else {
$(this).toggleClass('active');
}
update_points();
});
</script>
</body>
</html>

View File

@@ -0,0 +1,70 @@
var max_points = 0;
var points = 0;
function append_point_values() {
$('li[data-points]').each(function() {
points = $(this).attr('data-points');
$(this).append(' [' + points + ' points of FAIL]');
});
}
function calc_max_points() {
$('ul:not(.choose-one) > li[data-points]').each(function() {
points = $(this).attr('data-points');
max_points += +points;
});
$('li:has(ul.choose-one)').each(function() {
var this_max = NaN;
$(this).children('ul.choose-one').children('li').each(function() {
points = +$(this).attr('data-points');
if (isNaN(this_max) || points > this_max) {
this_max = points;
}
});
max_points += this_max;
});
}
function update_points() {
var points = 0;
$('.active').each(function() {
points += +$(this).attr('data-points');
});
if (max_points == 0) {
percent = 0;
} else {
percent = points / max_points * 100;
}
$('#failmeter').attr('aria-valuenow', percent).css('width', percent + '%');
$('#points').html(points + '/' + max_points);
if (percent == 0) {
failtext = 'Perfect! All signs point to succes!';
type = 'success';
} else if (percent < 1.6) {
failtext = 'You are probably doing okay, but you could be better.';
type = 'success';
} else if (percent < 3.8) {
failtext = 'Babies cry when your code is downloaded.';
type = 'info';
} else if (percent < 5.7) {
failtext = 'Kittens die when your code is downloaded.';
type = 'warning';
} else if (percent < 8.2) {
failtext = 'HONK HONK. THE FAILBOAT HAS ARRIVED!';
type = 'danger';
} else {
failtext = 'So much fail, your code should have its own reality show.';
type = 'danger';
}
$('#failmeter').removeClass('progress-bar-success progress-bar-info progress-bar-warning progress-bar-danger');
$('#failmeter').addClass('progress-bar-' + type);
$('#failtext').html(failtext);
}

BIN
content/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,4 @@
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCM/CS/IT/O d--(+) s++:- a C++$ UB++L++++$ P++ L+++$ E++>$ W+++$ N o? K w+ O M- V PS+ PE Y+ PGP+(++) t+ 5 X R !tv b+ DI++ D+ G e h----() r+++ y++++
-----END GEEK CODE BLOCK-----

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkAccelGroup" id="accelgroup1"/>
<object class="GtkActionGroup" id="actiongroup1">
<property name="accel_group">accelgroup1</property>
</object>
<object class="GtkAction" id="radio_action">
<property name="label" translatable="yes">Radio Action Label</property>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuBar" id="menubar1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu" id="menu1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkRadioMenuItem" id="imagemenuitem1">
<property name="use_action_appearance">True</property>
<property name="related_action">radio_action</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Radio 1</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="imagemenuitem2">
<property name="use_action_appearance">True</property>
<property name="related_action">radio_action</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Radio 2</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<property name="group">imagemenuitem1</property>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="imagemenuitem3">
<property name="use_action_appearance">True</property>
<property name="related_action">radio_action</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Radio 3</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<property name="group">imagemenuitem1</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkCheckMenuItem" id="imagemenuitem5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">menuitem2</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,132 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFGVyIEBEADyJd0ZKYSGRKO44QShxeeU3xE6JQBFHRaObxZr5kZ1DkmG1hbm
iVoRe0bwAUmYjaiK2YasQ0x/Sjl9C+KOYsovv33/td+s429d8dJQqiF2gppKI1wC
1Mbc8BJgq/QZn0K9y1bu5RgqWfRqZInvbpxj5ovtCC0iVgoO2wv9v/u81jagaT+3
Aswumi7JHXQgtZtYsKjTm1w2e/968AwRK3rAymrK4tKcf2/YkoL4SlZEnkFia42C
sFSHBXbaSNJFQG6KHtQiMCKvI4OpOxTdlrw11BEuwPuC8qsRMt0F5CH7VPUBiysq
NcuGhXhEPsVVZsL13jR8VZMY4sis1rwDqY8GI8nmH2dJ2OfGkr5EzLrSQ0NKGJ8Z
9YA79cxwnvBE/vKik0Td4/j8yJNGWHR63tpw0VgER2OSS61QWNsq+uBHr6AvjY71
kud3ojocKaO9xkud3O/7IBD9tU2PZskaS6rUDkaHh8a02R2qJToDYG0H7R5J+v+y
Cupi/kNmtY1V+jQQ4QdO574pGiTZTWCPkqHGWjMWf90u3ISakdfrLWJdtgNKkprD
6GjpuWDL7MiVnvCTxahFiBiLczKxLhm+vt05DNDfRCiS7wAPv7U3luw/tkOyC9tN
pZd/zcdF4iDFw+CBc/H+t8mi6lp0CaoajtaCGvIpCXQzMmCGw5oZeAA7nwARAQAB
tDJHZXJnZWx5IFBvbG9ua2FpIChXMDBkNXQwY2spIDxnZXJnZWx5QHBvbG9ua2Fp
LmV1PokCTgQTAQoAOAIbAwIeAQIXgAYLCQgHAwIGFQgCCQoLAxYCARYhBBPWBHaz
WvyovAE6MvQruliwdAxMBQJaXgYgAAoJEPQruliwdAxM/CMQAMxTiMnZ8P7QHErp
ptnQNJq7dygWNmIGWvdBlMg3ePGROTOBp74A5QOf/guzj+85aeIihjYNzP4DZX4B
wvOxuL3SnqsrYbJjkVqhxplvAfrNhqrVwxYJF0+fwuLaqr0UwAjlHdH30N5OjUPL
BTHvdBi5eb7HE19YsghvAiE0Q3i/TjaUtPsRa/JUBwS0DVD0cYhWy953wFY2Tn9X
FpoY3XtuNlwSQReYj4aOEjFOEomhkb0Adgldad3EpJQBTkcduyiJWtyfaKy7CSn8
HgVlhZ6AyNY5BeV4km5vEROGz476UtZh7j6dsvsUfTs+mdwyGVEmejY1e5GqZAN4
NBWJBq5uqR9qJC16AOHZZtV1FHskENpO9DcckwnP9dAwvynKhR1NwXmAJa/WI+WA
D7fwO5b/MQnYS6VFWTs0r+FaKCKhU26rOBFEUUDtMckexESIPvTRSx/++xenOUjT
vcgViZyRfiiU87JO/yWPY0s3Rhh1fsv3Sl+IlPymaoIEI0YDdfgR79d0QQxZwYba
AoTZ+fwjfTk7585pbcNfi+6WV16vx57Zk+ipY4RPaa990thPOYXYZq7NDsKUeYxU
sm8N6LBvVllQgF/9X5COj4gLwic3crAV/RNvym60FAQ4wK2QASNa7lxJh6Fe8pOc
1KY/hiRXADK37BGEyPqJHBpOTr1iuQINBFGVyIEBEADLCj4bc16zjenpGcAxOjAl
ItEEkvW9D1hgTtN4mT8FcZsaGRwH7HKhjmL85l1EwqsnDLR2BCyspp8S4D0MLg6v
yZSP3XGs7EASzqNgfgwSKSfpejUknMFtJeaWCheA2jyvUt2FwGnaEpd7QFl2O4Of
muJXUN5RipKSIcBC+AlRK8uZkTgXAgND0RY5ZlqeoOww+Cnt5La5mKta8DBwSAen
z5RM3xyPUBbnkx7n5F0FGLhklJguilfn+MFhS50IQpCrIaAIWc72hWc+lDz9Tht3
zcUzsVsbRdh4dSw7Ya7QSc53ozveuvXGXihKgSCwUjPrPq5C0MIs6+o0uvebj3Pp
BOKA4C6CS0R9ycxCFB9Xl4wO2c8bGzKPnD5TjoReeEAsmgH0BNX3FdpKWA4mBFY2
xqkW/xSN+JgKhcllOsuyhG4zUOwUpKfGm9tQUz4DXiPHCJXFMVYxIxt9rnc+5jBa
j2H8NVNOMeXuwoSkNDCqgfDdBKr5r/ntTNJmJ/Sdmosf4GQzyFv1W4InW6FRSLTD
BXtqWsGq6OvrcfgaZkt0b24/u7TzxOXuKpW3NLx8uFusNR0ZJ1tbei9ryzrnweqY
hu/tBnqoApMXl4VaWp+O4ujHohSzl/O0rXtYITNDex4nNyXUJjllNDayzEihVvzw
enwvq+Xg3NY8bt2Y2MpEiwARAQABiQI2BBgBCgAgAhsMFiEEE9YEdrNa/Ki8AToy
9Cu6WLB0DEwFAlpeBi0ACgkQ9Cu6WLB0DEwzeRAAmkBpax4kEs1S5saXy9MmMS+G
6ZcOzMynSW3GF2u/XOqDPErpSn/BesOuOmyw9WY30D8YOb25CVwkNzBv85S70Esc
y7sMBopjZ11cJt3K47syp2f+CwdgAx+kHoRoCVNnE+CdsA6COXUV/ulF4HMpNJqW
h174pg2cFkphdGAMVpqwuIvLVGioL2q7KK7Sbr01VgD7v45qA2V8ZbidjHp5fZWE
tmUiF0ETZQdbbHmsiOqIyip7CYjIoxcGhxq4Y5NlBxCZY8Z1lcJtuAr0B2umEMh0
Pg8DZyUobC0cilUhQAOzYVsZi/xrhYC91gnWXYSRoOJ9vEz20XUMztMEuppRVmON
c+V8DyO78VAgvDclGrj+GRTWpbB3kgJxeelCXnm16TrOwl+J2qQZ/rtCuZRHZ3ZF
/LPsg9T7/XTZHkcKheAnIH9Y59dPslTttENO40EBD9VxJGOYFntBykjTXPWhG6Eh
yxKjg87ZP5B9uS8pMOZS4GFYoLKd82Lpf9uItzOMNInTPw2Vi7Qx4J466msOvDa/
x9cd9PjEoG2S8Uac0+vJaEVcENc5y+Qmk17vY0lbyjtABC2vr7Vq1U9t00nQurjQ
ASUGFFde9E8KPbMILIoMMHzJB+GYQ2Yu45AI2y/xWzlQCmP32ZEG66l9NVrcVkhx
QVo+0DLn+NkGRR8Phuy5Ag0EWlzXfQEQAOpgMmUwZWVv1K+8De3xT1/8Yrqhp+z0
8wkg3ztOsrRfTBimALcgbF+IrJ15r4s8Tcqx7pwc+Gi5ijWTDJvJFneeJP+EgyM5
OYAroySP5oc5IrZuB9kTs6ol7ta5hlrCqlNSM/lgxaTqABliv8LhhpJVYjigyfoE
5hZTQ2+pL252qAm55vldG8CIVuWBllSlRaljVu25GSRj9hJfq3g94vaAQ9vMzPHp
+tKWUwg4PoO9p5VyP2oU9HawkkbJZskimMmyxAIHkidTmhcJh0Fa9XbZT5lH6QCg
DAVJdxBH5+fRak6/YM96zaebQ/RW+Dmbgo8ysb+M/B09ysIuxD0Iii9MvVyqkYPD
jyY98Kale800YwXWCDQ4mSDDO+loFWkGLp/NdztXEa5Wm+zEaGZhY3MtwupfbKk/
/bAdduUMylN0JAxkr9d3V+i7+ltJBAJf1R5s37fYYMkWN5SfgsRCgyib7+d9FCoC
afP3+RDjV55fIPQYFAmWH56PxXZvMQ7rOvpI1xUjomN4bxdvZY6oXyks+mgdddbT
BP9nPwZ9WCldYpEAZNUW6/Fxe6si/Khe7VWH23oXtt6ECEIX+ctyAn6hD1nDlGgR
UWl+eVCXSzmxWYRPt57g8Ysy99tUhfC3MFxRzdR+d5rxb/Xu9mBXsPI84n+0Hbgj
hR7ry9iZG6p1ABEBAAGJBGwEGAEKACAWIQQT1gR2s1r8qLwBOjL0K7pYsHQMTAUC
WlzXfQIbAgJACRD0K7pYsHQMTMF0IAQZAQoAHRYhBJrFyL2SFE2hJshDqgMcyLAQ
SguHBQJaXNd9AAoJEAMcyLAQSguHww8QAKY2Qc8EenhBiW1XQ61g1hdu6v8j7ika
FpHrkf7zAdAgE1zpPRXU+6Pu0f63Y9Y3/lsMy1iE5jb6+ZbIXEgLZ1BdYDFWrdhy
U3m3jURlVdHBhqcA7kHHjei44CwrBzi9zPnFExI2o87YtS7Dk2fvJP3Ds3Yru66L
BcdXndM+Iz6oZsEIRfI7BeFPWN1IXg8Q2VRjl+g6zXBHRHo4lRAxbfTAi3kFGcRM
Y/OhNGsSNA6sgq9CL35gG86HoSv89EMmWe2ZoGTu3DVJNy98q5bs31dUyNoYKoQn
/xUs4rpj5LgRO3tAaixEUMCzFevnQI+nZ6cj/JZRLG+EEdaRUXoUz3jJxSfyisj4
rFPyjAG373f449/1cqkb850OczOLU9FEGBLbl9B6S8iQZ7LSwwqVsw7Hwd/8eEND
9gXVjstGcgbRZgzgykQu5OAmc/R5JjJyTk5wIebVAxWXiUlO11mxE9ogYBMdc0ux
hrm4yu1xvFEOvADIBRfuWHTk2FUlORFnYIN/Oq4XfuO/ysvYjfoTom9gKMMmfEn/
Y0ZL+wy27jcIfX8BBhUyFQG9UWyZgkNQmuNgxPReZOWi1DrLzY/Q+PwafWJtDx3p
LJuYEqNXJsJ16BJ5srPpdia0SEQ1VQJe92nUf27QAs9fDcUrv1KRVDCp81MJGhIf
Gkm7QNwNblqMKF0P/jPGeEbbdoMxgBcgeH6cTbB8pq4EDmQnWF7mRQJJ+//1bbZY
Q6Pxv+HxEGF6R/rcJF9sCxn7Bu1ZDR4Tq0mGQvFkoFnyj4SADzt0Dwbq/CsNY1Sz
5TpiIFhG8gin0F812RqGY1wmcRWLRsUVsBpJwXGdguo06om7ofXdeZZckM6EUujH
RyRQHa8+F88ZoUb5X2+BYgD0iScxqG+sqGM5cSY8R4/CrELKAwX0mnYvpU6jMk+D
cPEnuccObJaR42CaqpCZEv5f7MwI1RMb7OZAt+vHBB5Di1kNCGUzrMcv7n/6H3g2
N+z9D4FlLHdPIV4LRCP2kkTAArjtNFokkXZWbkX1ZSJrR4MQUT4+cGVu8JkyGePT
AiHPDMAgggLS85lh5835/G56HJqku/w0CMrJmUvP8Dt8HuSaepOaCLlgTp/dM/lJ
emA5UK0k5SLOuJmru+6SZmlz7YzWJhQqFyAFnbC96x9/xy1gQvdYRCqMuMQVtMRL
Gt91e5wkTIvTyiugH4qf62WFuCfqpRsyI3d3+8eyKtiJibsFzRJSBdBNuvqyH9UQ
vkzD8i1IsI+0r7cNrIJia57LbVmEVr6Af5ZqZ9wgQS2W/Rqm8/fvLuruWnCJE6jo
wwe8Xil3EHO4Lz6yPiz5MG+4uS1AeVxSM1XYkhgvhYyFWj3VF4xobs3I2+GCuQIN
BFpc17wBEACmy9i8mQtd1GUCB8sk6Q7qzWuS8Dd/TJhDAVWVNPmzlPeB+FxIemAq
IbFNFxDiH+4H7zd3ntkpUnoj5u3D/Mrlwo0/rf8HM3XYOaElEaYfGarCAPobUYbV
opb9b9a9xYdHhbm/k6SYgax7wF7Q4gRuKvo3PMtcegO2dyVSWQuDW2fK2VXTGuJb
w8nWq/Lpr2JpxQw6mVaftAXP96UuuvlOSvEFBmkPrczeiv1rtqLRZ40JiEX80XFA
+uf9YGzmVWD3CSh9RCIk5R2AysT6yVF2S4ijmhyn4oT++Gq/uFIqGWi6q+fIpLwp
qyHyyS4XA1c1QfKXG27hmYGj59xvgw8uQKriMV6d8N5Wh5wBT7gqKYWKo15lXpom
/ac9vXESCPvASYqco6/qwbR8BvnsjpLMv9RsouMj92p9HxNEtY/qm7l36PbXc38s
Jkdr5QuQQzLhC5LZsuOHewHPaTxg4U67p1d5apAecWrL2kJwAjcArFr+SlJWgbgw
pW43xqsInodj44lK5fiO0umRCSEL5NVGYB5k0aUDBds+wOerCpy1onzt5wUlGCf8
oy2ixJSpHFxnczTzc3EyEEJYd76ScElYWPBDD+97MuZpYn4f9c8I868NgIFQ19aj
ys5RJC0bAWYCT/YlJt5MYM9ssLCSFoXWqjlMtv+QAhMoLcXTVHP61wARAQABiQI2
BBgBCgAgFiEEE9YEdrNa/Ki8AToy9Cu6WLB0DEwFAlpc17wCGwwACgkQ9Cu6WLB0
DEwM1xAAjerPLAf3KqhzSNBgte29NYXXMt2EW3X8LxwSNsuXaPIPrVnO5qPhLLNf
amqZ6qKyfxrPJ/KKLIClx4LAjs6Z9CxEyXvm6gdIOQaKt09p6Z/GglqJn5tNtxJW
RgegDvdJFo82bRE5N9NdpJbvyWJhmUXHY1FTVKs5OePOa4DfnXNOJL+ReEl2ZTU4
v301vAPyCCLfrVoCLChoi/Qg/PfcwV3x8RmBHZq2Q6Jvdyv0SMBvDO7C8LIdCNFA
HENkw0F1/LY2yZIKnnWTSLP+R7V11vLSEzOgpxx1qC2ierDcxjdZdxzYW+jVICKI
TH8Wn8zejPuqYvlRTZfSRq0EzqZNcc/1LWjZJb3zWCf14KGEcvVfvBCaFhflpTE1
J3BPZ0NXcqIA0nHHOg9hatvjnozWXapi8uwt01oM4w+4+vjA8sm3t79UbJ3DrJzc
atuXBN0gFQKoMqZdkIOejjctWVjZRF0dFDbxH1G5Rp+raH6N2sA+wHpeSCjYLbFg
bjRaK0aM29d5+1kqV4oft4+2jPu/ss9AvwLj9k5sk6cFPL7L5MR/WEOJ7Sc+QmM2
7uyDAhKwXYVXrDT7Cf3xomUwaoQo4EtVrIEjMFYBwl7+MY0YW5nZ1yAWj3qXWzdT
8tXEpQ4ZFjPQUJxAfyOmDUghPLGbFAA6AtROHwbZqpWf2LrYmxe5Ag0EWlzXzAEQ
AN2sn2uK9Z+0BhaUe36tPv44PnZK2CMji6vE/iAZr1mGK0cHvRHSDPFhLwZtefYj
0O0iBV6nI0t3L5JNvoJDxMmp00ZkG7yEIQdDlqL5Je9WqIu09aY3s47UKA7pCg1s
qpX092u+5B0qkQdzH4mp136aZPBR2TXWTbHoUMxOwpb2OaTct86EdltdTbEUkVHm
MfvciPj2Pw/41zQReL+FTWJaVq5vgUkkvOdVtruXxL8umgIwB5e27k9mWVB5w2UZ
1uI9B8cGU2y0F6upQRmYJerQirVc+5z6lnI+zMOi6nEFH8exqEejZmFubZpMQ6vi
zyZe0SGLQxTFLgWqpHHq/VOE2tsENzGU6rVFRquP8djl7/26SQaqqPH8b5y+5XDN
CSpNLWL3X2g/yKStlYIH6JzsGgA3vNS4be8ugXiwyXeDIo5um9cyMK3QxLPRU6cO
/haS1thZGV7uNqZe150APQLYIsO2nikqKmPgGblLqGfVZK56uWjW8kbxIullzdLM
3xsHeUcANKaaVrcBd2g2JQRdjVKI9dddvzOGAy++sCyXHR8fCeWYWIQukeOHZUmC
N3lLojg2IWxSh/J5XnBf8jQndyqsxX2y0QvYll7GqXG713xUy+gN/CEavTJXgLER
2a/eaYHvFovnMk7/5wvAsvKhoOUGzZl04j3KH5mQiF4rABEBAAGJAjYEGAEKACAW
IQQT1gR2s1r8qLwBOjL0K7pYsHQMTAUCWlzXzAIbIAAKCRD0K7pYsHQMTKIBD/4r
YOFjFMzHTRewOiqWIa60DQI153MZf3eQfOYEatrXOWB9NcO3iUzgK/8zpubgso5u
6Sa9+rrPW2CxW//N2jthFNs7h7FAqCXxQNpymC/BjbG9uP3xTlGk4fy0cddp7htn
JvIeb2cKTwzBc2iFp408wWCKiVROxQC+2KBhppMl9B11U4nTUuAJ06grwK83NLl6
9Nk8arMEs+cRDgwiJfgeViRu4leXI6Mztchpj+8fsUCOLqaK9SsTS7Oh1j9wVJQT
vezqKe41PhjmHKIk4kVNHuOB2Nu1HSqqQJ4mp1F+lqd7GGQT+/7TGIqTP+EVTLox
aw9jaC66v/QVhO+jGGlRBbNUMT24is3tXOg4GN2xq55sEJSnWEP9S0r1nqu+mtcj
Go716YZgpPbU/BltRdFO07zHS6pKSWtoaqt2J29bk4XBLgQ6Otn6sXBJJlYoopF/
iG0X4dt0SAZgD49AEcDdwGn81aAY0wlYYLy3ngZTfMyIplpTkQVlGZ3N0Fmptc5B
JBbkgjIn+ThyQhkK37npm6YfaWStcGZWmvVQcSkaweuH/ifuuCRYEVD6kRN3Ytvo
jRixSuRWDfcfVtZ3EIYSi74LStf80ecCqNgzmmow9IOeC80Epy2vciTgMaRYzAMw
WCnMUi1MXE2xy5yZXtc66Hv5zR6+EUWS+rPYBXYLaQ==
=ZVqC
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,16 @@
Title: README for the Gerrit dashboard generator
Status: draft
Date: 2017-09-17T03:00Z
---
# Dashboard URL generator for Gerrit
This little HTML file will generate URLs for Gerrit Dashboards. As constructing such URL is a real PITA, I created this tool to make my, and fellow developers life easier.
## Usage
To use the tool, put it on a static webserver (opening it from your local machine wont work, as it loads its dependencies from CDN hosts). For example, if you have Python installed, you can use
python -m SimpleHTTPServer 8000
and access the page via http://127.0.0.1:8000/. Static (ie. local machine-compatible) version is on the table, so if you cant fire up a static webserver, check back soon(ish).

View File

@@ -0,0 +1,335 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Gerrit Dashboard URL generator</title>
<meta name="date" content="2016-08-17T15:15Z">
<meta name="save_as" content="gerrit-dashboard-generator/index.html">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.0.slim.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<div class="container" id="main">
<div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="helpModalLabel">Help</h4>
</div>
<div class="modal-body">
<p><a href="https://gerrit-review.googlesource.com/Documentation/user-dashboards.html">Gerrit dashboards</a> are a powerful way to filter changes in a project into multiple categories. For example, you can construct a dashboard to show the changes in one project grouped by state (drafts, opened, reviewed, abandoned, closed).</p>
<p>One way to create dashboards is to modify the project configuration. Most developers dont have the necessary rights for this. The other way is to construct a special dashboard link. Anyone with access to the Gerrit instance can do that, but doing so is really painful. The goal of this tool is to lend a helping hand in that.</p>
<p>The <strong>Gerrit base URL</strong> is the base URL of your Gerrit instance.</p>
<p><strong>Dashboard title</strong> will be the title of your dashboard, and will be displayed on the top of the page.</p>
<p>To create a new section, just press the <strong>+ Add secion</strong> button. You can name all the sections by filling the <strong>Section title</strong> field. If you omit that, it will be called <em>Section &lt;n&gt;</em>, where &lt;n&gt; is the index of the section (numbered from 1; sorry about that.)</p>
<p>If you decide a section is not needed, press the big red <strong>- Remove</strong> button next to the section title.</p>
<p>To add a new filter to a section, press the <strong>+ Add filter</strong> button. You can choose the filter type (e.g. you can filter on branch name, state, project, and many other fields. There is a list at the bottom of this panel.) When you find the correct filtering field, just enter a filter value in the input box. If you actually want to <strong>exclude</strong> changes matching that filter, tick the checkbox on the right of the input box.</p>
<p>Gerrit filters are concatenated together by <strong>AND</strong> operators. If you want to match on, for example, multiple branches, dont create multiple <em>Branch</em> filters, but separate the branch names with colons (:), like <code>master:develop</code>.</p>
<p>If you decide a filter is not needed, select the <strong>Delete this filter</strong> from the filter type dropdown.</p>
<p>The dashboard URL on the bottom of the page will update with every change you make, just like the <strong>Try it!</strong> buttons target URL.</p>
<p>You can add dashboards to the <strong>My</strong> tab of the Gerrit page. Navigate to <strong>Settings &gt; Preferences</strong> and Enter a name in the input field under <strong>My Menu</strong>, and enter the generated <strong>Dashboard URL</strong> in the URL field, then press the <strong>+</strong> button on the left. Using the arrows on the rigt of the table you can reorganize the different dashboards you add here; the first link will be opened when you login to Gerrit. (<em>Hint</em>: You can add pretty much anything as the URL of a page, like basic queries or your settings page.)</p>
<p>Finally, the list of filters currently supported by this tool:</p>
<dl>
<dt>Project</dt>
<dd>The project where you want the changes from. If you dont specify this, changes from <em>all</em> projects will be shown!</dd>
<dt>Branch</dt>
<dd>The branch for which the change was submitted.</dd>
<dt>State</dt>
<dd>The change state. Some possible values are <em>starred</em> (will match on changes starred by the current user), <em>reviewed</em> (will match on changes with at least one non-zero vote in any category), <em>owner</em> (will match on changes owned by the current user), <em>reviewer</em> (will match on changes where the current user is added as a reviewer), <em>open</em> (will match on any open changes, ie. that is not merged nor abandoned yet), <em>draft</em> (will match on draft changes), <em>closed</em> (will match on closed changes, ie. merged or abandoned), <em>merged</em> (will match on changes that have been merged to the target branch), <em>mergeable</em> (will match on changes that have no merge conflicts).</dd>
</dl>
<p>If you want me to add new filter fields, have a problem to report, or you have a feature in your mind I could add, contact me!</p>
<h4>Known limitations</h4>
<ul>
<li>It is impossible to create complex queries with this tool (like closed changes on branch a <strong>OR</strong> drafts on branch b). Even though the example I provided is a bit silly, there are use cases where you want to do such complex queries, but if you need that, you are on your own. Sorry.</li>
<li>This page is not protected from XSS, CSRF, You-Name-It-Vulnerability, so use it with care. Gerrit, on the other hand, provides such protections, so your forgery will be prevented anyway.</li>
<li>This page is tested only in Google Chrome. If you bump into problems in other browsers, contact me!</li>
</ul>
<h4>Contact</h4>
<p>…in order of preference</p>
<ul>
<li>You have a problem with the tool? Or maybe a feature idea? <a href="https://github.com/gergelypolonkai/gerrit-dashboard-generator/issues">Open an issue on GitHub</a>!</li>
<li>Matrix (<a href="https://vector.im/beta/#/user/@gergely:polonkai.eu">@gergely:polonkai.eu</a></li>
<li><a href="mailto:gergely@polonkai.eu">e-mail</a></li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="jumbotron">
<h1>Gerrit Dashboard URL generator</h1>
<p>You can use this site to generate a dashboard URL for your Gerrit instance.</p>
<p><a class="btn btn-primary btn-lg" id="help-button" data-toggle="modal" data-target="#helpModal">Tell me the rules</a></p>
</div>
<form class="form-horizontal">
<div class="form-group">
<label for="gerrit-base" class="col-sm-2 control-label">Gerrit base URL</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="gerrit-base" placeholder="URL">
</div>
</div>
<div class="form-group">
<label for="dashboard-title" class="col-sm-2 control-label">Dashboard title</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="dashboard-title" placeholder="Title">
</div>
</div>
</form>
<h2 id="dashboard-title-header">Dashboard title goes here</h2>
<hr id="last-hr">
<button id="new-section">+ Add section</button>
<hr>
<form class="form-horizontal">
<div class="form-group">
<label for="dashboard-title" class="col-sm-2 control-label">Dashboard URL</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="dashboard-url" readonly="true">
</div>
</div>
</form>
<a id="test-link" href="#" target="_blank" class="hidden">Try it!</a>
</div>
<script type="text/javascript">
String.prototype.replaceAll = function(find, replacement) {
var str = this;
return str.replace(new RegExp(find, 'g'), replacement);
};
var filterList = {
"project": "Project",
"branch": "Branch",
"is": "State"
}
function filter_div(title) {
filter_list = $('<ul></ul>')
.addClass('dropdown-menu');
for (var key in filterList) {
filter_list.append($('<li></li>')
.append($('<a></a>')
.attr('href', '#')
.attr('data-field', key)
.addClass('filter-chooser')
.append(filterList[key])));
}
filter_list.append($('<li></li>')
.attr('role', 'separator')
.addClass('divider'));
filter_list.append($('<li></li>')
.append($('<a></a>')
.attr('href', '#')
.addClass('filter-delete')
.append('Delete this filter')));
return $('<div></div>')
.addClass('input-group')
.append($('<div></div>')
.addClass('input-group-btn')
.append($('<button></button>')
.addClass('btn')
.addClass('btn-default')
.addClass('dropdown-toggle')
.attr('data-toggle', 'dropdown')
.attr('aria-haspopup', 'true')
.attr('aria-expanded', 'false')
.append('<span>Field</span> ')
.append($('<span></span>')
.addClass('caret')))
.append(filter_list))
.append($('<input>')
.addClass('form-control')
.addClass('filter-value'))
.append($('<span></span>')
.addClass('input-group-addon')
.append($('<input type="checkbox">')
.addClass('negate')));
}
$(document).ready(function () {
$('test-link').hide();
$('#new-section').click(function() {
section_div = $('<div></div>')
.addClass('dashboard-section')
.append($('<h3>Title of the section </h3>')
.append($('<a></a>')
.addClass('btn')
.addClass('btn-danger')
.addClass('section-delete')
.append('- Remove section')));
filter_add_button = $('<button></button>')
.addClass('new-filter')
.append('+ Add filter');
title_group = $('<div></div>')
.addClass('form-group')
.append($('<label></label>')
.addClass('col-sm-2')
.addClass('control-label')
.append('Section title'))
.append($('<div></div>')
.addClass('col-sm-10')
.append($('<input type="text">')
.addClass('form-control')
.addClass('section-title')));
section_div.append(title_group);
section_div.append(filter_add_button);
section_div.insertBefore($('#last-hr'));
$(document).trigger('dashboard:changed');
});
});
$('#main').on('keyup', '.section-title', function() {
title = $(this).val();
if (title == '') {
title = 'Title of the section';
}
$(this).parent().parent().prev()[0].innerHTML = title;
$(document).trigger('dashboard:changed');
});
$('#main').on('click', '.section-delete', function() {
if (window.confirm("Are you sure you want to remove this whole section?")) {
$(this).parent().parent().remove();
$(document).trigger('dashboard:changed');
}
});
$('#main').on('click', '.new-filter', function() {
filter_row = filter_div();
filter_row.insertBefore($(this));
$(document).trigger('dashboard:changed');
});
$('#main').on('click', '.filter-chooser', function() {
input = $(this).parent().parent().parent().next();
button_text = $(this).parent().parent().prev().children().first()[0];
field = $(this).data().field;
input.data('field', field);
button_text.innerHTML = filterList[field];
$(document).trigger('dashboard:changed');
});
$('#main').on('click', '.filter-delete', function() {
if (window.confirm("Are you sure you want to remove this filter?")) {
$(this).parent().parent().parent().parent().remove();
$(document).trigger('dashboard:changed');
}
});
$('#main').on('keyup', '.filter-value, #gerrit-base, #dashboard-title', function() {
if ($(this).attr('id') == 'dashboard-title') {
title = $(this).val();
if (title == '') {
title = 'Title of the Dashboard';
}
$('#dashboard-title-header')[0].innerHTML = title;
}
$(document).trigger('dashboard:changed');
});
$('#main').on('change', '.negate', function() {
$(document).trigger('dashboard:changed');
});
$('#dashboard-url').on('click', function() {
$(this).select();
});
$(document).on('dashboard:changed', function() {
var params = {
title: $('#dashboard-title').val()
}
var i = 0;
$('.dashboard-section').each(function() {
i++;
section_title = $(this).find('.section-title').val();
if (section_title == '') {
section_title = 'Section ' + i;
}
var filters = new Array();
$(this).find('.filter-value').each(function() {
field = $(this).data().field;
value = $(this).val();
if ($(this).parent().find('.negate')[0].checked) {
field = '-' + field;
}
if (value.indexOf(' ') > -1) {
value = '"' + value + '"';
}
if ((field === undefined) || (value == '')) {
$(this).parent().addClass('has-error');
} else {
$(this).parent().removeClass('has-error');
if (value.indexOf(':') > -1) {
filters.push('(' + value.split(':').map(function(v) {return field + ':' + v}).join(' OR ') + ')');
} else {
filters.push(field + ':' + value);
}
}
});
params[section_title] = filters.join(" ");
});
sections = $.param(params)
.replaceAll('%20', '+')
.replaceAll('%3A', ':')
.replaceAll('%2F', '/');
url = '#/dashboard/?' + sections;
$('#dashboard-url').val(url);
url = $('#gerrit-base').val() + url;
$('#test-link')
.attr('href', url)
.removeClass('hidden');
});
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

232
content/images/profile.svg Normal file
View File

@@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.3.1 r9886"
width="900"
height="900"
xml:space="preserve"
sodipodi:docname="Jomagam by Juci.svg"
inkscape:export-filename="/home/BROKERNET-GROUP/polonkai.gergely/Dropbox/Jomagam by Juci favicon.png"
inkscape:export-xdpi="1.6"
inkscape:export-ydpi="1.6"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath16"><path
d="m 0,1190.551 841.89,0 L 841.89,0 0,0 0,1190.551 z"
id="path18"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1021"
id="namedview4"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.70710678"
inkscape:cx="304.5347"
inkscape:cy="432.05546"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="g10"
inkscape:snap-bbox="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-page="true"
showguides="true"
inkscape:guide-bbox="true"><sodipodi:guide
orientation="0,1"
position="450,450"
id="guide3178" /><sodipodi:guide
orientation="1,0"
position="450,450"
id="guide3180" /></sodipodi:namedview><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="PG_Vector"
transform="matrix(1.25,0,0,-1.25,-201.75833,1487.0383)"><path
inkscape:connector-curvature="0"
id="path22"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 519.65518,970.65954 c 8.739,0.76 18.998,9.499 25.838,14.818 6.839,5.32 14.818,6.84 23.558,6.08 6.838,-0.76 48.254,-7.219 47.115,-13.679 -1.52,-7.979 -12.539,-7.979 -17.859,-6.459 -6.839,2.28 -13.678,5.319 -20.517,7.219 -11.02,2.28 -28.117,5.7 -38.757,0.76" /><path
inkscape:connector-curvature="0"
id="path26"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 519.25388,969.07604 c 7.846,1.007 14.499,5.339 20.763,9.904 3.755,2.738 7.205,5.92 11.234,8.258 4.88,2.832 11.275,3.341 16.774,2.671 11.536,-1.405 23.174,-3.606 34.348,-6.792 2.683,-0.765 9.831,-2.207 10.878,-5.4 1.359,-4.147 -5.791,-5.439 -8.21,-5.453 -5.09,-0.028 -10.023,2.543 -14.683,4.299 -15.521,5.846 -36.499,10.811 -52.464,4.006 -3.726,-1.588 -0.308,-3.444 2.279,-2.342 10.231,4.362 22.824,1.469 33.295,-0.626 9.977,-1.996 19.039,-8.192 29.308,-8.587 6.261,-0.241 13.479,1.936 16.006,8.147 1.769,4.348 -5.071,6.465 -7.953,7.513 -12.167,4.425 -25.509,6.495 -38.299,8.23 -7.882,1.07 -16.319,0.372 -23.493,-3.284 -9.845,-5.017 -17.485,-15.9 -28.98,-17.377 -2.783,-0.357 -4.822,-3.684 -0.803,-3.167" /><path
inkscape:connector-curvature="0"
id="path30"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 647.69428,959.60584 c -5.333,-4.912 -4.42,-10.96 -2.134,-17.272 1.087,-3 2.488,-5.871 3.425,-8.927 1.678,-5.482 1.606,-11.701 2.307,-17.362 1.657,-13.415 10.161,-24.637 13.471,-37.641 1.37,-5.38 1.971,-12.215 -2.773,-16.121 -5.588,-4.602 -15.018,0.822 -20.424,3.275 -3.86,1.752 -7.716,3.291 -11.888,4.101 -7.417,1.439 -14.661,-1.886 -22.04,-0.988 -11.136,1.357 -5.041,17.951 1.543,21.116 3.496,1.68 -1.797,2.224 -3.509,1.401 -6.866,-3.3 -10.925,-10.949 -9.595,-18.477 1.446,-8.186 11.471,-7.471 17.627,-6.691 5.501,0.697 10.503,1.504 15.953,-0.135 5.378,-1.618 10.298,-4.56 15.56,-6.499 7.184,-2.646 17.624,-2.519 23.062,3.771 9.084,10.509 -1.765,28.732 -6.456,38.912 -4.333,9.403 -4.842,18.872 -6.31,29.033 -1.168,8.077 -10.91,20.752 -3.241,27.814 2.398,2.207 -3.349,1.821 -4.578,0.69" /><path
inkscape:connector-curvature="0"
id="path34"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 662.90128,963.44034 c 3.04,8.359 31.917,32.677 33.438,16.338 1.519,-16.718 -22.039,-12.159 -32.677,-16.338" /><path
inkscape:connector-curvature="0"
id="path38"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 665.76168,963.94234 c 2.152,5.327 22.347,26.55 26.974,17.918 1.423,-2.656 0.903,-6.467 -0.284,-9.068 -1.636,-3.589 -5.821,-4.531 -9.313,-5.149 -6.842,-1.211 -13.887,-1.106 -20.486,-3.514 -3.882,-1.416 -0.206,-2.19 2.019,-1.378 8.625,3.146 18.395,1.328 26.881,5.377 5.718,2.728 11.845,11.81 5.404,17.279 -5.003,4.248 -15.226,-1.975 -19.402,-4.699 -6.366,-4.154 -14.565,-10.472 -17.514,-17.77 -0.43,-1.067 5.114,-0.499 5.721,1.004" /><path
inkscape:connector-curvature="0"
id="path42"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 520.82218,954.52484 c 22.434,0.264 49.55,13.637 68.72,-3.634 1.567,-1.412 7.01,0.825 5.373,2.301 -20.603,18.562 -47.868,5.007 -71.866,4.725 -2.226,-0.026 -6.143,-3.438 -2.227,-3.392" /><path
inkscape:connector-curvature="0"
id="path46"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 653.00578,947.08734 c 6.661,-0.194 33.356,8.188 33.216,-3.422 -0.02,-1.596 5.769,-0.576 5.795,1.553 0.168,13.854 -29.533,4.728 -36.698,4.937 -2.041,0.06 -6.225,-2.954 -2.313,-3.068" /><path
inkscape:connector-curvature="0"
id="path50"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 665.56148,946.72164 c -7.22,-3.04 -0.76,-11.019 5.319,-11.019 6.08,0 10.259,7.979 4.56,12.159" /><path
inkscape:connector-curvature="0"
id="path54"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 664.40428,947.95984 c -3.177,-1.482 -5.961,-4.064 -4.516,-7.813 1.332,-3.455 5.292,-5.658 8.803,-6.049 4.22,-0.47 8.481,1.424 10.952,4.861 2.38,3.31 1.58,7.578 -1.515,10.05 -1.643,1.311 -7.021,-0.981 -5.375,-2.294 1.823,-1.456 2.76,-3.247 2.333,-5.598 -0.315,-1.73 -1.719,-3.781 -3.626,-3.708 -2.873,0.109 -9.197,5.997 -4.742,8.074 0.707,0.33 2.458,1.391 1.531,2.386 -0.878,0.941 -2.845,0.557 -3.845,0.091" /><path
inkscape:connector-curvature="0"
id="path58"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 610.64448,857.31484 c -4.052,-8.228 -10.829,-11.826 -19.727,-12.74 -6.781,-0.697 -13.363,0.073 -19.948,-2.041 -11.811,-3.792 -15.259,-17.369 -25.64,-23.048 -3.38,-1.849 1.961,-1.633 3.367,-0.864 5.663,3.098 9.551,7.618 13.434,12.674 1.906,2.48 3.869,4.876 6.196,6.977 3.61,3.261 7.685,3.445 12.327,3.516 13.929,0.213 28.966,2.81 35.716,16.516 0.478,0.971 -4.983,0.517 -5.725,-0.99" /><path
inkscape:connector-curvature="0"
id="path62"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 557.23918,820.62684 c -14.352,-10.616 -20.204,-27.121 -31.314,-40.377 -8.212,-9.798 -23.672,-19.801 -16.767,-34.545 0.913,-1.95 6.571,-0.102 5.796,1.552 -6.512,13.905 8.295,23.793 16.35,32.932 5.08,5.762 8.681,13.077 12.846,19.504 4.903,7.567 10.415,14.67 17.714,20.068 2.62,1.938 -3.209,1.913 -4.625,0.866" /><path
inkscape:connector-curvature="0"
id="path66"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 615.16888,854.37394 c 3.667,-7.75 21.753,-11.241 25.029,-1.392 1.029,3.092 -4.75,2.816 -5.508,0.537 -1.728,-5.195 -11.976,-1.291 -13.726,2.408 -1.144,2.418 -6.859,0.695 -5.795,-1.553" /><path
inkscape:connector-curvature="0"
id="path70"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 650.14248,850.92174 c -0.745,-9.934 5.588,-18.93 9.863,-27.428 1.385,-2.754 1.503,-3.047 -1.272,-4.685 -2.671,-1.577 -5.775,-2.322 -8.798,-2.845 -5.942,-1.029 -12.115,-0.604 -18.052,0.199 -12.044,1.628 -23.889,6.134 -35.215,10.356 -4.364,1.628 -8.368,2.226 -12.98,1.452 -5.317,-0.892 -10.783,-4.218 -16.098,-1.561 -1.457,0.729 -6.815,-1.486 -4.679,-2.553 8.016,-4.008 15.533,2.074 23.559,1.65 5.841,-0.308 12.467,-4.112 18.009,-5.96 5.093,-1.697 10.267,-3.257 15.474,-4.565 14.751,-3.706 34.352,-4.785 46.745,5.671 0.242,0.204 0.798,0.665 0.621,1.077 -4.042,9.45 -12.228,19.245 -11.417,30.05 0.15,2.01 -5.636,0.791 -5.76,-0.858" /><path
inkscape:connector-curvature="0"
id="path74"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 569.95308,816.75774 c 0.987,-12.188 18.904,-16.562 28.499,-18.946 13.859,-3.444 27.472,-3.137 37.284,8.48 0.238,0.283 -4.609,0.221 -5.703,-1.073 -2.455,-2.908 -5.325,-5.737 -9.069,-6.885 -3.208,-0.982 -6.915,-0.419 -10.157,0.053 -4.535,0.661 -9.045,1.864 -13.43,3.173 -8.009,2.392 -20.828,6.88 -21.629,16.751 -0.074,0.922 -5.913,-0.1 -5.795,-1.553" /><path
inkscape:connector-curvature="0"
id="path78"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 652.21088,810.04874 c -5.682,-8.583 -11.531,-17.167 -16.947,-25.912 -4.691,-7.573 -2.809,-15.877 0.466,-23.54 3.763,-8.808 7.047,-17.606 6.742,-27.344 -0.293,-9.298 -5.354,-20.822 -12.929,-26.477 -3.151,-2.353 1.749,-3.316 3.645,-1.902 15.019,11.215 17.597,31.034 12.167,47.773 -3.206,9.88 -10.07,19.053 -5.488,29.696 2.101,4.879 6.069,9.327 8.949,13.787 2.945,4.561 5.823,9.164 8.819,13.69 1.548,2.338 -4.317,1.903 -5.424,0.229" /><path
inkscape:connector-curvature="0"
id="path82"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 619.34858,740.00484 c 1.793,-9.024 4.636,-18.394 0.651,-27.243 -3.249,-7.215 -11.093,-14.999 -19.132,-16.296 -3.099,-0.5 -4.498,-4.715 -0.559,-4.08 9.492,1.532 17.385,7.932 22.779,15.671 7.282,10.448 4.357,21.921 2.056,33.501 -0.514,2.585 -6.321,1.096 -5.795,-1.553" /><path
inkscape:connector-curvature="0"
id="path86"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 602.20208,726.15864 c 0.315,-9.326 -8.25,-18.223 -16.232,-21.912 -3.589,-1.659 -0.408,-5.09 2.638,-3.683 9.385,4.337 19.859,14.913 19.485,25.963 -0.108,3.189 -5.985,2.411 -5.891,-0.368" /><path
inkscape:connector-curvature="0"
id="path90"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 583.37498,729.72844 c -5.05,-8.992 -10.76,-16.269 -21.323,-18.471 -3.657,-0.762 -2.517,-4.777 1.08,-4.027 12.498,2.605 19.786,11.112 25.792,21.806 1.609,2.866 -4.285,2.942 -5.549,0.692" /><path
inkscape:connector-curvature="0"
id="path94"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 566.77538,732.32164 c -6.334,-5.881 -11.186,-13.786 -20.424,-14.943 -2.545,-0.319 -5.015,-3.098 -0.957,-2.59 5.396,0.676 10.233,2.5 14.579,5.787 4.514,3.413 7.979,8.11 12.113,11.947 1.031,0.959 -0.887,1.287 -1.455,1.266 -1.379,-0.051 -2.835,-0.519 -3.856,-1.467" /><path
inkscape:connector-curvature="0"
id="path98"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 553.40718,740.56044 c -4.594,-7.337 -12.351,-13.475 -21.376,-10.607 -2.063,0.656 -6.832,-2.355 -3.475,-3.422 12.079,-3.839 23.982,3.62 30.3,13.711 1.549,2.474 -4.327,2.11 -5.449,0.318" /><path
inkscape:connector-curvature="0"
id="path102"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 682.46768,933.64984 c -3.94,-17.48 3.4,-35.168 -1.42,-52.577 -4.211,-15.21 -15.344,-29.051 -15.344,-45.317 0,-0.806 5.795,-0.013 5.795,1.553 0,15.86 10.744,30.064 15.253,44.831 5.281,17.296 -2.509,35.147 1.419,52.576 0.255,1.13 -5.397,0.293 -5.703,-1.066" /><path
inkscape:connector-curvature="0"
id="path106"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 651.45698,1106.7465 c 15.201,-11.729 24.591,-26.634 30.122,-44.904 3.446,-11.386 4.709,-22.954 5.539,-34.777 0.433,-6.16 0.912,-12.307 1.764,-18.426 0.758,-5.452 2.856,-10.63596 4.179,-15.95796 0.437,-1.76 6.243,-0.244 5.795,1.552 -1.328,5.346 -3.26,10.51296 -4.179,15.95896 -1.024,6.071 -1.333,12.292 -1.763,18.427 -0.832,11.856 -2.193,23.338 -5.54,34.776 -5.403,18.47 -15.218,33.714 -30.507,45.511 -1.486,1.147 -6.754,-1.123 -5.41,-2.16" /><path
inkscape:connector-curvature="0"
id="path110"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 642.71378,1103.5975 c -12.842,-1.804 -22.769,8.963 -35.264,10.7 -12.757,1.773 -24.802,-1.339 -36.282,-6.784 -5.458,-2.589 -10.726,-5.554 -16.2,-8.115 -7.82,-3.658 -14.991,-4.655 -23.574,-4.52 -13.041,0.205 -23.106,-3.92 -33.054,-12.245 -19.468,-16.294 -27.4,-41.739 -30.656,-66.126 -2.032,-15.215 -4.322,-30.17896 -7.574,-45.19696 -3.302,-15.243 -6.875,-30.427 -9.333,-45.838 -0.88,-5.529 -1.546,-11.088 -2.051,-16.663 -0.242,-2.676 5.626,-1.675 5.831,0.591 2.762,30.501 11.868,59.892 16.712,90.052 2.072,12.90196 2.99,25.76696 6.349,38.44896 3.416,12.895 8.849,25.692 17.599,35.894 4.242,4.945 9.568,9.294 15.045,12.777 7.027,4.468 14.514,4.642 22.574,4.524 13.229,-0.196 23.837,4.89 35.353,10.833 13.129,6.776 26.547,11.549 41.415,7.664 6.064,-1.585 11.284,-5.155 16.886,-7.802 4.969,-2.347 10.189,-2.651 15.564,-1.895 2.982,0.419 4.638,4.26 0.66,3.701" /><path
inkscape:connector-curvature="0"
id="path114"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 441.87398,969.27184 c -0.086,-9.163 -1.376,-18.324 -4.25,-27.049 -2.561,-7.778 -7.016,-14.74 -9.049,-22.726 -0.683,-2.685 5.237,-1.942 5.858,0.495 2.121,8.335 7.062,15.574 9.413,23.823 2.429,8.525 3.801,17.082 3.885,25.952 0.028,2.937 -5.834,1.98 -5.857,-0.495" /><path
inkscape:connector-curvature="0"
id="path118"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 428.22598,983.18154 c -0.126,-13.803 -3.634,-26.896 -13.412,-37.029 -1.278,-1.325 4.272,-0.647 5.262,0.379 10.105,10.471 13.815,23.926 13.946,38.203 0.009,1.021 -5.78,0.181 -5.796,-1.553" /><path
inkscape:connector-curvature="0"
id="path122"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 418.99218,982.69574 c -5.593,3.597 -8.523,9.997 -13.913,13.835 -5.079,3.61696 -11.005,1.865 -15.979,-0.938 -15.196,-8.561 -16.355,-29.519 -16.166,-44.94 0.214,-17.344 4.91,-34.757 17.014,-47.614 10.092,-10.72 24.413,-16.244 38.26,-20.199 1.826,-0.521 6.82,2.202 3.552,3.136 -12.207,3.486 -24.157,8.258 -33.777,16.76 -10.872,9.607 -16.229,23.352 -18.395,37.402 -1.308,8.481 -0.94,17.11 -0.021,25.607 0.815,7.526 1.807,14.869 5.998,21.339 2.215,3.418 5.456,6.065 9.085,7.851 3.146,1.549 6.216,-1.388 8.228,-3.395 3.923,-3.911 6.754,-8.587 11.5,-11.639 1.581,-1.017 6.946,1.295 4.614,2.795" /><path
inkscape:connector-curvature="0"
id="path126"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 429.74558,904.14934 c 4.695,-13.758 4.808,-28.257 6.042,-42.591 1.094,-12.705 3.472,-25.64 7.692,-37.688 4.402,-12.568 12.339,-21.713 22.8,-29.759 5.601,-4.309 11.501,-8.197 17.012,-12.629 6.35,-5.104 12.308,-10.685 18.476,-16.003 1.571,-1.355 6.985,0.895 5.379,2.28 -11.16,9.622 -22.251,18.842 -34.109,27.594 -10.959,8.089 -19.002,17.207 -23.763,30.07 -4.216,11.392 -6.264,23.847 -7.522,35.889 -1.56,14.939 -1.302,30.005 -6.211,44.39 -0.705,2.065 -6.463,0.404 -5.796,-1.553" /><path
inkscape:connector-curvature="0"
id="path130"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 678.61908,1071.6263 c 5.318,-1.33 12.266,-0.993 14.445,4.979 2.601,7.124 -3.383,17.237 -6.59,23.137 -5.981,11.007 -13.785,21.078 -22.383,30.153 -4.116,4.343 -8.572,8.533 -13.977,11.216 -4.935,2.448 -10.481,3.705 -15.685,5.441 -11.429,3.814 -22.389,8.969 -33.104,14.439 -9.623,4.913 -18.995,9.111 -29.806,10.462 -13.083,1.636 -26.569,1.155 -39.711,0.646 -23.016,-0.891 -45.99,-3.396 -67.847,-11.033 -21.218,-7.414 -40.837,-19.392 -56.534,-35.576 -7.666,-7.904 -12.171,-17.279 -16.004,-27.47 -4.698,-12.489 -7.95,-25.548 -10.239,-38.681 -1.072,-6.153 -1.481,-12.421 -2.077,-18.633 -0.588,-6.124 -1.946,-12.184 -1.873,-18.346 0.032,-2.696 0.424,-5.4 0.689,-8.079 0.344,-3.487 -0.079,-6.911 0.048,-10.377 0.226,-6.17996 2.869,-11.88496 3.139,-18.06296 0.087,-1.962 5.897,-0.759 5.796,1.553 -0.32,7.3 -3.379,13.74196 -2.922,21.16596 0.45,7.307 -1.591,14.394 -0.493,21.718 2.315,15.447 3.24,30.783 6.905,46.033 3.424,14.249 7.882,29.624 16.375,41.724 7.569,10.782 19.366,19.621 30.323,26.673 24.251,15.607 52.867,21.345 81.214,23.36 14.169,1.007 28.442,1.306 42.635,0.67 12.061,-0.54 22.225,-3.809 32.942,-9.178 12.873,-6.447 25.756,-12.611 39.474,-17.061 6.881,-2.233 13.345,-4.077 18.999,-8.801 10.907,-9.113 19.933,-21.292 27.141,-33.439 3.336,-5.621 6.309,-11.716 7.724,-18.131 0.456,-2.063 0.585,-4.162 0.037,-6.212 -0.673,-2.514 -3.221,-1.518 -5.12,-1.043 -1.924,0.481 -6.847,-2.415 -3.521,-3.247" /><path
inkscape:connector-curvature="0"
id="path134"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 404.28808,878.69184 c 5.97,-19.507 8.159,-39.821 6.255,-60.144 -0.895,-9.561 -2.901,-18.994 -5.687,-28.174 -2.968,-9.78 -7.526,-19.015 -10.824,-28.687 -0.661,-1.938 5.139,-1.166 5.79,0.745 3.301,9.68 7.726,18.939 10.824,28.687 3.09,9.723 4.906,19.822 5.856,29.966 1.862,19.893 -0.584,40.095 -6.418,59.16 -0.611,1.995 -6.388,0.382 -5.796,-1.553" /><path
inkscape:connector-curvature="0"
id="path138"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 585.12688,681.99504 c -1.835,-6.336 -1.178,-12.876 -1.076,-19.381 0.108,-7.028 -0.804,-14.101 -1.096,-21.122 -0.113,-2.706 -0.157,-5.408 0.024,-8.111 0.175,-2.632 0.86,-5.767 -0.335,-8.254 -1.226,-2.551 -4.504,-4.232 -6.732,-5.805 -2.501,-1.766 -4.581,-3.819 -6.66,-6.062 -9.418,-10.163 -15.53,-22.889 -20.969,-35.476 -2.975,-6.887 -5.708,-13.881 -8.949,-20.649 -3.46,-7.224 -7.358,-14.2 -10.265,-21.68 -1.153,-2.97 4.651,-2.629 5.491,-0.469 2.681,6.902 6.151,13.423 9.457,20.037 3.627,7.256 6.57,14.837 9.756,22.291 5.901,13.806 12.748,26.944 23.36,37.747 3.462,3.525 8.432,5.141 11.001,9.597 2.377,4.124 0.516,11.068 0.607,15.564 0.145,7.141 0.885,14.256 1.145,21.392 0.257,7.062 -0.917,14.008 1.085,20.925 0.729,2.518 -5.174,1.769 -5.844,-0.544" /><path
inkscape:connector-curvature="0"
id="path142"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 390.46768,769.62344 c -7.392,0.154 -12.729,-3.572 -14.93,-10.607 -3.211,-10.265 -0.249,-20.877 3.715,-30.441 5.416,-13.066 11.224,-25.88 17.738,-38.437 6.91,-13.319 13.907,-26.267 19.59,-40.175 2.446,-5.984 5.063,-11.909 8.408,-17.448 3.526,-5.843 7.757,-11.229 11.333,-17.043 3.128,-5.088 5.8,-10.414 9.353,-15.234 3.552,-4.821 8.363,-8.597 12.61,-12.771 4.792,-4.71 9.567,-9.379 15.157,-13.148 5.458,-3.681 11.728,-6.367 17.492,-9.544 11.503,-6.34 22.278,-13.677 31.303,-23.293 0.945,-1.007 6.227,1.115 5.476,1.916 -7.909,8.427 -17.127,15.076 -27.072,20.895 -10.045,5.88 -20.788,10.323 -29.582,18.096 -8.537,7.547 -17.649,15.625 -23.583,25.409 -3.039,5.011 -5.816,10.126 -9.105,14.987 -3.498,5.167 -7.132,10.204 -10.121,15.694 -6.113,11.23 -9.712,23.66 -15.755,34.955 -6.204,11.594 -12.45,23.165 -18.07,35.058 -5.207,11.019 -11.132,22.862 -13.739,34.815 -0.912,4.186 -0.814,8.598 -0.279,12.825 0.365,2.872 2.075,11.368 6.261,11.281 1.124,-0.023 6.582,2.152 3.8,2.21" /><path
inkscape:connector-curvature="0"
id="path146"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 640.92968,702.55704 c 9.753,-6.598 20.642,-11.134 31.593,-15.33 11.865,-4.546 23.62,-9.171 35.334,-14.101 12.848,-5.406 25.845,-10.548 39.142,-14.755 12.571,-3.978 23.997,-10.899 35.847,-16.539 2.582,-1.229 6.67,2.508 3.289,4.117 -11.344,5.398 -22.246,11.698 -34.105,15.949 -13.137,4.711 -26.231,9.246 -39.131,14.611 -11.278,4.69 -22.491,9.358 -33.932,13.642 -11.611,4.348 -23.29,8.919 -33.609,15.901 -2.285,1.546 -7.258,-1.58 -4.428,-3.495" /><path
inkscape:connector-curvature="0"
id="path150"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 365.91158,740.76504 c 0.868,-18.275 -25.202,-25.549 -38.362,-31.247 -11.191,-4.846 -21.739,-11.333 -32.296,-17.394 -12.988,-7.457 -26.397,-14.311 -38.794,-22.74 -3.241,-2.204 1.801,-2.788 3.561,-1.591 12.923,8.786 26.928,15.926 40.467,23.7 11.406,6.549 22.778,13.078 34.923,18.162 13.759,5.759 37.17,14.258 36.297,32.663 -0.084,1.756 -5.898,0.602 -5.796,-1.553" /><path
inkscape:connector-curvature="0"
id="path154"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 530.64838,487.02824 c 4.489,1.93 7.703,5.298 10.885,8.912 4.9,5.566 10.626,10.177 16.453,14.74 12.608,9.872 25.418,19.451 40.074,26.097 6.298,2.856 13.616,5.48 20.594,5.719 4.485,0.153 8.944,-0.382 13.424,0.154 9.138,1.093 6.927,10.161 6.217,16.848 -0.852,8.014 -2.243,16.477 -0.869,24.497 0.122,0.71 0.337,1.387 0.575,2.065 0.526,1.5 -1.891,0.42 -0.359,0.21 1.958,-0.268 3.862,-1.043 5.703,-1.726 4.469,-1.661 8.784,-3.74 13.105,-5.744 3.652,-1.693 7.395,-3.176 11.123,-4.695 2.832,-1.153 7.241,-2.304 9.93,-0.236 2.438,1.874 2.885,6.132 2.879,8.916 -0.01,6.139 -0.751,12.43 -1.994,18.43 -3.535,17.061 -12.175,33.468 -20.532,48.581 -8.729,15.785 -15.179,33.006 -26.452,47.252 -1.152,1.456 -6.728,-0.526 -5.399,-2.205 7.42,-9.378 12.6,-19.954 17.668,-30.712 5.111,-10.847 11.549,-21.01 16.774,-31.803 4.77,-9.858 9.051,-20.357 11.755,-30.979 1.264,-4.965 1.69,-10.041 2.175,-15.123 0.26,-2.728 1.178,-9.532 -1.476,-11.572 1.152,0.384 2.304,0.767 3.456,1.149 -3.868,0.094 -8.16,2.613 -11.699,4.075 -3.158,1.303 -6.223,2.853 -9.335,4.262 -5.205,2.356 -12.629,6.591 -18.597,4.992 -5.68,-1.522 -5.533,-8.02 -5.586,-12.833 -0.072,-6.642 0.907,-13.22 1.506,-19.817 0.169,-1.869 0.495,-3.722 0.656,-5.594 0.125,-1.449 0.019,-2.864 -0.273,-4.283 -0.305,-1.483 -0.741,-1.081 -2.307,-1.142 -3.74,-0.149 -7.505,0.357 -11.238,0.04 -11.42,-0.973 -22.088,-5.582 -32.169,-10.734 -11.722,-5.989 -22.182,-14.237 -32.561,-22.24 -5.045,-3.891 -10.054,-7.879 -14.668,-12.28 -3.803,-3.626 -6.671,-8.918 -11.667,-11.067 -3.731,-1.603 -0.285,-3.235 2.229,-2.154" /><path
inkscape:connector-curvature="0"
id="path158"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 350.83588,722.89204 c -5.492,-12.675 -6.728,-26.303 -6.663,-39.984 0.069,-14.428 1.077,-28.843 1.228,-43.276 0.171,-16.36 0.964,-32.708 1.846,-49.042 0.423,-7.848 0.878,-15.694 1.312,-23.54 0.265,-4.792 -0.71,-10.378 0.986,-14.958 3.679,-9.929 16.103,3.065 19.632,5.89 4.606,3.688 11.379,5.626 16.887,7.425 6.892,2.25 14.019,3.861 21.174,4.998 6.402,1.018 12.897,1.605 19.324,2.461 2.895,0.385 6.928,0.812 9.594,-0.705 1.503,-0.855 1.846,-4.244 2.295,-5.708 2.035,-6.629 5.86,-12.645 8.393,-19.09 1.191,-3.027 2.157,-6.922 5.51,-8.153 4.818,-1.769 11.796,-0.425 16.755,-0.206 4.352,0.191 8.684,0.069 12.825,-1.396 3.99,-1.411 7.503,-4.375 10.808,-6.934 11.955,-9.26 22.587,-19.449 29.962,-32.836 1.276,-2.316 6.79,-0.131 5.301,2.572 -6.282,11.401 -15.213,21.519 -25.45,29.531 -5.057,3.959 -10.058,8.044 -15.798,10.973 -6.289,3.209 -13.989,2.556 -20.794,2.23 -3.186,-0.152 -6.396,-0.179 -9.584,-0.031 -1.768,0.083 -2.107,1.856 -2.7,3.283 -2.849,6.862 -6.302,13.468 -9.018,20.378 -1.208,3.072 -1.34,6.562 -4.047,8.766 -3.73,3.04 -11.087,1.963 -15.321,1.398 -13.115,-1.746 -26.032,-3.198 -38.767,-7.008 -5.69,-1.704 -11.268,-3.859 -16.6,-6.476 -4.809,-2.359 -8.34,-6.22 -12.518,-9.474 -3.815,-2.97 -2.748,9.384 -2.865,11.532 -0.462,8.501 -0.957,17 -1.42,25.501 -0.891,16.337 -1.629,32.682 -1.846,49.043 -0.184,13.868 -0.938,27.699 -1.207,41.562 -0.267,13.798 0.772,27.78 6.317,40.576 1.334,3.08 -4.51,3.1 -5.551,0.698" /><path
inkscape:connector-curvature="0"
id="path162"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 373.96578,881.67274 c -12.686,0.555 -22.858,-7.416 -30.871,-16.478 -8.576,-9.699 -15.37,-21.702 -19.715,-33.879 -6.524,-18.284 -9.48,-38.065 -12.363,-57.182 -1.462,-9.69 -2.763,-19.402 -4.165,-29.1 -1.36,-9.407 -1.103,-19.23 -4.662,-28.181 -1.267,-3.186 4.564,-3.314 5.572,-0.778 2.898,7.289 3.468,15.072 4.195,22.809 0.832,8.848 2.358,17.662 3.61,26.459 2.606,18.311 5.503,36.606 10.211,54.512 3.442,13.09 8.794,25.104 16.551,36.227 6.559,9.403 16.997,21.737 29.684,21.182 2.931,-0.129 5.868,4.238 1.953,4.409" /><path
inkscape:connector-curvature="0"
id="path166"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 377.11858,865.56334 c -8.317,0.262 -13.875,-4.482 -18.668,-10.82 -6.405,-8.471 -13.046,-16.709 -18.098,-26.095 -5.72,-10.626 -8.09,-22.858 -10.492,-34.577 -2.517,-12.284 -4.14,-24.797 -4.225,-37.348 -0.008,-1.185 5.783,-0.289 5.796,1.553 0.136,20.273 3.889,41.375 10.081,60.68 2.991,9.325 8.403,17.707 14.178,25.521 2.375,3.214 4.917,6.3 7.288,9.517 2.325,3.154 5.936,9.123 10.441,8.981 1.368,-0.043 6.677,2.494 3.699,2.588" /><path
inkscape:connector-curvature="0"
id="path170"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 382.30758,857.54674 c -23.68,-12.641 -24.306,-43.878 -32.324,-66.326 -0.47,-1.316 5.172,-0.628 5.735,0.951 3.905,10.932 5.949,22.441 9.377,33.523 3.649,11.797 9.171,24.75 20.613,30.859 3.41,1.82 -1.923,1.782 -3.401,0.993" /><path
inkscape:connector-curvature="0"
id="path174"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 397.34468,853.14344 c -6.584,-2.528 -8.869,-9.616 -10.323,-15.931 -1.617,-7.027 -2.085,-14.398 -2.112,-21.595 -0.005,-1.55 5.789,-0.533 5.796,1.553 0.021,5.867 0.497,11.733 1.441,17.524 0.765,4.691 2.208,14.389 7.402,16.384 3.808,1.461 0.286,3.021 -2.204,2.065" /><path
inkscape:connector-curvature="0"
id="path178"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 580.72558,951.45304 c -0.456,-3.119 -5.252,-5.001 -10.711,-4.202 -5.461,0.8 -9.518,3.976 -9.061,7.096 0.457,3.119 5.252,5.001 10.711,4.202 5.461,-0.8 9.519,-3.976 9.061,-7.096" /><path
inkscape:connector-curvature="0"
id="path182"
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 580.72558,951.45304 c -0.456,-3.119 -5.252,-5.001 -10.711,-4.202 -5.461,0.8 -9.518,3.976 -9.061,7.096 0.457,3.119 5.252,5.001 10.711,4.202 5.461,-0.8 9.519,-3.976 9.061,-7.096 z" /></g></svg>

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,78 @@
.year {
font-weight: bold;
text-align: center;
font-size: 200%;
cursor: pointer;
}
.holiday {
text-align: center;
font-size: 150%;
font-weight: bold;
margin: .5em 0;
}
table.month {
float: left;
border: 2px solid black;
margin-right: 1em;
margin-bottom: 1em;
border-collapse: collapse;
position: relative;
}
.clear {
float: none;
clear: both;
}
.month-row {
margin-left: auto;
margin-right: auto;
position: relative;
}
td {
text-align: center;
padding: .1em;
white-space: nowrap;
border: 1px solid black;
}
.monthname td {
font-weight: bold;
border: 1px solid black;
}
.daynames {
border-bottom: 2px solid black;
}
.daynames td {
font-weight: bold;
border: 1px solid black;
width: 16.66%;
}
.prevYear {
float: left;
cursor: pointer;
}
.nextYear {
float: right;
cursor: pointer;
}
.today {
background-color: #a5ffff;
}
.date-popover {
text-align: center;
}
.holiday .small {
font-size: 75%;
font-weight: normal;
}

Binary file not shown.

View File

@@ -0,0 +1,288 @@
<?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></metadata>
<defs>
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
<font-face units-per-em="1200" ascent="960" descent="-240" />
<missing-glyph horiz-adv-x="500" />
<glyph horiz-adv-x="0" />
<glyph horiz-adv-x="400" />
<glyph unicode=" " />
<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xa0;" />
<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
<glyph unicode="&#x2000;" horiz-adv-x="650" />
<glyph unicode="&#x2001;" horiz-adv-x="1300" />
<glyph unicode="&#x2002;" horiz-adv-x="650" />
<glyph unicode="&#x2003;" horiz-adv-x="1300" />
<glyph unicode="&#x2004;" horiz-adv-x="433" />
<glyph unicode="&#x2005;" horiz-adv-x="325" />
<glyph unicode="&#x2006;" horiz-adv-x="216" />
<glyph unicode="&#x2007;" horiz-adv-x="216" />
<glyph unicode="&#x2008;" horiz-adv-x="162" />
<glyph unicode="&#x2009;" horiz-adv-x="260" />
<glyph unicode="&#x200a;" horiz-adv-x="72" />
<glyph unicode="&#x202f;" horiz-adv-x="260" />
<glyph unicode="&#x205f;" horiz-adv-x="325" />
<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Binary file not shown.

BIN
content/minari/images/0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
content/minari/images/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Some files were not shown because too many files have changed in this diff Show More