[vlc-devel] [RFC 59/82] qml: add a tool to generate an icon font from SVG graphics

Pierre Lamot pierre at videolabs.io
Fri Feb 1 14:02:03 CET 2019


  Bundle simple monochrome graphics as a vector font, this allows
  dynamic colorisation of the graphic, in the style of FontAwsome

  The script will generate a ttf font and a QML file wich will serve
  as an index for the glyphs
---
 modules/gui/qt/Makefile.am             |   5 +-
 modules/gui/qt/pixmaps/VLCIcons.json   | 125 +++++++++++++++++++++++++
 modules/gui/qt/pixmaps/VLCIcons.ttf    | Bin 0 -> 21684 bytes
 modules/gui/qt/pixmaps/makeIconFont.py | 110 ++++++++++++++++++++++
 4 files changed, 239 insertions(+), 1 deletion(-)
 create mode 100644 modules/gui/qt/pixmaps/VLCIcons.json
 create mode 100644 modules/gui/qt/pixmaps/VLCIcons.ttf
 create mode 100755 modules/gui/qt/pixmaps/makeIconFont.py

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index ef74b63329..39c5804214 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -389,6 +389,7 @@ EXTRA_DIST += $(libqt_plugin_la_UI)
 # Resources
 
 libqt_plugin_la_RES = \
+	gui/qt/pixmaps/VLCIcons.ttf \
 	gui/qt/pixmaps/clear.svg \
 	gui/qt/pixmaps/eject.svg \
 	gui/qt/pixmaps/faster.svg \
@@ -520,7 +521,9 @@ libqt_plugin_la_RES = \
 	gui/qt/pixmaps/update.svg \
 	gui/qt/pixmaps/valid.svg \
 	gui/qt/pixmaps/search_clear.svg \
-	gui/qt/pixmaps/lock.svg
+	gui/qt/pixmaps/lock.svg \
+	gui/qt/qml/style/VLCIcons.qml \
+
 EXTRA_DIST += gui/qt/vlc.qrc $(libqt_plugin_la_RES)
 
 nodist_libqt_plugin_la_SOURCES += gui/qt/resources.cpp
