Cheap and cheerful alternative to fluid.grid~ for larger data sets?

So due to a good breakthrough with fluid.jit.plotter (via some new info/knowledge from the Max beta forum being passed to @balintlaczko) I’ve been resisting 2d plotting of datasets for corpus scrubbing ala CataRT et al.

At the moment I’m doing something like this (ala my old experiments with fluid.datasetplot~):

This is really cool/handy for using a mouse, but I’d like to be able to navigate this with a gamepad or other grid-y surfaces.

Sadly fluid.grid~ absolutely chokes on a dataset of any significant size (as it turns out!). The dataset on the right is ~30k points and that pinwheeled Max for like 5min before I decided to just force quit it.

I imagine it’s doing loads of stuff trying to optimize the relationships between all the points, but for larger data, it seems like that’s not really viable. And there’s not really a lot of parameters to tweak with the algorithm to try and make it faster/dumber, so I’m wondering if there’s a cheap/fast way to make something grid-y out of larger datasets like this. Like some kind of brutal ordering/quantization or something like that? And/or is there any settings or pre-processing that can make fluid.grid~ happy with 30k data points.

1 Like

Ok I spent a bit of time this morning playing around with fluid.umap~ and although it’s quite a bit slower than I’d like, I can seem to make “circles” out of it, which is better than loop-de-loops.

For reference, with the ~30k dataset above, PCA takes 150ms to make this shape:

So that’s effectively “instant”.

And here is my best result with fluid.umap~:

You can see the settings below it, and this took ~13s.

So a few orders of magnitude slower, but a fair use of the space. Navigating it also sounds alright (some more extreme settings made a more evenly distributed circle, but the distribution sonically felt more random internally)

And here’s the same settings on a different corpus (~14k points):

This took about 4s, though it has produced a bit of an appendage. Playing with the settings it seems to make it more or less pronounced without ever getting rid of it.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

And here are some other settings and their durations:

This took 20s, and represents my first experiments of just trying way way less iterations. And it’s kind of a fuzzier version of the PCA shape, which is an improvement, though super slow.

By reducing the numneighbours I get something even fuzzier, and much faster:

This one took only 9.5s.

So that led me to focus on numenighbours as the main “rounding” factor. Bringing that quite low gave me this (in 8.5s):

So already kind of round-ish.

So overall the numneighbours appears to be the rounding factor, with 3 seeming like a sweet spot, although 2 also works pretty well.

I would have thought mindist would be the deciding factor given what it’s computing, but at rather small values you get wrinkle textures (@mindist 0.1 in 10s):

And pushing it the other way up to @mindist 3 gave me this (in 10s):

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

So this use of UMAP gives passable results, in that if you’re willing to wait ~12s, you can get a shape that better uses a 2d plane, but definitely too slow to be a default.

Ideally it would properly use the 2d plane by taking up the corners too, but this is a start at least.

The bad news is that this type of algorithm is intrinsically very expensive. I believe that there may be more approximate versions that could be less so, but I don’t really know what they are. Maybe we should have a vague feature request for someone to investigate that.

2 Likes

I’ll make an FR on the git with this thread as a link.

As an aside, for my immediate use case, I got to thinking that rather than trying to transform complex data, that perhaps it’s easier to just transform my input controller data instead. Since my intention here is to use a 2d control space (with an XY grid or a gamepad), that as long as I can get UMAP in to a circular shape, that I can perhaps map a 2d “square” onto a 2d “circle”?

I have/use this old bit of code from @a.harker where it takes a circular input and stretches it out to fill a square. Very useful as most gamepads can’t actually reach the corners otherwise:

