From d0997ef0943f0dcea5ee5754475e5b192a4aa6c9 Mon Sep 17 00:00:00 2001 From: Marcus Date: Thu, 25 Jun 2015 16:00:03 +0200 Subject: [PATCH] added initial version of the column chart widget --- src/GoogleCharts/GoogleColumnChart.xml | 93 ++++++ src/GoogleCharts/widget/GoogleColumnChart.js | 329 +++++++++++++++++++ src/package.xml | 1 + test/Test.mpr | Bin 2487296 -> 2520064 bytes test/widgets/GoogleCharts.mpk | Bin 123212 -> 132391 bytes 5 files changed, 423 insertions(+) create mode 100644 src/GoogleCharts/GoogleColumnChart.xml create mode 100644 src/GoogleCharts/widget/GoogleColumnChart.js diff --git a/src/GoogleCharts/GoogleColumnChart.xml b/src/GoogleCharts/GoogleColumnChart.xml new file mode 100644 index 0000000..ab73715 --- /dev/null +++ b/src/GoogleCharts/GoogleColumnChart.xml @@ -0,0 +1,93 @@ + + + Google Column Chart + A column chart is a vertical bar chart rendered in the browser using SVG or VML, whichever is appropriate for the user's browser. Like all Google charts, column charts display tooltips when the user hovers over the data. For a horizontal version of this chart, see the bar chart. + + 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 + + + + Title + Appearance + The title of the chart. + + + Background Color + Appearance + The background color for the main area of the chart. + + + Colors + Appearance + The colors to use for the chart elements. An array of strings, where each element is an HTML color string. + + + Enable Interactivity + Behavior + Whether the chart throws user-based events or reacts to user interaction. + + + Force Inline Frame + Behavior + Draws the chart inside an inline frame. + + + Legend + Appearance + A Javascript object with members to configure various aspects of the legend. + + + Tooltip + Appearance + A Javascript object with members to configure various tooltip elements. + + + Area Opacity + Appearance + The transparency of visible data, with 1.0 being completely opaque and 0.0 fully transparent. + + + Use Animation + Animation + Enable animations for this chart. + + + Startup + Animation + Determines if the chart will animate on the initial draw. If true, the chart will start at the baseline and animate to its final state. + + + Duration + Animation + The duration of the animation, in milliseconds. + + + Easing + Animation + The easing function applied to the animation. + + linear + in + out + inAndOut + + + + JSON + Data Source + The data source of the chart. + + + + + + + + diff --git a/src/GoogleCharts/widget/GoogleColumnChart.js b/src/GoogleCharts/widget/GoogleColumnChart.js new file mode 100644 index 0000000..7b77c71 --- /dev/null +++ b/src/GoogleCharts/widget/GoogleColumnChart.js @@ -0,0 +1,329 @@ +/*jslint white:true, nomen:true, plusplus:true, vars:true */ +/*jshint browser:true */ +/*global mx, define, require, browser, devel, console, google */ +/*mendix */ +/* + GoogleColumnChart + ======================== + + @file : GoogleColumnChart.js + @version : 1.0 + @author : Marcus Groen + @date : Fri, 19 Jun 2015 12:52:36 GMT + @copyright : Incentro + @license : Apache 2 + + Documentation + ======================== + A column chart is a vertical bar chart rendered in the browser using SVG or VML, whichever is appropriate for the user's browser. Like all Google charts, column charts display tooltips when the user hovers over the data. For a horizontal version of this chart, see the bar chart. + Google charts are powerful, simple to use, and free. +*/ + +// Required module list. Remove unnecessary modules, you can always get them back from the boilerplate. +define([ + 'dojo/_base/declare', 'mxui/widget/_WidgetBase', 'dijit/_TemplatedMixin', + 'mxui/dom', 'dojo/dom', 'dojo/query', 'dojo/dom-prop', 'dojo/dom-geometry', 'dojo/dom-class', 'dojo/dom-style', 'dojo/dom-construct', 'dojo/_base/array', 'dojo/_base/lang', 'dojo/html', 'dojo/_base/event', + 'GoogleCharts/lib/jquery-1.11.2', 'dojo/text!GoogleCharts/widget/template/GoogleChart.html' +], function (declare, _WidgetBase, _TemplatedMixin, dom, dojoDom, domQuery, domProp, domGeom, domClass, domStyle, domConstruct, dojoArray, lang, html, event, _jQuery, widgetTemplate) { + 'use strict'; + + var $ = _jQuery.noConflict(true); + + // Declare widget's prototype. + return declare('GoogleCharts.widget.GoogleColumnChart', [_WidgetBase, _TemplatedMixin], { + + // _TemplatedMixin will create our dom node using this HTML template. + templateString: widgetTemplate, + + // Parameters configured in the Modeler. + title: "", + backgroundColor: "", + colors: "", + enableInteractivity: null, + forceIFrame: null, + legend: "", + tooltip: "", + dataOpacity: "", + animation: false, + animationStartup: false, + animationDuration: 0, + animationEasing: "", + jsonDataSource: "", + mfToExecute: "", + + // Internal variables. Non-primitives created in the prototype are shared between all widget instances. + _handles: null, + _contextObj: null, + _alertDiv: null, + _googleApiLoadScript: null, + _googleVisualization: null, + _startTime: null, + _chartWrapper: null, + _chartInitialized: false, + + // dojo.declare.constructor is called to construct the widget instance. Implement to initialize non-primitive properties. + constructor: function () { + this._handles = []; + if (!window._googleLoading || window._googleLoading === false) { + window._googleLoading = true; + this._googleApiLoadScript = dom.script({'src' : 'https://www.google.com/jsapi', 'id' : 'GoogleApiLoadScript'}); + document.getElementsByTagName('head')[0].appendChild(this._googleApiLoadScript); + } + }, + + // dijit._WidgetBase.postCreate is called after constructing the widget. Implement to do extra setup work. + postCreate: function () { + console.debug(this.id + '.postCreate'); + this._updateRendering(); + this._setupEvents(); + }, + + // mxui.widget._WidgetBase.update is called when context is changed or initialized. Implement to re-render and / or fetch data. + update: function (obj, callback) { + console.debug(this.id + '.update'); + + this._contextObj = obj; + this._resetSubscriptions(); + this._updateRendering(); + + if (typeof callback !== 'undefined') { + callback(); + } + }, + + // mxui.widget._WidgetBase.enable is called when the widget should enable editing. Implement to enable editing if widget is input widget. + enable: function () {}, + + // mxui.widget._WidgetBase.enable is called when the widget should disable editing. Implement to disable editing if widget is input widget. + disable: function () {}, + + // mxui.widget._WidgetBase.resize is called when the page's layout is recalculated. Implement to do sizing calculations. Prefer using CSS instead. + resize: function (box) { + if (this._chartWrapper !== null) { + // Reset width to be able to shrink till 250. + this._chartWrapper.setOption('width', 250); + this._chartWrapper.draw(); + // Set chart width to parent width. + var parentWidth = $('#' + this.id).parent().width(); + if (parentWidth > 250) { + this._chartWrapper.setOption('width', parentWidth); + this._chartWrapper.draw(); + } + } + }, + + // mxui.widget._WidgetBase.uninitialize is called when the widget is destroyed. Implement to do special tear-down work. + uninitialize: function () { + // Clean up listeners, helper objects, etc. There is no need to remove listeners added with this.connect / this.subscribe / this.own. + }, + + // Using Google ChartWrapper to draw the chart. + _drawChart: function (data) { + if (typeof data !== 'undefined' || data.trim() !== '') { + var options = $.extend({},{ + 'animation': (this.animation !== false) ? { + 'startup': this.animationStartup, + 'duration': this.animationDuration, + 'easing': (this.animationEasing !== '') ? this.animationEasing : undefined + } : undefined, + 'title': (this.title !== '') ? this.title : undefined, + 'backgroundColor': (this.backgroundColor !== '') ? this.backgroundColor : undefined, + 'colors': (this.colors !== '') ? this.colors : undefined, + 'dataOpacity': (this.dataOpacity !== '') ? this.dataOpacity : undefined, + 'enableInteractivity': (this.enableInteractivity !== null) ? this.enableInteractivity : undefined, + 'forceIFrame': (this.forceIFrame !== null) ? this.forceIFrame : undefined, + 'legend': (this.legend !== '') ? this.legend : undefined, + 'tooltip': (this.tooltip !== '') ? this.tooltip : undefined + }); + this._chartWrapper = new google.visualization.ChartWrapper({ + 'chartType': 'ColumnChart', + 'dataTable': data, + 'options': options, + 'containerId': this.id + }); + this._chartWrapper.draw(); + } else { + this._showError('No data for chart.'); + } + }, + + // Draw chart with JSON input. + _drawChartWithJson: function () { + var jsonString = this._contextObj ? this._contextObj.get(this.jsonDataSource) : ""; + var data = new google.visualization.DataTable(jsonString); + if (this._chartInitialized === true) { + this._chartWrapper.setDataTable(data); + this._chartWrapper.draw(); + } else { + this._drawChart(data); + this._chartInitialized = true; + } + }, + + // We want to stop events on a mobile device + _stopBubblingEventOnMobile: function (e) { + if (typeof document.ontouchstart !== 'undefined') { + event.stop(e); + } + }, + + // Attach events to HTML dom elements + _setupEvents: function () { + /* + this.connect(this.colorSelectNode, 'change', function (e) { + // Function from mendix object to set an attribute. + this._contextObj.set(this.backgroundColor, this.colorSelectNode.value); + }); + + this.connect(this.infoTextNode, 'click', function (e) { + + // Only on mobile stop event bubbling! + this._stopBubblingEventOnMobile(e); + + // If a microflow has been set execute the microflow on a click. + if (this.mfToExecute !== '') { + mx.data.action({ + params: { + applyto: 'selection', + actionname: this.mfToExecute, + guids: [this._contextObj.getGuid()] + }, + callback: function (obj) { + //TODO what to do when all is ok! + }, + error: lang.hitch(this, function (error) { + console.debug(this.id + ': An error occurred while executing microflow: ' + error.description); + }) + }, this); + } + + }); + */ + }, + + // Rerender the interface. + _updateRendering: function () { + // Draw or reload chart. + if (this._contextObj !== null) { + // Display widget dom node. + domStyle.set(this.domNode, 'display', 'block'); + if(!window._googleVisualization || window._googleVisualization === false) { + this._googleVisualization = lang.hitch(this, function () { + if (typeof google !== 'undefined') { + window._googleVisualization = true; + google.load('visualization', '1', { + 'callback': lang.hitch(this,function(){ + this._drawChartWithJson(); + }) + }); + } else { + var duration = new Date().getTime() - this._startTime; + if (duration > 5000) { + console.warn('Timeout loading Google API.'); + return; + } + setTimeout(this._googleVisualization,250); + } + }); + this._startTime = new Date().getTime(); + setTimeout(this._googleVisualization,100); + } else { + this._drawChartWithJson(); + } + } else { + // Hide widget dom node. + domStyle.set(this.domNode, 'display', 'none'); + } + + // Important to clear all validations! + this._clearValidations(); + }, + + // Handle validations. + _handleValidation: function (_validations) { + this._clearValidations(); + + var _validation = _validations[0], + _message = _validation.getReasonByAttribute(this.jsonDataSource); + + if (this.readOnly) { + _validation.removeAttribute(this.jsonDataSource); + } else { + if (_message) { + this._addValidation(_message); + _validation.removeAttribute(this.jsonDataSource); + } + } + }, + + // Clear validations. + _clearValidations: function () { + domConstruct.destroy(this._alertdiv); + this._alertdiv = null; + }, + + // Show an error message. + _showError: function (message) { + console.log('[' + this.id + '] ERROR ' + message); + if (this._alertDiv !== null) { + html.set(this._alertDiv, message); + return true; + } + this._alertDiv = domConstruct.create("div", { + 'class': 'alert alert-danger', + 'innerHTML': message + }); + domConstruct.place(this.domNode, this._alertdiv); + }, + + // Add a validation. + _addValidation: function (message) { + this._showError(message); + }, + + // Reset subscriptions. + _resetSubscriptions: function () { + var _objectHandle = null, + _attrHandle = null, + _validationHandle = null; + + // Release handles on previous object, if any. + if (this._handles) { + dojoArray.forEach(this._handles, function (handle, i) { + mx.data.unsubscribe(handle); + }); + this._handles = []; + } + + // When a mendix object exists create subscribtions. + if (this._contextObj) { + + _objectHandle = this.subscribe({ + guid: this._contextObj.getGuid(), + callback: lang.hitch(this, function (guid) { + this._updateRendering(); + }) + }); + + _attrHandle = this.subscribe({ + guid: this._contextObj.getGuid(), + attr: this.jsonDataSource, + callback: lang.hitch(this, function (guid, attr, attrValue) { + this._updateRendering(); + }) + }); + + _validationHandle = this.subscribe({ + guid: this._contextObj.getGuid(), + val: true, + callback: lang.hitch(this, this._handleValidation) + }); + + this._handles = [_objectHandle, _attrHandle, _validationHandle]; + } + } + }); +}); +require(['GoogleCharts/widget/GoogleColumnChart'], function () { + 'use strict'; +}); \ No newline at end of file diff --git a/src/package.xml b/src/package.xml index e6b24bd..d970f80 100644 --- a/src/package.xml +++ b/src/package.xml @@ -3,6 +3,7 @@ + diff --git a/test/Test.mpr b/test/Test.mpr index a28a715c4e6334ecc1c2053d4aedf200d93586cb..bd2e34a496f3dab9a7266f121a05d49063d16dd0 100644 GIT binary patch delta 9356 zcmeHN2~<odr>gL)ErweYLjKzCLYh6|7b3b9m<_{t7{ByH?-(UH`9ZeWLfCbN1fn z?0xp$-zD!lK=ZDzL`z-ma}b1F1EEC_B&5tY7|qF-7s}B>IaVmg3*|(i+^SG+T`0FH zl-ur>lN&y>_C!!myaar5)5Zq`o+obz=Ka+zK<+_x13p_AvGEQMBQUH1^gqh%MtwnB zgXAoRC4i=5OeB>P-(HDqR(zbfg@T$ErVkX0HG#H7(K?XqM$KhMH!__O3`tQEr#f%*a`Z#HccQ-=d$JrlCP&2E94 zz0pm8UqTyzY?+e+&_zz=EVTDi3}`(l2jE=8NR0OdIDs~T+I>tHc32Iw74Fd-aS%wE zAR=%CKLSJzOgYHID1!ZTHRF$iZFZC^$mLTs+Qjx>!DQfY|xJhi4b1$;>k7>1c&PnF$oPc{5l|xTp*&<;|CIGme8=Z+;+~ z(OlZko zPlHPHNB|F&xFeA9;6fwk_&rJjD3DQ9Uv~N(K?x4dW{PcqLp8%495D(EsAk5q<<55Y zC^{O{xY#A5-?6POc0vrCs}Tp_2r(Kodh;FFSP6d*^l{qcEW|sYwoL58Cei#IaE~7H zO!kZcjSqRQY)Xcx9-e0_PYNZFGB)TTkHtM^q6lIoiHkyn&=(QMIm26rmDzzG?A`+M*U1wtROLUS5GnM=kokeRmzM!(tCN z-pG6C+3zr?MQ?D3&ld<+e_i(1ZylsbTi5ky*)>^9nq+o2I*sb3p7Qsk67+|qc}?2O zSc*xinvy=!l7?JsdZ(4cT!m;5W9~&~iB*{2^r|+-{#17zfg6HU0yJ3A) ze}PYUSxWhM@4JD!5G+YCO^GZ#%gK&rNfbfK%A-o{GA-ZkEw2~Bz3{o8Y2{^M9`}OVAJ^oBt3l#~)Wo`A#h}gCzT6IEMM?@N!J{6xpsGL z_};&WJnw#aKOD4rQGGr1UhT(NS`W@0XS|F@p=lU76SN&?oH17~kn2r#6=vVh|E8B~ zP51%r;y7yeWZjl+T9H@EKjgYc-kUbE!~0ms1i^)9o*OFmO#V{rEr} z*cLwN{oV7_+_Y%nl@GsFW%f#o*q9!m`NvNsF|5p;>Vq0jOE6!I7}qXbS?s<9mw-A~ zJLYwDLZPJ-g5-z1E@-gnPXCj=jtk&eAiB-#E}W)MTlqn@F=6wnbiSc!RugEcU>w1j zVbtuvL5^AWyZU^QTvN`kv{JwGC5$wwMWprdavWd#uc`5QKDR|{TE{PG7inQ(d&ZK9 zt7GPe=7hS}ZyjTbH0GZl$*R`f%S$}8b#FO4@T&Gjkro7?ug(nI?H}9o2g&rft!Pmn zDl>Hy6fZ+&cep`zZn%{e9CbILtpAqxN`6jDG>hNY#uEtdU;aAGE!I1HGco_7CVpIq z`Etp;+@`8Zr6YG~GBi$=)dU!Pn^zjP_@K34%ptGvwN>ZAg|LI6P*MO=+(FXUSJGS` ze&-vvI-+<)?Q+Anm?U+UR*AU7&?4i2Xpkr+Kv)FOYOCnD>OG&G-xwwzh~U9UR)*lG9=enp5>u#KPALc*HtnPagB^&>4=n-GB zpvrw!#J&hqVhwoIS5rCZPH-gnn}17;$Z!S0Ly%b=1YH* zcm4os>x2O<%XEgYqKC#_{#grwtWGQ!220jYO;s)nTejkyaJ9Zx4{Gbg%K{Qq@_S*| zP9~JLeHPv7_tkX-4@Gi1h`8DB+U8AbG*R1g2W~JdcHYU^GC;U}s3<@>_G-kEwMma6 zqWAobGb2<4_h`sZR@1k|t+||*Qh0Ij4wF7YTeRxxow}Y8`L%{2S9i|++-$RSTY71Y z^l~z=-c$^HA8a%$=-k{SvVIhvb5rp3OB2`F3U*_TqJ8RgY)K)kYPMYySK&`P}IP*5uyU=dp5a?2fOh zjcyC9TM)dj#VN|OvVW|uiV9nF{p7j_yN<`VJH`2n-uhzTR}NtZ4mauf9^aRlr8Njf zvsc!p#m-abIl0feI+Huax496E2cOi4BRk!DoHiu^mKP<02Uu9V{J<*7$a$4X2M%A? zZ}`M-pV{KO$G%*+rf_3abz$I>JeR;EvksOwrP*S&gg-mL@@hr!KnsiOpB&UB=B1af_ zgH4H*e)_o8*{*9JXXvBhbh;_m(&=2XrB!-bLC;X?461a6nx3f8J$M-l#^&6 zb+Plz^`o;hROuN?IMOsltJP_=Iu)#{>B$-$ZOBm4S$d_;M^8`GX|mzJ{OJVMyGmN2 zR?|-vG0D^Wbr7$oC#m#WwPF@+&}h^Kl~xbsC^Mg}M`viDL_HnL{V+Y9q%bJ_=@=+e z0blA=IhsrZRGb^7(qz(_$#4|3$t28=)+?2!S4oBIA2P7hiAOZl4cbGB#AZlsI)*V4K>Hxo9s zy%Qyjp0JiXSU1jT6M^)Jz)9Hc#OQufeb?|0BG#Y!b?4P!Qz;6Hp9p#gdwlApZ}2Ee zteJ9FTJl-5z3COfRUusc>LYYrargak@yXG7?^@X|BwP1Bt74l_IuJ>K4e4{$Evr3q zxv=D}K+w5R9GdG?WDH@5{y>UT*|ZEv?XZ+(J~1ujA@6XjS*9n@xPh5(YV}O5Er3;c z1s#C&fW|!6(K3CQbsX~;>ewmYz>=mv*!5W8CcK%LR$(a1kKVYoGWPo;5i0Wrc6lP` z%I$I*>y;yhwLjMtRO+aCv=rIe!5Yit3}pM6=uX+3h5Cn~<_7g3M(K@n7{ad7i*f|p zov9G;m`BypAxJ@ol{*!A2v2tn77Z>N;|+?sz`E2jv767=RI*xL?N3Wqt|_F05qWzR5X-dPZW+rw&n<(ZoF0?dwnL22 zL}V=C+S7hQ%LHXM#4@A(&%y6w^0{S{pzR3rvC#4cZl{9fmHpI`XM~E-G6QpSqlKNa zHPk#7BPajYi+;|^DgXOT52r@P?{AGUgfvkq7R~k47qsEzyDwI1WDw zaU9|!h-L^l4~O&cQxNANEAbUv8c@=xe37q?K1`;xuOnE%N9 z-@&qy1(pmgx6-^nO7xQRe;0#H7QU2(_Qc2qFQKli_5SkLx~t-Lx#CS% z{u+1XmH)4(q`sDo%*&{xsyDP_XW9|G;j4d>ujX#M6>q+d{7GL&R=(DseqZ?2t@uCi hxvjdx*T`lDCD7G>{5N9AH81~-7|v~rf8+OH{td;wdw&1` delta 2523 zcmbW3du$ZP8NhdD*1p?a`{o8X&M)AATVqlu_0<9!VPYE_hs1CE#E^C!+c60N_DoDL zZ_?gYuG-oT!e2;fAt;nqtq5+Lo4)V^DA*8s3ULfl`$wWy6>6&#r>T;(Safb(Sx4kF zw152WbUX9Sd^7X?cJ9#aW9ZOrK)tDn9g?K%7X&0pO7F|aK^=#Ukby!54jCk5$RQ&x zWW+`)a9mlQ+LHb3`p&1fK2^AmiVXzHLH%n%i~HOZU>kcSJr_0up{1$K$6^95*E3Vfb>B>cqWv`P(M65p%ja+ zQxnR7EY{M&du}Q_GqI8lBRA1fzATshj&ST$@ok8-voAsKNsk9ohW$M--0zWbAPY{O z_U`8CBmOA_bz9kw!XK(w#>&o^c#O}(dkS3*Zx=Df7qznEB&iEYQk?(sV#zHslIHEJ zxwD~9lJL-j&LV3>M#E73nzxKEGT1p1PSD6abP*z(SOCsF!!$UdP#0gYnf-)_mEkd% z994_Cw~_svgfldJ2ji;{sS%yy;^~vTxt1j&v=MgHu}btOK2*ot*h)*V(h|dIE^-Sw zAX3Q!@%u8TDggE8vz5G{iuI82$1ah_AVf-|v+CMbZg%P|h~Fq@Q%FophGC$R2B2!M zz6REI>0jlS*0V%{$p}P>L`biywZNfjdK8SE9yz>@MQ}9g0=)X6s~)Q6I%NKE0eejZ zT!dHCwZHJeJjO`aO~tI2;6$Ikn!7gB3xr7IG6Wr}w|_0W4ta`pgLl`_5__;KFzM7v z`NAqX5Zwtf3X88NE`;9iIt$`Rwp6$dR+iD<;*_-zUrvkYONFtO@@?K&PG7Lc8H1A- z&_WpevD4+AbMO77laI2dU#$A2d-W$j8-QS%GarmEB)jQJzS3vI)U5DjP+M_x|%@*(2-ub*J z^W&af{85GWMfXUqhJ$%51uBY|k2_@AM$jm1bI?jwmmIsRlDq-lno_U7@e2K7bZK%8 zpk1E1@cWNkemHkTpU+e7x?Z}>|$*S#-6%A~rAXZ^!<%$~3gM((H^ zd3sX9X@cc?2u!L=prC=u@VCFK3|cl&oiCTwllE8*(ENd#0)JShEkG_FOiu71E{1#E z9;p%7QSW!`O68~hn%|Dt2xFR-1Eqa>4?p75R@x6MXS5p-=OAyI)j7*#mN~~V=UV1G z%k)_0e9QD&W|CzlTV{%7rdnp2WiGJHg_gOu1!ICy!4<(}!6m^(!3DvH zU|29Ha7d{V76DiUV9^1K27F%dqDUqihQ^(>XbEf|)Fb$ADdZ37MfCa7*z*lS-;f^U z75`NCqcixDUp|AMW8&jYe+E`|eOhjgKlT$poJ!aJJngrr2xa|!b}Ns6hTX~&_uH+M z{(p8WW&exaO8Mv8ovX`v5A3$`W%u3+!S8vO-7o10yX83;C=uCxTGF#oNtJEj zKI%O_Bk58*Vmpj#TJDUbE9{3mVDz4v%f+3Phj@Xabz_l*2`pW^3F0c)&wW$s59~36 zaJU2I!_ayCELuEW)&KfWRqwp7s?C|IK7hE~ntqR*A#dtV^um9;%alE{-+)RNxWA=O r%;fSz`z6!_WB1gY*sP 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 delta 531 zcmZ49#c}2kJ8ytDGYc032$(kC*vR`xsM$buyMZd>#O2I3%{R6mIm7r;VEfE>jH?9e z9a?Uz#jTcKPS5>R4du&v> z>-8@mFK@Y}(v)}F=>Pv(W1Cl8NAp6iUV6b`_D@RU;@a z*37?N%CK|mQ@)M4(fbwVo;X+E@7s7;;F~Q+?WxBbCoOq9mFnX4n?oSu^+vPFS6 zrPAKaf17t*`r*egHOZTcLqhm{&i_qZy5Xm~uzO>z>m$X7-vbWVPZGDhW$oBk%sJ1> z?(px~CnXMbp8GiU;R`+MJO3+hf8Y!7X6MLty|nZw&~uv^85jb*8JR?wK_SEn4x;IP zj7)9QRhXFMrhj5&5}zK)#AL=Kpf-IX6O%2IJ(w1ryxu}U2ceOH0T_}fAtwS2K?Vi^ zhHZ>xyQU{HGl@+%WoFW1S^?&mOn=SHB*&C=8YCk#U7dx=lqvKMMA`fQjGWVJS%7LM wKt=YmFsV9&Vh7pbpxA)`1%_>nJa-w9<0`()0O(t@K>z>%