diff --git a/modules/gui/qt/pixmaps/VLCIcons.json b/modules/gui/qt/pixmaps/VLCIcons.json
new file mode 100644
index 0000000000..d5a8e8639f
--- /dev/null
+++ b/modules/gui/qt/pixmaps/VLCIcons.json
@@ -0,0 +1,125 @@
+{
+	"qml_name": "VLCIcons.qml",
+	"qml_file_prefix": "qrc:///",
+	"font_file": "VLCIcons.ttf",
+	"font_name": "VLCIcons",
+	"glyphs" : [
+		{"key":"eject", "path": "./eject.svg"},
+		{"key":"stop", "path": "./stop.svg"},
+		{"key":"faster", "path": "./faster.svg"},
+		{"key":"go_next", "path": "./go-next.svg"},
+		{"key":"update", "path": "./update.svg"},
+		{"key":"extended", "path": "./toolbar/extended_16px.svg"},
+		{"key":"renderer", "path": "./toolbar/renderer.svg"},
+		{"key":"tvtelx", "path": "./toolbar/tvtelx.svg"},
+		{"key":"visu", "path": "./toolbar/visu.svg"},
+		{"key":"defullscreen", "path": "./toolbar/defullscreen.svg"},
+		{"key":"tv", "path": "./toolbar/tv.svg"},
+		{"key":"skip_for", "path": "./toolbar/skip_for.svg"},
+		{"key":"skip_back", "path": "./toolbar/skip_back.svg"},
+		{"key":"frame_by_frame", "path": "./toolbar/frame-by-frame.svg"},
+		{"key":"atob_nob", "path": "./toolbar/atob_nob.svg"},
+		{"key":"atob", "path": "./toolbar/atob.svg"},
+		{"key":"atob_noa", "path": "./toolbar/atob_noa.svg"},
+		{"key":"volume_low", "path": "./toolbar/volume-low.svg"},
+		{"key":"dvd_prev", "path": "./toolbar/dvd_prev.svg"},
+		{"key":"volume_medium", "path": "./toolbar/volume-medium.svg"},
+		{"key":"dvd_next", "path": "./toolbar/dvd_next.svg"},
+		{"key":"audiosub", "path": "./toolbar/audiosub.svg"},
+		{"key":"volume_slider_outside", "path": "./toolbar/volume-slider-outside.svg"},
+		{"key":"arrows", "path": "./toolbar/arrows.svg"},
+		{"key":"aspect_ratio", "path": "./toolbar/aspect-ratio.svg"},
+		{"key":"fullscreen", "path": "./toolbar/fullscreen.svg"},
+		{"key":"dvd_menu", "path": "./toolbar/dvd_menu.svg"},
+		{"key":"play_reverse", "path": "./toolbar/play_reverse.svg"},
+		{"key":"record", "path": "./toolbar/record_16px.svg"},
+		{"key":"snapshot", "path": "./toolbar/snapshot.svg"},
+		{"key":"volume_high", "path": "./toolbar/volume-high.svg"},
+		{"key":"volume_slider_inside", "path": "./toolbar/volume-slider-inside.svg"},
+		{"key":"volume_muted", "path": "./toolbar/volume-muted.svg"},
+		{"key":"previous", "path": "./previous.svg"},
+		{"key":"type_node", "path": "./types/type_node.svg"},
+		{"key":"type_unknown", "path": "./types/type_unknown.svg"},
+		{"key":"file_asym", "path": "./types/file-asym_16px.svg"},
+		{"key":"folder_grey", "path": "./types/folder-grey_16px.svg"},
+		{"key":"type_file", "path": "./types/type_file.svg"},
+		{"key":"file_wide", "path": "./types/file-wide_16px.svg"},
+		{"key":"harddisk", "path": "./types/harddisk_16px.svg"},
+		{"key":"type_playlist", "path": "./types/type_playlist.svg"},
+		{"key":"folder_blue", "path": "./types/folder-blue_16px.svg"},
+		{"key":"capture_card", "path": "./types/capture-card_16px.svg"},
+		{"key":"tape", "path": "./types/tape_16px.svg"},
+		{"key":"type_stream", "path": "./types/type_stream.svg"},
+		{"key":"type_directory", "path": "./types/type_directory.svg"},
+		{"key":"disc", "path": "./types/disc_16px.svg"},
+		{"key":"repeat_one", "path": "./playlist/repeat_one.svg"},
+		{"key":"repeat_off", "path": "./playlist/repeat_off.svg"},
+		{"key":"dropzone", "path": "./playlist/dropzone.svg"},
+		{"key":"remove", "path": "./playlist/remove.svg"},
+		{"key":"add", "path": "./playlist/add.svg"},
+		{"key":"shuffle_on", "path": "./playlist/shuffle_on.svg"},
+		{"key":"appletrailers", "path": "./playlist/sidebar-icons/sd/appletrailers.svg"},
+		{"key":"metachannels", "path": "./playlist/sidebar-icons/sd/metachannels.svg"},
+		{"key":"assembleenationale", "path": "./playlist/sidebar-icons/sd/assembleenationale.svg"},
+		{"key":"fmc", "path": "./playlist/sidebar-icons/sd/fmc.svg"},
+		{"key":"jamendo", "path": "./playlist/sidebar-icons/sd/jamendo.svg"},
+		{"key":"icecast", "path": "./playlist/sidebar-icons/sd/icecast.svg"},
+		{"key":"katsomo", "path": "./playlist/sidebar-icons/sd/katsomo.svg"},
+		{"key":"frenchtv", "path": "./playlist/sidebar-icons/sd/frenchtv.svg"},
+		{"key":"mtp", "path": "./playlist/sidebar-icons/mtp.svg"},
+		{"key":"network", "path": "./playlist/sidebar-icons/network.svg"},
+		{"key":"movie", "path": "./playlist/sidebar-icons/movie.svg"},
+		{"key":"pictures", "path": "./playlist/sidebar-icons/pictures.svg"},
+		{"key":"screen", "path": "./playlist/sidebar-icons/screen.svg"},
+		{"key":"library", "path": "./playlist/sidebar-icons/library.svg"},
+		{"key":"music", "path": "./playlist/sidebar-icons/music.svg"},
+		{"key":"lan", "path": "./playlist/sidebar-icons/lan.svg"},
+		{"key":"capture", "path": "./playlist/sidebar-icons/capture.svg"},
+		{"key":"podcast", "path": "./playlist/sidebar-icons/podcast.svg"},
+		{"key":"playlist", "path": "./playlist/playlist.svg"},
+		{"key":"repeat_all", "path": "./playlist/repeat_all.svg"},
+		{"key":"lock", "path": "./lock.svg"},
+		{"key":"slower", "path": "./slower.svg"},
+		{"key":"clear", "path": "./clear.svg"},
+		{"key":"profile_new", "path": "./profile_new.svg"},
+		{"key":"addon_green", "path": "./addons/addon_green.svg"},
+		{"key":"addon_broken", "path": "./addons/addon_broken.svg"},
+		{"key":"addon_magenta", "path": "./addons/addon_magenta.svg"},
+		{"key":"addon_cyan", "path": "./addons/addon_cyan.svg"},
+		{"key":"score", "path": "./addons/score.svg"},
+		{"key":"addon_yellow", "path": "./addons/addon_yellow.svg"},
+		{"key":"addon_blue", "path": "./addons/addon_blue.svg"},
+		{"key":"addon", "path": "./addons/addon.svg"},
+		{"key":"addon_red", "path": "./addons/addon_red.svg"},
+		{"key":"advprefs_playlist", "path": "./prefs/advprefs_playlist.svg"},
+		{"key":"advprefs_audio", "path": "./prefs/advprefs_audio.svg"},
+		{"key":"advprefs_video", "path": "./prefs/advprefs_video.svg"},
+		{"key":"advprefs_extended", "path": "./prefs/advprefs_extended.svg"},
+		{"key":"advprefs_codec", "path": "./prefs/advprefs_codec.svg"},
+		{"key":"advprefs_intf", "path": "./prefs/advprefs_intf.svg"},
+		{"key":"advprefs_sout", "path": "./prefs/advprefs_sout.svg"},
+		{"key":"win7thumbnail_next", "path": "./win7/win7thumbnail_next.svg"},
+		{"key":"win7thumbnail_play", "path": "./win7/win7thumbnail_play.svg"},
+		{"key":"win7thumbnail_pause", "path": "./win7/win7thumbnail_pause.svg"},
+		{"key":"win7thumbnail_prev", "path": "./win7/win7thumbnail_prev.svg"},
+		{"key":"next", "path": "./next.svg"},
+		{"key":"play", "path": "./play.svg"},
+		{"key":"space", "path": "./space.svg"},
+		{"key":"pause", "path": "./pause.svg"},
+		{"key":"faster2", "path": "./faster2.svg"},
+		{"key":"wait1", "path": "./util/wait1.svg"},
+		{"key":"wait2", "path": "./util/wait2.svg"},
+		{"key":"wait3", "path": "./util/wait3.svg"},
+		{"key":"wait4", "path": "./util/wait4.svg"},
+		{"key":"slower2", "path": "./slower2.svg"},
+		{"key":"messages", "path": "./menus/messages_16px.svg"},
+		{"key":"settings", "path": "./menus/settings_16px.svg"},
+		{"key":"info", "path": "./menus/info_16px.svg"},
+		{"key":"preferences", "path": "./menus/preferences_16px.svg"},
+		{"key":"exit", "path": "./menus/exit_16px.svg"},
+		{"key":"help", "path": "./menus/help_16px.svg"},
+		{"key":"stream", "path": "./menus/stream_16px.svg"},
+		{"key":"valid", "path": "./valid.svg"},
+		{"key":"search_clear", "path": "./search_clear.svg"}
+	]
+}
diff --git a/modules/gui/qt/pixmaps/VLCIcons.ttf b/modules/gui/qt/pixmaps/VLCIcons.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..9bbececbccd0fd835f25a622bcc99ca7ca681a8a
GIT binary patch
literal 21684
zcmdsf3v?UTdFH({m>Ilg at Em|31%dzwKoTK}9K1+9Ks`v=5*1mBWQ%rW$&MiFVLd2Y
zrtH*o94G76ve#9W8qLP;$sXl2Y0?}scAPY)(zeOAJ>f}P$K92;={l{YHg(gSSf^{d
z+lEP?{r)=xic*w~leFh-7r at Nixij<6eg2Q{|1TJ4jOpxACbO*@HtcxM<M{`Fjj<gc
zL++wmwlB9T4{zSZ7 at xrTU3-t*J^7Dc{KqlIq|ae1?wvZ(!_v}2jJdvv>#qHG-#>Zf
z3MjE1r*ZDyfB2z$zVS!(?=YtPDPuQ%=fJ+Z8-blu`*7`B*s2GRA-jI~80bfF-h1H4
zi3eX<^(R+w{$-rMbNJZayZ^W6+eMJ3`!654`@u=}w~~tMLpbj_diRli8}A(XCC1+K
z63Vk^^4R?+*xr{v&Dbrk;F<rzsBYM9J#y$b_XJk`6Z6R^3uE70^q&s5kF5*1r6~P2
z&fQF+Tzv41$ho6+p>^R$pW#J8$-ZXqT_R_SzsmYV20h6|-Wt{~a$Kzo{4`TQ>6COH
zIZxR~evu7w+$}K$?bQAR+X)=E-ZR!<k6vUKPslx2hS(jVB%)07H}x>i53 at 95R}Nv@
zjco{DReUKWzOA_{sVhbCRj=&EwcS at bTR(8_Qm<@to=}jJ!e*Zj<Nm9(Y>LGzYU_e{
zj@}`O)MBwu;VIRj(|(GMML~@yI^Wjo?bQ6yelB(85bjOkdkB<vT&Z1gJ6}4duTwA7
z2K`QBOKgkm9^rYMQ7<oIF7CzAg)h!8p1?R{7a8qw?h;RNG`b5tqB0GA?O|T#V}6W%
zg9TWSg;<zHSd^J8#^S7lC0Hlx0^KC*W+{eo&N3{^dRdO;S%EEPOW0EMeUU9ge=lbP
zY>-*3#LBF~s;tI_*f3kcR<c!WHLJ4`wuY@`>)3iW%Es6Rb`!gqZDgC+INQwL!?v(n
z*jBcUy_aogJJ_x4Hnx*Zu-n-k?0sw(yOZr^d)Qs<ZuWk*mo?Zvb`RUn4zPpl5WANh
zW=Ggjc8pE3<Lo|mKRdx5K!s_Bpvv^2u{J-hMGj at Q6aOC{1z$oR4WXTPp`A{%|H^*I
z2l!V02!D}(TZ&0brKhEL<O%sf`IP*7^2 at GOuEVa6xn6etP}!jDQ0`HlQ{Ga&>JIg&
zdPaRqD{Al8KBaxnz1#h9_m at 3eJWb#8zW?SQ^*`u;TJO>O^>zATqhZVjjt0ZQM}rqa
zouS_k{V?i}ZjMexzhs8ZHRi9xqOtp8r(@@1m*Xtn89x-C?HKBKy5rkjw{<<g$hGLM
zMPFKUA-O9#*S)IySGvEO8cKaE^+!EM&*7er^fY^Zujl3TX!>aSW9hG?znkgEOk^I*
z{9fj7vaamb?3c2$*>}*F67dASRQfn(g~s|{;B5J-7d01q(|SQwzP0K_SwfP%AXBzN
z*)M7;|KX|^F-YFDN}+V9Pzq(!-1D8UeNFoKkM2oJVEY_A<_*@AA~f#`xTndBZ}1}V
zO<cPZ*Jh<K<`k3TmAF>X&OU$s{PR-ysi&IFr=FrRfrq_>d+2%GRj8y*Ii8;7r)Otd
zlP@(IeD^Hq46(;>&q+b2QX)dL&AB;tWo~+IZW`BB_8~SWO<{I2$%@y^Y%QP7sL_~J
zt(2l_CSN}A%Epc7Z>nwCa`fnPN9$)^IU`L`M)k;ZM~`kfaOMmI0*VMaFM-Y|W_}#A
znaL%yWM)J7R!X%}2x&80K{_Jx?ev9B`8<BlZ_efL`@DT7jauWaH+f{-YP~sbS>rs?
z9G{sP$2(l}?+Al~WWXz!oVH?SD601H3K|(y%T*0I*>XN>E<B=9%w*Dh?zz^al}sKu
zQ+(*w^?Uj at 45o_X(rD6bT`-dtFAfcv$>x~@w?0(dvwm<xv6zB*b=r6ooGgNxb%A5e
zzcriA<SU_aHExzFs8&TW(_%wE(%Xn?(j2#DAg|D?kcG~xk|y0?jpNg_tcGP#-R!;`
z730f?x1j|?S=w at Fy8^ad<Ku_N$N88zNTaPuB04wMY*PDQeO|+}aZ$=rl2g0XsKt at c
zR`MiAAJkTI(HYa at R%3i-e7s at JHBgp0oS`u&IX-SR=?vG1HnqVQFoyoE+d#B6*YKVo
zq(uiLL=TP0m|4;arE)%_Qt`_)tWc%-ZTqJls5crT8xL$mdC@>eoc4KOd!td_xUp<m
z+h3uo;6rt3eP7I(>)#<r;}!P1Zt#wAykMl!s9*OE%c6HQ8VlbcT}j~`mrxH$%sQQC
zL#0rIkG0NCqlITN7+aGli+ZIGbMvxvCuC(O<XsJNY%`6nB&QlzXvV}#R!sDo7~3m3
zoki8G$faRl$QbC=QUwDZ-E37?^Kw7WYECkro#DHw)U)Hd745bxEBQ~2U at R8YgQgig
zenD1c%dNcGsc1-b<`qp-q&qPz8u-m7O$^SanT!QH=n?GB;;wpK(fTwcg5)+jD%yg2
z=ooiPA*V+~J$}KW^M&nj_FWdgb*^1uzUkdofS+=zd`+L|m_ at zNIMza!z+7C|4RIQZ
zqRns6R||WmcB3w7S0$}zXnd<(-ZvL?jJ2>wu2v-HR?z%zKGg1_1zmGppFo$yoV73p
zJ<z{cBxXjnLbXy}&WRgm3t6o%pNS>^inve1;xBiX2a~;lt{%PCXiZ|)OG5s967olk
z;aZ_4V-TOcaA9uKrZ<{R;${xdZ{i(Z%-2PDOE-63Q_z0wg<CTDu}o#Scj0>_Gr6_+
zzE!=;Hr%`{+g%>$URZ?d%OJ<K2#Ri(K?*m)Wre83_)D-y*c;OQ;LZhTiX-T;oq|hu
zOEg>hxTa>osmqlb4wxa;cn0~Uw1sq5p)@8IrArIaBHy`ZVg4x|iDVK+rQms5QB-%&
zNAlGw_jvf79#89&9?w at jo;4oNF8hSz!dkDl%j1#m4|HTAU(Qz_bzzQ4C#rd*$2^NX
z`0cU}H#k8*wB{tnW$9Vy(2zV4s~gijYDhx#lxsOFKA<V8=~U(|MRQ4t;%dbdkB@(s
zOS~1AW&T}N`Z!+u0a<lPZq+9};^os^aw#8BMIXMw-OwRyxq*?M;sKtm6|OtZO&lr~
z4^1 at v&QW)cQke3a%>{c*qXn{><R(e$AD5cYcoZ;l!R2gG<%sFlBneJ%$+MGnYtFLj
z_3I=j4L{1x*KOI^);+GuK1aso9GQpr2pO1jWTFsud^ZWZ)>#sP{4*pCrBO=TVv)Gu
zxTwctkV#XhMHlRok}Z+!$pm>3jg?I3NVT{Dp<3rLD~9=>>F1SlN){RqYL`9m${AnE
z_3-B(et6=*nLkJ;y6@#1cK4^#@jz$bi^UCbtB$WUb>={>H)Wa=597}KnO8RLbN6+w
z+Pgp9pT>RhZ1JWzWHRO^zp at STh2|YBkVq)kY at H)@V3yjQ^gYrEN70{5Dp#pInb`+E
z^}qw4;!9``Bj&2EMs*Upnk{BfbZ9g*L00mZtpk?xf<nIBn6)gS)QG;ZzJ6dM1mbh`
zVzCaj#!8xVbP+oX*&7eUkzK4i<KQ{yg}b1Y^uU^{Ib1^33UwJ$tDq6jaL)Sq)l;-!
zKcDAT&n#WJa!EFvitD9pZ}-y0$&5E at cmiF4-f$uo%y at LS?sj;Yv at 7?K+R%q{xxg~3
z8ee`il}+4{&rc+JJ&RIlBhtUvpVbG<XurQ#P59iAfb4KQYCD(YWB($ZhCIeh!#qQC
zR4~b^Z>ef4hKckKTsp0OKygW!KlT{^g3x(2jE)rH6|%!!bMabSi)#g~0M2QTiF~0_
z$IL=@Eso5BhA}93uU4;D+Q0j6-oO9m?oFn-sb at Y9k6k3D{1@$;aOL>^)B97gcVekk
z3vQ$Sm!W&S0o@~lv7vzXGveHZ8ixXM>D;-Q^XFS{HU$5+dAMMpBr9y)Jw#T3Tv|99
zZ2dM}nLSmXz1si$v@}}pj$Rh?6uRu><;&C_+n~=}!d&Tv4L=0SoJF$bO1Uo8s`Mo#
zC8McY7U_}|hlEgZrfL;10lXAyJlY#mhcs&Nh6-kmWpVD}n%T+KSR}0Lt|d}OXSTm1
z5$+DSWau-~vrSU8jkun4^9{!nyu%|Ynxslb$mAZc5%u{(-7&l?8C=w%Yua{D{0zjG
znba|5VHD(B6Fik5bxi2FWGhXf?Lt5)QpB|il{mj~*{F;qQ!{JhzuRhEEry4WP9~mc
zoxd>syKnu?aab=u{<6u|EdT9E|KA*^cedMJa&%s at FDmie4Le~8H`6t<R)4zno$I;-
z)&P{sQ%`ecX6N5u*E5%2o`JP#+X#03bo6u99<NTb+jfl8>V<ZNugPuNbwrnoD$ZPc
zDou%s65F0{)clWUQ8`HO{SbQ<?W{m^&;<`#M&k}VI$cXjHLVgy5imUZIK*~D42RWZ
zx at ctNi80bRdmQHB(@#JBr_W#j%tav<-8^zU@%<c6wcga at y0mrj@+IlB^2Ef<&bj6#
zF;K^-WM^MZOy*h-=g|M6EVg|-<ycJv7`LSFId-KGvlx$UZrJN^MHQApH;>n<@mPS@
zd9AEEY!ZVio5|9!&J_B2O at l?a&>Ae7hG7P{%M1ie<KTVUc(G@**X>pkm5uxpOOwf^
z$ur at hn5u+jS<mZ!*<FOyIE4}JNJLZs&*NFK_ih``-W=>#-EQw<*S7MohUb$@KkW~7
z%Pw8_r*sI(`8v)410d|e2UIQztc}_`ONI_ at Ij!;&W?*9upXq5X at 3=HaQ|&BGH4mSf
zOz?BX6uznj%Vyyq&$V`9Mqz9dw$SD);HS3b;+V`Ud3*soIaQa`1>6LJBj7wcHE$0`
zAU#UJ^R@%K+XK9AKQOvuG*?Py4V&T|iJJgpAQQ;0ny{V#e55HOl$Ifo`A at kn14$sc
z4fP$=N)^z8U2mt)Hgk>ECF~lFoq2y}9v=(5v{|3z&rM$9AO7*Y1c!Q5&x=RIll-wm
zhsJWbCvv&be10^S<3st5#%610E^k?Lb1(>6XThaT-zc*PZRo<GL*hx0$e|k<)10;%
z6FMBB6e;MzkVb9!Uv>0=csi6;;-#9)8O2rSNOhYP68mMbf3D@{@3eM8^=iE>B>c-_
z-#RzP?-VI<S8<x3&RN!kePTZ-##<lCLzvP at G1`caW`WtR1`fLeIO<9ELH0HFC+r*S
zzq7w!f5k4bzhnQvu5g)a+y?;};c?!{yLpxuc!}5eN<PBZ^PBiMzlCq-JNf$<3t901
zbOTI2h}gJ>&W2RY7PLCg#Q_WyNb=TjF`JUK<&u^qW4bT`HeQPNiT#KKwMeTh=e0t1
zxn$A<P<Kao%2fh6EnleNQYBmH<M|4(1~8*2EC=LSDPF_84 at d<vp;91*ok?@PP^%Cz
z7Zr?(0J%59<0X>+C0qfIP;u)B&!b#o1COZEmZO(fa!9428qhJPWuYgS*?6r~OG&lm
zQYl|hoV)1>beA|+VrCgn<K9Z#jFoDIC at 5oMK`5oT*3XGn`z;HPic^AiNmR8{?+Rxp
z;<4D*tE0MUbZLg(>lx+CqfsrYX__%12Yen%Xu75wnP^7Cp-WTs<%^MHsETJ%M2qUt
z)luzjqiP_h%h00Wk*c}es4vgMK+&Q`)FoG=T?30XIiza8ndpee`ft+}m544L)$p($
z)lw%bh1`g~98ap5sAhEGvJq8!bwleiOntN(-_Vs#g}d}lrK~E7;nuWodOaSW$L;2M
zJRfbH(~#^n46XHbRaN;1qXxu2ii`t_ib{BVfz|_f)~&c)sta1(=XAAolO##}+iI&}
z7#Xe0>{7K~mSx$6LTgb|?Jn`}aSn5e!xWQcMaGkgqG$k2TEB|75Lv_RcGD(Jaeqeb
z_9==drmXGiGITTAr7nBF(uMk|MpW0NFqO%ma-|m=s-{)(7C<lQb+>i7y6A=LQGDHq
z5?Qpg)|H8NjRks=+Ik}z4F-cI?)NInoSKbA?;dpFo at jMFHF1}#Z?%7{E1K!TQ}h9i
zAm<$&YFE at mk9DmzOwPUCYQ_(n2C9`TNhT`cMw`hf8s6x3n|f46JrtBlH5R9-t3_$T
z0k_AaqoEBP6~pl3-cX{m6R%M<!$cu8PXM22)L5 at 2J9n)CkqGVy(jy*^hc-X at Y8dVA
zb-7$_Y#IsxJO8Sj_(k+j59mAwzB2{BL;719TIe8rMeE?F0ESK$8dM2 at +GKkGR}|=W
zTcW!h9@);X;r3D))3z=8<9IG!=atntv-{+hKRCIimh(mo_ZMCP0)B?S7slP^A8x$^
zV=djkR-F7sZOcg`ZY-yqbfnwN)wW3G<J!{LihF-+#l4Z^av&1t3LZZ5%3-n%KYvWz
z$^GKwuE at PB0?C*X5ESFFrP^`iK))x<kaQ;lI$SR_YykSe>ji!ZvrV(b9e4m~Pi8?N
zP?hPOJ6{dN#@F?~+OTrx=qNIzsfnFdEHE<Cziv7)J#E~Mge9`5Pk0BL;}?No`oMAN
zEtOIn;xOBQO3(oMa*<#{YrM%qup+h!PcPxtB!7D0#Up85gP(2$zPVfGWwy{dt`_$y
zj9V)SXafLmzK;_u0KQ8oD52kUdfhP^BMTqeA at ZrF6=0tgx(|<u?d@>bXY`~GtzG+}
zHESNlJ{;@}^ccSIkKXR-`5&KK(`>Hc at 9*jP(QHqTG<3}o_k=sr$V_(-jn?)y3F*^4
zhBp$4r+dT)MtLOSHSS%r=69OS-&sSSwX_rO#iJc*ye=Vb6}k`~M0<V>`V6#7Gd%|h
z>*rr1 at SgM}d)%U>ZNCX=AC=O0b7lrVX^Qqu^nKg5S48hK8EhUx2?C01kZ%wlsC(g~
zo&%Lq{qosb>+d|3`Wvp{+S%%`G>Tknq;j at Oxg&q~(s1=`ZP?bc{tR=b55Cq_u-Hc7
zKiw&M>sQ%F*>A9C*(ca1*{5L#<?U~cthsp1qFp=|#ncCLx042NHcc($VdK>>abV*S
z2#C%pK<|h^$AAh3T`Hp)5c4HaKwp#UA+qsMrjW-aO(kmdtyN(p!f+&7WqLboahQ%G
z*?#W&<8mO|UJb0;73k1`S-XRYKu1thLn;rsRmG*6ZbkKXK*&WG^Nt7rF&+ws710~{
z9N(S$O_v(!;9LoZL%j7i<$S^y1(}YZ*{y(OYF;y_yQ7dr9e!1Do2m;SV2I-dTCl^_
zdW)WDO<di-EkzQkSUl(rBto+6R#mqo2UW at CkE-58$PM}9_jd!eQ{9j!-wJoDvg9%&
zk$YNa`8HDUIyhA0usaelUD9&WHp3cd$VyM#8;r+NiHIa=kY%8#b^HAgS>VZDHR=b&
zpv<fE#LZ%7Ym4d?j<I$Hx*7TDGU)Xc at S8)Ug0=+5K_*+V;#bpEktVCXQq at Y`=(Lgv
zcq?B+I$mw3W9UnfeQPsXh<tDZB$`?~5MC18x|ouQno*9#k@~*42yuDqGsEH{lC}M7
z%i%Z at xJ^1awSE0vxlNnOz2zJq?>2Rw=fAOjPmVvZy|=`9j&Cgck(I=p at nO!`<JJwd
zrUM*j0OR*&Xqb1wBmE$8Ea>oQ%p#tyrE|pGf#<-TS*iUir5DmHETDNQ(SmLCTFVa=
zzV)&UOD-%gf7gfB?_P7O)Mx3roZh-%Jz5KgG5Y at vcED{E%<~^$Or+R4L_q)yffN+@
z44_R+<9I*MK$paP7A=Tbn5&wLxJk1eMs77;Q8hDWpXBMZTB>u!iZ9~O39h>(U&G_#
z4he?64UP5ljc0yI50VLy3K*e-_Z<uwffPZDL7ktIdBBTVqv`&|0S?_m!SpsfZZ3HT
zT9cTOI%c$_`aJO%_p5F%_i4Dn6N!8GJbu?*>x<)kQuvM$vs2Jhi}iXDJG`hfy5{$}
z%e~cY$Xt>mF1H&>!A1k%Ja?;p$)#>}OUi(xt<k)=K?=&MYDv;cp9?qmJd&)e(ePaB
z2kZCj`Q<%*zzl$E6fn2`60$jnNS8Du;0laL78;COgXTb18!Ti7D+8q(Fr#>_qJg;u
zxSAi~)mkjYDZQN289`&t1r7Gb)eGO`{F}6W at rz%aQ54-h;$Gxl<EqQDq`OmYzwFmi
z%9sl}@fvaAt58*u<<{x4B27)hjGvoca`2Ud2VY6aZvB`MG>)OEICmREhMQ}~kY_%-
z$|al|8ts81qHb4ZR08P15=7?=LR!_~k&MIE!1#c2WT&(6NnSm}6^N-q+|(-A73Mn6
zJa?wEH#YtFbSxV=FnJ)-8`x1yu3YBr^^L3>@%3s;i%Yee_ujSt&l?XOIl}*F(}4q<
z{3EyDKB8APZL0W}uIyUgrS}wzJ$|#h+w^wyFO@!U_h*aCJ}WRT!nSQ$8UU_TBv}h7
zWJ8Mr&2ph|rigAR=d~({87Qx0zX8OrF7!Web8=7Zq0c^4`(t->V7X5UB;M<mT=3*v
zi^mjedxma(=%HJO_Ka|EVzEcpqn7M_)&pqX4=lD_7UH#Q5R3Fa;1-7vS#%uHM2PN_
z32L`llfb%q?J1E_>1al&V7avI^MM>C*FwIM6_XGt+mi*=kCY+d`psvdt(pMCpbeD?
zqZ$-79faF2Udq;l`Ubx;VI(tpZZ at Zj9Ulusp|;ac^J(7J=lE^{c}y$d^#+>ACE))i
zLeK<cbJV`gd19_Hok$>z0a!Lbi-+ at me}0<i-Xk!oTe0`4e(f^QHehhx0FexMlO|5!
zG?*r$*yRnc=GOw|ZHCtu2>85TZ#0?!Sm-0h9^uMRg9H{75O at N`exMc<7a`gTZ9+a;
zI~D|uBrxPsNQQc$j*sVZBi&1q$tAb7y%c~9XBzy?T+V;aT+)qe{Ln&>t=@W`zqj=a
z;FYEG<B5>78(|q=Wq%Aw^ylnV_8NPg{Vn at G`w^y;!aZE)As*!&yodMl#k|ai_$t1J
zkMf)OX2eSEpvcdEhe(DBn1#@US_boa0iHqr4!|tG7=}TkxBz$}r<!Hur$8D1Prw+@
zb|&Jn<+uLKFh(q#-1{gD;umsR0yES>7|VXI*J}}mv6#?{KLxb$6VQt(sDPTf0KK>w
zX7n}ah3xue$SnRgZv_`%82^BQ>Ef~sWznUP^{v3K^=kk#f&eo@&IbHKPhZ6^76FI2
z0e)eq0>8*Cxr$%7dal7Q3_=s=a}~c(M+JTnfcC7uTl_)~IQRuHlSN%?^<Y<iE!u69
zuUk#)Tm>5ALIny0UT8or6pz>I63E380a8&pqhSNNeryCm0J-o1zzB48by4Yn$f#OW
zmN at uQz(bG*@QYCu_(cv^L+FG6x`sBwnpOZ5A`QTU28RYB0efxRWG1*n5>nrmjlzzr
zz(xgXj1agi1z-VFCM$>#Wine99%u8`<nh6Le(?CD1wi at IVC#H)2k$CAh+8B6Iz;=O
z^E=xIX=CgfY{D?~4i<Kh4a~%NpCps*1;5VSsaPx(Yi=8BG_B at 18K2Nk`9<W#Qu5iI
z(}+%*1oGUD>v$G6;V5i*fg{_|FEz8^xMWE16dbt<kO9?ebKG=jvgtK8Z#KM5F!J}<
zQFo2mhH$@}<`)9K+{ouga>V2x_5~)%b!R3M2`3;<yq)muwok?<yzT|)QFUmhq?OuA
zJPH6A9yj4EY##|OaGE+BN%D+{VJum7c{L(+2*9W9j%SY^efH?eB}?E<Ub6C3&YGFA
za%Z8TcXoy~-RD+v at N&ZwkElH=@wj=$->HtPoqo$X&J+=IQY`XF?vX at qrwa~7?K3%a
z$^-%5WS>6^Id!MN;bEmfc@}-q#@|t{EXt9k_8Z|g;{HVeoFB4gtnTQ{*95x0TkQGi
z#-$5=uf1%UIi*iv{I)J(`*5gV2w`Cnj3dH5+R{+iJUBO<tpa&ZTicgGBeF5wx->og
z$?4|I81EUI85{fivCm^0OH9w=%ESEPG!lGl8aL!}GcyRz6uag$K8RtPhD<gf7irur
z^v~GQky(tH^@zhJ56um|GdYy_U)y7|z$+tMEI*rvhCg=iy<_?OyhCR6+Ed#<GdOVr
z|IBrn3w^9XL_`%~lOifg#=HUMC_)-2!ofZh!4J3uWf|9ShENN-5tewhMiC^j-gN_u
zgz~#&!;-f4yK<=>T!i4~tSR*06ZK*|7&e>HNH8u<>E-oX^IL>^y}mdxYRoIx6FUOE
zN<5hf#)=uuR<T{hRJh<?@xfnO?J0!ebZ(dZJJQ&^pHLuGCeSJxP4E$l$VGBAU%JF+
zK1|Uv_~;Wen3 at Z4NsRpKP)R&~V>t3gP~@enC?wIfb-$B{A%e3j1YOu1OfFEFX)cv$
z2hBGrQ!29}O_NusdK<Ubi%n at Ny&{unARLhLv1=sC8?9n0F`h^?P;-izd4o}`8^v0i
zwNSw<_ at 96NJcU}fE+E_*Z9_3PUqNiZ5TT*uH>!cVlAmeXdg2M|iBr}o{Jz>wAP3L5
zNj3nAng%LLal?d)7J*ZgseMYOa9kC#6?l$HO4`)moP at Ip+!}3NgZmraZX3#MADeKu
zwtua!@`(Bl->pVklZcXT6jLH_soA8Ml4etSxP2p at NJP}u*>_X~RgYO#DninOKBC?q
zNBrp&W~+#^g|Y5fBLv=cOXxH*jKHxn1lAEgB)~q%vT{5|h-<lDrjQQsSc~AfRJ{mE
zxz<ejJubK5RbxRpsPKb|NAsD!NCG~QKMNUJBB%NT5w8;WKIPWE(p0X~6^BXi71gV0
z{-7t^>6hg7px_MwYXexe#jX2_DLo!Gw1B3)7&6pO!D~MxVm0~^Yr5^a@&{zt*c!0p
z8<x at zN&#-s4oJcD6IdmbDty77vhx*5)b){E?$nQ!`n9Y-Ei0iQ3>G;n<$KZvqXXz$
zwosU_4}iFl+<3xD+ at SoeBe1t)T`tY-3%Wgq)RD==^;p!as_XK3nu|0hpA~%rXE@{@
z0jUf620+Zho<SfQfw1#6MxYI9a-&|MNZxjzBytI#B-uTZOI+;^O4{Ag+1u`m_H(F<
zw{N7#?T*kA|K7@)X#KU+%`?(-h&>_Ha2eJBHQ<x}Fnfxf$2yi*;g9|<JkUw3XIaI^
z_(?>1o#xN+-{M%6A;)TQwV(|G{U+c5QKf1Dh)uRcKy`|%1waTj4L1z}%O2E9 at L>YL
z2GET-HXu2`Ok=<r2A6sUGvM}>x~qcwe^#1=k6)!p#Q;h$u+*O&0L>coifc&{F89-l
z`4dRGMKOVwUQhGgRQ+0--O at ExuPv;4Ni^q;$_cQ4zB$1SF{H1pI!q-MRhP3%acI~6
zZNFcOMBV-#zYDxq@|lPQg2L`es(|YNwo9 at Uh(<iPt^>=F^tg#hAbAv+>@vA{Wv+Vt
zK_lq*;Q`_Dg*7iV{XTaz;`XNitiy`(M>}-fOjIQh^a-l;)|B7y;5yekqJB7wy$HvJ
zZ9!CJRr7j$KA+d4sW_uNN#RW at ttbtwifalBSdR(|FQHRds?EaEx<v6byRh(i&}&?%
z1r^mUib5qp0~jcY(*RCU?W&*waD#yspt?{CfCPTj1Uk$i-K&a%5*f6?GtiLHa$Gb5
z3X3*yT2{1yj`o!T_M5qmRzPt(qITm_D at Y*g^9MC$K@$K*<<b+X8VdwEy<Q!y#r?od
z6m_e_(M~E?J-l%BnvScAssvp=yow41nlS%lDX6UenTdGee70$LwV&sC9&A4^`Cvi+
z>;(X#{I6OK%^OtO{MeT3w$1deWXHRb>1`=M5}l;SPnG8j1PB(K`~+G4?^D*TzoA@)
zIxj7h%=0?ayOPbS*KoI`v#l}x6!{$X1pV5)y5zHE`~OWwpM)j-Z>>)R)I{zV(I?t#
z*?xi at qFif-oSsA|@(8{<LJ@>sXverlu-^AhXxe}$G$^u;Ckrm*I+tT932qhgx+JA2
zd at UM0E)v`?5Zju%T!KtTuvdPygb=Q34I*BuQsft;e60#poiO$C%*a{cM#8g8Umy|S
zbGsC;8ut6cz_wg&oFghd;6}iVb19_jA?K2WsV^?72Eo$Z($w5^{j%^- at jpy?Bb!@u
zoU5wh5Bmcymq+(|WF>$T;B|@zf=BmIimocM2Xf5ia<1Yjx~vX?X!jB at 1Hw`shn_s@
ztf%Y68s|e;&%6+yGW%pZBI7!M3Odct-An{<wIgQ;+ybnX(5;T)ZFR!8E?U61{_*E-
zwAQz+Z`ti8u(8=~!&nD0kBtrgVoirta-DYTwb$2<ibxi_#RSR(a~3wj{3c>W2?e7K
zUk7o)5msEOGHK=TMQkU1^4FZy8#cOkUABFXaDI^A&Bpgk;0ZS7gEbWLwaB9F{OQBu
z0(yNd$@2pKqHL`AMH$)vSfeTM#Ytfa*EemNm^i0`ljllQMEX#92y4XZKX`q{$FV-w
zdW7S8E^(gf0PGPz+di?&wFRXi7ZsMeLBSO(uFL_%ut7P~qJsvOpe7}(x4_TfVqr|F
zk{?`+8HH~NYa3Qd<k6x)YqH{-JObZSLJR6HnZhl&vdH+PHxvy)Md84jxukfM&a*%a
zTW`Xemqy`OQa!56<5MP}3;^?{O^@^$>+k?9Nc at mkXDl@XP`hw(CxHN{o9)wVx2<iP
zQ^eBz%%C|z%X=K;_S#0J at h!rF?Ix$wISg|fVL%(tBB)X{YYP#(7T<=2JB`+~XkNQ%
zDR=kvO`D(w at 1XY8;5+<VM(a41B1U5nn86TYsldBsFd{6eKv*obc?gY4j>FY($=Eyc
ze37w%mCzA#^&u$LtmQB=39N`~eJ=UeU8=kj8&-quRNTL=8qcT(Vj<;cv~%_PXP$iW
zGf#5GK0Yah<*CE=t*y&AYU+`bislwO9#%E^<WWUyy*c;2W5 at pb7}k^PlgD14L{K)0
ziM8!7v6sMiLRi-jN5%mB+6n at O6yd}a{<&pP^-jSb!3W`o_y!83X<_bfy+fNcDxGr~
zu5*ZP;Sajp+18hS3m^EQY3<Vt=+b(kHll()yVmzdrn2J;v=@|USO7!cG|+glig1z^
zyH4Vb|C4s=B-XQPe>m~*MC-!D1b)(}rna8IJt{|yHKp|gYKsAM64M2tISA2iZwvd1
zyy63bTdY95Gm8*jZO1{u1HGIUI*FZd^@gx6#<u8dRT;bk5djG1r7$-D?K!j1r)tm0
zF2!xA&lu{jyOo`)25niUE|XuV|NWD^{N$6Z$-14A!kTjQB>Jay*{vxjkBA-Bi-+-y
zq^XCeWc1UV at z=-j`QF@{uOFLyojOXs(tYiEp#nnvLMd9YeCeG3{LV%L|42YfEosC3
z^q&QG`vWU0gfQa`-mLy*wfdJY at zd$Y)9J^BPhviHP)Gk$Os8O$g`7QGuvA&Z=r!~C
z24L<+K7V=h=EmmD{9=7G)^cOL@@9O1{cXp)UPNCL=8d=6UHG}_#x!1LuXv%c#;;WQ
zP3-H^Er>Hjo0FLx#|~2?o5{vZ3nvCI<O_6O$P{2k_Cu^!O9;^}RBM2(DC7cGbDWM8
zWR at 3EEpS8Pt~=CFKvkqj7wjY*u~{AuqHI%ULJy5BDi^$Ny~9i)Xcr4WIh;p|TlO2V
zK%%p at SmS|UyhBwBF-?Z6XiKO&918Lzu{TBKu80YluDgA@;)e`3BV??)Tn3hWC~h~R
zGJ;445L%|21-E8|x|T>-aYk*c0jv1F^ni%V4BBm*MGQ#EM8J0mSTglVHgQqOuiWy5
z*KdD>doFq&x&8J>+^<U~UN3H0nQy)AWbprm3)j+g0o at cdBiTwf2iK^}5zsB9LAUZR
zpw{|lLAVHd;&J{Ah&_HS-Pf<D>9J`7<}|n<tblGU1iGb!c>Ef=uYY8|)KpwoD?r7(
zT5lItwNdOV@#%h!WgiBYQP_AIG)*ewe2rTHYJ?)+>%7FiAc%@GVk|r3w40D+^uLI@
z$YS7-{DR8Zj<tZh>y}Uet81)iHcAI<i3xtu>J4DUjfoHfn6V^RXsc5o3a#t1*9Hc_
z{b-dXMJzZzv-YZ at xQVD3Onj2iSh=88YLx<(6J!^Lp{&g1c8<d<vvX%IcXoRE+J&%<
zkz68Q-)Rkw)K5)VJL~yGZWD))SSZ_Ue~}%ROKpak7ZS6N*q|LP8_MEeB=Va!J<)9D
zHg7&9(oz_2otz#Ao12^)zeImnK<iA%2W7A8Ad2)K4QXLd2nCybOo;5PWlI{EEMyKM
zc<lsMz#`E3wR#<krJS9e#H!bCeDtH=DA((EzV_N{e29*;r#g^bNdG%ACgcYgI_c?n
z5%hF&IAYOltx(-IxPf~<p?CJ`|2ft%xWT)nz9lA&ZW!!{e?sr=)IZ at F8%)HujJyYb
zVMMV(_J5tw8mO>s8-USOu<R at puZ3#qN*aHLfmJVO8_hYW;3^ii(aOsve`gLWoG2LO
zYJ8Dq``_l{#Q}qB;3C9B2(85!GT_`XORIRbf^0&Y2}&<j?6#O2?CzFpN-z-bz}g0-
zg4iO7S6xb^*XK`lZ(W6kp*FKRJM(f3i at Ed=0I8)R8O%hJ;i+^<o?v$<9O>=s`oYST
zV!Ztc`eqqwMk`T=@xKKk<{fTQglEwr%$(zRQUH4+Ov8Y3Lzl``tY}%_pK7mUd!aXx
z$s~Ha`~2X2$GiLbx_jLLAV986;-9nrP{^N!*YpkYoZ<}2Z+D61Ytpjbj_sq{J9<<5
z`%G(jF_7AS+x}Fq+l+U1cKR~gJF;2-(hShbaJ^g)iybmTzOIDZ6sy;$-|-(EUqM}l
zfYFk#CC=mH=d34q#QMs43(N1J9*KUibvNP%#0}u*F4QzEaU#DrDLb_G7Jur}x-fg;
z`RBRz)~;RY_D?LAo|(a)V_5AhT%$1u&nA0*{$HGu at ZSlxi@h6hrFI%#fA$}ow2U?3
zuQ_RygvXq;!h(FAlUA9V?}H5EE{ddEfz3{H at Wnfvw1oFQ;G|`EH2$NLcCj#*oV3Dv
zc#o4-L4P~^tn~j>55b;02yg2F{6|#}d`x>0o!5i^%o>2+I0TPV5AHdLxX%0V-G_7f
zvh~L%AG+`0{sSj^7VllsV+{-r6?-NR?z`{4eZ?X!--a@*$3JQ9#T$-d)fT&L^ZJc@
zj~zwoy&$q5g*}Wv&bkk$`}RL at _--UNh+9vH<9)bepD08>iqV5g_rM%KiUJ<Qb{N+h
zD4d;dp{Nv0IEa0_&}_r8qbD{TyKn!#9;<(#XGPDgM^79)ad=;25NXR=HaNJ9ip*|6
zl+E8twV+zxkC##{dQcQ<6DksYdvL?P`|dw@>}b!xz+nHtzyRg^<ccGtk3LsEjAGvC
zGlii`;3<KyDps?(5d(&BRDozx$a at g+U}3Cpi*l34;A80E39NMM;)~#I=;kTj!_z#2
zb#J|hbk1Y-+hV?iFNJzv<jXj%g&*L9+`^i;GOzF|R>lqSVZH)}z$(5PY;^>&Wo!95
ztd$#u-(mw+%-zg4@=aJbx0%0(Z^7!ht$Z7QFV at iQ;J5PIu##?q-_Gyg at 8i4poqRXn
z!|&pE^Y`<;yutVJd-#5SfFI<C_`UovKf;glV|<by=lAjZ`3e32pHlG`gp&sb?So|>
z2JA!0K9uc4#XeN+L(M)6*@t1xrZV6h2c4tk981oz>>Ml3vFaRa&T+^&I`k}up5 at T9
z9D0^R&vNKl4n51EXF2pNho0roD>?K^4!x2?ujJ4xIrLx>iu#lsdL at Tm$)Q(r=#?FM
zWrtqbp;vb3l^uFzhhEvCS9a)?9eP;tE8bUe=v5qg6^CBMp;vL}RUCQ<=C_}7=v5qg
z6^CBcp;vY2RULX&hhEj8S9R!B9eVKA2)b2=Ue%#jbLiC^dNqe$&7oIw=)nXM&(|D!
zHHTi!p;vS04LS6N9C||zy&;F*kV9|Cp*Q5v8*=CkIrN4cdczLAVTazZLvPrjH|)?G
zcIXW|^oAXJ!w$XSVftfE%!+}5c4Dxdu-b`IJ5g>YD(ytIov5`FL+wPH@?e|tV4Lz_
moAO|r@?e|tV4Lz_)#g_m|Jq1gjMM3>Z;pMLjtl>@^Zx)|S}L~y

literal 0
HcmV?d00001

diff --git a/modules/gui/qt/pixmaps/makeIconFont.py b/modules/gui/qt/pixmaps/makeIconFont.py
new file mode 100755
index 0000000000..8b0b1bafc7
--- /dev/null
+++ b/modules/gui/qt/pixmaps/makeIconFont.py
@@ -0,0 +1,110 @@
+#! /usr/bin/env python2
+# -*- coding: utf-8 -*-
+import sys
+import json
+import fontforge
+import six
+from jinja2 import Template
+
+DOC= """
+tranform a batch of SVG to a font usable in QML. a QML object is generated to serve as an index
+
+known issues:
+
+  - SVG should not have overlapping
+  - SVG should have a viewbox equal to the size of the SVG, ie:
+         <svg width="48" height="48" viewBox="0 0 48 48">
+
+Input files must respect the format described by CONFIG_SCHEMA
+"""
+
+CONFIG_SCHEMA = {
+    "type": "object",
+    "properties": {
+        "qml_name": { "type" : "string", "description" : "name of the generated QML class {{qml_name}}.qml" },
+	"qml_file_prefix": { "type" : "string", "description" : "import path within QML" },
+	"font_file": { "type" : "string", "description" : "output font file" },
+	"font_name": { "type" : "string", "description": "font family name" },
+	"glyphs" : {
+            "type" : "array",
+            "items" : {
+                "type": "object",
+                "properties" : {
+                    "key" : { "type" : "string", "description": "keyword of the glyph, should be unique within the list" },
+                    "path" : { "type" : "string", "description" : "path of the SVG to use for glyph" },
+                    "charcode" : { "type" : "string", "description": "utf8 code" },
+                },
+                "required": ["key", "path"]
+            }
+        }
+    },
+    "required": ["glyphs", "qml_name", "font_name", "font_file", "qml_file_prefix"]
+}
+
+
+QML_TEMPLATE=u"""
+/**
+ * This file was generated by makeIconFont.py, please do not edit by hand
+ */
+pragma Singleton
+import QtQuick 2.0
+
+Item {
+    FontLoader {
+        source: "{{qml_file_prefix}}{{font_file}}"
+    }
+
+    property string fontFamily: "{{font_name}}"
+
+    // Icons
+{% for f in glyphs %}    property string {{f.key}} : "{{f.charcode}}"
+{% endfor %}
+}
+"""
+
+UTF8_AREA = 0xE000
+
+def genQml(data):
+    template = Template(QML_TEMPLATE)
+    qmlout = template.render(**data)
+    with open(data["qml_name"], "w+") as fd:
+        fd.write(qmlout)
+
+def validateModel(model):
+    try:
+        import jsonschema
+    except ImportError:
+        return True
+
+    jsonschema.validate(model, CONFIG_SCHEMA)
+    return True
+
+def main(model_fd):
+    data = json.load(model_fd)
+    if not data:
+        return
+
+    validateModel(data)
+
+    font = fontforge.font()
+    font.familyname = data["font_name"]
+    font.fontname = data["font_name"]
+    font.design_size = 1000.0
+    for i, glyph in enumerate(data["glyphs"]):
+        charcode = UTF8_AREA + i
+        c = font.createChar(charcode)
+        glyph["charcode"]  = "\\u{:x}".format(charcode)
+        c.importOutlines(glyph["path"])
+        #scale glyph to fit between 200 (base line) and 800 (x 0.6) and center it horizontally around 0
+        c.transform((0.6, 0.0, 0.0, 0.6, -300.0, 200.0))
+        c.vwidth = 1000
+    font.generate(data["font_file"])
+    genQml(data)
+
+if __name__ == "__main__":
+    import argparse
+    parser = argparse.ArgumentParser(description="generate an icon font for QML from SVG")
+    parser.add_argument("model", metavar="model",type=argparse.FileType("r"), default=sys.stdin,
+                        help="the input model")
+    args = parser.parse_args()
+    main(args.model)
-- 
2.19.1



More information about the vlc-devel mailing list