<pre><code>
----------begin_max5_patcher----------
1916.3oc6aszbaaCD9r7uBTM8PcpsLwC9P8TyzY5s1K8PO3zQCDEjMRoHYIg
rcZlLS+G1+REuHMoLoBkDgRlznCTivBP7seXwhEKfd+ESltL6IV4TvO.tELY
x6uXxDcQpBlX+8joanOEmPK0UaZb1lMrTwzqLxDrmD5xWUPeDPAw7h3DVkzz
sax1JRXBca8rkxWoaQ1x2dcTiZxSqpHzVXNUDeOO8tEErXgAjjfnYdWAf3P0
WgApmHuYdf+P0jObwEpGWMPcImlxR1OVKumlyZhokYEqXEwYIYEFD4ofvyOf
Jr7RE0eZq1qJGcfpNJTqy95mvHu5up6uMYqXMAOM8tDcAnPUss.3tVfGcUqG
O+xxKxxyJD7rT8qbl+wPv7XQYBWovcxxUTfoHw6LT8sfobkEl4qtXSzzZZpf
tgIXEKXozkIsz9V7JpedMRaDEfQujW+LRkCgioNaskFKkNk8nDiuvmvCrmxK
.e6ZH3U.HJbF3GKioIzBkcJ.1M+.6ie5lUHSOxYQQMmFgPiqhmCJyYrUI7M+
lTgYiglhvSOtwXju2KzzlMx3LZRsBNY5ZdB6AVQocpuEmR2I44MJdRilnXk2
Z7oDcUcQ7TSQA0EUvdfW0dRcozBIzERbusPSASeJnZX05TqHcKWCESgxwGKj
ziDoxoCk4zXSiUCXUhelL7mqIAOh5KLRyLXuF96TNFSxh+S1pFymjCN4rTdZ
dAqTtnGs1aXk3Ur0zsIhEqyREk7+1rRAZVmxWaQXmBU5fF9utfSSpUf6J3qx
RUfn0Hgp3pt6V.zWqa9MUFcMRo4czXo0jjV5QXoTI2VtjVnFnrNWPUBEYYIs
EU2tD1ZgUbNOMcGVTjk2uvB9c2um1tLSJby9d2ZIkK1lZjtPZSHVTRenMaKn
II1oqse8OQS4anBlfaFBPd0BMNXuuLtHKIok9Zj7PGRVIswiYOxWIt2rvYiw
aY044UFQSqGkWwuiUJZWlfdWY6RJEuyP5MJZ6R6b3EB1l7DoVztBxYG7RQ48
YOVZqXkgVSB34H.aNmtouuVkuOefs8CV4ED360Tdm9A+H9B20eHLbm23K7I1
aHjP8zkP+YHeYHj31K.LoZQ.qilwmTdaFOczYC7IxFXY.dcrbn6YiazQFbj7
w5jLpneRAdrjBxSGWTj+rPIqfm+EDo3eZFJtkRzf4HU6lAN+hfm75Uq8FhVi
wl3Epd1pep1QbSGu59OcE6oFQs74MCAOVFxNW4znHzHRQF8teNxqGF.0KC.G
hMBB4M1FIOGNWBOsuEo0.RIuapoLaaQbkEPkWQPavICLQvSqit81mWSA.G37
6CFE3ghhPSEcCJBGHJTFGNCEJuSCBE9tDDC1r.5PT3eH1lcCBagU6QbpZi.q
VX1zyBpPTvWtUXlL0bSuGTv4xcJtjlrSD0cE69EOCtOSxiDLvA4QpqbRN1oQ
56T4Q56AvKA2.PiRFUpBJXZ26du6TJ06l02G8PvlrO36hjM0fddE.cI35wI0
ZX34hdPyIF5A6N5QVyuSBWEK8l2H6qKUOuFd4XvTmMhx2DpEjL2cDkxL5F4S
z3mrV3AMgCcBDEIvtGehaxt6q2j+qYEanI7xCM4ts2cVS5gD3b6HhIe+Dn1.
Z97+OmQXH130wjYXhm9bEwJ6mulR3ulR3ulR3SIkvmRVJ1e5qHjiNSNlDT.G
3lzes5ryA7TvuHmOxySXkfr0f+8ebdFdNxzWP7O5zWXybS3.Yl5U9z99.+LM
VjU3bZo88No8Bx+DMIdqxRGjZwlAZqeAzFDU1JW583Feujb+du6YH.ZncTfY
eTAyaesVNCT3uWPyATqMuHCv9qs7GnIxpaL6ugb3IT6SEMFZV7ybB+iNKtmz
1+MWqtmLt4rLBNJ5DcJz4b6sqx3eH5beHHk4IbgjPUWMo8PpnONod0GmcgGC
6hOE10lSfP8BRgnyM6FmU5FCUe+y97dCUZ8dhN6mV2q.3YPhbiDXGwnm+o9V
FEq8jFb1YToiTniNSXe3YmLiL28HyYlJ2At+mL+nt1MZ6q4w4zMpI50.+ysk
JcYojWcioJY9mHOol.nH6+lw3lCmToyC6Df78b4ACpe6vAgCnywwf3i.2hC3
ghiF0bCeUdlbaEVij4Q56ZT.YFIJvCgla9DM+JfOpGQNSuPC1dy2o76PO4Sh
SgQvfGl8QNGGCZ5WfawA5P4i9M6UG+mdo+nYjPRjO1ZbOGWY22gHGoXpznML
8pxg7WtmzdOmxyMfq2Ir9S+HdBBb9IfYOhGr4fvBgt3.vhoEhr7rDSPkG38S
nmXIaQSNmkvg160mNRmd9SfngV6naLj1ty1rTWGtOZ5EquqVTq5T+uCC14v0
A0ydCnm8F6dNjLfdNrQrJGcO09ZS0WOQFidBOfdBOF5zvrXvcax3cFLYvcay
bhc8P5YuwfdGhIyXLNhGhJsCZFoIfCpqaOVuSfJnn.UzHXjuIwud0+ZrG3IA
Cklfm3.xPlWEDLBi7ACQkH6k+IDnhwIdvYQymSPj.yGnbCR8Kqikt145Ynf7
NWKictRFu75Xz+UwX2qggNLv9t9EW7gK9OHF2jAL
-----------end_max5_patcher-----------
</code></pre>

(though revisiting this now, it looks like drawing a smaller circle makes for some jerky movement in the output?)

But perhaps something similar to this, but the inverse, where it maps the 2d square onto the UMAP “circle”.

A logical conclusion to that would be some kind of transform tool where you can take a 2d input and add additional points/dots to stretch/distort any normalized 2d input into any arbitrarily-shaped output as a mapping problem, rather than a data transformation one.

1 Like

A bit tangential to the thread, but I managed to work this out.

For the first part, it seems that Alex’s original code was turning a circle to a square at all magnitudes, so I amplitude output of cartopol to scale the “square”-ness, which feels quite natural. Diagonal lines feel more natural, and curving/swooping movements are less jagged.

Then for the second transformation (square2circ), I do a similar process turning it back around. I can’t tell if it’s mathematically perfect, but the output definitely follows the circle shape.

<pre><code>
----------begin_max5_patcher----------
3239.3oc6c0siaqaD95ceJTM5EYS85PRIpe5EEMn.EnWbJJPunWjTrP1V1qx
QVRGI5Ma5AGf9F1Wox+jsjrDEsM0ZmrKBfSrnj4Leb3v4a3Pke81alLO64nx
IV+QqOYcyM+5s2bC+RrKbi762LYS3yKRBK421j7vznjISEsjGRV7Xb55GJhV
PD+JPf2LvTKHDJ9aevt+x5eKer4YEKiJVjkjUHdH98r+CXs6MdIuayl+k6cl
z34YWGIuR51MwoIQDtLBkWr7wv7n5WfdWYaIU2FPd0MYKip+8vz0I7Kf7XRi
rKW2PbQSa7wdwMuHKOqfDmkx+ImgYW92t8V1GSMDD6F3OVPr8qDHNM5qT0sR
YIQOyg1IOE8bdg0ueEz58VPj2Lq+b4hvjvBl7aAqtcgBR9lPy+j0jI6ksCGs
rCvL.2A4TavBg5F+gNfIpv6lvK7Dz7EYa1DkRNP0K+ksgEQVjhvzxUYEahVZ
QxrVDWrHIx596u+OovfDiE1THogoTGA8ni1AGgNBLnNJ0lV5nTyGPGQN3iRG
8uP53mkZ4mmXQ6g7sDE5jmicccJX.Ux8BoRv4yrVVD90JqwMgoaCSR9lJKRe
9rMrbPy1SolgfirlMjG8JeD3.S6PGhPutcomaUlGEsLIdy+j5JO5r7g6hQ53
CGY2o4Dpae306UwvyM6zvalrJNI5onhRIzHuaJbmmW6x2T6QXvxWDXt+zcWJ
NUbI2cWpH5o3pm2Y2UCKn5Ngp3aK3HyjmcqB6RNnWjtMd2hO7AHoHwGJRC2D
UlGtP7vrQrplqM4TXkC3SQsQ74l1fZ1CLCmjrE+bzxZVXzwr7nz3z7hnRpWh
vcVKUMuLZU31DxCqxRIkw+GgMLZVmsuRJgc1HSG3h+GKhCS1o.qKhWlkxDhF
iDrKW0czveENbv0UF9cjFl2wCSsWnvROMVRUxskyCKXCTykytpZjjkkzrocO
WRzJhr473zzVnHIKu+FKhW+nhmcdFswMp9s4sT9v1TQqOPsIHOTF9TSzlPce
Kmu17m+4vz3MgjHRrXH.A10XTZHUQerbQQVRRC8UzxSczxRpM9hnuFuj7nvw
Rswa5sGmWYDMY2n7x30QkjlWiDttr4UJIeS.50tz14x4vOPh1jmP0hl2.c1Q
bIo7wruVJuwJCs5.vd1X0mSW24WiqqxIXq.7jtAsvf5s2uiv9bF5.4l3d3YH
7TKO619BOvenW89qKWh8EZ6MUqBHczXdP4KYwoFAMroKZ04JCGFF00KZ7ANo
Gk3wpjrPxffBBvWnzGOyihJ1ACBJvWAfhvRQaLAeggDd+oTsiS0UossEqwW8
Ye5LBzqRC5Woq0REEh5Nd48Q5xnmuNQH4bEsgH3XCQHCBQBYXhN1HHDPSD.0
KB.6EA.mqQx9v4RhS6aQZtxwZuanoLaawhJaC4bbql5IMtDRb5tfa+z9EMX2
nViLGqPvrnzSJfioT.zTJvinPvBUQKgfYCNdRgstCHdioT.OFiSXmRg7hUbD
mvHBr7AAomGBIjh34aIhIS0I8dTAmSYJNOLoUD0cE69s6EtiM8MwTNZIwrrm
zW5CXd5m1zg+IlnmFYRvYeRiJnpFgRtPv1odpWzHKCHykPEdJxeGz5dVdxuy
5Obp4E2GyWwy2Sj6QekoTYGGhwJs3laHVmcmogpgt9FiGi8AoBW.hw8gRhFz
djGwUp5uio6TS66r9fE5L0WfLcWX056to5cm+JsfgZ+BsRhkoAH5c9Np7vvo
O+Yp1cG6y6g2cVXUfq.xbBTCU3uqfJlozGnehL3rn.QVSgdNpQJ2iAoPu.HU
e6wCZ9LqOK2DRZ30krsuZU0F9rlJJVkjhrz0QEVjGirVjjUJ+mQKWGY8srsV
zmr5mkElyhrshX7cTrodth4lhjXQcYyyxeudpgWnM.CMyJb4W1VRp.D9HYW5
JRUnGhMu.x0UOuJRmcqpfK0d8MiNPGVPrB2Rx1PC0bgTmUr6YN9bMStA61Hk
60GH3hswrBqac1XVGG+iXiYAdW18SONUs1.ccpqMttp0lwdalGLtVYvsn6nQ
+7tNWnCb2cm3JcN9AhndkNtsU4+1O3X1HwqvXfjzcnw.4qQLPA1eWst96DwG
SMSt+LqMH2.WA7nzZH.+JNBQIRE3ZqQDhA9udCPrBnfAZDfXPv0V7g8VEGeb
S9eOqXSXRbY+EwQyMhQQop4KRybfZhF.vnZG85qxOf1hHADo+xQrpfMKVz2J
8i2J8i2J8iyozOFd2H0bapEaDITuMiywwfaG4GY0PHkNg0OQmOFmmDUxRBv+
6+N56jqdaSobGZ8zDYvFbaJ2szG22m0eMbAIqXzgkl79Zth7eILYwVlktUpT
1Dh1pCDstXDJfOjqHKVhrvfT.lMJZld7xehvbOws7B.g+qhvbqPoMOIyJ5W1
F+TXB81El8evQOXzSrviu2PnH56UTTQ4476tmUuvFvuWfLsDtrB4x1evRVx8
jPSjVNEuXnYYdRLgBnrRzVGPc5wsphLQqdngQW3oft18htnqAzcQVowVfFQg
RpgJZ3ZqCiM6z9qBC00QolCJcDqFEvATkP4oT5Qv1xvdtdMU9d470GuuVOdW
7+5gCX+7.GlKXe7AavIrOdgKKym0brqN+PjuHAgRpThrfibraNjzMGQM3IpC
WwA4KpImQE7F0i63.7GGjC4f7HGfK4v7IGjSoF7J0ga4wvuTAGyA4YplqoZ9
lp4bpj2YebO6l+YObP0hGplbQ6lOZamMscheP6C4LuoC8+weqcSpqE+dKqHe
QpkphE9PO5s8p61ti6iEqpBttwJdMW0ajANJcYnYfNwNmJgNecfN322P26MI
tIL77v5fa1JwMz0NtQklCs45EXf1blU1ZgLNJQFnRjAn.YZtr5Akv8g.VWkK
aGv1AkMqa6plUQky1pvYOpAzSU9rOB4yoY4E+hHeviD+TKe0ZbeKidBIfl33
BIJT.nMmUBclzfbSf+XmOhwHcD.Www5dXNzfe.SGQ37RJtZLZzdbaTmgOOnN
AW5DRLJGlGGGcOvDL.X7N2FtHckC7g24l3k4Ywojxp2lSXtiGaa9oVDi1+sQ
S7ghUEGV7cG0CgiK7XgwwQNv5dHwbF0SFEVeqpwUNzdXoiAvVV2A97CssqaM
iaw2FMoGbrR+HJGZMICOpxQkmPMjCPuxwOHmxrdJ8o8YK8Lp2IOYhUOHE2Mq
2oio.2+g9EWSqzTebon9sRX5sRX5sRXxrbUdu08CvpdXB0016Ya3PrTbOkc5
6kg2ViTkex.g33xf.m96gDvkFHZk56S.JDGiNITLbMeb8BEevD3.DA5OG18V
NVWWutdZmaZEZq3zlZOn15bJEx2KUVGb0L.59eIML8E60Xh6HRkP22YFNiIc
liXrX.pLli+vhvBZPSYIhrnN.Uho5voPdF17juPqTeN9Any+HlfL5QLw3uMO
z8U8fG30wa5gcm5OsdSO3gG4WzCjr0qU7hecnAYL1q1dEHCUvoGcw8nGgG8W
nEqY0nM7TGKqzdr38oLR4Ho8HebUoLzKCWGcfJdu8LnCckb5mrXX.m3QyMfq
pXWwAMTolhtLGLW1ZQpbhybZMOLcsN5oPCcfpzS2tO.x1uLdkL2AP1V5IR84
O18p6XiRWKl9yelC2.b8YvG5Kl8lvOjTKGarjtEug1u0S5PCfBbxt4npW0OM
rNtNN1QvYmQpSk1NHwA9QcpSw9WFGB4gK9YqUVqNuYGh2PQNdplbf8FYMzbg
koy+EzTWyvuNBKqBVzKrLr6k48uEwZtByYt2N8HoDTOvkAl8hNBc0fixTVYj
LJ+LyQMqxmEFJ10GkivfImlsM+GqYNLDfPa9xRn3.dxAM10udHIydINTwR9.
3V6dxWmdpQtClr6+lLfieWyeCc0UeCNu9FqiZGLJpsNcMOq.0tqV6KuCvgMc
0ikQ1f8+AhPzUoDaZeGsYbPzVCMwCa.qT+.cGtf8BYBXIP3iGiC18MSO.qkv
Ba9lz0TCIdt5LjXafgDOcLi8.lnmzxLCYhdBoQO4FXfdxsosphwInI5ogzIr
IPOWsVJAOFl8Z007+qiy79ycA5.v9FXnDqiVhMwTNrmNSDLQ7GXcbXgMwZHX
jtiSFomf5LNc1VDZY64YBcBniN4Y.cp8zzdlLibLfVs6WYf9x1X8ETq95rwP
j8EyWrd8M1cL7E2NpJUbJNaLF5pUeYBeW69UFnuLxbBnVyIfFYNAzVq9xDgm
zlRU28kefw5pAmpCfFoufZwmDnhOojNjOkVYP.v111Cy+iyz9a5rkaftCGvg
DaWdgo6AP69VCgSjNlV0UKStZUOsspk1Cqi19qg110OKu1Y66092s+1s+eHn
dTGM
-----------end_max5_patcher-----------
</code></pre>

Actually reworked the square2circ part quite a bit as it was doing weird motions near the extremes:

<pre><code>
----------begin_max5_patcher----------
3343.3oc6cszajiaD9r8uBEgbX7D6dHodmSYQ.BPNjf.jC4vNKLTqltslUsj
VI0d8rKVf7OL+kBEIkZI05QoWss2wXATuVTRUUerXQVEqhyud8Upaidllpp7
mU9dkqt5Wu9pq32J+FWI+6qTO39rWfaJ+wT8hNbfFlodqnsL5yY76qsQwc2W
Nlloj5+KTknGTdxOI6nafR5OczMgV7BA9gTunig72RSdyX2LuG8C2eeB0KSv
MFFlaP2pnYYuw3VEas7+P2ZCR4GjuS3wCQGyBnYb9BIuq+NN2Ds8K2oYPTO8
r9gEOJN+d+10Wme4VfRcH8mYexyD5fH2cGnooJX0djDjNWRz3BjEJ+Jgzojf
aSRPEeewCl80Xp3iqpV8yrJBYJMPA0i7oirEhjPL0GP9HsHe51cJeacC2qda
mxIYBxYdOl6d54BZVTbOxolinqyhKtZ3IzOpaM19woHewtgzfdDDBl2Gg0rH
7esQk+LhQW55EjH8QWgXTHxaiR1QSp1YKtiWTPThfG3j7zEbcRWQOVdyCQ6n
U4DlVQ.+FD9.JIU1WiBjaqc4DEhShhiRx7iB4exMFSAj88xRC7ykykDoaczg
wIRj3dflQStmF5tMnFhblFketUZwOKmtUG1Hdh9bbhxe7ArxGYWIJ+kTO2.2
j7dsdsMRrE.ClvGTgszlvnJMyBJ7PTXV9zO7mjrAM7fs72Hjgo7u12k36Fnt
xPEGo9.V4NwEFZcCCz9.6U+.ifefgge9yLj3l7qnat4l9r7JlRAirkVfmD5g
tD1j5.LhU9tCw+ynjCtA9ozdDUScwPGj3WGmoHo3wpm7.aB9rQqrfqJFB6fW
UBKruhe.8IZRpz7i7oYlzhiqb6qp7J4X4WD10bts7V9ghagJuUB8I+h2+zcc
SXfYFCIOlH37mMKLcKMrlDdzubQC7dUIKw6+xk3zXWOwKm2MWz7otGrXZerA
ueQth.MqJqWK25bPj2OR2Uk6Tihog9gwIzT1hJcyZv7p6nO3dLH6916vp29C
RVr0Fasa6J08I96hByYhZcE42tfbLgyPHaUEF9SD5F2xKyz0X3RGMlxDxioa
cSx6ojVvIEMlEEETuox2Kf9Plr4X+vvFnHagKc2Xh+9G64c2FwZ7PeeadKo2
eLTz58Lkhr6ScepNZm4FDHGkW+y+ran+A2LZlunKffJaTLK1iodIQAA0jWQK
O0RK6XJ4dze1eW1ihYuqzeydb+3BkH0xd4c96ooY0uWl69z52IM6qBPuxsNt
UNH99L5g3.lTT+AXCO7SyReL5mSkOXghF5zXniTF90DTN40U0A5UMiV69MLm
xM1TNHtqYGNsNUMTw0RU3NsY1ztotdUBMfMxysFhpzPgyi7Ah4qfSwOT4evF
i5GGPSycZ7+8eqRL+vczmqXYRNsizH0DwNgD.C7PVfQOTGnmgZWHCtCjob9P
t8Pk+lqWVTxpCK0cru9zz+U2.ui4Z+JgRdSvZObFq0BThEvGwjikXSwT2SBL
0pRpNlSn2Ip6vQ4K.D9eRbiUbk57YQJze5n+StArGWn1+IcXvnkXxHaqoihj
W2nXskJVGD+C2k6s1..kio.ZLyCbjlcyEJB2vG1DJRAwn3HPSxkAMSiC7yX.
ZtCxFfrGJ8OS3M6.fJoKPEOOP814htZWFz0KJEDlRXXJSQk3LCEUCiWFE0Kz
v98rEQCBJENGxfRioCkjYsZGbS97j+e0E9N8CrKeAa75s4SXG9E1sugC6eXW
9HVyOwt7UbWZ7l58cU8YjXymJiHcuRWXoNumrJ71tei.7cDh+iC5CIP+H6wW
RX9SNfOkC5W4f9VNf+kC6i4f9YBvWSH9aNFeN6wuyA88re+O62Gz98CsWeQ6
xez18IsC+RA4aJP+S6xG018SsoQnlF2Oq8gLxW2P++5u2roVr0KB1ozTOpsY
M62beSS9lMoY2wAsCObq1V4Lg0mMbkANlazX.PmFoBzYOenC+6.n6ifwMghm
vAr4gaZyE2Hu73FikGgNGVrUEZPAOT2fmtZeHCtGjo9zs4Yhv.F23hS9y0Or
kFcLwqnmSZRQ4bIjMmPleX4BU99RcAErxOLoNzoxeZif+zEO6Ek+viD+5m+p
2sGwVihenTehwf2oizzrsUu972d0ClAdy.90X6HF7v8ngMRZF90f+VIVF.Ck
AhaPxzXFgxnLsb9cdnLb2lxvUPvpEWGUWaFAyP240SvLNsgemMawI7sMqbUP
4yrtoq2z7VGl13PQUia81MOV1fGdSX7gw4O4A+cwQ9gYRLAiL3Fmzz1Xw90f
b5uVM1GKl4bX1uPPWQ9XTv35vG4AADDenarprAbsp0kO.2szRGXCsaGdRnhM
MqnbK9qUi6Qik6WQ9.zfLiUkOJrDBfOPcxGmrl29h.KiDfZTpWJMbWirNr79
G2E6taGOdIpXh0FlC0avpm+P4YYHedZ1W2pRyrYMo9OQa6yKapwKaW4I9oiz
judV9+waJNg9f+ys8YEsHBPz0UCdqZdP01cuH3h26lkk3u8XlXptpYsznRth
8AQacCZDwo1x8hqO0CsLIT1ovM2SVj43n299D.IIxHp.yVrucxIrFw4ebw3+
87B687B687BagxKrdbh6iJ2Mb3Fpr89mWfCv8gyr28PsusO8x3Pas8YnafPT
QKsuGCv.BioBDnKCPzXeCZME8sp.EyIaZdkCEeBDNfInt2D.X.g1TAhKTnzZ
FX+d.CS6tCpOvzi7kObLl.8rnQf5WT+af55t4J5ikFzvGrl94Mh9hI4imC5a
Je7V5J7p0pT5N7MCWCb5hDbCqaMgJ2oL8DWuJ7ZJELKygO12.Po+Zy+w.MgR
iknCo3+XBh+AFqTcgus.J2Jqm1JfSxAWNyZ1a0W59bwmmspvWAkMnTmRlR4S
ppAIj2RUMXUjBuwXrHkr1kmFRgcdUN5CBRwraOVnRdvCHqU2QBUH8KQg520Y
v.Y6FkOqJNuEXKOJ8yp40VfmehW.UYOifJoYIQg6oIJYORU7BhRk+uzc6oJe
M5nRWmTC5ciaxhOEIzvvb2FMGWsjiLTWcro77oPhGb831DURepHhjYQDFQKQ
wAoMNQ0b0EU7FV+raRlh6wrHl4ceOoL22ga.hKYFxj0gzr5RfHYVKljkEsee
+rqkXPp7zln75XFpZO4ppujJoOsuZbeVMaZ6yK8JbuVuJPD6J8ii03kyknRv
65z23NsMXc1vI1Ul4CTem3HZXtrJVUkrbeF4TZujE8dt0lS4SQOBHVnXqimv
5FwXU3KC77jJYImKN2aAk+DyYAkOoP.LArnnKyynfIzwRda5of7zyoX36T7T
.q86XOEvaFVwgnM8s0CqOos0aIOJLb89QkGTd.vh4E4R6j7jFa7BZ3KSYaux
WgYOwffA6GacPf4fmjT8tMsKX+YTPVjmahHoDAn8JNWorrmxPeqAzdu8hoF6
E3GmKx8NfUmH5nkAP1XBdkRrGsqVZqvYoUgjLqyRKhky2zmkVKxpGJ5IHNjI
u7Ahk4aoPc.XJiRTQrjhAstzJnneQN05fbfpM9gasXtjXZ+l5.UaTQwpDgzH
SNLVDSmWvyaRvSbVpail7LmDyWfYNGbNEw5XMMzmwTJkmcEuOkRsyatzXJcW
f+g+Ma3Dc3NAacyYLLRazFN+16niSbjwgk6TFQdfKgdOCAeOCAeOCAunYHXg
oQk500VaFGwhcSzXCg4ht0bp1KqW4YC0Wh7CggFZHdYgXOizED+ZO2v9Dewn
CkbXh8Rx1fWsLZy4fMBOqCimWSfhPIYAvDiWMPBnCgRbwdjNuCgRBpWwtpOY
vOBJW8yTQHHjbzxB.Q3KEDQt3mFmxc.CM2SiSBYzmFmfURVkjSEZhgh0Vwrx
j.tTJWyZ.j.sjHW0xJ0BHSPV0Z8EZt5VvtqCWfGixIdRoqK48Rx7MSIYBKBt
iM3VsF0N82HAv8ChH3RtQ4t9iZq.UbDQAAilxFhYhdKs2EdtIYQwQACGkWwt
c6HpcTazTBx6D+G9gam5+BPTUOh+t0WRf.1ZZtUBdmWWF0OK.5phHHUpKiy5
h.Sq7+kXZXZoasHzxBBsptlhoSKMS.zhumxK.sHPjKsZyd17DmvTmm8CXDVa
iiCa5FMKi7+yjXcaeMNadGCh2QmlPeFzBjdMuma1zhX.ZLDYI5+I5fo07kKP
5Z3EQtvNfjKiEgVvrMrbzBChVyt+BaBhVVKFsFFCWDadXPiuvNKBs.M9BuHy
QU2Sqdwv42eAZrLZY5u.YmGatXzZPc97rOeAvPzkaMEHP1CwnEgVvVWV8mpb
e9QWBh2.NJINdlDGzncciWNhycGc4g8xUiN.wWB6b7DeC.sbVDZARtrVBaOk
b7.xk8hPKKPxk9hQKLHZgmMsfoGpsHxkND4xTaQjKMPxEZQjKLXecVbqXDSP
S.2vs0kxJlIbOJWIhiAYBEu7vNBj904qEQDxnFI0UNYZjLWMRjqyShqtSfql
IuEO1yckzVW+aW++AMQEQZB
-----------end_max5_patcher-----------
</code></pre>