From 577c59d4cfde721fe07c4a90330f889ecf58d861 Mon Sep 17 00:00:00 2001 From: Tait Hoyem Date: Sat, 8 Jan 2022 17:54:07 -0700 Subject: [PATCH] finally split games up; allow websockets from /urls.py --- chat/urls.py | 9 +- chess/__init__.py | 0 chess/admin.py | 3 - chess/apps.py | 5 - chess/chessboard/CHANGELOG.md | 32 - chess/chessboard/LICENSE.md | 20 - chess/chessboard/README.md | 82 - chess/chessboard/chessboardjs-1.0.0.zip | Bin 48475 -> 0 bytes chess/chessboard/css/chessboard-1.0.0.css | 54 - chess/chessboard/css/chessboard-1.0.0.min.css | 2 - .../img/chesspieces/wikipedia/bB.png | Bin 1405 -> 0 bytes .../img/chesspieces/wikipedia/bK.png | Bin 3009 -> 0 bytes .../img/chesspieces/wikipedia/bN.png | Bin 1875 -> 0 bytes .../img/chesspieces/wikipedia/bP.png | Bin 777 -> 0 bytes .../img/chesspieces/wikipedia/bQ.png | Bin 2648 -> 0 bytes .../img/chesspieces/wikipedia/bR.png | Bin 748 -> 0 bytes .../img/chesspieces/wikipedia/wB.png | Bin 2374 -> 0 bytes .../img/chesspieces/wikipedia/wK.png | Bin 2823 -> 0 bytes .../img/chesspieces/wikipedia/wN.png | Bin 2388 -> 0 bytes .../img/chesspieces/wikipedia/wP.png | Bin 1571 -> 0 bytes .../img/chesspieces/wikipedia/wQ.png | Bin 3812 -> 0 bytes .../img/chesspieces/wikipedia/wR.png | Bin 1097 -> 0 bytes chess/chessboard/js/chessboard-1.0.0.js | 1817 ----------------- chess/chessboard/js/chessboard-1.0.0.min.js | 2 - chess/chessboard/package.json | 29 - chess/migrations/__init__.py | 0 chess/models.py | 4 - chess/static/chess/chessboard.js | 1817 ----------------- chess/static/chess/css/chessboard.css | 2 - chess/static/chess/img/bB.png | Bin 1405 -> 0 bytes chess/static/chess/img/bK.png | Bin 3009 -> 0 bytes chess/static/chess/img/bN.png | Bin 1875 -> 0 bytes chess/static/chess/img/bP.png | Bin 777 -> 0 bytes chess/static/chess/img/bQ.png | Bin 2648 -> 0 bytes chess/static/chess/img/bR.png | Bin 748 -> 0 bytes chess/static/chess/img/wB.png | Bin 2374 -> 0 bytes chess/static/chess/img/wK.png | Bin 2823 -> 0 bytes chess/static/chess/img/wN.png | Bin 2388 -> 0 bytes chess/static/chess/img/wP.png | Bin 1571 -> 0 bytes chess/static/chess/img/wQ.png | Bin 3812 -> 0 bytes chess/static/chess/img/wR.png | Bin 1097 -> 0 bytes chess/templates/chess/board.html | 25 - chess/templates/chess/rooms.html | 1 - chess/tests.py | 3 - chess/urls.py | 6 - chess/views.py | 5 - common/templates/signed_in.html | 2 +- common/views.py | 2 +- lamegames/routing.py | 2 +- lamegames/settings.py | 20 +- lamegames/urls.py | 9 +- minesweeper/urls.py | 5 + rps/urls.py | 8 +- 53 files changed, 33 insertions(+), 3933 deletions(-) delete mode 100644 chess/__init__.py delete mode 100644 chess/admin.py delete mode 100644 chess/apps.py delete mode 100644 chess/chessboard/CHANGELOG.md delete mode 100644 chess/chessboard/LICENSE.md delete mode 100644 chess/chessboard/README.md delete mode 100644 chess/chessboard/chessboardjs-1.0.0.zip delete mode 100644 chess/chessboard/css/chessboard-1.0.0.css delete mode 100644 chess/chessboard/css/chessboard-1.0.0.min.css delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/bB.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/bK.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/bN.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/bP.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/bQ.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/bR.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/wB.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/wK.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/wN.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/wP.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/wQ.png delete mode 100644 chess/chessboard/img/chesspieces/wikipedia/wR.png delete mode 100644 chess/chessboard/js/chessboard-1.0.0.js delete mode 100644 chess/chessboard/js/chessboard-1.0.0.min.js delete mode 100644 chess/chessboard/package.json delete mode 100644 chess/migrations/__init__.py delete mode 100644 chess/models.py delete mode 100644 chess/static/chess/chessboard.js delete mode 100644 chess/static/chess/css/chessboard.css delete mode 100644 chess/static/chess/img/bB.png delete mode 100644 chess/static/chess/img/bK.png delete mode 100644 chess/static/chess/img/bN.png delete mode 100644 chess/static/chess/img/bP.png delete mode 100644 chess/static/chess/img/bQ.png delete mode 100644 chess/static/chess/img/bR.png delete mode 100644 chess/static/chess/img/wB.png delete mode 100644 chess/static/chess/img/wK.png delete mode 100644 chess/static/chess/img/wN.png delete mode 100644 chess/static/chess/img/wP.png delete mode 100644 chess/static/chess/img/wQ.png delete mode 100644 chess/static/chess/img/wR.png delete mode 100644 chess/templates/chess/board.html delete mode 100644 chess/templates/chess/rooms.html delete mode 100644 chess/tests.py delete mode 100644 chess/urls.py delete mode 100644 chess/views.py diff --git a/chat/urls.py b/chat/urls.py index 9064e71..0c04fbf 100644 --- a/chat/urls.py +++ b/chat/urls.py @@ -1,7 +1,12 @@ -from django.urls import path +from django.urls import path, re_path from . import views +from . import consumers urlpatterns = [ path('', views.index, name='chat') -] \ No newline at end of file +] + +websocket_urlpatterns = [ + re_path(r'ws/chat/(?P\w+)/$', consumers.ChatConsumer.as_asgi ()), +] diff --git a/chess/__init__.py b/chess/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/chess/admin.py b/chess/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/chess/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/chess/apps.py b/chess/apps.py deleted file mode 100644 index bff74ff..0000000 --- a/chess/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class ChessConfig(AppConfig): - name = 'chess' diff --git a/chess/chessboard/CHANGELOG.md b/chess/chessboard/CHANGELOG.md deleted file mode 100644 index c0c6b2f..0000000 --- a/chess/chessboard/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -# chessboard.js Change Log - -All notable changes to this project will be documented in this file. - -## [1.0.0] - 2019-06-11 -- Orientation methods now return current orientation. [Issue #64] -- Drop support for IE8 -- Do not check for `window.JSON` (Error #1004) -- Rename `ChessBoard` to `Chessboard` (`ChessBoard` is still supported, however) -- id query selectors are now supported as the first argument to `Chessboard()` -- Remove Error #1002 -- Format code according to [StandardJS] -- Bump minimum jQuery version to 1.8.3 -- Throttle piece drag functions - -## [0.3.0] - 2013-08-10 -- Added `appearSpeed` animation config property -- Added `onSnapbackEnd` event -- Added `onMoveEnd` event - -## [0.2.0] - 2013-08-05 -- Added `onMouseoverSquare` and `onMouseoutSquare` events -- Added `onSnapEnd` event -- Added square code as CSS class on the squares -- Added [chess.js] integration examples - -## [0.1.0] - 2013-05-21 -- Initial release - -[chess.js]:https://github.com/jhlywa/chess.js -[Issue #64]:https://github.com/oakmac/chessboardjs/issues/64 -[StandardJS]:https://standardjs.com/ diff --git a/chess/chessboard/LICENSE.md b/chess/chessboard/LICENSE.md deleted file mode 100644 index 20b7d61..0000000 --- a/chess/chessboard/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ -Copyright 2019 Chris Oakman - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/chess/chessboard/README.md b/chess/chessboard/README.md deleted file mode 100644 index 60c8997..0000000 --- a/chess/chessboard/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# chessboard.js - -chessboard.js is a JavaScript chessboard component. It depends on [jQuery]. - -Please see [chessboardjs.com] for documentation and examples. - -## What is chessboard.js? - -chessboard.js is a JavaScript chessboard component with a flexible "just a -board" API that - -chessboard.js is a standalone JavaScript Chess Board. It is designed to be "just -a board" and expose a powerful API so that it can be used in different ways. -Here's a non-exhaustive list of things you can do with chessboard.js: - -- Use chessboard.js to show game positions alongside your expert commentary. -- Use chessboard.js to have a tactics website where users have to guess the best - move. -- Integrate chessboard.js and [chess.js] with a PGN database and allow people to - search and playback games (see [Example 5000]) -- Build a chess server and have users play their games out using the - chessboard.js board. - -chessboard.js is flexible enough to handle any of these situations with relative -ease. - -## What can chessboard.js **not** do? - -The scope of chessboard.js is limited to "just a board." This is intentional and -makes chessboard.js flexible for handling a multitude of chess-related problems. - -This is a common source of confusion for new users. [remove?] - -Specifically, chessboard.js does not understand anything about how the game of -chess is played: how a knight moves, who's turn is it, is White in check?, etc. - -Fortunately, the powerful [chess.js] library deals with exactly this sort of -problem domain and plays nicely with chessboard.js's flexible API. Some examples -of chessboard.js combined with chess.js: 5000, 5001, 5002 - -Please see the powerful [chess.js] library for an API to deal with these sorts -of questions. - - -This logic is distinct from the logic of the board. Please see the powerful -[chess.js] library for this aspect of your application. - - - -Here is a list of things that chessboard.js is **not**: - -- A chess engine -- A legal move validator -- A PGN parser - -chessboard.js is designed to work well with any of those things, but the idea -behind chessboard.js is that the logic that controls the board should be -independent of those other problems. - -## Docs and Examples - -- Docs - -- Examples - - -## Developer Tools - -```sh -# create a build in the build/ directory -npm run build - -# re-build the website -npm run website -``` - -## License - -[MIT License](LICENSE.md) - -[jQuery]:https://jquery.com/ -[chessboardjs.com]:http://chessboardjs.com -[chess.js]:https://github.com/jhlywa/chess.js -[Example 5000]:http://chessboardjs.com/examples#5000 diff --git a/chess/chessboard/chessboardjs-1.0.0.zip b/chess/chessboard/chessboardjs-1.0.0.zip deleted file mode 100644 index 1b3fdb0e08dd485a01ebf0d8bc7ef6e1537adb5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48475 zcma&N1za3omo19BySuvtcXxMpcbDL9!Civ~cY?dSyGzhu2@c^_=H35%@6Ee&=PUXY z{i9A*H`V*>z4ltGmF2)8Fu*}TU_ksWCl!NUR^&LrKtO09KtK>cKtRN#MHHnZHrxXX_=G35T?bRPDrplvT8dOOfF+;jRYmmJ;ZBCKh{I zrL#9}z>Z->V@bC0>Y;A6h;qRQ$)`|o89;A%H=LpzDO2A-`BlMGv(u*%t;C4Hhi#0_ z6+dW)F6fP^dSp_Ln}ap6(KjC8s%ByxuQs>IPqNAEkJDPh)Wt;*`P05>k5SDrGq}L*-PRjpf$kw?b!R~{yDGbCnJ1vB)ceEP z^_l>i+Cn9_fb9+0cAk9d+7#_OYc$X6(X~I@6wi4h-`%C(Bj<|IR}MQrF>L5cJVWpf zL=;bgWEY45li!?Z!YHF*xyj_SKP{uK2Ro_De~B15?Vw05t1$&|)nZ@HFTse)9@>`X zNEc`ro@S3HXvCdz{>Jhx)gboOekU?-kU#iD-Z53%$R6?Tkayc7Ru4xh`coWy@~ee> zUaK5KW79j@?7{&ZBRtj45=TxJyq!wh1eq&;h|y-P241&1qV^6tZ!hkxq?Yblcp~#- zHg0b2L*#bBrT66}gnR-d2KH#G@YpA_$jXDHPOgI5uHDBc;S?-O_GFWf+e6b^XRXremY&Cg z&-lVk98$FJKsVF`;)?)?FE}8+0pa`C0slTUYpBg z_!h$LUV;^gMMHcKR`kwe1T?ij1HD>%7|L5+DSYCRAA;RRUV)07|Llq$k0%6sUwG#? ziR&5`!+FcILaNH12ztlhs>Q+0ngZDif_fiIn`nIs)eZ(-j3%6d8H?(eo;{!bzC64E z!G^aIlY%=s!Am|k1A&b#=I3e;e0CW;{SqnxM_UD(>7d~<-FWI+l1w)>5{yaT?*=EC zv3i>#_pU`(oz#X`DT#f}%cki#pY@^kubx6ha%78@a@nu3rWxc)(xrFuUOC4S-Xc*P z6Bw&8UfO4owVjN*MU%UJ3KqRG$0B%=MVOHIUTbORR=q=icWK44A>cVnC*pAhV|?q) z^c)_5qs5lW^2r~sVR2Tuz9`^cCH!~}PY4uyB)(qFdu09r`zG^E*PgyJQIpOQ8xid^ zn*K+5zNSM8=p8X`8QKPb;gD;^=SZy_OxAAv zmDfcUItJVRdNiOoZTg;{Bbx!T|Cq!;l_+^j8HR&urMb6 zW^KvU3iY9#XM~8hd%Lts^DNrn!cf{h^xcpe!!uJjCTmIAVnX~2|R+O9!}bBI>> z)BbJ6E7ZTDPv3Y_QGEeN0*#+8(u8(W(vNW%C}tmUayrx=26(TS*?oS#m_MJA`rAZzIDA*>QtjB?1Fy$>myhOKSei_k^=KO8qUI`y$m(3)!=+J0aq%&h8a?6#SzZ)y&#+E zL%^U3&sr{zuWS}wpB;6rm^jAaH`YnYNO@r=l{7EzEp+*rPVgQ_4z^5=6b|FV3>dR5 zx`h>F9@RtmTl|vvRNk+3Nlt>8Qw{g{x@YmQG+#bZqIr`S*=UDAk@k_wn7ADdc;1#9 z*BHXjmt2^iOXJs~B-<>yj=hO8P_Y;w-avXnd8o&I`(>BjN6mCgciN0kR7$`RzBs(J zHR~j#Qk+st(rI5*16i2w??j0VCbd%N_{+lSzIEYVgNooRVCBqZo>;)=>1KZzoWz?4 zCsvqJ2=qQXvcsW*E4IwS zxX_tt+97Z~MlxkK$6tFNoBbTk5iXW<648jo6dbBSv3Al>CNrl2v#P~doj%ylW1(< z*QJMqI__pZnzIlKnFoz^&)=(j-h8sbpn!;L|L7IOL8P50RiHmes??^=(}HV6NjStJ zJzQFz-1s|I{)~%DYF&6SjlGJ~VtmAZY|~6|5k;R#Wn+}MSuEAbmG8Xj*A7Eq$`sWfVz>BLjYv2VNFccxXvQ(jM36y`3$h zby0ZUdlFs;rpPwk6vq;$7cH1RjXu5zod@DN$CIt zf~F&E+tl!TdbN{MJLki5@yR{DTY9a-uDHrlAz{_tNOjpNatMlH#ww-9?(j^Ah_7Rv z+*NK~uM9UEn4Q+BX#O)jqA2N|$lfLWLfiHD8v3c%t;}h3f z54Ng1@8AmFMcEfrl3M(MO4GzVv}uZM-YbCTS-53_bUM^m^U*_SEsRNXIff51$X4^! zj_}F;W$63!qOmK1IxW~Vz*|^pGxeo-aBy2Gd=Tn!)|l(%ZP`=xx+yt+)!rW&$7)B9 z;`Pt_XM0S+&tMlrjf;1_T#D9dgQO6cZIbujC+-Qu`_tedd;6e=!GA2`J2Ym`BvV*@ z1ogWmrSX1vyK?3+T?KOcc)Xqc_MYcJPR$m~h!0bSD4ryCozY+VSyxspbdztvFQqF2 zA(lpN(CXPaADQx{<2jq}MT_-1ChG$MV&>+?{Lc&+5DH+1 zAb+UW2Pg>00)WtP{`U+sYYR6wQzsKwb4FGs7T^as%|mtkFE;DOzX1T2oLy!kg`VM& z+PoaRd;4!_8dr1HGU>FEE{dPMUKI2$_(Npgb6q~yF6rw>gi&za%nV*^zBkU&Mcgs_ zTwU12Bwtbx{VH?sZbGl^9BKaioK$+MguqMqP$u@HuoqYaXUY09QY>wKRI5(in(W6D zS&k}9JW*I*xDhWEIAWm7+!v#vOJRT%tVl*#It|;kEIaT{b~V!qtu$37W#P#KV+WSq zN7G8!{8pFFXRbp9J*cWj0#a!F7aA~Agzw>F&f`9r-2`5WI77_c(Ut~=4_NdP2Mmw9x_AOh`@*3e@s{OT9uFz z6mWb&?84`uEjxzF_kCP>o-s5X*YnqjUdZl~HKg~S*}q~x2Zy5M_8Y~zF1ta?9FQt+ z%MUpjVNXy@(-Qni@gtETd$Ee+F#LN5qW|ofiar;n6`O+A?Xg5SV*iRbVP-8o&-DZ@ zPFc;kY`rQ&`dK)-eTo<_O2=|pFX_jB2^!^mUcv?-XlDKbt^Y1)9Bdr_29ATuX8a;h z`A+Dk9w0S6vP%@0XV4EIDVUhwf|w6S^hVL`%Ng}g~eP*Tz2=kgc0u{`` zNnwr*Es%qAV;N>$?^3#woMf`Fq3?QbsS@knmRvJ#W{G=~lq5soZ&uI5#wc3pUq7`O zbx)K)UbVC@rz{>ISZRw*&{4w7~o^ndo zCXN2da{u$Jz+9zjw1(bMlFnSi6-%b|94m6Vlv_l$p>VEz3F_x{)kN%UsOanahU@YZt+azuLgaQwWD$!U1dZ+q?;u=C8MH|=O zFOHHFV%-@Z(|kSMHY-0&aGFL4@N?*}+zlLKw(lZRf0NK_AT?DXYI&QCKt@q0Ic*!9 z=vwC`WDSl{lcP&jActQ13(sO$?`&$@$%|O;;Jt=!`-6Oru%@6k`Wo4JToCX)gYTFT z+$jw1U3}6>t7JS}*15BAK=$>gnQQcB?Y?^2F_RLT*-$#B&7#tsPI5--y~9DW`s8#g z0hwpDJiOY=qSYJZKluR!q~ZUNL2MkX{xcXrKwAIH3=|+3{?7Q14B~8KVP^5KeDnXm z9^U_9wwH~ajkAThjmdw!3LKD?KtR4BXi6R&dZPG4f`I%TB>&g*OhuWT9j&636{Qg2 z@cy;{h%(aRs=#mMzXJve*vF&Z)qsFNipz+LsC#ex)Hkpu(7@=iX;SrAKBv>fZ;)QD z7S-s$#Qa%TlezX%6tW;IYDQ8^Vofwm!7OqS`jp7O^qs+$CaG1Kg)t2h6@oThP~D+L zz3MVk4)D*aAm?F;%Igzu)CJUA*(q3k3-J`!N@W?gY1SOf$z(W&a4Oo z#YDqybicUlmsYdAT@DNj2HIiUu{rI^ejsMh<}Y>^EDs#{MmHYNNVSEB@gorHn$q4L zq72bv-I5zf_-!V5M~jOhAs`%$j|xio$#LBhk>@|E73=Ei9xW}Y=lfl%2@|aoFH3Y) zMMJ-FZoBgeP?Hd6%%wgKdL7-0)B5Xv{`{I7DLB35Ai`a*Vou)W{XYR;C`j+Zfcd^ezzo<>dli|3U$<6Z?G zzlg#3gbbygeFBW={^ctumr0sb5yRefsbU;Bo;ZbR6h-Z*Uv-Iw6z*c?L4TN8l)3I$ zO#t;QsC-G@80!|=GGo=R(v?263|B>tM6))|%IT+76i&pqy9^p+vRCZjpaMyqzC2P# zBOik=T^JUi&j!QhnBvX;3dY223({IDeOexC@_RgMCzu%X4=(D~saR96Nmgml%?G#M z0lsJu>*<*V)4rP4nPKfo-nqo}g@yeSmQBxJLR|Yf*RVFjymzBSRXft#vLxh7RbB1v z<)I*3hdD_NMXlpb+S8Yom&eP>sMeR4DLXqmC&@OA_3Y6(Zg>oaJCPS-SfJ711(Q3X zM}PH$W8y?FW6SCuPx3Qt{rVF^b%I*EDAQ-4p*_)E9qY|{eks)V&2Ie0q@gZ9KmRct zX|J8@&!u2dCAMT_Hj)$uYsiLOtNntH&Jq8 zWsTerS6BqkqFnu4pc01QYBE_Hg_|W(E4t|6CnF8{9qm1A!9e48-b1l2+^xY!BolDb zyQ15xYq*2Fq2-~^4c~f+b8?W;R%1keoccPW-%6;AQb}#QKRxM^w#|E+upt z^@$t0zzSuMcE}x!)v}?zzd=aPX1^_Ay*!GAJ_H|x&ZqAE5%eQ!Kq!P?BPlHlt(mg& zR}a@z#VoanVvio(r;MufsB`!VsSvCL^kHUex*gF18G9sGuID^FlsfGpuh6aKAIQ1X zb#u5U%9aFGplOGD5Zo2cqU|R|G=2jU#2SG#aCM?w`%j;04b<&<*Rz%1c!pWeOl}U@ zl%Tic^rA;uY^TXGuf_L;5S|j84M`nG{TL+tVB}2#M%-E$ha85e!u94QoZCC2CiP9V zBiLxSnp(zIIG@%)3Tz23P&SccgmKM-=ZsCSYm$y)@{Du|4PqIj*Same2i@~_m5rHV(}4-W$JcaQ+H{%e8w zSIRe)`!`cJeAGXw8(JAd4~uY73j)<`Cf!ECB8|s*hr_JGZiUUii6(tr1HmGlO~p3r z`_#*Hk=;z~w^CCi98~leT+GYPM}EUcrw9?tdg#br|0+e+-|}9)UN1fPyFk#!(3WNX zv#X`9pp=&h@n(^f_Re(YX8MUsF~3tX=z=@;M8`T;Lhd3nIyNyzm2oLe7)*ZLV1LJc zCf{)|Nh6u+xK0&D^Q@y*O)-Xarw)9;Gi4M|_EkpfU_r?W z{58ux({PP~rF8t77c7wLtlnq~M*)WvK?1DqgLIeu7&`YPft`7i zi$It#{jpedJ>D$+2tjJ1|9AzW~$!ua0$@?uRpo&-#~o6sE;cc zGL9f}adA}|^$IFvu}Sc_9>ECs{*Kz|@t3>a?Jd8#aqjTGC95&$O!xEm$8>UXk{2d? zLX>2V$nZmvp{%c@K*E!(P%AHs!K9}%==3b@>l5bnxhvr;^Sa)dZ?c-D;pWavXV58X zcG}H{!=MSW^D{<}&f#=;Iik4M$m8{}-tF=Ky*~)uC?$LjTxV=|x8Ux0vK-Ahdp^lU z2=>U|WJ~SCX|e1}quD6Z@puZgd0kjo7!3|GMsVG&6V?0~VPCGdDIu?WAG(G&LJV&v zHnZW}kLetnm)~b|(z*?%kaPa2H$bR;x#gh3Vn3nc^;fI&%hR*sfH|(7DXd&$~Zd>Qw5t-yu_P zeN!RdXtBfY_W325TTI<8`32APZ2c^lqpx))la(9^w?NRps7k9&_2bX`_~Igazgv^# zv@CE#%2w-)F2*&FCNfVL?p{uS|47%CNJ2tlJ`5I}K-aULCxuF(NbkGjaF(~Qa8PDy z_bRPX4}Zgo%}L<%UAX7q<7A03tQ-Y$uQ%NT>b{1yTvBf6+_a%pSB5@w0qPRMZ^QY-DuTHx?HU+yK9`qIy zsb}RQphpvFa^6lziR$K=FyRv11v^2L!zgfac}nSI|>iUWM-d=clEr4nfneF@a- z3=J4GB%<&2e*Ktcw?_!dEyye`C?JkURT(TGP zQv2L%JzwPh`rz=>pBseyx^6?mBfLhp1#VQ69U&T#-9j|KEHl= zY`iNs@C3ZIwXKdO5GN4@q!|bgmT=-fOEZv5TU&pNI>?hDyR+5cbl5mr`s{JFrPH}u zC>H5_8B(|{#Q9BoL`1DzartiV`Pa$Cg>3{lEioMO+>=g|CC^X6u|ObNEAPrNm<{=} z6B67cnclo4F=U0$x1kVl_L`#$b&JtX*KZ96kG@Hhw{>mR83{2;h7t() zst-9gwqiq%=_lHdY}Bb&pxs|>>sf0kE29|n1_;b}prK*N18IwS;&;>{is#q1pj6}v z;|K&?G)g4gxbNS;r#A+7<#0J2;L(^My1U8s)No1Qd^oJu=Fx~(#zR6*&lgL@nu5T9 z>)bfUVlfs0A4L@98G?vPS+6Dc({x(b^qFNs-1fr34r2;`A1HTq* z68G&6kD|T8AB(<4ni9dq?Gm{gZP$V0ELVk#I9f`I0t*;4|i!(S{1A<_n{kep1)c zZMG)8(^LPvue`J~G7HD+4vj>BLJCI&A`e|j@64^qT49Girb`MVKHuc|bAyaZ%=_0~ zKX~VO(64<2DQ*&oP7p)#o+Yj$bo5VUK%9}As&ZqkpSk%U%Ktn$!48f{)O~2AJUt{5 z^wS>l_;zKSWy-F6u~JiEvshNdV_0V>VA2WFB{?!*B7@!##^-rS6N3X|lqgD;Bf^=K zC`leF(lvg2>?OEc3OhB1_j|(^O!^juzziO`8GRDIf%t%Tt*k^d%Y~_nu@;g&xDCzU z(pu0LZ^dNl*U9Ys`sCFD9=F?%DVX2#iL9UOR;HN9jLY{JMWF1dU_j@*K$kvD7KM4i z9QB@C8P#ia)6$s?=*Hj?5Y*RDE!=b-)>bIa!$n}?_}M@iv>3LN$faV`5g|i>tQJKX z{rhUI!K`R1el?2myTc|`x+ zh7>D_eJt#M6L8vRo*sy#SiGymLE_;O5L_-8uH6Ce>ulF`}qwbQkp@eB6 z0-WB7Ktolo^SW)2%pDjQc+17Wz#srUaL;`?=Y*#f02&-q%Z9F2BpxkN?SFOI#y~4k zp99+Kb~9G=dKHlZ({c|fp`LwPnr(v>`tbctwm;yIBaWVPOrEY#7R&^$=TFNv+AHE? z@7A@$ez`0jON5T8m*Dm%;n%PGe7NX1(>SFJAJECNO!P{)8EH*J0qan`&`m)ND#?un zx5Oh%BbFnka+lweeOW5C|Ga^b`X>EQI?DP77MEovSKkS}C4Bg}@eT(3_wZkVI+0%u z8U*C;_#fcE;=c+1q4EBK|90{Kb3u$4Pr91_@b#8P-T@LtjxO zQ%Jg=-E1S%T$bHPT83ldV9L=zsn8Nsx&X1!w}D5roEX!>x+Z%AU8X4lfe~}8^22-f za%%q~h=LnwNi`vbqN8oYCZI&mN+b``=FhMx$Qz5B|-X;+oPE zrAZ9_>IvEoCB%TCsM%L|ZpPSP0`e(O7YEov8Y8)n9+a^IiSeRnIFTFv!SR-?Fm$-v z)BF2i2IFQ1oNv{(Q7oD+1`zwmF&C+CtaFh!1#}|cJeDWHMp1eS(X_{D2b2e-2kM0} z>JJ6eOIu~u<}SzBuxyHkhlgk3;D9tUGZUUUk*7ju68ss4Pb3bC&yR8)IQTl2 zL_W8=3VnEZm>h*6CMH(zaiJNNkRT*hD@TS9pd4{MMJDF1g8&a7IyEK#t+qBIKc6Tw zFAp<1{$My3o0N+SyXJv$S@zmXn&i^OEdEz!LqkJiMh0|EO^tQj!SCOnmX?-;&CQQ2 z?w-y5&=4UJ)6320vVQu60S6CnVrdCggUY1e1_BjolI-`;+zb2Ev2mwas}GA63pp`4 znFXJfmh71#EOWBtd%#5Uhj0{&j#*m@W*X>R2YG1iBT>rE{a?XLu#D?HGSai zt*Z?{v-YpKQlLhZ`pQCnZf;FtT>#t_b9S!(0Y(N72UkKH_7qn{P|tWE!ylK5!2RnP zDAzDwzI>^-nk6EsDpVR0JHYljU!pyW{ggAk_P}WKISLz;-az0D=x_WiePpSqsRw^< zemC*<#yL1RsIN(dzBTn{oKn@+(xR@J03vkYmtb&c?j*LZ{c4v)@qAP)tbV7bg7`^( z^YOE47sI*(>iamHot+&eJp&WdgUtkqczrot|1N|+fCQQ|_YNX{vD<7O!GpTNP`}G? z%WlEW*Ocz27+K;lYzPPGo0P%8t~yTypS%dO*E>77NRtkk3;d?FK-kzb9qQ7!5m&nX%At zV;{SXm2%a7H=WiM6@jIwu&}X-ZW@|0?y2nW3=q@M(k7ik?w<7L=%E>j<1efxK z#*SXg8dVk-50a7)F|!^NHS<<8tOXVX?3(bL#K*^jY4REm80LFrL1H`az9uxfrHoT( zK#<&e<7!Hs@M+nMf~JG1YW=ueZ)#?YPYZfVKD12`q@t2MU_10LfT_Ls`klqF`D;y$ z0vZat*Ar1lcX}l3&4`$xwnA9-fj3{&yH7&xA59G8nu}Nwk@)0btV3J zdr~wDw*Af{Lqp<`LDY)5i3edJ?^iGPVB;59m{%Oqfg1FQP5mgc0#}g zR;Le-XgD^BoJ}7#O5z$LlQ?}l^U(*xnegH*qI^CxJss;@x_7iVNa^n26}Ix+KW4F9 zY0+1N>7-BILo)#yfIfqyd$)(9XNFG(M38Z(AtZOg?)oDH6@K%P75ib0maAf$H3CufWY7jG&L(GNg^3BD&oR&lS^l19p6#B zv;5(IlYO|R*Ylb0(Q@ZdSOr7kUysxf2B;Y@u|Aj^SZ{EB@C}XGB?gd=AeX+SB3<~D zSi!F{9`E#ZyQo&VW4#X`+O->0r`eJ_=44K`REpI;hwP~t3Dp`TA)7e)}8RG^i2%SE{-~@Toest+Zes1>R->0Pn)?`N%r?aQB7dd*#-glM>Ndz6> zi{;H~864Rlbt?#&4;<9oi=}p1$7`dv3`XpeN?3o)fk4u}_F*U?24if1-`W!~#u`;! zhu^&?xy7xg!wh!ldqq3`viz_nGavo4GL7^`*7i;l9Gnu40D@OF>H98^GR=js2f}H* zfg!Tm?0XvNyfHK@zG>V&?h1J1zy4x}{;_xC&Y4mzG7rX|KYHnAhM`TI+=nD` z*ZA5-l-x%>0D-rMSe!%h0$C|4|L#a(u=6evu!EM^HvGU8EsIgyXs}0Py;xG1E)o@Ea?dC~3lP+Ih>Rkd7~pYG z(Cfi7Jn4hVG4|gtqwZ6h8*M;e{5$@KWu)?NE+aVNe{e0lJmwiDQGTpaHA<=OB$N5_ zd8Nbxg!}xHEo*JPWYgEBHO`H1g_exN2G-7@^D7#+4LbJT6e|Yk*fQey&M5{uka#P$ z_#(+g!gDJICEtRO#SPtF3ijg&%YQvZ#y-w?oXGWf=e-vE`Z&q?C1lkWvey?34z#Y^ z&cKsymXO=eL#XitD>s~nCvnJ8PdvAsG(!v{h;id_=sXSq<7l{ z?6WXC@jkqu^l$@OQHl)P(2l9 z`2A1HX+Ld^+`2^i2&r(F6wqUd@DN7&@S!|~sCOj~K332}p4j3|2xf7n<`Dym+#Zi- z^WxYMF9&gZm+Ob^g#7x!pj6`yX)TSkhVkWaHN?JjPG`(N2ne*473Ntafc%#g&NyMErKNt5? zxGsEs>?*|JT@pupizM4~I=#9;Jb$Lze#Y!LyleZuVJaqQd`TYAXA?S^$$*GD%NBv- zzUde0xGSftEg3y-e&dA4JVlZ*+sIvpL2Dn&(CQz4@T1pJl{3?nHKt{#(mPYYD3jY? zG?cL}2oY-ponQEy>YC;}2a$35361?UOTKTEO0|*mRZ#w5fk*Cmg~1?g)Pg6j)iyg$ z4u+?K`xod#96kn^DApxB1Px(b?Ge?DzE~(eFk(ee3*zHk59YFQvD&KG+FRq4$~^u< z%MOu7ehYoJr7Ui>6Z0c__-&QEcA>rc^{*-?P%|&tjBqqo`&xJ&Mc%lzwU8OAaEDo2 zn67@~#+vNtH%eF|EXUbQk!Dy%Me~?GD59*O!%sZJUE(;BdkA=?*4ky^Ox5O9G7s_Q zZ>ob=axXJ5X?ULe2Ha{Yg0|eAB>W+JFP9v#U=wB&k|{D@6~v-AUlftuPT%G$gX&Zm zG}%@tX+|^8NzF+bm-d)?ZR>Nrm%rwN$AOEX)a$CWt`mY`RgGjdlftYGaBG$O#q^7a z$HXh(916Lgvx#O;1UB$N_!%wtd8W8=cH8@ESs_fb*N-n&kc&L+7K0dqo+xjoS?qd6 z2FY<)jaiD(z=GuDmy#tzp+o~nkj{)1g(UAzBHT1e9(#iS8Yja)tHxX9KA^AZWP zVN>H2B7-X|PL&9)YgFZrK-vdVEN)IYxp#PYlWYcxH1&61>X}Jy$W(_$Op8fw2nMxO zBd274ThI(#f;KD|M_=0$F=$v{#6J(2RWzFuDm@x1Ju?HDxZ)1r*vL{5kX49{ zwm}ay{9qFaJiC^;3VB(IhFLZL>@lye3QrV)0p0b^pkIBBdp6|u;>cM5euV+K==x( z``h$ZJf>gi2Bo$a0{2O&KlJIHg;9#1gKts^TL5ay&uD>ry`|IJm5;go7l;UQTSMJl z5ku;xHtkI}U~`26iE8!R!GIQV zZean;!NFnH`|-*^fo}3E;zkkjZ;zMXHsgSq8-T*hGz<+jrJt)pIwC2;AR zN*<1|gF_7r-s$yqB+wL}UR_1h)-rkjK1JpCz5(Io<^9^-O?b82`w<6-J)h$zuIm{# zzB0ZD8=a#2n-S`MtEfOlCgO+b@9)pUOMtu#HXDs68~}0L>7vzCSC`gNQC0@&^!yp( zu-V%Ga(`iRJdsxKeQO#O9UZ*hWF-dhpQ)4p{l((A#f>B2`zelq2Mr7yynlDsh%8{l z?ujtHztK9h^%UH{Q0ey<4`Tyu>Xk1J->R#_e*CaR4Iklz^Mvf27m<;XF;dFmL>!4H zw9C0ow8-Q3I9HdJmVUz9w3fS7%;%>KjKgR)YPk9ITH!F!x`EbDHB0m-K~PX|@8SYJ zARu72!$DZM&n>mi43{C66ASWf#2|suVAu_LXMG4Pg<1*fQq=8aCcLeU8(gQ^u&ax}N|<1%v=nA0l^O07|Dvy>*07sy`HMqe z>(@O%M{E5k{wafti|cUSr>mz|*wLX22bF;aG=_=E$zb%F)rl*%>{c^jGAUFdfV3f= zYtcdzm|!svwVL_&_RRuRkj&p3SdN#KmGy!8v|D{Yw)V)(`D*%zwjKu!@CZZ&{LU4j z4kmK=sGC#>JxNY-ekI@Y21SThozbb}gJ{*tqz3>kgV1t1oAQfJTl}E>P~3ovJs^|S z14@&Xew%ZlJ7Mprt9HJJlnr83fHK8zK9>V=9CpjNPxCM%PTRc}owc!>%e*g^x|hmZ$gGrraWD&_KeiqI9nEb6w6CX6w$Vy`uDzc_`kNc z0V^!wvSb%#rAC&u6AvF>0>k`dCND8Jm%)SQvi7pJ(_?GU!_3>8duU{2Ae+O^`7Q{M z8v6j^rZmo=$IquG4+&kg>y{#$aVUil)PN6p%N`r_mhf1q`%;_O2vNuKyUtVHz@FH7 zfQh%!G>#(i`_hQgX+=>@P;cE0{fLk<_@uNtLH+H|ax7n{%~vq?s*H2%LSDNHM2n>| zfhCXbgGaL)=A@BD7oi?rtm!skoVWK-jX0Tsy=(LR>#4oZvrm=Rjw8t7{k^;cp|ko2 zCLIr?Y2#Em>UT-vf`=9H)|KqJ8+-I!M|~jgQGbR&Fpn=>+cOL?{=sD6&=13bphtaT zrOOnr8vhlQ{y*QZ`s&hF2K%`wM)O;|di{*y_aEZ5Ozm2rQ5J>QQ+Ttg@G=n}vbf?v&s{QO}gl!N8>ey@dWbtvDofS81g7H9eAsQ}~Pm~J`M z(%?hT;-bX05Of^GWAkF=>{{7!pnx6XpkIphH+6k1!=*_S`RSJ@wR z@W^7nfO?Lu{&>mYIM!^eC~wBi5|<;65ZaiSZ2mo?KHoh2j`bxa6F*p_JzGN|O6_s@ zJNGMnek_u`(BtV2A#>BZ7P1gR+wg0(;`=gto>#tSLZg%O@$1nvk8bDS&O_JDRq>Zj zumolSE5l;GTQ_pAk+Xxt)o_OI6L1orLIsB0?nrl|*Jt5Nve+JbJqj53+np+o2QTrz zUs3MRdFA*!8XhskdRt1<={|)%tM*R0M84_Vlhl@16-@G$hf#t2e_cqk2{gKrz;|-~ zj{p0@@cMTRq_Bwpv}>Q`HKnk6$!G*uusIrsEr)+6X%0IkYE*4T#xOT?*m6`!FHMhV zXItxk`crt1Nxb}xRnYV%DYK08pennvxqq*?OwuJs@)d-#r7b3;ej5`5(Xad${>-U! z`z|!`XV&i3XUbmh_Q#nlx4`@?9(J!QE1iFtuzHE#L~b1V5&8q+dWKIB@PcJRcHxu1 z?Ec~iMR`)LmqcgmQx81U?MNEO^@p4!Q3p2T=euKdeSL;@`*k*-c!?naSjpNK?N}JQ z^~O?+sd&K8fmZ8+QOn`FJc=DvA5X})P^0&~#5!157!63pWnCjGPvJ>bOuDcEur3|$ zXQGeSyLH&XX=!Oo?QT|-#;wMwNi|G@!Q2iT&4oZ7UW)AlVAZ4@!yYy8I+;}3;VN9T zw9x>`f7TxgoxECWK%RSu`W$RrnM5xx1XI}I`BN5f2$TY)5hcFGedKo_>6}FU5NWh# z7x~&c;9B*9tb^5zL_t}FgBZnW&)@UuXYhYOB_vb;TqtGaQt{FUI4AZ^XsOSKO$_=N z$OIO$7)fOiR7&~syk%JRED4X?Q!G%s^eX)&yMunEEnhQBMrI`tB8TmcG&Xj2SXd6t zuObA81hxA_%hbHxC_2uL51m!n%K%KLzN))9njh{Xbp{MVHAmAp<*K^yv9G>>6V z%Mhy`2l=lpg^r%y&Kcu95DJy>8@xwj(6Aw99r%e^FrXnX6iX%05QL?StOa){Q;X&^o__LhwSeUMt(9Kg24>FDa_N# zx$Q-T1cyTSnw*?mPezj~I2+IBb)^jWb~GS%Zth4z&M<~YMiu}KYtS)50TsE;c^}N< zVnqSgdu|d8@CDtJDdZ4nWp0NxCP3;sDDn?af*lx0P!dr9&^M@TIW-E7+EfMl-1L^t zn{Z(faQ$+d41`f}O^$GSEfq@aLI-He3nO`|MrQ&5X4j?-aqX{c%w!mUTMtQP2M9c8fCY$6!G><$99U*bE-o%Fjw=O>#Et`gdN+C(<0}TPSrb2ct2Y$R zdWPJxqozfou+5%vt}l@J%|;N~J-o(~DHX^jO!MZc4#az79`VXCL8qL&F4y)qKtf8H z){ZRWcn$A!yvLx0q{5o5=gERjUGVE+H&;@yWqUT5e__WyzTclMp1AD%kYxI14=8ru zyasKFO_B>Bcy@O7>GQ*-C8@pLyD{wQPak)TH%R1CEcBZzplx?l{mD!q6wrlsgI&A% z%i7N7GZ-thr*HqxT8n7;>k_=j+R96xJ#eVcuzTH?TF7}%c%#(;ABc3t0PxjRcPI;G zEKXy1PKQv8^hVt$3yKk@3Z9ThcT&J~N5jgh($gaL(c-wxyV2>zY++?3XYwDGCLfLG5FHsCXKBqWPyBfgiKUQ5%#$M`O zUR#uQMDFdjuM?n7VRn%`7G zN3F|aZZaJ6#Lh_eSrxN{wuf{Bn?}=_qJOy}!&bzq! zS!Wz}x^#913;f$zIl`_VYc`A^aBn{i0kSNTxVZS(^#&k&lSmCdJ$Yv-8q<%qxf~vq z>i`W~aTdGPMAiUcMzRJPmu5ixY(E4RaqLWikkaw-aeRfWhet~Zx-yi733#h9dMmIx zMDxDk3-)0@LG134`-RVL37mew7I0YI32f(2GU_%*ArbLQ17^h9nr}eG8oQQqb#=8~ zuG9!Ky5G2c@7wmC(O9vm`jDzXeL(aCSFq2Q z4{B=08S1ANJCv}kzdQmxlZNO%qTx3ykdJuUHCk<~X80ILC%U_T z2-fpZWw|)68LnB7LY(#m=goPR=6lX9LO(xIi|tw#am~gqOCR$7o0v1hiP<~E$JFKM zGp=h(VaOn)l%4z!Ca}kQj5wryu}`~;36m6?_J}9EI|sZTLdk32z1CM-E?<@27;MF7 z4*&G%pipziNtua{$fbYhy6$_-c-B#UT0dX_|IaP-$FLKt5#^2hCDG7-ZBG8>1otS# zRDlLu;D5*efWiJn(B?{Q^enZP0L;nh0ps*&%V z_m+Xddq=>xkHAe+)?o}a`G0oT=tiJwJ)&T^f9O!G7m_@pElGl{Q{t;9kr67ugfiXR zu!JIvBTxz(h3Fvu(DcBgjy`3%Tcm17U`RORkxCHQ#Yi4(lPHnxl+YK4vA+$WjI!jL z2#IC)1>73sa#L-UOt$#dt@T|i@X9mWqh&5qNRqOQlnnZh&(5XqvxRDa6l_NIW+g{s zn5`wrJT)2+n8kq8jwO;rHDb}K4guNC3G7CvS{!W@aGhJE8kJ0}RH#Kd?)E6q($W$D zeLb09`M2N9R0aPdt=b>0@x?c zyOOcl&F@as5@~^dG*jThasQCmXY+x5_Jl7Hmy`@JnT`fBgfy5_hY7q}G=ie$k6)eD zUwc_{&AjQB;Js&V;`WUY)Ntu|c!b1#*8#7wmA3ze2Di-u#WH;)Hx4rC-0rZLPg#}{ z+8}I1Ar|wPE4FdwC7GS+@>{%jZ8=pwJ>5qSfLFEP6aSjH0QdmX?9n&ElJ{iuWxJ`}pQ z3mDEeDT4uiM;$f_ZHThU4Hf~R#CEw-1+WBH0MwM9AW(qIeecgzfGXO8{D3%U9MP3e z!7QWr75HPb=TBV#{-RM*Q*Tym0hYNlfWB(>x;DfEI5$j2UG+}70JEofQq*2#9F{)H z;P=}NlFtq;FzrAClv$*uslgNl+5Py~xP&twj2fv9Uf5EW1cgdWzF zar5cyZ+urL^TlqoE7Q|)Kw^EL!!mZL!*L%9gH}z3+$liu;5~g8jbQ=EPI^6E;`_#w z1W%{4h6xD?olB&1+GlS%p32*t9XPgFmgE;W)^n#uVKIKu9xN+3DdO}j3H~)OaCb2J z4`9EZN?K0`bq1bF8C|~s#yCza5Py%nz~-s|()0-J$>$?LW?nT$0_CQ{Zmy4n#!SO^ z)${bU_4W-|s}%s|@^awo<6{A&uiS=##6$es`}@mw`ulGHOeX5(ZwUjzR`LLQoQxAu z0^WJ~Ik{iooI~%?J;ASI=cJ9vZ2(~V19@7nT#bJH)VX1CUK-FbOV|2Py#~Wxus;F> z;W6nfMh*@=G%OtuTGS%Gkb5W@0&fS$ZQ3$tG%q!sS@N=Wxw=ibz|(i^1|YK>y6KPS z4E$FdeOgU6mdcxDs^x2YGNje|rAp+U@1zJHUMLpp=k6zSgEf?l_8?oG*2`5mO-9yB z70f;lg4ekN>~YKxe*}p*Ha~}Qnd-7zU_Ct3;3f5d-RNYi)B6C{a9zL>oD=r0FbZ)a zT9BE`Q-a&=+=8?Q*u6saq#442WPh0)nOb!vKJTovU3EL!c{Q z^TNR=u@D>ZmX`oAb_QsXA-BiVjHAM0?UA$8l|Q7ukdl((+r4d)k0$s$UkAi}vsq!n z4KN;x9(`;c2`}u1`pYvk?Tq`ckn%Nk~Y5=E=%Q3l-I_A<$X~k0s!<5yLj_EDU=l%7ewG&)(mHF*5JE|}7&(U7G zGbQ^edfqp^ySir0Z$WB2(XlM zRk}O`Hnh|<)s!>pU(#?C<_FJ`XoE@j1|5=JO4}q-gOXehl&=9s0Z0gpdVq zA608Wfr6Xg55j?lZ-mr`y^3`FPK#m{<)-5f0YRbwh2ua&1mSUagc$aQ&w==xbVtnp zA~p-)Cx~^Ga$i|Gr=glGW&^iN)C6F-F9Df+auFjNgD(J3Ee>q0|Lg}zkst_xmMa#B zy*ZbwReFe`SjFA*tFgIZ0o4C!@cL}IdcAR}G|<>N3$0gHda=Xjg@sDyD0!N8L>6!xwVS;`&weu% z6?967a+DlkU7Gxb+)-cdID;9uKeOte9P`+WC!UK5BUr=90JL$Q(iGIOy*)Gr!Zk7O zVe`e!0oRE)Dk#-qh9WFpeBQZ)gq{-RS?Z*ApB8yA1Bcb@dIqA`)vd`r9Ur_Jp*Y|b z3W(Be=dl-i7>;1F{|#95*U8~vG&f;}lhi4x8o?<$crQ{f4^0TPqqturFB36x2hBuB zL+f8$TKr%yr$u=WDalNtRgYc&ew17BbrC-iZDih!b>|arqu#{FJ!l&*3!G(Uy~%dp z5Qh5?Y9tX=Xc?&{5iz*wz5I5kcWRgbj6BL#c&O{eU&0Z#ec3=9uZQNh>_ESLSAKx4Z~5W;X%GKd22t5Z zN`LZ8{&SHSX#j4!pD7`aPuO()GvFDf5$=njD5CW1IEMwP9vL30#J3)Y_+9l-TZD1o z50F2Ymsr2tf*JZny)fSX--uFK=BDNixty3UK3V84?*AJ^>yu~`ssJM9zt?{OqW`;j zYFOO=1)@D2WYw|dgGGdF4e2Bk;*s!^nhJ)#wqswQAn3{rqc=80Cp{uZyA>fYOQ;~S zOA6CB$`%l7FR~P&s`lmfQ&~k6N(Ps(J9cMppM0AhMb+H)z2a}}PTxLgz3TFwdf&Xt zy8CtYmw}NHmjgg0080Z3WdDBH#}Q%b(h9g!#<6FfGOtkl6#{S6F(eU)i-Viu_yOry zMf?$4IRz$X>QfO8`q8(N8|)l}Q;&XgVE<7z1tuog^OfC7q0{R@rCe%ms-J0-LX?2b z0!221EdqTOS4|z%Tu9*i_wQOY2B5B2Te@0msQc<;p8LNw0OOZ6GBVNvV6bI7zUAfq zXxM~HWvWp?%2-lUQ*$9#5ZqGLGkP0__-gOpFP{v>;6jj*lP3TL9$wBA=IC0~ed%bw zMbRFH=+C}Hpx)CLq6sX4md^RV|LKuHlz8{}VzoZZYPqU12Y#HdwQy?#us(n_+?`iB!hMIsierqe|3eY-4UrQU9bE+2 zgbw!r57{4}!*~;ulZC*tkZ6dF1bTxryz&$RBqei!_jCsEgI=K!}oB;hIyQGA~4reGaT^!+ezpRNs zA11);$_21rxe$So%_%I{kn|0pvklo(P*4=5{bdH!J10oM1(pH&I7;hsCKbk}H?PcF zVIBZ@K5mC=A!_^NFdaiz4hh1Lk`8XH$B*UCLaU(3{%#D%J=$ak)no?(2HxgBm&bvt zGyp*HGv~cyHFPGW3a^D)WAUw?Arxg?N?6wEjo%hz+rth zO3cZ*3U5$B4@YLutP9@u0G#&_!ay%OV2N9NxyCm3Z-;!-L)u(fSuq!x1BXcN1(Z=3 zhJ=ROGCC@twMkCjhjt=&vnA4l{_A9+RJqn6i4_a<+yF&B>CVEGF!W7ULnDo5=bL-P zasM+ZckdAf_*9*y-3UMe@RvCK-kxdn?E&7`hJoZ9<{u8VEeNgEY-c-0psrUATrd)7 z0%i%#?d>gqZ8WxzTG7MpDpKW9_U~?=5 z$}^t%PaLs~bp#w_H+CdYfDw#gp_>~3Ifydppqh28D)ejhmwUi;FpGRJH8Z@cA{G`U zjBA8_+A5T5rmy!84}}d4Y{k=_8e}3CdRr?{FP?x<va|0C~ z)4~jhirMVtr>Er~NKvR|*bN5?)-U$#_U8x&83HW&wfEE5os;Meoef>j&(BKx4j35r zyL}-l#d7%U)abN6lOIX~fa!^7@{q)#n4`Q-chfh(D+pl2{TQIH`U_wQqpg5&52u;$ zwFML`9wIBgNwwEIBBZ2eXJ5L2Hj*uDM?Xw{xyE0e0VJ!JCPZ9sPlQ>_;A$EYJWP0# z^CVmWg+1`fO?1z9z$E#m+XEoc6VUA=v+%HuQ=L{40R5)3u&_izN-MItT<`QcMTGqs z12#2<%RDXo3Z9N&31k{oL=8BwhAF5wL0j#oCe8FF4fd~r!A({l&(X%Fhg3j9LJIgW z9U1;OEF}dc)DmjH8W)9^YrqlEj4%t(&r~%y$nZdWm&+TI$L`Go~a zD)y5=@{T{NQQJNmO!U6M1ZG44__!QQkJTC#hZr{^D$0B4Yf@`4nvj%1$m8Rq+Mw_y zS536Ss+i{oP~eo26-idGGuLVzQf2f1!s=Sm*M|wv?+Ua6v6#K>tIc*S;TeTn6twZ# zCGT5qpcKQ-=gVn6h389bX}TnoNCQ^Vp(YQBXXrVfrVMm-mg?>%mqRiwNKj|3Qe8Kn>*l+xk&Bg^7;o=ZT6>{ zL1V13`q4ZNeUIWZsSCIG6B3(>th=3yx7$V$kCE-o~)=RXw<|L)2nh z-=;_Lhr7VpNKQ1dsSdR27b}-82TFsn8((uO;aA0I~MbJ{;>Kg|!j9`5MaMM2E;V)@~XG zaHWaL9{jyg`qGpiqfKr8%u*=%D_O_D*7GU~)aX?}KWpnef(~m$ixpiD8Fp1b8(U0b zRR{0T6!rDow3D4U&A}YSD&3ft$MdgJeMp)thXDC_gFy!eOzU#UmToTTumluOuT1tR0tz4bY5f-OJOqg4Ej=1j9_z zB~?x*<_*2!8M5c|pH)L7dXC&Zhi&-Zu%tlc4SJFi>!!GO_Wx(VMdiKU87VMV=-=zV zKxF^jKt1H?e-K%wrG%|2`ta3a`H<`YHTiq)@82baeZ=Gn+2H}yD!If+ruhMBq!vgb zu!-_0;{sI9G#q{|t_PH%P0Y-MbanCB*w_U0^az5( z!j$9D_n`6C)9(jSaKJI?tQ6KX1|X`mYfWERMy>{ zBYU{Kh=6j|Ax|4`DIfJ$1pg%X+6W~2Ft5^klrK zd)5(t{0EVYloZ^}-F=c@M4_>$s(t`Dfla6>!mB3iui(bLo01Q}*L zle71D#}(N+In~V?Fr^`0k%R*wuXDfW2oFA$hL66%ww9Kj>uV+nVsmqIxNAZqbMpSE zxh&U=n23l7c??%|Q6q0}9&L?bY8(Udn;%V0O*3n2uM4H#=`|n#m@NkBR%7Y8a!f!% zLIN6rCp$YJ!1Yq~kQRasOgSPmeBpdA zC?FjLF~Z{E;mPES!JwwUL2eNc7Z=yi*H1;*`S{>Z5kb!u9Q8I}Wk|GnW@2L_TP0|z zuP1eJ7V+<C6un;)|-2i|Y*NE3YMlXNKV9Va8r#BqG-=LrV+I_BV)8g$5Wr(YlG;{gSxu9W`K+u8$@he++?H>T^}%S ziI{|>51p*3o+Js5QKWz3v$efl*xC86Ff6F`^y~~A7*o)MB+^~V=22~thS~(+He7e( zm0`*b^?jR|#zuB{W>M;EUQG|c^s4FXe1{0m#GI$3r0f%*K#Sn|f>#-gxnxhrOZWY^ z)o;C|SD-0)p4}pIZZrzgje?9|tfP~qDW9t3Ur|wELV6=E4SWJ+NU!hjgI8BIM@g^B zI+=-y141+mEU#?_G6QPDflsP-!0<=(&5a}QnB|ssP^2he7GSp_larI<*eexnhyZy% zE_>l(tgbpT|N9*jGfg|~d*qOx?{;=}Y;d1MNDUAk32d&;&dwq0gSO%X@U?Ai8GOmk zgT;`VX9+7!oWMTarwe~I1%TaqrWaA?$5!-JxMI-|&+mAGKW|TNDHJsn6nez+nzKOR zg!i>7F{PxWE)RBEB!2$WRSL;8Fd>alDb^wPAJ@jKp z|I4t0im~yr0%d3nu0p{2&sS>4!*`F;tG`PMnT`M7l)v=; zEa(6U1mxfAzt~{@yHyjU^8aiwS+LQnqL`uj^=vNnS2HMX&?a$A{#^e4b%hb|eN^j2 zihV{PA^vpuJR+JrC0w~oHg&)ibY%R+P-QG;eCl+^ zJz0)>mUEhGzN%DqJ?(DH;y&KMf+3?4gq2bV{F0OlK~5!jBOHQncXBP!Pe0kIPmbZj zrH?eW?CO!+KQ>4^S+9@C?(PxWPm8B_d5s=ME0RFHdu<1*HBGRSLtU4RA(x5l6SE*2{ z^b5IEiOXV|Y?(o-@kj=q)JO%=>qD*>qASbiKI?Y=^;C;^ANs;mQINA^|Hf_zG z%SWiey>BC`0oEk54~QNw%|92!@hgpvj?NY_`FhS5g(IoEi*!Qr})7+Br}&O0pNKRU>b@Fuu?S0{`SW~p^?$A#-(!-F~!?5NH%;0 z^iDP3hedU|Yo)v~R53;Iuus}CKYN)hGQtbvBOBB@Z6EAig?1Q5JB>6{oxv1pKy8WV zpHqL8*`BONghJcC*A9y#*(g<}>`YmiG#F2zcM|-;FU4mp3e99A{nw^D!uo{E;_@YL ztZIJZNpT_-6!V&~`;A3gADF#iamHoEbR%m!p;ZVZ=5fo=`JIoVbx4OqODX$JXC7}? z{jlnH#s|Bj9S*P7-A_KEc>(`%vPSdz0YncJ(kJpRpyieW%22RdBak|m z6yQEY>Cxq1Cp@jqMSh^>Sz0s;jY};Y2ehSc3)6reJU)-Cu`mtmU!k0{5(%2n-0Onb zexgXI%+e1Yo}y@yi0>Cx2l$GDDz4zf&-%%a`3mLTl3LsSAY}d-Al;8=x(|L}FqTv&UjI=1JhV6=-o$^gCz!Wl&9D4(it=3&e|3h!@a&(YgA5U z(4CuTTzTm%NnJcXOx0Hd#Fs@|G0>X8*-bv8vY`RpLvDsnT*RK~@1HvB>Oi$XEnBoL zd^k^U88F=)Y@>R0qBu6?5b|B6EBQT)ma25mpnKf;V!eAcTAJ_W)B$0kgT85Z9LfC} zd@L>OPCHxab-Oh&z(q)dc zWi^%ct94(4?$l7SE(h$Punaq(v# z08VTrpiUJF9kw22Q~yxHD;Lw$HJi@HcLEausY!5E%4KaUi1J9EGy*ly{5u2)u*DeJ z-+y$e?5$gXd^xk-XsNyDD9%tuMpC>ObVGZR!95O1Xy5kFb30!_rNIU5v8UhpgD?xt z3^qOlCg9fF$rj#?(6{hsqqY7bm)Ft*3dBs zz>jazEMK0$?JgW_N25R+MR#`f@NONKSjJJFdJ)Qj$${SYW)N%6gKx)yJ&dviw80;x z3^4I)4`InBot`l>2LZwA3Oitf6?c>#P3}1pR_~-GtYRH<2ciI;+Y*0vF_CF5HM8rG z8#Ok|GK^1=Q@XnIF(V7<2ggv|F--6P8~@(5VHIGdSNXl&4D*aR#hLegFD|x!I9x|C9eIE-w9t;r%APP;g!_8*5R%?>`xb8>3^p|7WfC*0g`Ln(?=e&&u z^d?*}IPIrYFe-MEe?cah3)b|!F{}Z+cPtsWAj9)-=V-$3{MwZLF#>VA3gZ2JsM98^ z0EhNWagGs~{1a^FWGv+Fm~D?L4Pvc%H4Hr69?(<}jUkkp?q)#DBKz0jJrNJL@2g9r zzbTvkt9#(g zr@3fC>+A3pMQ=Tu^O20ww}wC&Wg|onRbYBmIgNT%#WJgj@WkgH zSMhmlBrgxOYciw09-vA~*VFgcCcJ%x&n4Ss)xo7j6Pq*gwj;m)2B?dRfZmuMfRUw*O)v#rJmIe>y8pxQHtZL~Iu3<-b?{ z^ykWXyxP|9yzYZvP4nh0Krl@ZOyMqx;x5hPuo#c^Bb-2bH`4>*8Y4KMS1(hM%+Yi# zMf>XW_oBHGw8Ll+t~1njyG!?Ct5X{vnC{?hDv|F}t^bYKq%^3l zy9iRc2#aI+L;Mswfb{=`-xd4?7_&HA9z=C}`;55Esu17ac6l4R;B6QJRklZvWp2M`AJ_8p zd3{EqyzIg$CEly}*Cjhs3_#>G?1S)i7={PtJSh3H?OTX{d6obE{#zW@&bvKo|J-CC zJ`2ftk}tb<-MES9KY#A2!}HEXyFqeYp7$nL2n%$}Q5}z>s-zq8`evB$={{*710;vc z9n|1cAZuQT#};PofITlLZ44gl33N5f*q8hI-v?l>ilT^Cj1dT;)2;ta%A;fP3kOL7 zxqbmqV7Ep!+%Vk|eOEFNwoaYW)NHo<J|k5-INAF?PsWd5Weqvz2j_Ec|@TMMFZJ<-nTwzg3wv*6h1g?Td7+& zPz2qkHPd2?T=r5%v*z@Dv=jMq#W2?n4MvlFvHdY|xRI{W_iR~cDK9yHdCeCTvl%06 zKue*$F}ZLnB0Hf$P~wbz+H0QxPQ8)RLcvKQ8aGoRW@B0(^i++0}Ppd^R4r-cgk~85#jQ zS1gX8(l;>2_c7gN_vej1gI>>g%8mukW#fkfgmHlVN==^J6Zv3Z0|GZUp!;{OC(4Z4 zNe@dN?=XHk=NvP3J?Hx|`+!bIS#Gv9ZvEy8ilPIbMil!q$m!F#57~3{g-GWTX#QCN z4uDr1v##l*5FL!SBM>g&4gs&eKdbJp+9x7mBD@m-kiMPxHlS)dPd>Rbj{FW=A>BOH zIP4QCD8&@WJou?j^jfO@`|c8EVAOtQ0gHK)NRj!?*~c)Lx}Or-XKx21b&@`xer-T( zAXpH~MTqm}0{_t<&jSRddo7KsI5-!u$0fOT*ez|!QI5}$+j}b*w;HF*A!9Scbi32BGNCL0_ zf+7Ep+8YQN*!uf_V@5m#%719GcDFRCAhs?ktVN=-3|+9n?sr3KBS&*v$3+Yy*Q16u zDHM!aOyq)Mx4=PS%%xc>tw;mgUBX<~XI51lrec<5W zH-Uj3K{;B$21l8C5C6BJ$_m)npX%H*HcIyP{<^xlDy1p}vZ+$!8EI(>L*-iW4;mMM z_<~LJ*lB{$A%wODcMV}b1qpL-=Q(D=^1+`4858brW^VqTVb%DmQQcIFJj{j*{&gm> z2+16LA;^RJbg{!7uNd5C@*orc@0z0y9Mjgh@Bk(RzsMd34c5!vZfXjoFO-ve> z$$5InD}pOc#~W-}89GfgK156h*BU#2$`x5O$o%~%d|pkOk9PBFHZ3f~y4tYR z-1gqql{oDqr_5xT=X;SYh1SRC>M^i3o>v+=nczFy`uJN}%;*a3?J%u<`2OAx9mH5# zhgFrugZ_3)WJ!9UhG_{EyISlV+tl47mDOh{)G_CjMRp zQPe#_KS7tQ8(BgG%F|V!_ZAI=4h@-iG7K;%GHcdqeoGa2FDW4fryeMWPEHbEveC#J|XwlBQ%g5f8nk}2?JzwR4sk|C&qL@h0Dmv zc_KWuCE@MGLNVlV?6(02jkejRY$aR#?~&^;$Wt8-uw@CbF^2lcwVA7;<5 z1?m2P-lg_qMRWe>ABpq-l-5dxA=KuVK|HoN7R?Z7r?@sF? zD4*S|o?$^JMCog42R@iEtdgff7W~l{eN5@`v%}xiNTkcimYK;}c@dF^e%3U%%}dpt zbIq^><<+|UT?dBZb#8X@;6gbM@k*Z0L~cIX_HAWeOgp5JSRUFVuA#lKjv@#a#?4&bDLIZ zJT)a3I`M=@K=uafyXI$si$*KyX_J+W=ROU+`8eR)L@Yv9icvfP*Jr>FTMR3m#k7Yz z-L)h>-y_+{WZ)I#yW%mF#v#kqV>~U{Xny^%6}jr{)?=o(6Iw5Q@i~2B3JACHemymQ`Eh0Bz%s#2aASb2x6iyN`S zU3m&`Tj~p@23mFvn~CDY_8rmSQ7zU+4GtY4_7U$O=Owr~_KsIn1#aw~|9Ra&rax=+ z5#27o`y5kBm4_emxgYtpQ9yKm=~W#_TR5?r1}L1s)z|RRw`-8R0r>Th90;oKCVC zmpGn4J0;} z7q;E!(Wf=yh8dwhzartn(nq;-SmT5ls`Mv^Dq4Hj*W06ww^Prc(&T9K@Yor$m>DxB zyZG3oZ@4@)$YZ!ocMKTXD^HtOn~FWNfpSfAo^U}azh<2jP~3q@XkF2Fr;}4ih=NQm zDWA%EaLM)}WtPcSbuH^nP}@l*Vr-Mmc)-3$viF|4`0`I2CMgl*YqVm$d5{(ei=RTB|pgV^i3M(^yG$d(5p>6#->|?j7sN9TOx} zy$qwMOB>aTMaP%mZuyoY*$AV9PZBz7+9bJ8UA-doCfrTpt78{--7$fRqPq{j(&6O- zV=$JFeV-(|*aIUvC0s;wTK1CHRk~itDtr(9)pqMOo{u+4ZOrAgRfz*pqdiRi?B=@` z&k-saW)<$!kZipH6*T#gah##eYkG3*dMzYrmOz+3i*s|YpSUqrTkN_emxQrIKKD$0 zL`Zey62ox<)sOVpm!|v=DF){rf23awJ>ybI+ldmKQ4&KDp-jjcnFxLv}C$R{#tt(oD%>LCjHwND2v( zdekLWfjmD36Ah`Bn*T*Os8e9*Gz@z-Hf|pS&$i4(ky~2#U|rdjc!=Fq(P5zwU3iqk zXi1_S(tI!kKcp-9mN-XbFY{z)Ulwz%*=kNKH<}^TbNIL?;V0FbkhHfAIaYlxmM~1j zd@It5SkO1(7SVWdb!rh;$SCC`L_)SlA+~<~3qewqZ=+;Jp58Gv^V zwY05_TFO55zQU0dJkA(E=TdWUEMeaCdW{5Axmi4$gOSYa{d%k(OoDd)bRixm=hIAk z-u5HXlr`&r$}-uSR@~_?rcv-_cISg$co}dlO*Lsn#1tYoFT4v6BTX>@mqRI}XLvtw z%{CH$_#&1LF{nfdehb@;n$A#yg$je(qFv`%QOnpx70RLjDx^FX&??mX#(&$-1obr% zrsU4(=$lG0D7YgwNE3>_6ox$+?g3W?+2YDocfFAIUVlmjadMFmN`V$XH??YSNs1bx z1Xi9~z211BpXyO1#Ncdz?)SDeStSe)L?pe zXE%sn`T9^5YmPOX2k(3wd|8(+{B;VK7u|d^TUWR11r>?d`_pbq0$I1-+a!0fhtnF& z+#3Av_)$^ho2Rcy2g95ennYLaSINs8Y^UU~jw6yBM;Y;`1SA+~@L#O5#Q8A;qqLzF z6wXA3&pk^fyskvIF+v=X{jg911TEi=qpfSX3LcI%1t)(dwFA?hnQnruMsUp|X!gNG z>*np&9_t>Xj>UdjYJqp6lHdIuf!nC)mrR;6B{I_FAKc$xw@hSVB`!^bMVQ5)TLorc z|7q26G?Hib%^}B=P3sXhiEshGm`UeKID#E?G3Q0R{8HKy{U>xOH!ILzNo2b^ji>oB zjmJG&drHGqZ_Cn%AKYd*bk zd$Z|zmix8X(1g7S_q%wA-Jo`@q1ZarB*zuE*ur`w_ny;n$vk+(EJx(}WjAyBq}KH| z1*>{6Oyb}5;&|)Q@sjsJ?UHx#)#cXlS1O@{kd^(q$D8`0#kG0S3)@d+&2pAT1Yd_# z=<&=G6gX+(7teKRudYK$kU48oR#6BXMb(6IGC}2s>)wI_XpJ05m(nSav=u}ZXKD1v zv{{tRw_@fz8|F?Q_BD%&acJc_{uFluXWlc*&*0+Gjm3=|dh_pIB=c`4e2VO~1UmgW z1Qut`DqtS2=DY~SQ_mPbuDphS6bPxN^(f9;La0=A2!{sIqiVuO9eP%@ULBd}- zyC~l)ne_K|1Ks?u3XyZ8t2nhlQ2G@MP;0%#wK6+3wWvJHvgY&#b_-H*aX3*uWp+I}VYen3wj?1Fxx9-*5nIaM-^C)dNl5&FUVH#0>^RL4w z#D8}YB>v*Y*%P7&{Q?8~h}4ls(g^0t`?0qL|81qTA($`}^@GB|i*>4racU)!9y%I~ zBRApzDLp@Tnf??~e>;5Y@Cb5CQgAh4V~@F@;YJ#UqzGR`XKU^e3i-E%d;!E$UXRn+jxt(tiv2T;`p1@9H`2k_=`nP&`%;&0^H8{iDAVj2(0 zRJ6(VHWdpSWV-O=Sw1w}$~T3B6Kgc`Ck=wAxot~>x5ez8R)^qvbT33Q>B)r~Wpo%& zDnAiwuT>DhA57u=X;1?&6LbnQ9u+awex+XhbgsS+Siik5;K%rG^tL5EH}*xN!%OA3 zDG6O_H@vgNgoaqCRjpue`jFh@Ad0zeq_TXDUAg?G;g(~dpS?|-Mok1eV-LKE(yPP} z=FI5>x7fL$FJKliY$;8s0c<%3D`6b|UipcAOu0N0XJTE2zuH8#IV)1;Co_K) zA2ItPTaB^|>mt9#Do@uQGuewaG!M^wEY1-ezd+{=C0Am*ya3I!IaFrh7k3$n-7;E2 zld80^lKCu(OV%?P&v^l_X-o#e6O4lNHn|tRXV?h)g6(exVmsp6?4<;@I&er^9XWv3UTBekSey*mYbAe7JRVBzR<&B9Spo&QW z%|`LpWj=R8eT=MWEO+W$v12s&^r|Noty1FUD%@p?Cl(P>Pt`3sTK>c1hU0Sg8+esE zh)OnH2>g`Kcmw6}bb~*rK7^dGJrlH<+Es~6}k;0qh8#Zu|{Scq<3(Vd9w6Q{j;(-|9r$acarbUk$?RjMo<4f+5LFt7`HhuBsI z*WzcHrRHEaD{GT;)(SP`LtlRgZk%~X^f2oq&ivnjv#qia<(TQ0Ieoe>dKnvpPRXVS zR!&5aCImED=YfU7U+6d&D~{KK0`tnCo;8q%YD|B}VC&IkN)i3u2`AxmP#q-sDL9dUbsh1N$VO62qY=Ue}?C|4{m# z=_xqy^r}fhahW!b#6O3kzKfD!e4F_(Ljn^vHF%w;W7wl99p=rah)H;N@{u0KoSxt^ zZWhpyHCx4M+`g760eY#uiM1+tA&ONrkPIB;0)c1faEU(YKP}zyUG^xB3`)Wj7Ww>S`mzan-6(o0V}RyGYV_G2!qh+plJ*T^p#22TS^>*xdfZ_YEASNB%Y zG%XbSvv_fS9a5(x>@GYCekpy9JR|odEP`~%w#K3&N8y3W^$PB*hZ7{8mhVc-7=}J@ zc5Sk|UIk9=TJBZqx#_BeQJR=-g*n>bh*bVVwUaErP;y=HRn&RGeQ#0@lWQOCnWWLz zy-Lo#_uDhVElc#G3YE{4Vh1)%wN`$ECwoY`j<)P2UzwtNa?gfg~4cWU0;=zvMULj9|{)poz`_tfgx7(vaitQHs%OK?`Wqmo#~k#?0%Kv;V_83Rs|)vH+X z%8>Mdns%4neKB-48i{r$aBr+q{^e<>_*2Cq5mVGsm)o6(lAdejOebrb9|sX4oD*+D z2TE!;28p1?r}DOJYNRv_71z+D#n(XX_nW^WO!HEwv+sUWR?p1vNOFA1d~KauwZJYO zBJ9fK85z36bt#X?0@q>CfBMgGt+ z#G{dSsy`yCY%`A|VikMtcXfZuzWK8;(*^Ebn1eHnoLB8p>F{WHZ*nN+9h*hOXzdf< z1aTOg=GJ(QEvQB-6N-aM2dAfk3M1Hi`b@G0a(YPAzFXxRKPTpEy*sjQcl)^o-<<-c&uvJ&#CV+|Ek(|N1N1%Gm6q`HvcJB^mN%LsoZ?C{y2yzBIQ zU@D*C*f6oB&jab0JF_UoueeK%JOANC*Ux#boMHIQ`Z3Mwvrfd*@P6PZGix|NOU2{> zHdbXsYEvDUBxv?P6 zZ?@!9gfR$V@>}KJ+xGeESwEDD7dDB6K^Q;@m*A4#*Ek-rc^qjcAXGkDT%%Ls`#T|! zsuvk1{+uXYT$CKqa?e7AF(8MUHxtNmU|bQ}y>;^MGEtus>`kVXHDD1!^dFXy-&%QV z#2?BY*J%>1s5;)^XU}*oheX}iADyWZ3Mi(paHLfk;J4Gjwk=oezyywiK2dH+b5}$E zo?F5N8#%Mb3T!3{ij1!t9|S$USS$Yy_qM8br?(%HO^d~#kH^+UhKvY&tS##g#;2ku zRi)+R3*iqranr{+Fsiv( zFi;+NkCnf5oz|D)N4ZGFe#pRg6sS0Ns=+(vy!4rCs4tz#p>omXCGWEoZ_@tqg<>?x zj4+cJ@#IG@H;zMW{oO#BQ8Gi}jCIOdno-(^`&hJNQdGT0pnWrlqN)(ZqO9&~c3}0g zPm&}2)-UZL)M>T`{(7tC1#|w3&{F!!+ZVk1jt@bWwr-5texOrxOq1|7FzUDHvqNwZ zkrVD(el;2iIao0_7U!Swq~e@B!|evH^sY>szjKK_Jr?8O_F|s*#S5yA)>E@)mv^nR zHmQuD-7rsP(zCER=M|7ML2xTPcYgTz1S-74e$f~p-ItT2xI+|uI(Ui0^zf)Og^m)b z!sekpIViiXdMJ9N0v$~z4j?BFqucMkoCFcLNA)d^<|DZAl;Gak)KSx2A_!v}I}JCq z7=NQEa=Kr*oFLvztb>I?vcHJ7w!oA+fjL^5F@@`vQV%?V?|4HLQ9w- zJ=6Dr8he$1-t4+Ss@FgX?t9A0DySWYa8Y!ghv(O(HuZ3g zqHa59pWe_+QsNn|#?Ku8QBCDc_9g6R_~jR$oJATgFHmBF+ zKIYj9_u2vewE=BVm<00Y?}e$7*_q!GKV-O3ZuZUWv8-r5_Hq>n$R4?edA~4Nyc&fH zsliRm-oR|W{?&<#9e3k`V7IMMGJd&OlesgVyQzce=f%Z`wjJjfT8}S0yN@QmIb&gu zV+(JO$HBI=s4U5!*U*Ne2$+iqlyI?0ij?1R42%2z>-2QF1CH?x8SU(=gg=udb2;V% z?kngHmWJT`to~mWclWsOlH*hF!u@pCmKlGn-OKao5d>|H4mg!DEzS~}Qf#YlXp2g# z?UwfW2lm8xnjR-RTP{)DK^`v(F#MiZ3(aCQ1+p3N7=jHI`^<`p?LXYap-JwlI?qPL z{yH%Gwq_9ZZ+>T6ja7ri-|`=EiaADfGcxV*_Gavl1UHRm5;g^4&NKP^L?0nzTMj9A$VT=vaQy>lPJD!3>5xy;E)jT1?uzxD0w~rRB>U7&jS&7-`&@ zwQpLV^|0*kcBc8q2W9CtN0mkn;dBMEPmYeV5*{T>9eA6E6%b;O^mH;D2{>L`{HRO}jo*0_ROFM-XX!QqA1 zMEyv>61X8#7`zWAJpl*ECb$b+A0h9N-o z7&bb2FxI8?GS;O52{n*2?~=C4F(A%kKiA(AvgZ*+0NdJ(ZR`XO3lWeayEZO-E4vac~_kNpGH&kn;3=(0(8=#o{TLPht+~FyiX&zoM zq+Toano}r}Dh-491w+%@L}}=@EAm*wUHq{ZifX{ju?94`Ts#wCzE@x>>Qeswv@57+KR5*+&$9?7XKBm)T% zVJ57ym@moZ9v=n;<%FS3U&KTVg=AcB4Qovcx8Elm*DPp`MB3kY)dvg`4qc%)CQfOJ z5@#DLr6u&){Zcz%;&?zs-=BLZ=^>#*)e*|6AH--FRYNl$4x*aL;cnLShb@aSxJW6DsRK*&7C}o++Ll_j7cg@T15n10a?cypn{m@g zXNJ<@^i1hD0)4HO@v!4gyuL4IwxeV-DQcnz%7gDVLpRr`=JaVnz=}RlHcBYi^fC^G zpXXlK)en8|y&mTbQJjIAl>$vPqp}Y~H-$i+Y?=}Tx1)7b^2EXwPbexSW(j|yQ^Zf( zE7h3k1c>G$Znb!LIY_{y$A!}mQ+74XQc~BnxvXMssC7fbz-SA9I4ORvqD%;njYmz z(&B*MEj)5(Brf4Rto2eany#jjazXhyWj4BM67g(|mqOQvRj$PScslvIqtqxJ?&N3Q$BFn*-_XV-5Fx@> zR$b6I5rQRTAOJ;hEJ8p5Z$@}in^6(xy!(w@*=WW@3OV1Csi|Pc08REp+DlnuN-K?v z=qoOMPnsKZuS^O_0^ElGS_N?2TDX zG4dCL?d>HN*VxL5?w``VKJG=l8EZ132ECwR#oO<3-N6T57UT84baTp7dU7C(tjP&a zd3LTmmF2GGYK@uZt&BB?w_>74)uWP{Cm6cv;0>8Cg+hfxM7bcY5C;Gg-VhmBfw`@w zYNlY9>6OWFsr^uaz@Akc`|@-#kU@Rl0jzIY-))ABI1jPHA5@B$EqSecH}cT`5EtR| zz~vB+s1TsI*X7udQdX_5r>OXY%7WPji6s(3f?9LC4UcViG9ibDHr$$`Q(jv8hGUC` zS#%Nb4JrU^ySC@*Ab=D+yfw`X#$qE!Ma}2OlY}^NB3;fds80PD%g1iMU@)=wn4A;b zT@^w`m!8dic=Rw{m!{fr)65hqRQOP@l8n(?7{{=kaS`ijchb@WECQAgSDyZN1x)dt z+SFm`XQx|2Ro~=;gT{F$7(#6hc)bv?XD^jMW?Xh0nh(dBPH!QcLIM@Uc%W+&iBj0; zy^9P74&&`iSrSd-!V;tBj!>9}oXn^;OizJvzc`p_qrMr#e+PZpm}Zsgl({^2S_!;V z4<&@4nQ0 z!KgH!QrYV`h0~#8LCl<(>%TkQ1hP=pZ7&gUkAjAdwp&D5i3ny{!HdtWtNSECIR*#n zmQK7^>mY!dM=@YuuOrHON*ZcJ?_P$|*84?+hKSiDXD#1@$>T=*v*wJBPkplt)N^Nn1F7AiN0;Ftf z>oqjpx71QE{uiu;7JGcL0mdSwVsG`GgGyv~#Xn9$p`n6njisW*kG?a#{8p z!RjpKMC+l_M$zgUuh@TZBG=lt+q5S$=W@?h3>BWoWQxUyg#_=a>I>NwfCbS8nZq;D zw9kxf_+-Eq^CV$CujvqBko4A8*F8|22XNma8%O>I#7(@I zny6`LRkHvWbf|c@TYv;lYJ2^=oR(hT{Qyly*H>&nhRt>iC{GudoR;M`Sn!HfJzFkD zV0ch`V~nGm)=I+?&6wMAjpKpxNMdQ$2j0R|An`Jyb7y6LdtpTwud-EvGAnaAJyHYm z#+dpFeL0a>F+un1)!7zO`%lP>vF5ep9R^D~t!Yr9)4@@3soXVvprD!Fr=Q#a!|e!W zRH+zQgHhQXbWU1Dt(ZWEpMprgiS>HzWQGO~k`TPiaGO#DMn*QYQF0>icYQ{tPxNn_ z)l5>zFtdA?_fFcA2A=gY}qRL;1>+ zZ5r^GXo$+q6d7EGW$ag`MPq@na33NIkoD4Gky=*Q+#cIXm|`_CVR(C#$~`E!MlU}< zo;jCShml>9bh%P7?=~FV=Sm>T`YPkF8Ng6w@ zc^jR7cCxR)Z=wc)Y4QS#@~v+;YHHW)5rc`*`%6SWqhkG(dI44pC<-I-lJR8X(N%9p zpoG%>XfLUYUB7n2Xd_CA%z*&aI9QAx_*E=r)*Ku5H?yOIv%YU!FH&J$LcQw!*YLp3 z(9?4U#rF2&Jr?hZMwVgFiaNV>mgkL67p1Hmz#^QzTg|$XL}iY( zh&eh##`~fuX}ZO==_D_=Q!y5dccX$PX@?-G%$*VH7Jsru1N` zMBrp%OUGcQBLPqNmB<*pT~+I#UY1V0F5$1yqpQ_r@HMi7q-U`0Nj-ycD8&&!8sN7X z_!8*)TT3bjM5HgzuL_!6cxeC<1b{WwOCb@0GjHoc=S>&e*ePN-Sx`d=`s?|!s6_Kv zn@}oLwgO_Qb8h-C(6ws!uHD`oai_l7`NG2e98D=P*Ya|DgEfLOB?M=C(IOZ3apj!l zx(qOn>Kmh%MdUkAe9YANDA;0kSA$EgSQ&dJH0^Xi{cg_4AK7VFVwYT4RFy4m_N?v4 zKO8>om!R(DmP`$wbj26xmK7kkYQZ&|I{{;h4%RWn4T)^$U=o&cpHS1L5sg9oNV)ZE z*?RTC`yp$@E=%B970Bh2d?bROetMr=m{G@1+k>(BNP~n}Cnj6wtq@{%s2jcNi3Ycx z+ir^VsVr?r=d;Y9R4tCGVGUX!nL#+LpdR)F5h?34H{J1robudvQ6HR;GBbv(2rSWz ztk1dCX#mlr1yBo_aY$9^aYzboH_=X`{%6TF1Q$=H_nWleI`9jiPmn%%x}7T@v%Pwk zW=0QY2*0nC65%Wh8I^YruCGRis-T%rn6xuTb`BqAwQc6?Z!fhj(T!p%&c0n<+U9}W@3+v`-DW`MhK+tMT zucTveVRH{hZ0WXSEuu;|G$Ep-r@X}Gms*2Hr?}_`I5cLw!A7I{VFU@zrpJ|C;Jc!_ z4MqVmF6!TO%P)u|$rJAf5ZYi9_mqPT+?-ohEUx=JMpT4FN#>NKzr;H}j6Cpiz;#6` zf19*4; z=m9|a%(oBIBX!~pJv*R&JtK;Fm+KO`?NA$&s z`n1rEH+5FPvc)M2Xs({oqZOnIQJFE#vtTqHCshN@#OTL9g)1dHPeKjc!BJSIM|#Nz z2RjL2xzMk(jB#A9T30Q@d))hOl)L_(pev+fx4^wG{-gr*;f1bLA253$1|Ve~F1~s& zMz3|Tdx{~@;)voXL?!cF%8tCUbg-qq&aIkeL9)VqeScDvEkD~) zI)}hqZc_n$tl|Pa)sL@G4FdByWD5I!arV2;O#NQ6z%$EjEE??G>%iPi6{XhqSB}RT zHPj51lD8L$2z$9&_$Hcp(=wmIeg-f3+s_-`y}eoNs;uR9iUI%xa{vI?|KY`9D>G|4 zbB8Z#9u8Y9h_9Kl8_)%HRidAd&Fd6yCv{@z0vQ#1uW8)O{7by2B;C8d6H4XkO&t2*de%=g zLDAinkS6;2+|EX_YagLKCkx}*&Pg1vNCZ(f?y;X zGP)fp5-YTay0^72Eu}sy1Q~qyFRA3?K7?12D&ca%N`fx$%~uqww(xh3DnB^Pg!h6Gm%_@ny;Pm)ohYQ3#KgZOx@v?qIEtAI(etW(3JP>>LpbVS!QziXHz8p1< zMllH$vQ9#;6@?jo*$0h<_=K*4?9dbYzH84q)G6%ZvFyjyx1j13?3ZuR94nS$aqgU6 z9tDtThy1@1AFVp>)#8;MP#h8PJw$yM$>Ef8#}c*ikk_A$)??=k88XGI+j^a>hiQK~ z-*i*3w-Vmx{bUhq(m=Sy%D4cEH7&&=DkG*;;?uBAACKQ`-Ts+vW@|O@#sf)v*B<9o z)pgLS`Rp8MllOyQ7FJiNLR91zASZ?Iuq*5ql zspuWUnS)ctB<2N$Wi7+(PolAU`rp3h7f%u+9-nE{;>L!fbSJgZ1`T;~9t^YY2Yk*a zr%)X(n#fpq@wU#`WolShd1Bb87Joi(tO6}rYbPy`o4>wY)j4oKNWX_G zOQk$(*mI01=Dm5y#Vc_h2#yB2`Wh!V(4^ftCEtyO?yl0EJmrG8gM_p%@hQcfq)`Ur zvQrN+Nkw)|&%=FaEXZwmG)4xzyQi zcM>;euFrP3v)zrD=JyRYvAQ9a6!@<%KUhI`tBITV4&1fo2-*^EJcS-p-?1lxjqmhc z<%`jF-kRjv9Yd#uE@-!4N8+7O0uih?u0t8T4_oD|McU|#xxOd@x&H9@X!BW0WqfM;`7s5x+zsD4s}i8(u{63!XZ?i(a|rU(sxSAYMm@ICuMeA`@I`We2TcOZ?ajp&rzWjdsI9qd(XKo%=+igJ zi^)DV_@xK?EOV&3D`fitU-V*);Ekq0%*I?o!S7naLi=%7gAbsteXyVr zrroshuOw1$M`ho7iU>G(o_hK+bG*xL8=wsTGnU0~B z!QQ;;2HV+GeK|TH(`IPg==Dmem+WE@9|_;lDH*Y-E7lxcQYk5z^>129mz7p?t`0@F z;yfP7^6W$3i}>h=g`?1ACId%nCZWob%iNsR3yCXlhVzg;dYKZO7`5tIUZUm#25u|) zl}WJ1heK0K`KnnuJI6H+LaR&&>IK?rCfRDKuummzu_`4JKl}tYr^Qz+@SL!id+X2` zsR91Wz4{EQ=P{byW5-leOhPU!Okzu|(;vv4A*3J)=-Jb_-1n2wBHL28sVRG#)OF&g;JbM>Jo%pw-< zp39qMM$UdjkeYwS1V4=Fw0@<*5FTh2t#7O+=V^0p28i@6mrs16e!}HRy3m|B|doUW6Jd zoHhgwt0{{ZFlD8*JqXLhst8%I(GG_uQ1nA!COvIjHC^j@ANFf{IEhJ4W;vx~qmALq zMox9o4+iy?KFr8#sn)HfZ+$yD>zT#iH%wS#nDTUzF@Cy3JVd|ul<({~W}fnPfrp5G zB-gwKsqmh-=Xjq2SE<7$Ba=dJ%00mA>|_f+>oz3zJUKYk-(MbI!~2Hui#1jhu4^_1 z#ZS-e8Wax?J?-s5lt}oKIZqtDmv}_!cNn<0jY zpSe^CAxD9kRb{Gh#!eW@Ek-~_-yqBC=g4&PQ5$|uGI3`pi!AEAg7<^L`TAwVDR7ao zzrQzRyR$J<4q}mVN=}ih9)G`}rQzBKr$eQR>%}-t^kFr!?o!rdpWaRKAY&xICPaK>1V96Fy|ZJYTlH!XFoqpeVQ@3xONF_6R+ z98hypZsQ=o2{Qx<59o30JJA{wQqKgRC=qLQcqYp=kJLU554JX>6zpJLAEuwvdc-hK zT-6Et^jy2KOz*cWcM2V9<*PFI4H0?xV(<0f7S|)sA@5P_HdT$_$znVKs5+}YNQim*u#bTm8jES4W z`!Y!(tzgjI5-cwF5v3P06I;2IVP8!d-VIn*BXp#jyqz$z2-HQtH8|?f5?r=8DJFPU zjM|x9)9mD7cu6Y0z+4@@J3KoRuC}H(DAC$I2l)tE$M_taz<7kTu?{Uen|i#D&-&h~ zYy+)&ekzw|*IE3TeHWA|aegGZIe-T{`Bs1I+z3xMN+g12?nBpwPs}A9Zmcsk}%19iF=m3TX2=9hi~G)L=okTUX(~P_zQbT^KxRg zZIw%GYRBWPSZEma9Ig|3gMU3u0!5o3s&dOza|VbYKTWs9pK!o|Y^eG{3Ii7qTGwe( z0Y%g<_uIpixi{8UrlQ7GYk9e}pD*BX%K+IuFOrS9^0e>X87I{3;B;TeaKsN-PFUXa z$4jTiI*mCvMDXKlJ|An=GN=}o0nCW&5ad)ov@hvJ82b##Fn;F(=`NAW+r}C3nOYQK zuJ@qzf(ep&fy0n_R|YQAU2dUCdgP@CUNGYKnsLWSfL7X<1)c}dC~Ny36HKU&P?u#6 zDQ9y#moXSLa8W;I-cyZl$6D;FNGp!~-D&r>o*TuFC<8 zYnslC#TO5jYVDJzF&I+e>%Q&qN!AV9hwxCBd{UQAI)&Qq~{wDH@x$ zX(boz{#4Hy{iQ)31%pLX&pp@+b3o9su9F0A#oZL|YEwEDeiR{_zV`$op+s%*9`10d z^8-6S82)+|YKOJ|&~z^I-U9F>iY2?`xCHy$YMgj8pNKxPtLDY~w{Lz58k} zZzc|5ZZ>Zke7hTSf*s!|Dn$qF&p(sJekl07Id`C)(tkR zU%6J)7;#I$p2}n+|2CByri~NjUN+;}Fqc(^Fu$m=M{GSTq`oAzE|^l8JFoAv4h zHC_9w5d|xRm&kk_^`jZM>5q$|?0E(fsv4G9bLQH!KDt(S@~|nkova^*L@%yL%fJIT zHV!;CM@^|N_$k>9EY$q#+sX0QaPRTxZixyImu>kMl_p$V>KHoQ*s&&5W-4J& zWr@?#8am-0^3M7j_u@H*a4)hXMLOCbGUV`H$1qd6$vIAq<|tNRG|+Suy9Or>$yjWP z%bQ1;)V2D)Uddv54$IoxNeRfLbEQi9c9`Eu3vmWj;Q1#tJlYMFwkEdH z0sxEE6~hN8{vPW0?kc1P@1D);oLMdz-5?IURV2QlmZ?xJHPj2gEP6Mq2Z*qT;^qL% zW9T0=+Q!9aUG6dOb_sb+!HJjsCIyZ~Ac6?GP< z?MJv6tyk!+{W(!fS~sCPB%e6!c#i`5(vMV=bd=;iN{yi4UWI9nVq+C0D%qdxaPnO( znuX9Tr5hAr^A$~mMJ?omV=0RJ2)I_Lk&2v}&j&pBQBNJ2ln$kwvNady#Hop=Tp8M_ z25q@Au;5g$1h2za^7&AuP%<_Q%y|g56TOT3)ztGPM)nad>0?)LgXrgEB)nu6tJKtW zvcy6ZT^e)TOML3jBwERhqy{)|N9>f8GxDi4r>S9m3HV4IcA>#Wf}gd9Srt`fG$83N zUrtp+dOx8GIp!(@gU2HU66tCkwRDaVD?38OS`~=$A0|C}+=!NPt!)3OtgbsWJe`hs znTAAO`2c30!C`NnqM}^*-E5xcx*cty7k^n4;$+W}My7@5vvuoMUQ?nCxgr$H9177R z1aWx?=k72jk49Zg5JXo;&2A zLQvFa(}*8Bqnm8}X6}sXn5aRS3VB}XhVw*F$ZrVP#Li(gj?S~0nykivzCK*e&!NQS zKje{OMrDkWKKgJr?EZ@ltKhTDVSK(o_`({40;FYu_r@jovpY*Eh=fs>o(&EE-isf zfN5u7Pz8Y`qw!^lB?%uUFF+MId-JpbbY%+|rYC(_$oQOiy-LgQ2mD5Xk+gdT8q{*W zIBR{ETtA=Xsl`LrO?9B)YRr0UX1&~#Z*~?@LKDmrJ zcZ%qTZSNgsw0MpL4$SPEa~pmoZYhR%XIG)aWz?g7pqn_?A)&r>BKTC2ekgm%!{En| zG4N^v!8=e0?>VvqKdwPYRf_E>Bwye+1mqDi=XzbXR2TvX%|o*(oL|q$uE)DF$E)@N zfksm(Jw=SCP0*u&JhjFrsrU0Mke6(Vi3o+C&=fQYp+$Ltjcl?aD7Dz`Lc$Jl7IY=^ zIjn-j=`VS*-mp4)fW1en=eP74V);B=vuAdV9|^8VESK`VH44$)5Mz(p?Oh_J=(pVm zSy^$zHUrXVb-ubX)71tN5zpi^j2X3FkTa&@H!Pz}!+dG>rb`PA z06_hwz4~@lK}0}U`p?q7gIEDBKX11n_WIvT0|4=Va?Sw#hcu$^vw-zmlp6yF2l_u& zhOd2e^Di}@h2fw1|9t;rW&GSV=j91-d3_rWQ*Xlo^B<}|t2*ZIs{i7?@rL>%3BZ-Y z{YS!oBFSZN;Z?nn#(q})Z=~M0P?taN|6fQyx9k7EX#hagU)EM78~|WuW%65X0aD49 ze%02W@_*JA08sxYRm6Xk;b$96{ay7}8Enmr42*tn4}d4``Y*zt@;?&(eBao=5dd$- z#y{`-j|3Mp3o~0IL$iP)l6mr=zk-kD_~Q0y|wnw^gHqL?d0Y^mrnmzsMG(3C`}&2qX+>2{7kVn0j*s5b??gS;za;)L7W=;w|Jhf^qbW2*-=0W6)9*yLxAVUL+;d$1 z>%RJXAl^StLeBz!N&K(->hDp@{zw#*{!8M2-B*8)%JE0yjLKgU|LeZ`yG{EaiLBax zN&K(->hHF9eVJqoXNhIoUyfJ54S-LtQ@peM1u(#kc007q8zv$be@U{BqxBmyIc!#$D diff --git a/chess/chessboard/css/chessboard-1.0.0.css b/chess/chessboard/css/chessboard-1.0.0.css deleted file mode 100644 index 8de95f4..0000000 --- a/chess/chessboard/css/chessboard-1.0.0.css +++ /dev/null @@ -1,54 +0,0 @@ -/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ - -.clearfix-7da63 { - clear: both; -} - -.board-b72b1 { - border: 2px solid #404040; - box-sizing: content-box; -} - -.square-55d63 { - float: left; - position: relative; - - /* disable any native browser highlighting */ - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.white-1e1d7 { - background-color: #f0d9b5; - color: #b58863; -} - -.black-3c85d { - background-color: #b58863; - color: #f0d9b5; -} - -.highlight1-32417, .highlight2-9c5d2 { - box-shadow: inset 0 0 3px 3px yellow; -} - -.notation-322f9 { - cursor: default; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - position: absolute; -} - -.alpha-d2270 { - bottom: 1px; - right: 3px; -} - -.numeric-fc462 { - top: 2px; - left: 2px; -} diff --git a/chess/chessboard/css/chessboard-1.0.0.min.css b/chess/chessboard/css/chessboard-1.0.0.min.css deleted file mode 100644 index 73f844a..0000000 --- a/chess/chessboard/css/chessboard-1.0.0.min.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ -.clearfix-7da63{clear:both}.board-b72b1{border:2px solid #404040;box-sizing:content-box}.square-55d63{float:left;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.white-1e1d7{background-color:#f0d9b5;color:#b58863}.black-3c85d{background-color:#b58863;color:#f0d9b5}.highlight1-32417,.highlight2-9c5d2{box-shadow:inset 0 0 3px 3px #ff0}.notation-322f9{cursor:default;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;position:absolute}.alpha-d2270{bottom:1px;right:3px}.numeric-fc462{top:2px;left:2px} \ No newline at end of file diff --git a/chess/chessboard/img/chesspieces/wikipedia/bB.png b/chess/chessboard/img/chesspieces/wikipedia/bB.png deleted file mode 100644 index be3007dd0cdc7662268e103458b30a035da1cebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1405 zcmV-@1%mpCP);OAg&;29>pXtLFL9VGS_o&_2gy))=`i$DX3vw-9Gh)}RQ7JcwuWkdbRXt|A`xA>c4EW@MX> zj1K`bMy|`TiE&}qk z)5K?tT>s;C;y#C_DqWhf#67pwvT!jB9HSn^b1L&UY}D79cyZ!hpTfBbxfeETrsfTo zDW224pVh+TdWo{)C`Y)3gggu%T4E{j;}FCv7V#rpMSR#zUWI`}!j4;@#o3 zwq!Dyxf++t==OPfWGs*%U_4=RzH(`}WqAcL=rA~|k z8bl;wh$ODZe5|BZM;X(Y;=zPth-6yGt$ruZ0ZgQw$T8d!)h(;@rPja_mvT-ukYl(u zs?GS<5H=0`@|P$NBKsGCfS*QLz?~s(UwK`PycA^t`CY|i6-2asO<*4~(nwcPz*lwH zOyD`#=M@yu_Hk5blorehk!O_$wBqr2etHrF*_N1}&3aa7n1s2Jc$^=wp`pRbX0!Q? zf^xw&*cRJ_c;ARZQo5G7nMF*cQgUo;Oa=wE#Wo>cLTHTVxt7$`)ybx&CfU{1CA+)3 z%OcxgTWk|G@Ht(@yARWfFb5I~K9ahL$MeAh6&Q)t7fM>?%RDUH^ZtS+=Mk>cNx)rI zSjxSui+C~W>_5P$Ysv6ov9F$kz?Yr25HN<*lqbT}EQgl6svu9+Hr%txLo=goZiOOR&&?PZU1ak|MYyb7l^<6GG!O zUsX)rSl|~ve_;JO<3qd|+{5<{VFMxZqVewU3gVr_)x>+TsJ|bZn-3D#ibCe-dTAJ#4RquQl+UL@cWj+ls}qQ@x6~8_nh*F-!cKc!KyX@f7g~ z;u+#k#B;>oh$F-?G&xy9Q+6togUu26I0v6+5W^|NbOJGEvAMyqKU-C93njH_WNeCt*&$TPie{tCooB3#mtf7LOCfFK8;> zLZ3-&4stj7of;6YSj2aO+|}j}oF}i)8Rt-D9IFA9~G_GA#Y&zMRQ2aT?G3jCO<1$YN-Hcm_$1rNmBAD+);Xe%ck8oZgZpVBqMSKWM zVSdJQwJpSL#3qGX(M52%yNJtNVpxVUDcrNQ$ksOa*Z`ku9P1F<4#c_#v44+eu}9=% z=trP|Z1_lNO1_lNO2I1mAaAmM>MWmh600000 LNkvXXu0mjfilMA( diff --git a/chess/chessboard/img/chesspieces/wikipedia/bK.png b/chess/chessboard/img/chesspieces/wikipedia/bK.png deleted file mode 100644 index de9880ce6390d6a53464f1b028bff7be0fd0f131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3009 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 DNo%uI diff --git a/chess/chessboard/img/chesspieces/wikipedia/bN.png b/chess/chessboard/img/chesspieces/wikipedia/bN.png deleted file mode 100644 index e31a6d0224819791210e91218fc99b7cd3b848ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1875 zcmV-Z2dwysP)9wVNxLjD`@*iP6__$6VA8`tL&-X#RW zUP5D_3pg!{fgB^uc5!V9p(tNV|Gp5&;zh}#i3&mRJj2PgnS>Jx@#yvSfh=IOEEuS) zYKSmaaa{!A4~pxQ{4vmn@SiF{sCCuL0>==(p%PfhDZ)^~NW!o{6tLqymZi2z(Zy#! z%lA1-SS~L#j}it2f`CuC5C&X`M>(%N&&tYzef##^$h?u1g{eeo%(*%pyZ{SquvcgUrlKsIIPto}M0{~GzX|xd+VWPeTnQG71|}zqobjzsYw#CySp0~m(fM`;oP82 zZGH9i^^$O+D2*(Lii*-?NRv4b8X6j;u1}sk2@w$yzwz!f78Cxfe2Mkz*MkzBot>J_ zi$Os_*r&8Y@7}!|&wt@nJdE3Qsb2tBLnYGF(?RRS1y|{tH*doH{Jgkk%^Ga`oJRp) zC0tNHd~4?}Qpu;v0H3knLPDTMfpq8zX-;z>M=lnglY`8ICc2#t-6uxHO6 zAgiHI#6#j2ck0wB>5DX*&Di!WX?utl0V`cS{E8JTd}et{CMPGu?c29ucz77%;^MHa zln3!*eJ#vVSXWmkt;&ZE9m4ZIfrFgO7g}uByhWqYh>HnayLL@P=bp6X`BJ~~C=smv@?6opVFtPUR>}+XoJUKZDX=!QL z_9n}8C}!Edak8(JfX7~NQ$BXm?*>+LZc6k$(}ExzT4cYhRPPGX4GiQjkGTO)$&%e&+@8x)lE1V!?_D)&d?pcu*4X z)~#Do`hm1nvvgw`Jbd8K1owWrfWeB(TI_gm7lOb_FRVS3Lv+kw5|&?W)h)RHyN^1- zz2ZxcSyWWy@FcLVMvDOJnI#NYdORYyUnNzhWsnw~X^NdYcVgS$TI`2w2?u3sqz`jP z6?RgFqTCG?y{z8pux3U^hC{%;d-qC}3|d8H(4scW3F-pDUbxfi5PVpenWuQT8-)38?k({PSnyS@n8IqcN|mpqeVyP(DAH=daK^;M zM2CPUPMnb9go6E7Q+|Q%EOH)8Ar>A{U_GH+ep2WU;yo{~cs@;wDg``u?i|(-V*4w+ zi}x_$Fb^qCOlwkLh#!kGNxPYM0lyYFNysbbK%31*1>DcGc&`Z@RWm3BymaXj74U6d z#WQ#q(P1hemLJRY+f}>@xJ}-%a8pY|>ts|GXyH}BPkFLFWJ*fPJ!uJ9z#1OKi;*KT zTnUIp?-ZCHmfe{5c@%IR>->hN(U_K&7V1d9$D@Ex^5Xjms_K1;)2C0k zj|cA9vBM$Y@#DwoUie)e1$>6^55fLVBzWQEu3fukF|m#%9#*S$E-WkzW1I(g6fjn{ z!sj^Rvu3k-^T5DB!QkLvfyH9kLIlLP<|Bd*9XfRA(4j+z4jnq!;y-|v529HMk23%O N002ovPDHLkV1nn}h0*{3 diff --git a/chess/chessboard/img/chesspieces/wikipedia/bP.png b/chess/chessboard/img/chesspieces/wikipedia/bP.png deleted file mode 100644 index afa0c9d4459e4d04648ca413ba90690bfdd49a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 777 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 l`)^ z-n=PRR8&Y=QBY6-yLRn@ZQHiN`t|E!<;sAcp zw%QWGCeI%Jk3K#=;OpxPetv$>x@|x}z;l$ZV;L-qHWmf^#$AssUBz<`-r2+glP6CG z>_T(r&V{(RIEasrhgGXq!P>QJVbi8fuzmY>$jZus-Me?gzJ2>3CnpCEA3h96j~SgBFX6i=n){9A`ir z#HFPO&Xg|-=o{<6x~^WmD%Fi`z_y^^(b3Vi|D)|m85tRE>cCoCTcNtTS_%f25@~5^ zkdl%DD^{$K)@n0n&V)&mCP8Rus6?D)wJ3j&Wzh!LnCJt2q0d8y4oP)jU0A0YnVFgY z5%}M%^~l)wFE;yP_Y&ER2N4kw9-lmLse^4{OB)f}CJerjZ%cfnx1Ga5AJ=dbCQN`S zQ>IA5PM(V}NuxNxC#9lytNSe|u9X$^>eP$cv_ zapFW6GiHo5(Fn$G-M?kKu8Z3v9K5khZP~H~_UzdM`T6;9>eMMHEiHu$7cRi%%a@_9 zt`2V8xPgmpX*-6yjE4^&O1p_CPo7BQSZ{Byw4)dp7?9Z4*C$=a@8ul~?nv(3xdXRu z-GYXO2FWjO>n>ir2xVnuQdcf4EQGy#_d;rFDkLT*!i*U+ASfsZp8#grO1<3N+@D^% zcC8n;R!^Tk1yR)8$w^x<9N^hj52~uF;M}=$P*hYT1)7(a2S<(^k!D<+Z87ld>}=^@ z{6AhtVmZ7qY%M3<7~EyxB-PZ^B#CM?!QhR$efze!dGqFv?4;ia)~!l0yBZrCMHFP` z&Yh5)oGf)Y?5^ytyLH^dbz^vVIK;-r!kRT}aPoi?Cr-fi>(`}>UA}yIt(^`NLcH-L znk~eW9RXcC58P}Q0r4H>Prd9|A72ewX17`RufpI%>V9E(U(Fa!AN|zEPw1(lt$@F; z@GHhYPy@?IR2;DJ?WY!c2HX1rGpm>CXrVf5sSRb+rajbkz2f&{@Gp_Z({Vq(Iu^~i zKp6b}gH?=4!r<>@;qT1gd(Zf)?{3Bqg~7i%!h_FT;$gb>A(hD{n^f|VL_XuGj%cbg zoZ8?kyyUPnW0000+NjA?5IGAHvP4t z54%KWsa~*up#S25g4PyUJ-=B#vU8SfOkVC3u;J1>CCN>xZx>V_Sh(vMyUFU{q&A(T z%a1H=@4r>w>!lpyyYBwP?~T)?JD%6QuQd^xTrI;6v+VaXtCeeiy8Wc6`Rl~%4ZC%_?Pl1m|0#bk z^7R^V?ErQbHRi&f$MXc79yDCv;r+Zw?g6KO{)aj8(mb3yc@;lQyRI|;dChg!RlNKE z2Rz^KOH@NqfTL01M}LIQvs-Etth*oXd|r8f`Q??<_)3?oyAnC+!1AR*FSp!&`>Jlg ze_+iNk^RBzuU~#z^mB@p_ivL;)4i7N+qG`>cNAB`UCr7Rwbo5)mgnY` z%;g)qY$tQOpL?4le&-}t+^m}H?YFCJM3nTCehM|;g7cR zGA+F`RWxmJzeVFD=0;#pu4Yve;?#ZdEzbUm=b{7K&po<#$IEQ?)x!@1Zt*^=Q-AeL z=bfkBqwE`8`967bj@It5w>>Ys`)K2?z~f8Lnb+t}{M^W$ak}{Ubs@{GvO*EfV88O5 ze8_iV_VWU1rp*0s-6soA?ptd4F#E=>dx^Ko-DaPg7dgu!o*9yi7XDzq)Gu?~A%9jq ONWjz8&t;ucLK6U+JX?nV diff --git a/chess/chessboard/img/chesspieces/wikipedia/wB.png b/chess/chessboard/img/chesspieces/wikipedia/wB.png deleted file mode 100644 index 70e0e14088f6ea09b84b728df6aaae6d4776ab4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2374 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 Z{12-kJ&=_`^N#=k002ovPDHLkV1l3JS(E?( diff --git a/chess/chessboard/img/chesspieces/wikipedia/wN.png b/chess/chessboard/img/chesspieces/wikipedia/wN.png deleted file mode 100644 index 237250c164f652f0ea61f5e8f65c9b4cb83489b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 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 V@B7wJo3#J{002ovPDHLkV1iHz`5piO diff --git a/chess/chessboard/img/chesspieces/wikipedia/wQ.png b/chess/chessboard/img/chesspieces/wikipedia/wQ.png deleted file mode 100644 index c3dfc15e556cbbeb546374aa9ee5e6bf121e929d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3812 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 minimum - function validSemanticVersion (version, minimum) { - version = parseSemVer(version) - minimum = parseSemVer(minimum) - - var versionNum = (version.major * 100000 * 100000) + - (version.minor * 100000) + - version.patch - var minimumNum = (minimum.major * 100000 * 100000) + - (minimum.minor * 100000) + - minimum.patch - - return versionNum >= minimumNum - } - - function interpolateTemplate (str, obj) { - for (var key in obj) { - if (!obj.hasOwnProperty(key)) continue - var keyTemplateStr = '{' + key + '}' - var value = obj[key] - while (str.indexOf(keyTemplateStr) !== -1) { - str = str.replace(keyTemplateStr, value) - } - } - return str - } - - if (RUN_ASSERTS) { - console.assert(interpolateTemplate('abc', {a: 'x'}) === 'abc') - console.assert(interpolateTemplate('{a}bc', {}) === '{a}bc') - console.assert(interpolateTemplate('{a}bc', {p: 'q'}) === '{a}bc') - console.assert(interpolateTemplate('{a}bc', {a: 'x'}) === 'xbc') - console.assert(interpolateTemplate('{a}bc{a}bc', {a: 'x'}) === 'xbcxbc') - console.assert(interpolateTemplate('{a}{a}{b}', {a: 'x', b: 'y'}) === 'xxy') - } - - // --------------------------------------------------------------------------- - // Predicates - // --------------------------------------------------------------------------- - - function isString (s) { - return typeof s === 'string' - } - - function isFunction (f) { - return typeof f === 'function' - } - - function isInteger (n) { - return typeof n === 'number' && - isFinite(n) && - Math.floor(n) === n - } - - function validAnimationSpeed (speed) { - if (speed === 'fast' || speed === 'slow') return true - if (!isInteger(speed)) return false - return speed >= 0 - } - - function validThrottleRate (rate) { - return isInteger(rate) && - rate >= 1 - } - - function validMove (move) { - // move should be a string - if (!isString(move)) return false - - // move should be in the form of "e2-e4", "f6-d5" - var squares = move.split('-') - if (squares.length !== 2) return false - - return validSquare(squares[0]) && validSquare(squares[1]) - } - - function validSquare (square) { - return isString(square) && square.search(/^[a-h][1-8]$/) !== -1 - } - - if (RUN_ASSERTS) { - console.assert(validSquare('a1')) - console.assert(validSquare('e2')) - console.assert(!validSquare('D2')) - console.assert(!validSquare('g9')) - console.assert(!validSquare('a')) - console.assert(!validSquare(true)) - console.assert(!validSquare(null)) - console.assert(!validSquare({})) - } - - function validPieceCode (code) { - return isString(code) && code.search(/^[bw][KQRNBP]$/) !== -1 - } - - if (RUN_ASSERTS) { - console.assert(validPieceCode('bP')) - console.assert(validPieceCode('bK')) - console.assert(validPieceCode('wK')) - console.assert(validPieceCode('wR')) - console.assert(!validPieceCode('WR')) - console.assert(!validPieceCode('Wr')) - console.assert(!validPieceCode('a')) - console.assert(!validPieceCode(true)) - console.assert(!validPieceCode(null)) - console.assert(!validPieceCode({})) - } - - function validFen (fen) { - if (!isString(fen)) return false - - // cut off any move, castling, etc info from the end - // we're only interested in position information - fen = fen.replace(/ .+$/, '') - - // expand the empty square numbers to just 1s - fen = expandFenEmptySquares(fen) - - // FEN should be 8 sections separated by slashes - var chunks = fen.split('/') - if (chunks.length !== 8) return false - - // check each section - for (var i = 0; i < 8; i++) { - if (chunks[i].length !== 8 || - chunks[i].search(/[^kqrnbpKQRNBP1]/) !== -1) { - return false - } - } - - return true - } - - if (RUN_ASSERTS) { - console.assert(validFen(START_FEN)) - console.assert(validFen('8/8/8/8/8/8/8/8')) - console.assert(validFen('r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R')) - console.assert(validFen('3r3r/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1')) - console.assert(!validFen('3r3z/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1')) - console.assert(!validFen('anbqkbnr/8/8/8/8/8/PPPPPPPP/8')) - console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/')) - console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBN')) - console.assert(!validFen('888888/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR')) - console.assert(!validFen('888888/pppppppp/74/8/8/8/PPPPPPPP/RNBQKBNR')) - console.assert(!validFen({})) - } - - function validPositionObject (pos) { - if (!$.isPlainObject(pos)) return false - - for (var i in pos) { - if (!pos.hasOwnProperty(i)) continue - - if (!validSquare(i) || !validPieceCode(pos[i])) { - return false - } - } - - return true - } - - if (RUN_ASSERTS) { - console.assert(validPositionObject(START_POSITION)) - console.assert(validPositionObject({})) - console.assert(validPositionObject({e2: 'wP'})) - console.assert(validPositionObject({e2: 'wP', d2: 'wP'})) - console.assert(!validPositionObject({e2: 'BP'})) - console.assert(!validPositionObject({y2: 'wP'})) - console.assert(!validPositionObject(null)) - console.assert(!validPositionObject('start')) - console.assert(!validPositionObject(START_FEN)) - } - - function isTouchDevice () { - return 'ontouchstart' in document.documentElement - } - - function validJQueryVersion () { - return typeof window.$ && - $.fn && - $.fn.jquery && - validSemanticVersion($.fn.jquery, MINIMUM_JQUERY_VERSION) - } - - // --------------------------------------------------------------------------- - // Chess Util Functions - // --------------------------------------------------------------------------- - - // convert FEN piece code to bP, wK, etc - function fenToPieceCode (piece) { - // black piece - if (piece.toLowerCase() === piece) { - return 'b' + piece.toUpperCase() - } - - // white piece - return 'w' + piece.toUpperCase() - } - - // convert bP, wK, etc code to FEN structure - function pieceCodeToFen (piece) { - var pieceCodeLetters = piece.split('') - - // white piece - if (pieceCodeLetters[0] === 'w') { - return pieceCodeLetters[1].toUpperCase() - } - - // black piece - return pieceCodeLetters[1].toLowerCase() - } - - // convert FEN string to position object - // returns false if the FEN string is invalid - function fenToObj (fen) { - if (!validFen(fen)) return false - - // cut off any move, castling, etc info from the end - // we're only interested in position information - fen = fen.replace(/ .+$/, '') - - var rows = fen.split('/') - var position = {} - - var currentRow = 8 - for (var i = 0; i < 8; i++) { - var row = rows[i].split('') - var colIdx = 0 - - // loop through each character in the FEN section - for (var j = 0; j < row.length; j++) { - // number / empty squares - if (row[j].search(/[1-8]/) !== -1) { - var numEmptySquares = parseInt(row[j], 10) - colIdx = colIdx + numEmptySquares - } else { - // piece - var square = COLUMNS[colIdx] + currentRow - position[square] = fenToPieceCode(row[j]) - colIdx = colIdx + 1 - } - } - - currentRow = currentRow - 1 - } - - return position - } - - // position object to FEN string - // returns false if the obj is not a valid position object - function objToFen (obj) { - if (!validPositionObject(obj)) return false - - var fen = '' - - var currentRow = 8 - for (var i = 0; i < 8; i++) { - for (var j = 0; j < 8; j++) { - var square = COLUMNS[j] + currentRow - - // piece exists - if (obj.hasOwnProperty(square)) { - fen = fen + pieceCodeToFen(obj[square]) - } else { - // empty space - fen = fen + '1' - } - } - - if (i !== 7) { - fen = fen + '/' - } - - currentRow = currentRow - 1 - } - - // squeeze the empty numbers together - fen = squeezeFenEmptySquares(fen) - - return fen - } - - if (RUN_ASSERTS) { - console.assert(objToFen(START_POSITION) === START_FEN) - console.assert(objToFen({}) === '8/8/8/8/8/8/8/8') - console.assert(objToFen({a2: 'wP', 'b2': 'bP'}) === '8/8/8/8/8/8/Pp6/8') - } - - function squeezeFenEmptySquares (fen) { - return fen.replace(/11111111/g, '8') - .replace(/1111111/g, '7') - .replace(/111111/g, '6') - .replace(/11111/g, '5') - .replace(/1111/g, '4') - .replace(/111/g, '3') - .replace(/11/g, '2') - } - - function expandFenEmptySquares (fen) { - return fen.replace(/8/g, '11111111') - .replace(/7/g, '1111111') - .replace(/6/g, '111111') - .replace(/5/g, '11111') - .replace(/4/g, '1111') - .replace(/3/g, '111') - .replace(/2/g, '11') - } - - // returns the distance between two squares - function squareDistance (squareA, squareB) { - var squareAArray = squareA.split('') - var squareAx = COLUMNS.indexOf(squareAArray[0]) + 1 - var squareAy = parseInt(squareAArray[1], 10) - - var squareBArray = squareB.split('') - var squareBx = COLUMNS.indexOf(squareBArray[0]) + 1 - var squareBy = parseInt(squareBArray[1], 10) - - var xDelta = Math.abs(squareAx - squareBx) - var yDelta = Math.abs(squareAy - squareBy) - - if (xDelta >= yDelta) return xDelta - return yDelta - } - - // returns the square of the closest instance of piece - // returns false if no instance of piece is found in position - function findClosestPiece (position, piece, square) { - // create array of closest squares from square - var closestSquares = createRadius(square) - - // search through the position in order of distance for the piece - for (var i = 0; i < closestSquares.length; i++) { - var s = closestSquares[i] - - if (position.hasOwnProperty(s) && position[s] === piece) { - return s - } - } - - return false - } - - // returns an array of closest squares from square - function createRadius (square) { - var squares = [] - - // calculate distance of all squares - for (var i = 0; i < 8; i++) { - for (var j = 0; j < 8; j++) { - var s = COLUMNS[i] + (j + 1) - - // skip the square we're starting from - if (square === s) continue - - squares.push({ - square: s, - distance: squareDistance(square, s) - }) - } - } - - // sort by distance - squares.sort(function (a, b) { - return a.distance - b.distance - }) - - // just return the square code - var surroundingSquares = [] - for (i = 0; i < squares.length; i++) { - surroundingSquares.push(squares[i].square) - } - - return surroundingSquares - } - - // given a position and a set of moves, return a new position - // with the moves executed - function calculatePositionFromMoves (position, moves) { - var newPosition = deepCopy(position) - - for (var i in moves) { - if (!moves.hasOwnProperty(i)) continue - - // skip the move if the position doesn't have a piece on the source square - if (!newPosition.hasOwnProperty(i)) continue - - var piece = newPosition[i] - delete newPosition[i] - newPosition[moves[i]] = piece - } - - return newPosition - } - - // TODO: add some asserts here for calculatePositionFromMoves - - // --------------------------------------------------------------------------- - // HTML - // --------------------------------------------------------------------------- - - function buildContainerHTML (hasSparePieces) { - var html = '
' - - if (hasSparePieces) { - html += '
' - } - - html += '
' - - if (hasSparePieces) { - html += '
' - } - - html += '
' - - return interpolateTemplate(html, CSS) - } - - // --------------------------------------------------------------------------- - // Config - // --------------------------------------------------------------------------- - - function expandConfigArgumentShorthand (config) { - if (config === 'start') { - config = {position: deepCopy(START_POSITION)} - } else if (validFen(config)) { - config = {position: fenToObj(config)} - } else if (validPositionObject(config)) { - config = {position: deepCopy(config)} - } - - // config must be an object - if (!$.isPlainObject(config)) config = {} - - return config - } - - // validate config / set default options - function expandConfig (config) { - // default for orientation is white - if (config.orientation !== 'black') config.orientation = 'white' - - // default for showNotation is true - if (config.showNotation !== false) config.showNotation = true - - // default for draggable is false - if (config.draggable !== true) config.draggable = false - - // default for dropOffBoard is 'snapback' - if (config.dropOffBoard !== 'trash') config.dropOffBoard = 'snapback' - - // default for sparePieces is false - if (config.sparePieces !== true) config.sparePieces = false - - // draggable must be true if sparePieces is enabled - if (config.sparePieces) config.draggable = true - - // default piece theme is wikipedia - if (!config.hasOwnProperty('pieceTheme') || - (!isString(config.pieceTheme) && !isFunction(config.pieceTheme))) { - config.pieceTheme = 'img/chesspieces/wikipedia/{piece}.png' - } - - // animation speeds - if (!validAnimationSpeed(config.appearSpeed)) config.appearSpeed = DEFAULT_APPEAR_SPEED - if (!validAnimationSpeed(config.moveSpeed)) config.moveSpeed = DEFAULT_MOVE_SPEED - if (!validAnimationSpeed(config.snapbackSpeed)) config.snapbackSpeed = DEFAULT_SNAPBACK_SPEED - if (!validAnimationSpeed(config.snapSpeed)) config.snapSpeed = DEFAULT_SNAP_SPEED - if (!validAnimationSpeed(config.trashSpeed)) config.trashSpeed = DEFAULT_TRASH_SPEED - - // throttle rate - if (!validThrottleRate(config.dragThrottleRate)) config.dragThrottleRate = DEFAULT_DRAG_THROTTLE_RATE - - return config - } - - // --------------------------------------------------------------------------- - // Dependencies - // --------------------------------------------------------------------------- - - // check for a compatible version of jQuery - function checkJQuery () { - if (!validJQueryVersion()) { - var errorMsg = 'Chessboard Error 1005: Unable to find a valid version of jQuery. ' + - 'Please include jQuery ' + MINIMUM_JQUERY_VERSION + ' or higher on the page' + - '\n\n' + - 'Exiting' + ELLIPSIS - window.alert(errorMsg) - return false - } - - return true - } - - // return either boolean false or the $container element - function checkContainerArg (containerElOrString) { - if (containerElOrString === '') { - var errorMsg1 = 'Chessboard Error 1001: ' + - 'The first argument to Chessboard() cannot be an empty string.' + - '\n\n' + - 'Exiting' + ELLIPSIS - window.alert(errorMsg1) - return false - } - - // convert containerEl to query selector if it is a string - if (isString(containerElOrString) && - containerElOrString.charAt(0) !== '#') { - containerElOrString = '#' + containerElOrString - } - - // containerEl must be something that becomes a jQuery collection of size 1 - var $container = $(containerElOrString) - if ($container.length !== 1) { - var errorMsg2 = 'Chessboard Error 1003: ' + - 'The first argument to Chessboard() must be the ID of a DOM node, ' + - 'an ID query selector, or a single DOM node.' + - '\n\n' + - 'Exiting' + ELLIPSIS - window.alert(errorMsg2) - return false - } - - return $container - } - - // --------------------------------------------------------------------------- - // Constructor - // --------------------------------------------------------------------------- - - function constructor (containerElOrString, config) { - // first things first: check basic dependencies - if (!checkJQuery()) return null - var $container = checkContainerArg(containerElOrString) - if (!$container) return null - - // ensure the config object is what we expect - config = expandConfigArgumentShorthand(config) - config = expandConfig(config) - - // DOM elements - var $board = null - var $draggedPiece = null - var $sparePiecesTop = null - var $sparePiecesBottom = null - - // constructor return object - var widget = {} - - // ------------------------------------------------------------------------- - // Stateful - // ------------------------------------------------------------------------- - - var boardBorderSize = 2 - var currentOrientation = 'white' - var currentPosition = {} - var draggedPiece = null - var draggedPieceLocation = null - var draggedPieceSource = null - var isDragging = false - var sparePiecesElsIds = {} - var squareElsIds = {} - var squareElsOffsets = {} - var squareSize = 16 - - // ------------------------------------------------------------------------- - // Validation / Errors - // ------------------------------------------------------------------------- - - function error (code, msg, obj) { - // do nothing if showErrors is not set - if ( - config.hasOwnProperty('showErrors') !== true || - config.showErrors === false - ) { - return - } - - var errorText = 'Chessboard Error ' + code + ': ' + msg - - // print to console - if ( - config.showErrors === 'console' && - typeof console === 'object' && - typeof console.log === 'function' - ) { - console.log(errorText) - if (arguments.length >= 2) { - console.log(obj) - } - return - } - - // alert errors - if (config.showErrors === 'alert') { - if (obj) { - errorText += '\n\n' + JSON.stringify(obj) - } - window.alert(errorText) - return - } - - // custom function - if (isFunction(config.showErrors)) { - config.showErrors(code, msg, obj) - } - } - - function setInitialState () { - currentOrientation = config.orientation - - // make sure position is valid - if (config.hasOwnProperty('position')) { - if (config.position === 'start') { - currentPosition = deepCopy(START_POSITION) - } else if (validFen(config.position)) { - currentPosition = fenToObj(config.position) - } else if (validPositionObject(config.position)) { - currentPosition = deepCopy(config.position) - } else { - error( - 7263, - 'Invalid value passed to config.position.', - config.position - ) - } - } - } - - // ------------------------------------------------------------------------- - // DOM Misc - // ------------------------------------------------------------------------- - - // calculates square size based on the width of the container - // got a little CSS black magic here, so let me explain: - // get the width of the container element (could be anything), reduce by 1 for - // fudge factor, and then keep reducing until we find an exact mod 8 for - // our square size - function calculateSquareSize () { - var containerWidth = parseInt($container.width(), 10) - - // defensive, prevent infinite loop - if (!containerWidth || containerWidth <= 0) { - return 0 - } - - // pad one pixel - var boardWidth = containerWidth - 1 - - while (boardWidth % 8 !== 0 && boardWidth > 0) { - boardWidth = boardWidth - 1 - } - - return boardWidth / 8 - } - - // create random IDs for elements - function createElIds () { - // squares on the board - for (var i = 0; i < COLUMNS.length; i++) { - for (var j = 1; j <= 8; j++) { - var square = COLUMNS[i] + j - squareElsIds[square] = square + '-' + uuid() - } - } - - // spare pieces - var pieces = 'KQRNBP'.split('') - for (i = 0; i < pieces.length; i++) { - var whitePiece = 'w' + pieces[i] - var blackPiece = 'b' + pieces[i] - sparePiecesElsIds[whitePiece] = whitePiece + '-' + uuid() - sparePiecesElsIds[blackPiece] = blackPiece + '-' + uuid() - } - } - - // ------------------------------------------------------------------------- - // Markup Building - // ------------------------------------------------------------------------- - - function buildBoardHTML (orientation) { - if (orientation !== 'black') { - orientation = 'white' - } - - var html = '' - - // algebraic notation / orientation - var alpha = deepCopy(COLUMNS) - var row = 8 - if (orientation === 'black') { - alpha.reverse() - row = 1 - } - - var squareColor = 'white' - for (var i = 0; i < 8; i++) { - html += '
' - for (var j = 0; j < 8; j++) { - var square = alpha[j] + row - - html += '
' - - if (config.showNotation) { - // alpha notation - if ((orientation === 'white' && row === 1) || - (orientation === 'black' && row === 8)) { - html += '
' + alpha[j] + '
' - } - - // numeric notation - if (j === 0) { - html += '
' + row + '
' - } - } - - html += '
' // end .square - - squareColor = (squareColor === 'white') ? 'black' : 'white' - } - html += '
' - - squareColor = (squareColor === 'white') ? 'black' : 'white' - - if (orientation === 'white') { - row = row - 1 - } else { - row = row + 1 - } - } - - return interpolateTemplate(html, CSS) - } - - function buildPieceImgSrc (piece) { - if (isFunction(config.pieceTheme)) { - return config.pieceTheme(piece) - } - - if (isString(config.pieceTheme)) { - return interpolateTemplate(config.pieceTheme, {piece: piece}) - } - - // NOTE: this should never happen - error(8272, 'Unable to build image source for config.pieceTheme.') - return '' - } - - function buildPieceHTML (piece, hidden, id) { - var html = '' - - return interpolateTemplate(html, CSS) - } - - function buildSparePiecesHTML (color) { - var pieces = ['wK', 'wQ', 'wR', 'wB', 'wN', 'wP'] - if (color === 'black') { - pieces = ['bK', 'bQ', 'bR', 'bB', 'bN', 'bP'] - } - - var html = '' - for (var i = 0; i < pieces.length; i++) { - html += buildPieceHTML(pieces[i], false, sparePiecesElsIds[pieces[i]]) - } - - return html - } - - // ------------------------------------------------------------------------- - // Animations - // ------------------------------------------------------------------------- - - function animateSquareToSquare (src, dest, piece, completeFn) { - // get information about the source and destination squares - var $srcSquare = $('#' + squareElsIds[src]) - var srcSquarePosition = $srcSquare.offset() - var $destSquare = $('#' + squareElsIds[dest]) - var destSquarePosition = $destSquare.offset() - - // create the animated piece and absolutely position it - // over the source square - var animatedPieceId = uuid() - $('body').append(buildPieceHTML(piece, true, animatedPieceId)) - var $animatedPiece = $('#' + animatedPieceId) - $animatedPiece.css({ - display: '', - position: 'absolute', - top: srcSquarePosition.top, - left: srcSquarePosition.left - }) - - // remove original piece from source square - $srcSquare.find('.' + CSS.piece).remove() - - function onFinishAnimation1 () { - // add the "real" piece to the destination square - $destSquare.append(buildPieceHTML(piece)) - - // remove the animated piece - $animatedPiece.remove() - - // run complete function - if (isFunction(completeFn)) { - completeFn() - } - } - - // animate the piece to the destination square - var opts = { - duration: config.moveSpeed, - complete: onFinishAnimation1 - } - $animatedPiece.animate(destSquarePosition, opts) - } - - function animateSparePieceToSquare (piece, dest, completeFn) { - var srcOffset = $('#' + sparePiecesElsIds[piece]).offset() - var $destSquare = $('#' + squareElsIds[dest]) - var destOffset = $destSquare.offset() - - // create the animate piece - var pieceId = uuid() - $('body').append(buildPieceHTML(piece, true, pieceId)) - var $animatedPiece = $('#' + pieceId) - $animatedPiece.css({ - display: '', - position: 'absolute', - left: srcOffset.left, - top: srcOffset.top - }) - - // on complete - function onFinishAnimation2 () { - // add the "real" piece to the destination square - $destSquare.find('.' + CSS.piece).remove() - $destSquare.append(buildPieceHTML(piece)) - - // remove the animated piece - $animatedPiece.remove() - - // run complete function - if (isFunction(completeFn)) { - completeFn() - } - } - - // animate the piece to the destination square - var opts = { - duration: config.moveSpeed, - complete: onFinishAnimation2 - } - $animatedPiece.animate(destOffset, opts) - } - - // execute an array of animations - function doAnimations (animations, oldPos, newPos) { - if (animations.length === 0) return - - var numFinished = 0 - function onFinishAnimation3 () { - // exit if all the animations aren't finished - numFinished = numFinished + 1 - if (numFinished !== animations.length) return - - drawPositionInstant() - - // run their onMoveEnd function - if (isFunction(config.onMoveEnd)) { - config.onMoveEnd(deepCopy(oldPos), deepCopy(newPos)) - } - } - - for (var i = 0; i < animations.length; i++) { - var animation = animations[i] - - // clear a piece - if (animation.type === 'clear') { - $('#' + squareElsIds[animation.square] + ' .' + CSS.piece) - .fadeOut(config.trashSpeed, onFinishAnimation3) - - // add a piece with no spare pieces - fade the piece onto the square - } else if (animation.type === 'add' && !config.sparePieces) { - $('#' + squareElsIds[animation.square]) - .append(buildPieceHTML(animation.piece, true)) - .find('.' + CSS.piece) - .fadeIn(config.appearSpeed, onFinishAnimation3) - - // add a piece with spare pieces - animate from the spares - } else if (animation.type === 'add' && config.sparePieces) { - animateSparePieceToSquare(animation.piece, animation.square, onFinishAnimation3) - - // move a piece from squareA to squareB - } else if (animation.type === 'move') { - animateSquareToSquare(animation.source, animation.destination, animation.piece, onFinishAnimation3) - } - } - } - - // calculate an array of animations that need to happen in order to get - // from pos1 to pos2 - function calculateAnimations (pos1, pos2) { - // make copies of both - pos1 = deepCopy(pos1) - pos2 = deepCopy(pos2) - - var animations = [] - var squaresMovedTo = {} - - // remove pieces that are the same in both positions - for (var i in pos2) { - if (!pos2.hasOwnProperty(i)) continue - - if (pos1.hasOwnProperty(i) && pos1[i] === pos2[i]) { - delete pos1[i] - delete pos2[i] - } - } - - // find all the "move" animations - for (i in pos2) { - if (!pos2.hasOwnProperty(i)) continue - - var closestPiece = findClosestPiece(pos1, pos2[i], i) - if (closestPiece) { - animations.push({ - type: 'move', - source: closestPiece, - destination: i, - piece: pos2[i] - }) - - delete pos1[closestPiece] - delete pos2[i] - squaresMovedTo[i] = true - } - } - - // "add" animations - for (i in pos2) { - if (!pos2.hasOwnProperty(i)) continue - - animations.push({ - type: 'add', - square: i, - piece: pos2[i] - }) - - delete pos2[i] - } - - // "clear" animations - for (i in pos1) { - if (!pos1.hasOwnProperty(i)) continue - - // do not clear a piece if it is on a square that is the result - // of a "move", ie: a piece capture - if (squaresMovedTo.hasOwnProperty(i)) continue - - animations.push({ - type: 'clear', - square: i, - piece: pos1[i] - }) - - delete pos1[i] - } - - return animations - } - - // ------------------------------------------------------------------------- - // Control Flow - // ------------------------------------------------------------------------- - - function drawPositionInstant () { - // clear the board - $board.find('.' + CSS.piece).remove() - - // add the pieces - for (var i in currentPosition) { - if (!currentPosition.hasOwnProperty(i)) continue - - $('#' + squareElsIds[i]).append(buildPieceHTML(currentPosition[i])) - } - } - - function drawBoard () { - $board.html(buildBoardHTML(currentOrientation, squareSize, config.showNotation)) - drawPositionInstant() - - if (config.sparePieces) { - if (currentOrientation === 'white') { - $sparePiecesTop.html(buildSparePiecesHTML('black')) - $sparePiecesBottom.html(buildSparePiecesHTML('white')) - } else { - $sparePiecesTop.html(buildSparePiecesHTML('white')) - $sparePiecesBottom.html(buildSparePiecesHTML('black')) - } - } - } - - function setCurrentPosition (position) { - var oldPos = deepCopy(currentPosition) - var newPos = deepCopy(position) - var oldFen = objToFen(oldPos) - var newFen = objToFen(newPos) - - // do nothing if no change in position - if (oldFen === newFen) return - - // run their onChange function - if (isFunction(config.onChange)) { - config.onChange(oldPos, newPos) - } - - // update state - currentPosition = position - } - - function isXYOnSquare (x, y) { - for (var i in squareElsOffsets) { - if (!squareElsOffsets.hasOwnProperty(i)) continue - - var s = squareElsOffsets[i] - if (x >= s.left && - x < s.left + squareSize && - y >= s.top && - y < s.top + squareSize) { - return i - } - } - - return 'offboard' - } - - // records the XY coords of every square into memory - function captureSquareOffsets () { - squareElsOffsets = {} - - for (var i in squareElsIds) { - if (!squareElsIds.hasOwnProperty(i)) continue - - squareElsOffsets[i] = $('#' + squareElsIds[i]).offset() - } - } - - function removeSquareHighlights () { - $board - .find('.' + CSS.square) - .removeClass(CSS.highlight1 + ' ' + CSS.highlight2) - } - - function snapbackDraggedPiece () { - // there is no "snapback" for spare pieces - if (draggedPieceSource === 'spare') { - trashDraggedPiece() - return - } - - removeSquareHighlights() - - // animation complete - function complete () { - drawPositionInstant() - $draggedPiece.css('display', 'none') - - // run their onSnapbackEnd function - if (isFunction(config.onSnapbackEnd)) { - config.onSnapbackEnd( - draggedPiece, - draggedPieceSource, - deepCopy(currentPosition), - currentOrientation - ) - } - } - - // get source square position - var sourceSquarePosition = $('#' + squareElsIds[draggedPieceSource]).offset() - - // animate the piece to the target square - var opts = { - duration: config.snapbackSpeed, - complete: complete - } - $draggedPiece.animate(sourceSquarePosition, opts) - - // set state - isDragging = false - } - - function trashDraggedPiece () { - removeSquareHighlights() - - // remove the source piece - var newPosition = deepCopy(currentPosition) - delete newPosition[draggedPieceSource] - setCurrentPosition(newPosition) - - // redraw the position - drawPositionInstant() - - // hide the dragged piece - $draggedPiece.fadeOut(config.trashSpeed) - - // set state - isDragging = false - } - - function dropDraggedPieceOnSquare (square) { - removeSquareHighlights() - - // update position - var newPosition = deepCopy(currentPosition) - delete newPosition[draggedPieceSource] - newPosition[square] = draggedPiece - setCurrentPosition(newPosition) - - // get target square information - var targetSquarePosition = $('#' + squareElsIds[square]).offset() - - // animation complete - function onAnimationComplete () { - drawPositionInstant() - $draggedPiece.css('display', 'none') - - // execute their onSnapEnd function - if (isFunction(config.onSnapEnd)) { - config.onSnapEnd(draggedPieceSource, square, draggedPiece) - } - } - - // snap the piece to the target square - var opts = { - duration: config.snapSpeed, - complete: onAnimationComplete - } - $draggedPiece.animate(targetSquarePosition, opts) - - // set state - isDragging = false - } - - function beginDraggingPiece (source, piece, x, y) { - // run their custom onDragStart function - // their custom onDragStart function can cancel drag start - if (isFunction(config.onDragStart) && - config.onDragStart(source, piece, deepCopy(currentPosition), currentOrientation) === false) { - return - } - - // set state - isDragging = true - draggedPiece = piece - draggedPieceSource = source - - // if the piece came from spare pieces, location is offboard - if (source === 'spare') { - draggedPieceLocation = 'offboard' - } else { - draggedPieceLocation = source - } - - // capture the x, y coords of all squares in memory - captureSquareOffsets() - - // create the dragged piece - $draggedPiece.attr('src', buildPieceImgSrc(piece)).css({ - display: '', - position: 'absolute', - left: x - squareSize / 2, - top: y - squareSize / 2 - }) - - if (source !== 'spare') { - // highlight the source square and hide the piece - $('#' + squareElsIds[source]) - .addClass(CSS.highlight1) - .find('.' + CSS.piece) - .css('display', 'none') - } - } - - function updateDraggedPiece (x, y) { - // put the dragged piece over the mouse cursor - $draggedPiece.css({ - left: x - squareSize / 2, - top: y - squareSize / 2 - }) - - // get location - var location = isXYOnSquare(x, y) - - // do nothing if the location has not changed - if (location === draggedPieceLocation) return - - // remove highlight from previous square - if (validSquare(draggedPieceLocation)) { - $('#' + squareElsIds[draggedPieceLocation]).removeClass(CSS.highlight2) - } - - // add highlight to new square - if (validSquare(location)) { - $('#' + squareElsIds[location]).addClass(CSS.highlight2) - } - - // run onDragMove - if (isFunction(config.onDragMove)) { - config.onDragMove( - location, - draggedPieceLocation, - draggedPieceSource, - draggedPiece, - deepCopy(currentPosition), - currentOrientation - ) - } - - // update state - draggedPieceLocation = location - } - - function stopDraggedPiece (location) { - // determine what the action should be - var action = 'drop' - if (location === 'offboard' && config.dropOffBoard === 'snapback') { - action = 'snapback' - } - if (location === 'offboard' && config.dropOffBoard === 'trash') { - action = 'trash' - } - - // run their onDrop function, which can potentially change the drop action - if (isFunction(config.onDrop)) { - var newPosition = deepCopy(currentPosition) - - // source piece is a spare piece and position is off the board - // if (draggedPieceSource === 'spare' && location === 'offboard') {...} - // position has not changed; do nothing - - // source piece is a spare piece and position is on the board - if (draggedPieceSource === 'spare' && validSquare(location)) { - // add the piece to the board - newPosition[location] = draggedPiece - } - - // source piece was on the board and position is off the board - if (validSquare(draggedPieceSource) && location === 'offboard') { - // remove the piece from the board - delete newPosition[draggedPieceSource] - } - - // source piece was on the board and position is on the board - if (validSquare(draggedPieceSource) && validSquare(location)) { - // move the piece - delete newPosition[draggedPieceSource] - newPosition[location] = draggedPiece - } - - var oldPosition = deepCopy(currentPosition) - - var result = config.onDrop( - draggedPieceSource, - location, - draggedPiece, - newPosition, - oldPosition, - currentOrientation - ) - if (result === 'snapback' || result === 'trash') { - action = result - } - } - - // do it! - if (action === 'snapback') { - snapbackDraggedPiece() - } else if (action === 'trash') { - trashDraggedPiece() - } else if (action === 'drop') { - dropDraggedPieceOnSquare(location) - } - } - - // ------------------------------------------------------------------------- - // Public Methods - // ------------------------------------------------------------------------- - - // clear the board - widget.clear = function (useAnimation) { - widget.position({}, useAnimation) - } - - // remove the widget from the page - widget.destroy = function () { - // remove markup - $container.html('') - $draggedPiece.remove() - - // remove event handlers - $container.unbind() - } - - // shorthand method to get the current FEN - widget.fen = function () { - return widget.position('fen') - } - - // flip orientation - widget.flip = function () { - return widget.orientation('flip') - } - - // move pieces - // TODO: this method should be variadic as well as accept an array of moves - widget.move = function () { - // no need to throw an error here; just do nothing - // TODO: this should return the current position - if (arguments.length === 0) return - - var useAnimation = true - - // collect the moves into an object - var moves = {} - for (var i = 0; i < arguments.length; i++) { - // any "false" to this function means no animations - if (arguments[i] === false) { - useAnimation = false - continue - } - - // skip invalid arguments - if (!validMove(arguments[i])) { - error(2826, 'Invalid move passed to the move method.', arguments[i]) - continue - } - - var tmp = arguments[i].split('-') - moves[tmp[0]] = tmp[1] - } - - // calculate position from moves - var newPos = calculatePositionFromMoves(currentPosition, moves) - - // update the board - widget.position(newPos, useAnimation) - - // return the new position object - return newPos - } - - widget.orientation = function (arg) { - // no arguments, return the current orientation - if (arguments.length === 0) { - return currentOrientation - } - - // set to white or black - if (arg === 'white' || arg === 'black') { - currentOrientation = arg - drawBoard() - return currentOrientation - } - - // flip orientation - if (arg === 'flip') { - currentOrientation = currentOrientation === 'white' ? 'black' : 'white' - drawBoard() - return currentOrientation - } - - error(5482, 'Invalid value passed to the orientation method.', arg) - } - - widget.position = function (position, useAnimation) { - // no arguments, return the current position - if (arguments.length === 0) { - return deepCopy(currentPosition) - } - - // get position as FEN - if (isString(position) && position.toLowerCase() === 'fen') { - return objToFen(currentPosition) - } - - // start position - if (isString(position) && position.toLowerCase() === 'start') { - position = deepCopy(START_POSITION) - } - - // convert FEN to position object - if (validFen(position)) { - position = fenToObj(position) - } - - // validate position object - if (!validPositionObject(position)) { - error(6482, 'Invalid value passed to the position method.', position) - return - } - - // default for useAnimations is true - if (useAnimation !== false) useAnimation = true - - if (useAnimation) { - // start the animations - var animations = calculateAnimations(currentPosition, position) - doAnimations(animations, currentPosition, position) - - // set the new position - setCurrentPosition(position) - } else { - // instant update - setCurrentPosition(position) - drawPositionInstant() - } - } - - widget.resize = function () { - // calulate the new square size - squareSize = calculateSquareSize() - - // set board width - $board.css('width', squareSize * 8 + 'px') - - // set drag piece size - $draggedPiece.css({ - height: squareSize, - width: squareSize - }) - - // spare pieces - if (config.sparePieces) { - $container - .find('.' + CSS.sparePieces) - .css('paddingLeft', squareSize + boardBorderSize + 'px') - } - - // redraw the board - drawBoard() - } - - // set the starting position - widget.start = function (useAnimation) { - widget.position('start', useAnimation) - } - - // ------------------------------------------------------------------------- - // Browser Events - // ------------------------------------------------------------------------- - - function stopDefault (evt) { - evt.preventDefault() - } - - function mousedownSquare (evt) { - // do nothing if we're not draggable - if (!config.draggable) return - - // do nothing if there is no piece on this square - var square = $(this).attr('data-square') - if (!validSquare(square)) return - if (!currentPosition.hasOwnProperty(square)) return - - beginDraggingPiece(square, currentPosition[square], evt.pageX, evt.pageY) - } - - function touchstartSquare (e) { - // do nothing if we're not draggable - if (!config.draggable) return - - // do nothing if there is no piece on this square - var square = $(this).attr('data-square') - if (!validSquare(square)) return - if (!currentPosition.hasOwnProperty(square)) return - - e = e.originalEvent - beginDraggingPiece( - square, - currentPosition[square], - e.changedTouches[0].pageX, - e.changedTouches[0].pageY - ) - } - - function mousedownSparePiece (evt) { - // do nothing if sparePieces is not enabled - if (!config.sparePieces) return - - var piece = $(this).attr('data-piece') - - beginDraggingPiece('spare', piece, evt.pageX, evt.pageY) - } - - function touchstartSparePiece (e) { - // do nothing if sparePieces is not enabled - if (!config.sparePieces) return - - var piece = $(this).attr('data-piece') - - e = e.originalEvent - beginDraggingPiece( - 'spare', - piece, - e.changedTouches[0].pageX, - e.changedTouches[0].pageY - ) - } - - function mousemoveWindow (evt) { - if (isDragging) { - updateDraggedPiece(evt.pageX, evt.pageY) - } - } - - var throttledMousemoveWindow = throttle(mousemoveWindow, config.dragThrottleRate) - - function touchmoveWindow (evt) { - // do nothing if we are not dragging a piece - if (!isDragging) return - - // prevent screen from scrolling - evt.preventDefault() - - updateDraggedPiece(evt.originalEvent.changedTouches[0].pageX, - evt.originalEvent.changedTouches[0].pageY) - } - - var throttledTouchmoveWindow = throttle(touchmoveWindow, config.dragThrottleRate) - - function mouseupWindow (evt) { - // do nothing if we are not dragging a piece - if (!isDragging) return - - // get the location - var location = isXYOnSquare(evt.pageX, evt.pageY) - - stopDraggedPiece(location) - } - - function touchendWindow (evt) { - // do nothing if we are not dragging a piece - if (!isDragging) return - - // get the location - var location = isXYOnSquare(evt.originalEvent.changedTouches[0].pageX, - evt.originalEvent.changedTouches[0].pageY) - - stopDraggedPiece(location) - } - - function mouseenterSquare (evt) { - // do not fire this event if we are dragging a piece - // NOTE: this should never happen, but it's a safeguard - if (isDragging) return - - // exit if they did not provide a onMouseoverSquare function - if (!isFunction(config.onMouseoverSquare)) return - - // get the square - var square = $(evt.currentTarget).attr('data-square') - - // NOTE: this should never happen; defensive - if (!validSquare(square)) return - - // get the piece on this square - var piece = false - if (currentPosition.hasOwnProperty(square)) { - piece = currentPosition[square] - } - - // execute their function - config.onMouseoverSquare(square, piece, deepCopy(currentPosition), currentOrientation) - } - - function mouseleaveSquare (evt) { - // do not fire this event if we are dragging a piece - // NOTE: this should never happen, but it's a safeguard - if (isDragging) return - - // exit if they did not provide an onMouseoutSquare function - if (!isFunction(config.onMouseoutSquare)) return - - // get the square - var square = $(evt.currentTarget).attr('data-square') - - // NOTE: this should never happen; defensive - if (!validSquare(square)) return - - // get the piece on this square - var piece = false - if (currentPosition.hasOwnProperty(square)) { - piece = currentPosition[square] - } - - // execute their function - config.onMouseoutSquare(square, piece, deepCopy(currentPosition), currentOrientation) - } - - // ------------------------------------------------------------------------- - // Initialization - // ------------------------------------------------------------------------- - - function addEvents () { - // prevent "image drag" - $('body').on('mousedown mousemove', '.' + CSS.piece, stopDefault) - - // mouse drag pieces - $board.on('mousedown', '.' + CSS.square, mousedownSquare) - $container.on('mousedown', '.' + CSS.sparePieces + ' .' + CSS.piece, mousedownSparePiece) - - // mouse enter / leave square - $board - .on('mouseenter', '.' + CSS.square, mouseenterSquare) - .on('mouseleave', '.' + CSS.square, mouseleaveSquare) - - // piece drag - var $window = $(window) - $window - .on('mousemove', throttledMousemoveWindow) - .on('mouseup', mouseupWindow) - - // touch drag pieces - if (isTouchDevice()) { - $board.on('touchstart', '.' + CSS.square, touchstartSquare) - $container.on('touchstart', '.' + CSS.sparePieces + ' .' + CSS.piece, touchstartSparePiece) - $window - .on('touchmove', throttledTouchmoveWindow) - .on('touchend', touchendWindow) - } - } - - function initDOM () { - // create unique IDs for all the elements we will create - createElIds() - - // build board and save it in memory - $container.html(buildContainerHTML(config.sparePieces)) - $board = $container.find('.' + CSS.board) - - if (config.sparePieces) { - $sparePiecesTop = $container.find('.' + CSS.sparePiecesTop) - $sparePiecesBottom = $container.find('.' + CSS.sparePiecesBottom) - } - - // create the drag piece - var draggedPieceId = uuid() - $('body').append(buildPieceHTML('wP', true, draggedPieceId)) - $draggedPiece = $('#' + draggedPieceId) - - // TODO: need to remove this dragged piece element if the board is no - // longer in the DOM - - // get the border size - boardBorderSize = parseInt($board.css('borderLeftWidth'), 10) - - // set the size and draw the board - widget.resize() - } - - // ------------------------------------------------------------------------- - // Initialization - // ------------------------------------------------------------------------- - - setInitialState() - initDOM() - addEvents() - - // return the widget object - return widget - } // end constructor - - // TODO: do module exports here - window['Chessboard'] = constructor - - // support legacy ChessBoard name - window['ChessBoard'] = window['Chessboard'] - - // expose util functions - window['Chessboard']['fenToObj'] = fenToObj - window['Chessboard']['objToFen'] = objToFen -})() // end anonymous wrapper diff --git a/chess/chessboard/js/chessboard-1.0.0.min.js b/chess/chessboard/js/chessboard-1.0.0.min.js deleted file mode 100644 index 73ea287..0000000 --- a/chess/chessboard/js/chessboard-1.0.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ -!function(){"use strict";var z=window.jQuery,F="abcdefgh".split(""),r=20,A="…",W="1.8.3",e="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR",G=pe(e),n=200,t=200,o=60,a=30,i=100,H={};function V(e,r,n){function t(){o=0,a&&(a=!1,s())}var o=0,a=!1,i=[],s=function(){o=window.setTimeout(t,r),e.apply(n,i)};return function(e){i=arguments,o?a=!0:s()}}function Z(){return"xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx".replace(/x/g,function(e){return(16*Math.random()|0).toString(16)})}function _(e){return JSON.parse(JSON.stringify(e))}function s(e){var r=e.split(".");return{major:parseInt(r[0],10),minor:parseInt(r[1],10),patch:parseInt(r[2],10)}}function ee(e,r){for(var n in r)if(r.hasOwnProperty(n))for(var t="{"+n+"}",o=r[n];-1!==e.indexOf(t);)e=e.replace(t,o);return e}function re(e){return"string"==typeof e}function ne(e){return"function"==typeof e}function p(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e}function c(e){return"fast"===e||"slow"===e||!!p(e)&&0<=e}function te(e){if(!re(e))return!1;var r=e.split("-");return 2===r.length&&(oe(r[0])&&oe(r[1]))}function oe(e){return re(e)&&-1!==e.search(/^[a-h][1-8]$/)}function u(e){return re(e)&&-1!==e.search(/^[bw][KQRNBP]$/)}function ae(e){if(!re(e))return!1;var r=(e=function(e){return e.replace(/8/g,"11111111").replace(/7/g,"1111111").replace(/6/g,"111111").replace(/5/g,"11111").replace(/4/g,"1111").replace(/3/g,"111").replace(/2/g,"11")}(e=e.replace(/ .+$/,""))).split("/");if(8!==r.length)return!1;for(var n=0;n<8;n++)if(8!==r[n].length||-1!==r[n].search(/[^kqrnbpKQRNBP1]/))return!1;return!0}function ie(e){if(!z.isPlainObject(e))return!1;for(var r in e)if(e.hasOwnProperty(r)&&(!oe(r)||!u(e[r])))return!1;return!0}function se(){return typeof window.$&&z.fn&&z.fn.jquery&&function(e,r){e=s(e),r=s(r);var n=1e5*e.major*1e5+1e5*e.minor+e.patch;return 1e5*r.major*1e5+1e5*r.minor+r.patch<=n}(z.fn.jquery,W)}function pe(e){if(!ae(e))return!1;for(var r,n=(e=e.replace(/ .+$/,"")).split("/"),t={},o=8,a=0;a<8;a++){for(var i=n[a].split(""),s=0,p=0;p';for(var i=0;i<8;i++){var s=n[i]+t;r+='
',f.showNotation&&(("white"===e&&1===t||"black"===e&&8===t)&&(r+='
'+n[i]+"
"),0===i&&(r+='
'+t+"
")),r+="
",o="white"===o?"black":"white"}r+='
',o="white"===o?"black":"white","white"===e?t-=1:t+=1}return ee(r,H)}(p,f.showNotation)),T(),f.sparePieces&&("white"===p?(t.html(x("black")),o.html(x("white"))):(t.html(x("white")),o.html(x("black"))))}function k(e){var r=_(c),n=_(e);ce(r)!==ce(n)&&(ne(f.onChange)&&f.onChange(r,n),c=e)}function E(e,r){for(var n in w)if(w.hasOwnProperty(n)){var t=w[n];if(e>=t.left&&e=t.top&&r (http://chrisoakman.com/)", - "name": "@chrisoakman/chessboardjs", - "description": "JavaScript chessboard widget", - "homepage": "https://chessboardjs.com", - "license": "MIT", - "version": "1.0.0", - "repository": { - "type": "git", - "url": "git://github.com/oakmac/chessboardjs.git" - }, - "files": ["dist/"], - "dependencies": { - "jquery": ">=3.4.1" - }, - "devDependencies": { - "csso": "3.5.1", - "fs-plus": "3.1.1", - "kidif": "1.1.0", - "mustache": "2.3.0", - "standard": "10.0.2", - "uglify-js": "3.6.0" - }, - "scripts": { - "build": "standard lib/chessboard.js && node scripts/build.js", - "standard": "standard --fix lib/*.js website/js/*.js", - "website": "node scripts/website.js" - } -} diff --git a/chess/migrations/__init__.py b/chess/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/chess/models.py b/chess/models.py deleted file mode 100644 index f6bc526..0000000 --- a/chess/models.py +++ /dev/null @@ -1,4 +0,0 @@ -from django.db import models -from common.models import LameUser - -# Create your models here. \ No newline at end of file diff --git a/chess/static/chess/chessboard.js b/chess/static/chess/chessboard.js deleted file mode 100644 index 0939efc..0000000 --- a/chess/static/chess/chessboard.js +++ /dev/null @@ -1,1817 +0,0 @@ -// chessboard.js v1.0.0 -// https://github.com/oakmac/chessboardjs/ -// -// Copyright (c) 2019, Chris Oakman -// Released under the MIT license -// https://github.com/oakmac/chessboardjs/blob/master/LICENSE.md - -// start anonymous scope -;(function () { - 'use strict' - - var $ = window['jQuery'] - - // --------------------------------------------------------------------------- - // Constants - // --------------------------------------------------------------------------- - - var COLUMNS = 'abcdefgh'.split('') - var DEFAULT_DRAG_THROTTLE_RATE = 20 - var ELLIPSIS = '…' - var MINIMUM_JQUERY_VERSION = '1.8.3' - var RUN_ASSERTS = false - var START_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR' - var START_POSITION = fenToObj(START_FEN) - - // default animation speeds - var DEFAULT_APPEAR_SPEED = 200 - var DEFAULT_MOVE_SPEED = 200 - var DEFAULT_SNAPBACK_SPEED = 60 - var DEFAULT_SNAP_SPEED = 30 - var DEFAULT_TRASH_SPEED = 100 - - // use unique class names to prevent clashing with anything else on the page - // and simplify selectors - // NOTE: these should never change - var CSS = {} - CSS['alpha'] = 'alpha-d2270' - CSS['black'] = 'black-3c85d' - CSS['board'] = 'board-b72b1' - CSS['chessboard'] = 'chessboard-63f37' - CSS['clearfix'] = 'clearfix-7da63' - CSS['highlight1'] = 'highlight1-32417' - CSS['highlight2'] = 'highlight2-9c5d2' - CSS['notation'] = 'notation-322f9' - CSS['numeric'] = 'numeric-fc462' - CSS['piece'] = 'piece-417db' - CSS['row'] = 'row-5277c' - CSS['sparePieces'] = 'spare-pieces-7492f' - CSS['sparePiecesBottom'] = 'spare-pieces-bottom-ae20f' - CSS['sparePiecesTop'] = 'spare-pieces-top-4028b' - CSS['square'] = 'square-55d63' - CSS['white'] = 'white-1e1d7' - - // --------------------------------------------------------------------------- - // Misc Util Functions - // --------------------------------------------------------------------------- - - function throttle (f, interval, scope) { - var timeout = 0 - var shouldFire = false - var args = [] - - var handleTimeout = function () { - timeout = 0 - if (shouldFire) { - shouldFire = false - fire() - } - } - - var fire = function () { - timeout = window.setTimeout(handleTimeout, interval) - f.apply(scope, args) - } - - return function (_args) { - args = arguments - if (!timeout) { - fire() - } else { - shouldFire = true - } - } - } - - // function debounce (f, interval, scope) { - // var timeout = 0 - // return function (_args) { - // window.clearTimeout(timeout) - // var args = arguments - // timeout = window.setTimeout(function () { - // f.apply(scope, args) - // }, interval) - // } - // } - - function uuid () { - return 'xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx'.replace(/x/g, function (c) { - var r = (Math.random() * 16) | 0 - return r.toString(16) - }) - } - - function deepCopy (thing) { - return JSON.parse(JSON.stringify(thing)) - } - - function parseSemVer (version) { - var tmp = version.split('.') - return { - major: parseInt(tmp[0], 10), - minor: parseInt(tmp[1], 10), - patch: parseInt(tmp[2], 10) - } - } - - // returns true if version is >= minimum - function validSemanticVersion (version, minimum) { - version = parseSemVer(version) - minimum = parseSemVer(minimum) - - var versionNum = (version.major * 100000 * 100000) + - (version.minor * 100000) + - version.patch - var minimumNum = (minimum.major * 100000 * 100000) + - (minimum.minor * 100000) + - minimum.patch - - return versionNum >= minimumNum - } - - function interpolateTemplate (str, obj) { - for (var key in obj) { - if (!obj.hasOwnProperty(key)) continue - var keyTemplateStr = '{' + key + '}' - var value = obj[key] - while (str.indexOf(keyTemplateStr) !== -1) { - str = str.replace(keyTemplateStr, value) - } - } - return str - } - - if (RUN_ASSERTS) { - console.assert(interpolateTemplate('abc', {a: 'x'}) === 'abc') - console.assert(interpolateTemplate('{a}bc', {}) === '{a}bc') - console.assert(interpolateTemplate('{a}bc', {p: 'q'}) === '{a}bc') - console.assert(interpolateTemplate('{a}bc', {a: 'x'}) === 'xbc') - console.assert(interpolateTemplate('{a}bc{a}bc', {a: 'x'}) === 'xbcxbc') - console.assert(interpolateTemplate('{a}{a}{b}', {a: 'x', b: 'y'}) === 'xxy') - } - - // --------------------------------------------------------------------------- - // Predicates - // --------------------------------------------------------------------------- - - function isString (s) { - return typeof s === 'string' - } - - function isFunction (f) { - return typeof f === 'function' - } - - function isInteger (n) { - return typeof n === 'number' && - isFinite(n) && - Math.floor(n) === n - } - - function validAnimationSpeed (speed) { - if (speed === 'fast' || speed === 'slow') return true - if (!isInteger(speed)) return false - return speed >= 0 - } - - function validThrottleRate (rate) { - return isInteger(rate) && - rate >= 1 - } - - function validMove (move) { - // move should be a string - if (!isString(move)) return false - - // move should be in the form of "e2-e4", "f6-d5" - var squares = move.split('-') - if (squares.length !== 2) return false - - return validSquare(squares[0]) && validSquare(squares[1]) - } - - function validSquare (square) { - return isString(square) && square.search(/^[a-h][1-8]$/) !== -1 - } - - if (RUN_ASSERTS) { - console.assert(validSquare('a1')) - console.assert(validSquare('e2')) - console.assert(!validSquare('D2')) - console.assert(!validSquare('g9')) - console.assert(!validSquare('a')) - console.assert(!validSquare(true)) - console.assert(!validSquare(null)) - console.assert(!validSquare({})) - } - - function validPieceCode (code) { - return isString(code) && code.search(/^[bw][KQRNBP]$/) !== -1 - } - - if (RUN_ASSERTS) { - console.assert(validPieceCode('bP')) - console.assert(validPieceCode('bK')) - console.assert(validPieceCode('wK')) - console.assert(validPieceCode('wR')) - console.assert(!validPieceCode('WR')) - console.assert(!validPieceCode('Wr')) - console.assert(!validPieceCode('a')) - console.assert(!validPieceCode(true)) - console.assert(!validPieceCode(null)) - console.assert(!validPieceCode({})) - } - - function validFen (fen) { - if (!isString(fen)) return false - - // cut off any move, castling, etc info from the end - // we're only interested in position information - fen = fen.replace(/ .+$/, '') - - // expand the empty square numbers to just 1s - fen = expandFenEmptySquares(fen) - - // FEN should be 8 sections separated by slashes - var chunks = fen.split('/') - if (chunks.length !== 8) return false - - // check each section - for (var i = 0; i < 8; i++) { - if (chunks[i].length !== 8 || - chunks[i].search(/[^kqrnbpKQRNBP1]/) !== -1) { - return false - } - } - - return true - } - - if (RUN_ASSERTS) { - console.assert(validFen(START_FEN)) - console.assert(validFen('8/8/8/8/8/8/8/8')) - console.assert(validFen('r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R')) - console.assert(validFen('3r3r/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1')) - console.assert(!validFen('3r3z/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1')) - console.assert(!validFen('anbqkbnr/8/8/8/8/8/PPPPPPPP/8')) - console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/')) - console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBN')) - console.assert(!validFen('888888/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR')) - console.assert(!validFen('888888/pppppppp/74/8/8/8/PPPPPPPP/RNBQKBNR')) - console.assert(!validFen({})) - } - - function validPositionObject (pos) { - if (!$.isPlainObject(pos)) return false - - for (var i in pos) { - if (!pos.hasOwnProperty(i)) continue - - if (!validSquare(i) || !validPieceCode(pos[i])) { - return false - } - } - - return true - } - - if (RUN_ASSERTS) { - console.assert(validPositionObject(START_POSITION)) - console.assert(validPositionObject({})) - console.assert(validPositionObject({e2: 'wP'})) - console.assert(validPositionObject({e2: 'wP', d2: 'wP'})) - console.assert(!validPositionObject({e2: 'BP'})) - console.assert(!validPositionObject({y2: 'wP'})) - console.assert(!validPositionObject(null)) - console.assert(!validPositionObject('start')) - console.assert(!validPositionObject(START_FEN)) - } - - function isTouchDevice () { - return 'ontouchstart' in document.documentElement - } - - function validJQueryVersion () { - return typeof window.$ && - $.fn && - $.fn.jquery && - validSemanticVersion($.fn.jquery, MINIMUM_JQUERY_VERSION) - } - - // --------------------------------------------------------------------------- - // Chess Util Functions - // --------------------------------------------------------------------------- - - // convert FEN piece code to bP, wK, etc - function fenToPieceCode (piece) { - // black piece - if (piece.toLowerCase() === piece) { - return 'b' + piece.toUpperCase() - } - - // white piece - return 'w' + piece.toUpperCase() - } - - // convert bP, wK, etc code to FEN structure - function pieceCodeToFen (piece) { - var pieceCodeLetters = piece.split('') - - // white piece - if (pieceCodeLetters[0] === 'w') { - return pieceCodeLetters[1].toUpperCase() - } - - // black piece - return pieceCodeLetters[1].toLowerCase() - } - - // convert FEN string to position object - // returns false if the FEN string is invalid - function fenToObj (fen) { - if (!validFen(fen)) return false - - // cut off any move, castling, etc info from the end - // we're only interested in position information - fen = fen.replace(/ .+$/, '') - - var rows = fen.split('/') - var position = {} - - var currentRow = 8 - for (var i = 0; i < 8; i++) { - var row = rows[i].split('') - var colIdx = 0 - - // loop through each character in the FEN section - for (var j = 0; j < row.length; j++) { - // number / empty squares - if (row[j].search(/[1-8]/) !== -1) { - var numEmptySquares = parseInt(row[j], 10) - colIdx = colIdx + numEmptySquares - } else { - // piece - var square = COLUMNS[colIdx] + currentRow - position[square] = fenToPieceCode(row[j]) - colIdx = colIdx + 1 - } - } - - currentRow = currentRow - 1 - } - - return position - } - - // position object to FEN string - // returns false if the obj is not a valid position object - function objToFen (obj) { - if (!validPositionObject(obj)) return false - - var fen = '' - - var currentRow = 8 - for (var i = 0; i < 8; i++) { - for (var j = 0; j < 8; j++) { - var square = COLUMNS[j] + currentRow - - // piece exists - if (obj.hasOwnProperty(square)) { - fen = fen + pieceCodeToFen(obj[square]) - } else { - // empty space - fen = fen + '1' - } - } - - if (i !== 7) { - fen = fen + '/' - } - - currentRow = currentRow - 1 - } - - // squeeze the empty numbers together - fen = squeezeFenEmptySquares(fen) - - return fen - } - - if (RUN_ASSERTS) { - console.assert(objToFen(START_POSITION) === START_FEN) - console.assert(objToFen({}) === '8/8/8/8/8/8/8/8') - console.assert(objToFen({a2: 'wP', 'b2': 'bP'}) === '8/8/8/8/8/8/Pp6/8') - } - - function squeezeFenEmptySquares (fen) { - return fen.replace(/11111111/g, '8') - .replace(/1111111/g, '7') - .replace(/111111/g, '6') - .replace(/11111/g, '5') - .replace(/1111/g, '4') - .replace(/111/g, '3') - .replace(/11/g, '2') - } - - function expandFenEmptySquares (fen) { - return fen.replace(/8/g, '11111111') - .replace(/7/g, '1111111') - .replace(/6/g, '111111') - .replace(/5/g, '11111') - .replace(/4/g, '1111') - .replace(/3/g, '111') - .replace(/2/g, '11') - } - - // returns the distance between two squares - function squareDistance (squareA, squareB) { - var squareAArray = squareA.split('') - var squareAx = COLUMNS.indexOf(squareAArray[0]) + 1 - var squareAy = parseInt(squareAArray[1], 10) - - var squareBArray = squareB.split('') - var squareBx = COLUMNS.indexOf(squareBArray[0]) + 1 - var squareBy = parseInt(squareBArray[1], 10) - - var xDelta = Math.abs(squareAx - squareBx) - var yDelta = Math.abs(squareAy - squareBy) - - if (xDelta >= yDelta) return xDelta - return yDelta - } - - // returns the square of the closest instance of piece - // returns false if no instance of piece is found in position - function findClosestPiece (position, piece, square) { - // create array of closest squares from square - var closestSquares = createRadius(square) - - // search through the position in order of distance for the piece - for (var i = 0; i < closestSquares.length; i++) { - var s = closestSquares[i] - - if (position.hasOwnProperty(s) && position[s] === piece) { - return s - } - } - - return false - } - - // returns an array of closest squares from square - function createRadius (square) { - var squares = [] - - // calculate distance of all squares - for (var i = 0; i < 8; i++) { - for (var j = 0; j < 8; j++) { - var s = COLUMNS[i] + (j + 1) - - // skip the square we're starting from - if (square === s) continue - - squares.push({ - square: s, - distance: squareDistance(square, s) - }) - } - } - - // sort by distance - squares.sort(function (a, b) { - return a.distance - b.distance - }) - - // just return the square code - var surroundingSquares = [] - for (i = 0; i < squares.length; i++) { - surroundingSquares.push(squares[i].square) - } - - return surroundingSquares - } - - // given a position and a set of moves, return a new position - // with the moves executed - function calculatePositionFromMoves (position, moves) { - var newPosition = deepCopy(position) - - for (var i in moves) { - if (!moves.hasOwnProperty(i)) continue - - // skip the move if the position doesn't have a piece on the source square - if (!newPosition.hasOwnProperty(i)) continue - - var piece = newPosition[i] - delete newPosition[i] - newPosition[moves[i]] = piece - } - - return newPosition - } - - // TODO: add some asserts here for calculatePositionFromMoves - - // --------------------------------------------------------------------------- - // HTML - // --------------------------------------------------------------------------- - - function buildContainerHTML (hasSparePieces) { - var html = '
' - - if (hasSparePieces) { - html += '
' - } - - html += '
' - - if (hasSparePieces) { - html += '
' - } - - html += '
' - - return interpolateTemplate(html, CSS) - } - - // --------------------------------------------------------------------------- - // Config - // --------------------------------------------------------------------------- - - function expandConfigArgumentShorthand (config) { - if (config === 'start') { - config = {position: deepCopy(START_POSITION)} - } else if (validFen(config)) { - config = {position: fenToObj(config)} - } else if (validPositionObject(config)) { - config = {position: deepCopy(config)} - } - - // config must be an object - if (!$.isPlainObject(config)) config = {} - - return config - } - - // validate config / set default options - function expandConfig (config) { - // default for orientation is white - if (config.orientation !== 'black') config.orientation = 'white' - - // default for showNotation is true - if (config.showNotation !== false) config.showNotation = true - - // default for draggable is false - if (config.draggable !== true) config.draggable = false - - // default for dropOffBoard is 'snapback' - if (config.dropOffBoard !== 'trash') config.dropOffBoard = 'snapback' - - // default for sparePieces is false - if (config.sparePieces !== true) config.sparePieces = false - - // draggable must be true if sparePieces is enabled - if (config.sparePieces) config.draggable = true - - // default piece theme is wikipedia - if (!config.hasOwnProperty('pieceTheme') || - (!isString(config.pieceTheme) && !isFunction(config.pieceTheme))) { - config.pieceTheme = 'img/chesspieces/wikipedia/{piece}.png' - } - - // animation speeds - if (!validAnimationSpeed(config.appearSpeed)) config.appearSpeed = DEFAULT_APPEAR_SPEED - if (!validAnimationSpeed(config.moveSpeed)) config.moveSpeed = DEFAULT_MOVE_SPEED - if (!validAnimationSpeed(config.snapbackSpeed)) config.snapbackSpeed = DEFAULT_SNAPBACK_SPEED - if (!validAnimationSpeed(config.snapSpeed)) config.snapSpeed = DEFAULT_SNAP_SPEED - if (!validAnimationSpeed(config.trashSpeed)) config.trashSpeed = DEFAULT_TRASH_SPEED - - // throttle rate - if (!validThrottleRate(config.dragThrottleRate)) config.dragThrottleRate = DEFAULT_DRAG_THROTTLE_RATE - - return config - } - - // --------------------------------------------------------------------------- - // Dependencies - // --------------------------------------------------------------------------- - - // check for a compatible version of jQuery - function checkJQuery () { - if (!validJQueryVersion()) { - var errorMsg = 'Chessboard Error 1005: Unable to find a valid version of jQuery. ' + - 'Please include jQuery ' + MINIMUM_JQUERY_VERSION + ' or higher on the page' + - '\n\n' + - 'Exiting' + ELLIPSIS - window.alert(errorMsg) - return false - } - - return true - } - - // return either boolean false or the $container element - function checkContainerArg (containerElOrString) { - if (containerElOrString === '') { - var errorMsg1 = 'Chessboard Error 1001: ' + - 'The first argument to Chessboard() cannot be an empty string.' + - '\n\n' + - 'Exiting' + ELLIPSIS - window.alert(errorMsg1) - return false - } - - // convert containerEl to query selector if it is a string - if (isString(containerElOrString) && - containerElOrString.charAt(0) !== '#') { - containerElOrString = '#' + containerElOrString - } - - // containerEl must be something that becomes a jQuery collection of size 1 - var $container = $(containerElOrString) - if ($container.length !== 1) { - var errorMsg2 = 'Chessboard Error 1003: ' + - 'The first argument to Chessboard() must be the ID of a DOM node, ' + - 'an ID query selector, or a single DOM node.' + - '\n\n' + - 'Exiting' + ELLIPSIS - window.alert(errorMsg2) - return false - } - - return $container - } - - // --------------------------------------------------------------------------- - // Constructor - // --------------------------------------------------------------------------- - - function constructor (containerElOrString, config) { - // first things first: check basic dependencies - if (!checkJQuery()) return null - var $container = checkContainerArg(containerElOrString) - if (!$container) return null - - // ensure the config object is what we expect - config = expandConfigArgumentShorthand(config) - config = expandConfig(config) - - // DOM elements - var $board = null - var $draggedPiece = null - var $sparePiecesTop = null - var $sparePiecesBottom = null - - // constructor return object - var widget = {} - - // ------------------------------------------------------------------------- - // Stateful - // ------------------------------------------------------------------------- - - var boardBorderSize = 2 - var currentOrientation = 'white' - var currentPosition = {} - var draggedPiece = null - var draggedPieceLocation = null - var draggedPieceSource = null - var isDragging = false - var sparePiecesElsIds = {} - var squareElsIds = {} - var squareElsOffsets = {} - var squareSize = 16 - - // ------------------------------------------------------------------------- - // Validation / Errors - // ------------------------------------------------------------------------- - - function error (code, msg, obj) { - // do nothing if showErrors is not set - if ( - config.hasOwnProperty('showErrors') !== true || - config.showErrors === false - ) { - return - } - - var errorText = 'Chessboard Error ' + code + ': ' + msg - - // print to console - if ( - config.showErrors === 'console' && - typeof console === 'object' && - typeof console.log === 'function' - ) { - console.log(errorText) - if (arguments.length >= 2) { - console.log(obj) - } - return - } - - // alert errors - if (config.showErrors === 'alert') { - if (obj) { - errorText += '\n\n' + JSON.stringify(obj) - } - window.alert(errorText) - return - } - - // custom function - if (isFunction(config.showErrors)) { - config.showErrors(code, msg, obj) - } - } - - function setInitialState () { - currentOrientation = config.orientation - - // make sure position is valid - if (config.hasOwnProperty('position')) { - if (config.position === 'start') { - currentPosition = deepCopy(START_POSITION) - } else if (validFen(config.position)) { - currentPosition = fenToObj(config.position) - } else if (validPositionObject(config.position)) { - currentPosition = deepCopy(config.position) - } else { - error( - 7263, - 'Invalid value passed to config.position.', - config.position - ) - } - } - } - - // ------------------------------------------------------------------------- - // DOM Misc - // ------------------------------------------------------------------------- - - // calculates square size based on the width of the container - // got a little CSS black magic here, so let me explain: - // get the width of the container element (could be anything), reduce by 1 for - // fudge factor, and then keep reducing until we find an exact mod 8 for - // our square size - function calculateSquareSize () { - var containerWidth = parseInt($container.width(), 10) - - // defensive, prevent infinite loop - if (!containerWidth || containerWidth <= 0) { - return 0 - } - - // pad one pixel - var boardWidth = containerWidth - 1 - - while (boardWidth % 8 !== 0 && boardWidth > 0) { - boardWidth = boardWidth - 1 - } - - return boardWidth / 8 - } - - // create random IDs for elements - function createElIds () { - // squares on the board - for (var i = 0; i < COLUMNS.length; i++) { - for (var j = 1; j <= 8; j++) { - var square = COLUMNS[i] + j - squareElsIds[square] = square + '-' + uuid() - } - } - - // spare pieces - var pieces = 'KQRNBP'.split('') - for (i = 0; i < pieces.length; i++) { - var whitePiece = 'w' + pieces[i] - var blackPiece = 'b' + pieces[i] - sparePiecesElsIds[whitePiece] = whitePiece + '-' + uuid() - sparePiecesElsIds[blackPiece] = blackPiece + '-' + uuid() - } - } - - // ------------------------------------------------------------------------- - // Markup Building - // ------------------------------------------------------------------------- - - function buildBoardHTML (orientation) { - if (orientation !== 'black') { - orientation = 'white' - } - - var html = '' - - // algebraic notation / orientation - var alpha = deepCopy(COLUMNS) - var row = 8 - if (orientation === 'black') { - alpha.reverse() - row = 1 - } - - var squareColor = 'white' - for (var i = 0; i < 8; i++) { - html += '
' - for (var j = 0; j < 8; j++) { - var square = alpha[j] + row - - html += '
' - - if (config.showNotation) { - // alpha notation - if ((orientation === 'white' && row === 1) || - (orientation === 'black' && row === 8)) { - html += '
' + alpha[j] + '
' - } - - // numeric notation - if (j === 0) { - html += '
' + row + '
' - } - } - - html += '
' // end .square - - squareColor = (squareColor === 'white') ? 'black' : 'white' - } - html += '
' - - squareColor = (squareColor === 'white') ? 'black' : 'white' - - if (orientation === 'white') { - row = row - 1 - } else { - row = row + 1 - } - } - - return interpolateTemplate(html, CSS) - } - - function buildPieceImgSrc (piece) { - if (isFunction(config.pieceTheme)) { - return config.pieceTheme(piece) - } - - if (isString(config.pieceTheme)) { - return interpolateTemplate(config.pieceTheme, {piece: piece}) - } - - // NOTE: this should never happen - error(8272, 'Unable to build image source for config.pieceTheme.') - return '' - } - - function buildPieceHTML (piece, hidden, id) { - var html = '' - - return interpolateTemplate(html, CSS) - } - - function buildSparePiecesHTML (color) { - var pieces = ['wK', 'wQ', 'wR', 'wB', 'wN', 'wP'] - if (color === 'black') { - pieces = ['bK', 'bQ', 'bR', 'bB', 'bN', 'bP'] - } - - var html = '' - for (var i = 0; i < pieces.length; i++) { - html += buildPieceHTML(pieces[i], false, sparePiecesElsIds[pieces[i]]) - } - - return html - } - - // ------------------------------------------------------------------------- - // Animations - // ------------------------------------------------------------------------- - - function animateSquareToSquare (src, dest, piece, completeFn) { - // get information about the source and destination squares - var $srcSquare = $('#' + squareElsIds[src]) - var srcSquarePosition = $srcSquare.offset() - var $destSquare = $('#' + squareElsIds[dest]) - var destSquarePosition = $destSquare.offset() - - // create the animated piece and absolutely position it - // over the source square - var animatedPieceId = uuid() - $('body').append(buildPieceHTML(piece, true, animatedPieceId)) - var $animatedPiece = $('#' + animatedPieceId) - $animatedPiece.css({ - display: '', - position: 'absolute', - top: srcSquarePosition.top, - left: srcSquarePosition.left - }) - - // remove original piece from source square - $srcSquare.find('.' + CSS.piece).remove() - - function onFinishAnimation1 () { - // add the "real" piece to the destination square - $destSquare.append(buildPieceHTML(piece)) - - // remove the animated piece - $animatedPiece.remove() - - // run complete function - if (isFunction(completeFn)) { - completeFn() - } - } - - // animate the piece to the destination square - var opts = { - duration: config.moveSpeed, - complete: onFinishAnimation1 - } - $animatedPiece.animate(destSquarePosition, opts) - } - - function animateSparePieceToSquare (piece, dest, completeFn) { - var srcOffset = $('#' + sparePiecesElsIds[piece]).offset() - var $destSquare = $('#' + squareElsIds[dest]) - var destOffset = $destSquare.offset() - - // create the animate piece - var pieceId = uuid() - $('body').append(buildPieceHTML(piece, true, pieceId)) - var $animatedPiece = $('#' + pieceId) - $animatedPiece.css({ - display: '', - position: 'absolute', - left: srcOffset.left, - top: srcOffset.top - }) - - // on complete - function onFinishAnimation2 () { - // add the "real" piece to the destination square - $destSquare.find('.' + CSS.piece).remove() - $destSquare.append(buildPieceHTML(piece)) - - // remove the animated piece - $animatedPiece.remove() - - // run complete function - if (isFunction(completeFn)) { - completeFn() - } - } - - // animate the piece to the destination square - var opts = { - duration: config.moveSpeed, - complete: onFinishAnimation2 - } - $animatedPiece.animate(destOffset, opts) - } - - // execute an array of animations - function doAnimations (animations, oldPos, newPos) { - if (animations.length === 0) return - - var numFinished = 0 - function onFinishAnimation3 () { - // exit if all the animations aren't finished - numFinished = numFinished + 1 - if (numFinished !== animations.length) return - - drawPositionInstant() - - // run their onMoveEnd function - if (isFunction(config.onMoveEnd)) { - config.onMoveEnd(deepCopy(oldPos), deepCopy(newPos)) - } - } - - for (var i = 0; i < animations.length; i++) { - var animation = animations[i] - - // clear a piece - if (animation.type === 'clear') { - $('#' + squareElsIds[animation.square] + ' .' + CSS.piece) - .fadeOut(config.trashSpeed, onFinishAnimation3) - - // add a piece with no spare pieces - fade the piece onto the square - } else if (animation.type === 'add' && !config.sparePieces) { - $('#' + squareElsIds[animation.square]) - .append(buildPieceHTML(animation.piece, true)) - .find('.' + CSS.piece) - .fadeIn(config.appearSpeed, onFinishAnimation3) - - // add a piece with spare pieces - animate from the spares - } else if (animation.type === 'add' && config.sparePieces) { - animateSparePieceToSquare(animation.piece, animation.square, onFinishAnimation3) - - // move a piece from squareA to squareB - } else if (animation.type === 'move') { - animateSquareToSquare(animation.source, animation.destination, animation.piece, onFinishAnimation3) - } - } - } - - // calculate an array of animations that need to happen in order to get - // from pos1 to pos2 - function calculateAnimations (pos1, pos2) { - // make copies of both - pos1 = deepCopy(pos1) - pos2 = deepCopy(pos2) - - var animations = [] - var squaresMovedTo = {} - - // remove pieces that are the same in both positions - for (var i in pos2) { - if (!pos2.hasOwnProperty(i)) continue - - if (pos1.hasOwnProperty(i) && pos1[i] === pos2[i]) { - delete pos1[i] - delete pos2[i] - } - } - - // find all the "move" animations - for (i in pos2) { - if (!pos2.hasOwnProperty(i)) continue - - var closestPiece = findClosestPiece(pos1, pos2[i], i) - if (closestPiece) { - animations.push({ - type: 'move', - source: closestPiece, - destination: i, - piece: pos2[i] - }) - - delete pos1[closestPiece] - delete pos2[i] - squaresMovedTo[i] = true - } - } - - // "add" animations - for (i in pos2) { - if (!pos2.hasOwnProperty(i)) continue - - animations.push({ - type: 'add', - square: i, - piece: pos2[i] - }) - - delete pos2[i] - } - - // "clear" animations - for (i in pos1) { - if (!pos1.hasOwnProperty(i)) continue - - // do not clear a piece if it is on a square that is the result - // of a "move", ie: a piece capture - if (squaresMovedTo.hasOwnProperty(i)) continue - - animations.push({ - type: 'clear', - square: i, - piece: pos1[i] - }) - - delete pos1[i] - } - - return animations - } - - // ------------------------------------------------------------------------- - // Control Flow - // ------------------------------------------------------------------------- - - function drawPositionInstant () { - // clear the board - $board.find('.' + CSS.piece).remove() - - // add the pieces - for (var i in currentPosition) { - if (!currentPosition.hasOwnProperty(i)) continue - - $('#' + squareElsIds[i]).append(buildPieceHTML(currentPosition[i])) - } - } - - function drawBoard () { - $board.html(buildBoardHTML(currentOrientation, squareSize, config.showNotation)) - drawPositionInstant() - - if (config.sparePieces) { - if (currentOrientation === 'white') { - $sparePiecesTop.html(buildSparePiecesHTML('black')) - $sparePiecesBottom.html(buildSparePiecesHTML('white')) - } else { - $sparePiecesTop.html(buildSparePiecesHTML('white')) - $sparePiecesBottom.html(buildSparePiecesHTML('black')) - } - } - } - - function setCurrentPosition (position) { - var oldPos = deepCopy(currentPosition) - var newPos = deepCopy(position) - var oldFen = objToFen(oldPos) - var newFen = objToFen(newPos) - - // do nothing if no change in position - if (oldFen === newFen) return - - // run their onChange function - if (isFunction(config.onChange)) { - config.onChange(oldPos, newPos) - } - - // update state - currentPosition = position - } - - function isXYOnSquare (x, y) { - for (var i in squareElsOffsets) { - if (!squareElsOffsets.hasOwnProperty(i)) continue - - var s = squareElsOffsets[i] - if (x >= s.left && - x < s.left + squareSize && - y >= s.top && - y < s.top + squareSize) { - return i - } - } - - return 'offboard' - } - - // records the XY coords of every square into memory - function captureSquareOffsets () { - squareElsOffsets = {} - - for (var i in squareElsIds) { - if (!squareElsIds.hasOwnProperty(i)) continue - - squareElsOffsets[i] = $('#' + squareElsIds[i]).offset() - } - } - - function removeSquareHighlights () { - $board - .find('.' + CSS.square) - .removeClass(CSS.highlight1 + ' ' + CSS.highlight2) - } - - function snapbackDraggedPiece () { - // there is no "snapback" for spare pieces - if (draggedPieceSource === 'spare') { - trashDraggedPiece() - return - } - - removeSquareHighlights() - - // animation complete - function complete () { - drawPositionInstant() - $draggedPiece.css('display', 'none') - - // run their onSnapbackEnd function - if (isFunction(config.onSnapbackEnd)) { - config.onSnapbackEnd( - draggedPiece, - draggedPieceSource, - deepCopy(currentPosition), - currentOrientation - ) - } - } - - // get source square position - var sourceSquarePosition = $('#' + squareElsIds[draggedPieceSource]).offset() - - // animate the piece to the target square - var opts = { - duration: config.snapbackSpeed, - complete: complete - } - $draggedPiece.animate(sourceSquarePosition, opts) - - // set state - isDragging = false - } - - function trashDraggedPiece () { - removeSquareHighlights() - - // remove the source piece - var newPosition = deepCopy(currentPosition) - delete newPosition[draggedPieceSource] - setCurrentPosition(newPosition) - - // redraw the position - drawPositionInstant() - - // hide the dragged piece - $draggedPiece.fadeOut(config.trashSpeed) - - // set state - isDragging = false - } - - function dropDraggedPieceOnSquare (square) { - removeSquareHighlights() - - // update position - var newPosition = deepCopy(currentPosition) - delete newPosition[draggedPieceSource] - newPosition[square] = draggedPiece - setCurrentPosition(newPosition) - - // get target square information - var targetSquarePosition = $('#' + squareElsIds[square]).offset() - - // animation complete - function onAnimationComplete () { - drawPositionInstant() - $draggedPiece.css('display', 'none') - - // execute their onSnapEnd function - if (isFunction(config.onSnapEnd)) { - config.onSnapEnd(draggedPieceSource, square, draggedPiece) - } - } - - // snap the piece to the target square - var opts = { - duration: config.snapSpeed, - complete: onAnimationComplete - } - $draggedPiece.animate(targetSquarePosition, opts) - - // set state - isDragging = false - } - - function beginDraggingPiece (source, piece, x, y) { - // run their custom onDragStart function - // their custom onDragStart function can cancel drag start - if (isFunction(config.onDragStart) && - config.onDragStart(source, piece, deepCopy(currentPosition), currentOrientation) === false) { - return - } - - // set state - isDragging = true - draggedPiece = piece - draggedPieceSource = source - - // if the piece came from spare pieces, location is offboard - if (source === 'spare') { - draggedPieceLocation = 'offboard' - } else { - draggedPieceLocation = source - } - - // capture the x, y coords of all squares in memory - captureSquareOffsets() - - // create the dragged piece - $draggedPiece.attr('src', buildPieceImgSrc(piece)).css({ - display: '', - position: 'absolute', - left: x - squareSize / 2, - top: y - squareSize / 2 - }) - - if (source !== 'spare') { - // highlight the source square and hide the piece - $('#' + squareElsIds[source]) - .addClass(CSS.highlight1) - .find('.' + CSS.piece) - .css('display', 'none') - } - } - - function updateDraggedPiece (x, y) { - // put the dragged piece over the mouse cursor - $draggedPiece.css({ - left: x - squareSize / 2, - top: y - squareSize / 2 - }) - - // get location - var location = isXYOnSquare(x, y) - - // do nothing if the location has not changed - if (location === draggedPieceLocation) return - - // remove highlight from previous square - if (validSquare(draggedPieceLocation)) { - $('#' + squareElsIds[draggedPieceLocation]).removeClass(CSS.highlight2) - } - - // add highlight to new square - if (validSquare(location)) { - $('#' + squareElsIds[location]).addClass(CSS.highlight2) - } - - // run onDragMove - if (isFunction(config.onDragMove)) { - config.onDragMove( - location, - draggedPieceLocation, - draggedPieceSource, - draggedPiece, - deepCopy(currentPosition), - currentOrientation - ) - } - - // update state - draggedPieceLocation = location - } - - function stopDraggedPiece (location) { - // determine what the action should be - var action = 'drop' - if (location === 'offboard' && config.dropOffBoard === 'snapback') { - action = 'snapback' - } - if (location === 'offboard' && config.dropOffBoard === 'trash') { - action = 'trash' - } - - // run their onDrop function, which can potentially change the drop action - if (isFunction(config.onDrop)) { - var newPosition = deepCopy(currentPosition) - - // source piece is a spare piece and position is off the board - // if (draggedPieceSource === 'spare' && location === 'offboard') {...} - // position has not changed; do nothing - - // source piece is a spare piece and position is on the board - if (draggedPieceSource === 'spare' && validSquare(location)) { - // add the piece to the board - newPosition[location] = draggedPiece - } - - // source piece was on the board and position is off the board - if (validSquare(draggedPieceSource) && location === 'offboard') { - // remove the piece from the board - delete newPosition[draggedPieceSource] - } - - // source piece was on the board and position is on the board - if (validSquare(draggedPieceSource) && validSquare(location)) { - // move the piece - delete newPosition[draggedPieceSource] - newPosition[location] = draggedPiece - } - - var oldPosition = deepCopy(currentPosition) - - var result = config.onDrop( - draggedPieceSource, - location, - draggedPiece, - newPosition, - oldPosition, - currentOrientation - ) - if (result === 'snapback' || result === 'trash') { - action = result - } - } - - // do it! - if (action === 'snapback') { - snapbackDraggedPiece() - } else if (action === 'trash') { - trashDraggedPiece() - } else if (action === 'drop') { - dropDraggedPieceOnSquare(location) - } - } - - // ------------------------------------------------------------------------- - // Public Methods - // ------------------------------------------------------------------------- - - // clear the board - widget.clear = function (useAnimation) { - widget.position({}, useAnimation) - } - - // remove the widget from the page - widget.destroy = function () { - // remove markup - $container.html('') - $draggedPiece.remove() - - // remove event handlers - $container.unbind() - } - - // shorthand method to get the current FEN - widget.fen = function () { - return widget.position('fen') - } - - // flip orientation - widget.flip = function () { - return widget.orientation('flip') - } - - // move pieces - // TODO: this method should be variadic as well as accept an array of moves - widget.move = function () { - // no need to throw an error here; just do nothing - // TODO: this should return the current position - if (arguments.length === 0) return - - var useAnimation = true - - // collect the moves into an object - var moves = {} - for (var i = 0; i < arguments.length; i++) { - // any "false" to this function means no animations - if (arguments[i] === false) { - useAnimation = false - continue - } - - // skip invalid arguments - if (!validMove(arguments[i])) { - error(2826, 'Invalid move passed to the move method.', arguments[i]) - continue - } - - var tmp = arguments[i].split('-') - moves[tmp[0]] = tmp[1] - } - - // calculate position from moves - var newPos = calculatePositionFromMoves(currentPosition, moves) - - // update the board - widget.position(newPos, useAnimation) - - // return the new position object - return newPos - } - - widget.orientation = function (arg) { - // no arguments, return the current orientation - if (arguments.length === 0) { - return currentOrientation - } - - // set to white or black - if (arg === 'white' || arg === 'black') { - currentOrientation = arg - drawBoard() - return currentOrientation - } - - // flip orientation - if (arg === 'flip') { - currentOrientation = currentOrientation === 'white' ? 'black' : 'white' - drawBoard() - return currentOrientation - } - - error(5482, 'Invalid value passed to the orientation method.', arg) - } - - widget.position = function (position, useAnimation) { - // no arguments, return the current position - if (arguments.length === 0) { - return deepCopy(currentPosition) - } - - // get position as FEN - if (isString(position) && position.toLowerCase() === 'fen') { - return objToFen(currentPosition) - } - - // start position - if (isString(position) && position.toLowerCase() === 'start') { - position = deepCopy(START_POSITION) - } - - // convert FEN to position object - if (validFen(position)) { - position = fenToObj(position) - } - - // validate position object - if (!validPositionObject(position)) { - error(6482, 'Invalid value passed to the position method.', position) - return - } - - // default for useAnimations is true - if (useAnimation !== false) useAnimation = true - - if (useAnimation) { - // start the animations - var animations = calculateAnimations(currentPosition, position) - doAnimations(animations, currentPosition, position) - - // set the new position - setCurrentPosition(position) - } else { - // instant update - setCurrentPosition(position) - drawPositionInstant() - } - } - - widget.resize = function () { - // calulate the new square size - squareSize = calculateSquareSize() - - // set board width - $board.css('width', squareSize * 8 + 'px') - - // set drag piece size - $draggedPiece.css({ - height: squareSize, - width: squareSize - }) - - // spare pieces - if (config.sparePieces) { - $container - .find('.' + CSS.sparePieces) - .css('paddingLeft', squareSize + boardBorderSize + 'px') - } - - // redraw the board - drawBoard() - } - - // set the starting position - widget.start = function (useAnimation) { - widget.position('start', useAnimation) - } - - // ------------------------------------------------------------------------- - // Browser Events - // ------------------------------------------------------------------------- - - function stopDefault (evt) { - evt.preventDefault() - } - - function mousedownSquare (evt) { - // do nothing if we're not draggable - if (!config.draggable) return - - // do nothing if there is no piece on this square - var square = $(this).attr('data-square') - if (!validSquare(square)) return - if (!currentPosition.hasOwnProperty(square)) return - - beginDraggingPiece(square, currentPosition[square], evt.pageX, evt.pageY) - } - - function touchstartSquare (e) { - // do nothing if we're not draggable - if (!config.draggable) return - - // do nothing if there is no piece on this square - var square = $(this).attr('data-square') - if (!validSquare(square)) return - if (!currentPosition.hasOwnProperty(square)) return - - e = e.originalEvent - beginDraggingPiece( - square, - currentPosition[square], - e.changedTouches[0].pageX, - e.changedTouches[0].pageY - ) - } - - function mousedownSparePiece (evt) { - // do nothing if sparePieces is not enabled - if (!config.sparePieces) return - - var piece = $(this).attr('data-piece') - - beginDraggingPiece('spare', piece, evt.pageX, evt.pageY) - } - - function touchstartSparePiece (e) { - // do nothing if sparePieces is not enabled - if (!config.sparePieces) return - - var piece = $(this).attr('data-piece') - - e = e.originalEvent - beginDraggingPiece( - 'spare', - piece, - e.changedTouches[0].pageX, - e.changedTouches[0].pageY - ) - } - - function mousemoveWindow (evt) { - if (isDragging) { - updateDraggedPiece(evt.pageX, evt.pageY) - } - } - - var throttledMousemoveWindow = throttle(mousemoveWindow, config.dragThrottleRate) - - function touchmoveWindow (evt) { - // do nothing if we are not dragging a piece - if (!isDragging) return - - // prevent screen from scrolling - evt.preventDefault() - - updateDraggedPiece(evt.originalEvent.changedTouches[0].pageX, - evt.originalEvent.changedTouches[0].pageY) - } - - var throttledTouchmoveWindow = throttle(touchmoveWindow, config.dragThrottleRate) - - function mouseupWindow (evt) { - // do nothing if we are not dragging a piece - if (!isDragging) return - - // get the location - var location = isXYOnSquare(evt.pageX, evt.pageY) - - stopDraggedPiece(location) - } - - function touchendWindow (evt) { - // do nothing if we are not dragging a piece - if (!isDragging) return - - // get the location - var location = isXYOnSquare(evt.originalEvent.changedTouches[0].pageX, - evt.originalEvent.changedTouches[0].pageY) - - stopDraggedPiece(location) - } - - function mouseenterSquare (evt) { - // do not fire this event if we are dragging a piece - // NOTE: this should never happen, but it's a safeguard - if (isDragging) return - - // exit if they did not provide a onMouseoverSquare function - if (!isFunction(config.onMouseoverSquare)) return - - // get the square - var square = $(evt.currentTarget).attr('data-square') - - // NOTE: this should never happen; defensive - if (!validSquare(square)) return - - // get the piece on this square - var piece = false - if (currentPosition.hasOwnProperty(square)) { - piece = currentPosition[square] - } - - // execute their function - config.onMouseoverSquare(square, piece, deepCopy(currentPosition), currentOrientation) - } - - function mouseleaveSquare (evt) { - // do not fire this event if we are dragging a piece - // NOTE: this should never happen, but it's a safeguard - if (isDragging) return - - // exit if they did not provide an onMouseoutSquare function - if (!isFunction(config.onMouseoutSquare)) return - - // get the square - var square = $(evt.currentTarget).attr('data-square') - - // NOTE: this should never happen; defensive - if (!validSquare(square)) return - - // get the piece on this square - var piece = false - if (currentPosition.hasOwnProperty(square)) { - piece = currentPosition[square] - } - - // execute their function - config.onMouseoutSquare(square, piece, deepCopy(currentPosition), currentOrientation) - } - - // ------------------------------------------------------------------------- - // Initialization - // ------------------------------------------------------------------------- - - function addEvents () { - // prevent "image drag" - $('body').on('mousedown mousemove', '.' + CSS.piece, stopDefault) - - // mouse drag pieces - $board.on('mousedown', '.' + CSS.square, mousedownSquare) - $container.on('mousedown', '.' + CSS.sparePieces + ' .' + CSS.piece, mousedownSparePiece) - - // mouse enter / leave square - $board - .on('mouseenter', '.' + CSS.square, mouseenterSquare) - .on('mouseleave', '.' + CSS.square, mouseleaveSquare) - - // piece drag - var $window = $(window) - $window - .on('mousemove', throttledMousemoveWindow) - .on('mouseup', mouseupWindow) - - // touch drag pieces - if (isTouchDevice()) { - $board.on('touchstart', '.' + CSS.square, touchstartSquare) - $container.on('touchstart', '.' + CSS.sparePieces + ' .' + CSS.piece, touchstartSparePiece) - $window - .on('touchmove', throttledTouchmoveWindow) - .on('touchend', touchendWindow) - } - } - - function initDOM () { - // create unique IDs for all the elements we will create - createElIds() - - // build board and save it in memory - $container.html(buildContainerHTML(config.sparePieces)) - $board = $container.find('.' + CSS.board) - - if (config.sparePieces) { - $sparePiecesTop = $container.find('.' + CSS.sparePiecesTop) - $sparePiecesBottom = $container.find('.' + CSS.sparePiecesBottom) - } - - // create the drag piece - var draggedPieceId = uuid() - $('body').append(buildPieceHTML('wP', true, draggedPieceId)) - $draggedPiece = $('#' + draggedPieceId) - - // TODO: need to remove this dragged piece element if the board is no - // longer in the DOM - - // get the border size - boardBorderSize = parseInt($board.css('borderLeftWidth'), 10) - - // set the size and draw the board - widget.resize() - } - - // ------------------------------------------------------------------------- - // Initialization - // ------------------------------------------------------------------------- - - setInitialState() - initDOM() - addEvents() - - // return the widget object - return widget - } // end constructor - - // TODO: do module exports here - window['Chessboard'] = constructor - - // support legacy ChessBoard name - window['ChessBoard'] = window['Chessboard'] - - // expose util functions - window['Chessboard']['fenToObj'] = fenToObj - window['Chessboard']['objToFen'] = objToFen -})() // end anonymous wrapper diff --git a/chess/static/chess/css/chessboard.css b/chess/static/chess/css/chessboard.css deleted file mode 100644 index 73f844a..0000000 --- a/chess/static/chess/css/chessboard.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ -.clearfix-7da63{clear:both}.board-b72b1{border:2px solid #404040;box-sizing:content-box}.square-55d63{float:left;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.white-1e1d7{background-color:#f0d9b5;color:#b58863}.black-3c85d{background-color:#b58863;color:#f0d9b5}.highlight1-32417,.highlight2-9c5d2{box-shadow:inset 0 0 3px 3px #ff0}.notation-322f9{cursor:default;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;position:absolute}.alpha-d2270{bottom:1px;right:3px}.numeric-fc462{top:2px;left:2px} \ No newline at end of file diff --git a/chess/static/chess/img/bB.png b/chess/static/chess/img/bB.png deleted file mode 100644 index be3007dd0cdc7662268e103458b30a035da1cebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1405 zcmV-@1%mpCP);OAg&;29>pXtLFL9VGS_o&_2gy))=`i$DX3vw-9Gh)}RQ7JcwuWkdbRXt|A`xA>c4EW@MX> zj1K`bMy|`TiE&}qk z)5K?tT>s;C;y#C_DqWhf#67pwvT!jB9HSn^b1L&UY}D79cyZ!hpTfBbxfeETrsfTo zDW224pVh+TdWo{)C`Y)3gggu%T4E{j;}FCv7V#rpMSR#zUWI`}!j4;@#o3 zwq!Dyxf++t==OPfWGs*%U_4=RzH(`}WqAcL=rA~|k z8bl;wh$ODZe5|BZM;X(Y;=zPth-6yGt$ruZ0ZgQw$T8d!)h(;@rPja_mvT-ukYl(u zs?GS<5H=0`@|P$NBKsGCfS*QLz?~s(UwK`PycA^t`CY|i6-2asO<*4~(nwcPz*lwH zOyD`#=M@yu_Hk5blorehk!O_$wBqr2etHrF*_N1}&3aa7n1s2Jc$^=wp`pRbX0!Q? zf^xw&*cRJ_c;ARZQo5G7nMF*cQgUo;Oa=wE#Wo>cLTHTVxt7$`)ybx&CfU{1CA+)3 z%OcxgTWk|G@Ht(@yARWfFb5I~K9ahL$MeAh6&Q)t7fM>?%RDUH^ZtS+=Mk>cNx)rI zSjxSui+C~W>_5P$Ysv6ov9F$kz?Yr25HN<*lqbT}EQgl6svu9+Hr%txLo=goZiOOR&&?PZU1ak|MYyb7l^<6GG!O zUsX)rSl|~ve_;JO<3qd|+{5<{VFMxZqVewU3gVr_)x>+TsJ|bZn-3D#ibCe-dTAJ#4RquQl+UL@cWj+ls}qQ@x6~8_nh*F-!cKc!KyX@f7g~ z;u+#k#B;>oh$F-?G&xy9Q+6togUu26I0v6+5W^|NbOJGEvAMyqKU-C93njH_WNeCt*&$TPie{tCooB3#mtf7LOCfFK8;> zLZ3-&4stj7of;6YSj2aO+|}j}oF}i)8Rt-D9IFA9~G_GA#Y&zMRQ2aT?G3jCO<1$YN-Hcm_$1rNmBAD+);Xe%ck8oZgZpVBqMSKWM zVSdJQwJpSL#3qGX(M52%yNJtNVpxVUDcrNQ$ksOa*Z`ku9P1F<4#c_#v44+eu}9=% z=trP|Z1_lNO1_lNO2I1mAaAmM>MWmh600000 LNkvXXu0mjfilMA( diff --git a/chess/static/chess/img/bK.png b/chess/static/chess/img/bK.png deleted file mode 100644 index de9880ce6390d6a53464f1b028bff7be0fd0f131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3009 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 DNo%uI diff --git a/chess/static/chess/img/bN.png b/chess/static/chess/img/bN.png deleted file mode 100644 index e31a6d0224819791210e91218fc99b7cd3b848ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1875 zcmV-Z2dwysP)9wVNxLjD`@*iP6__$6VA8`tL&-X#RW zUP5D_3pg!{fgB^uc5!V9p(tNV|Gp5&;zh}#i3&mRJj2PgnS>Jx@#yvSfh=IOEEuS) zYKSmaaa{!A4~pxQ{4vmn@SiF{sCCuL0>==(p%PfhDZ)^~NW!o{6tLqymZi2z(Zy#! z%lA1-SS~L#j}it2f`CuC5C&X`M>(%N&&tYzef##^$h?u1g{eeo%(*%pyZ{SquvcgUrlKsIIPto}M0{~GzX|xd+VWPeTnQG71|}zqobjzsYw#CySp0~m(fM`;oP82 zZGH9i^^$O+D2*(Lii*-?NRv4b8X6j;u1}sk2@w$yzwz!f78Cxfe2Mkz*MkzBot>J_ zi$Os_*r&8Y@7}!|&wt@nJdE3Qsb2tBLnYGF(?RRS1y|{tH*doH{Jgkk%^Ga`oJRp) zC0tNHd~4?}Qpu;v0H3knLPDTMfpq8zX-;z>M=lnglY`8ICc2#t-6uxHO6 zAgiHI#6#j2ck0wB>5DX*&Di!WX?utl0V`cS{E8JTd}et{CMPGu?c29ucz77%;^MHa zln3!*eJ#vVSXWmkt;&ZE9m4ZIfrFgO7g}uByhWqYh>HnayLL@P=bp6X`BJ~~C=smv@?6opVFtPUR>}+XoJUKZDX=!QL z_9n}8C}!Edak8(JfX7~NQ$BXm?*>+LZc6k$(}ExzT4cYhRPPGX4GiQjkGTO)$&%e&+@8x)lE1V!?_D)&d?pcu*4X z)~#Do`hm1nvvgw`Jbd8K1owWrfWeB(TI_gm7lOb_FRVS3Lv+kw5|&?W)h)RHyN^1- zz2ZxcSyWWy@FcLVMvDOJnI#NYdORYyUnNzhWsnw~X^NdYcVgS$TI`2w2?u3sqz`jP z6?RgFqTCG?y{z8pux3U^hC{%;d-qC}3|d8H(4scW3F-pDUbxfi5PVpenWuQT8-)38?k({PSnyS@n8IqcN|mpqeVyP(DAH=daK^;M zM2CPUPMnb9go6E7Q+|Q%EOH)8Ar>A{U_GH+ep2WU;yo{~cs@;wDg``u?i|(-V*4w+ zi}x_$Fb^qCOlwkLh#!kGNxPYM0lyYFNysbbK%31*1>DcGc&`Z@RWm3BymaXj74U6d z#WQ#q(P1hemLJRY+f}>@xJ}-%a8pY|>ts|GXyH}BPkFLFWJ*fPJ!uJ9z#1OKi;*KT zTnUIp?-ZCHmfe{5c@%IR>->hN(U_K&7V1d9$D@Ex^5Xjms_K1;)2C0k zj|cA9vBM$Y@#DwoUie)e1$>6^55fLVBzWQEu3fukF|m#%9#*S$E-WkzW1I(g6fjn{ z!sj^Rvu3k-^T5DB!QkLvfyH9kLIlLP<|Bd*9XfRA(4j+z4jnq!;y-|v529HMk23%O N002ovPDHLkV1nn}h0*{3 diff --git a/chess/static/chess/img/bP.png b/chess/static/chess/img/bP.png deleted file mode 100644 index afa0c9d4459e4d04648ca413ba90690bfdd49a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 777 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 l`)^ z-n=PRR8&Y=QBY6-yLRn@ZQHiN`t|E!<;sAcp zw%QWGCeI%Jk3K#=;OpxPetv$>x@|x}z;l$ZV;L-qHWmf^#$AssUBz<`-r2+glP6CG z>_T(r&V{(RIEasrhgGXq!P>QJVbi8fuzmY>$jZus-Me?gzJ2>3CnpCEA3h96j~SgBFX6i=n){9A`ir z#HFPO&Xg|-=o{<6x~^WmD%Fi`z_y^^(b3Vi|D)|m85tRE>cCoCTcNtTS_%f25@~5^ zkdl%DD^{$K)@n0n&V)&mCP8Rus6?D)wJ3j&Wzh!LnCJt2q0d8y4oP)jU0A0YnVFgY z5%}M%^~l)wFE;yP_Y&ER2N4kw9-lmLse^4{OB)f}CJerjZ%cfnx1Ga5AJ=dbCQN`S zQ>IA5PM(V}NuxNxC#9lytNSe|u9X$^>eP$cv_ zapFW6GiHo5(Fn$G-M?kKu8Z3v9K5khZP~H~_UzdM`T6;9>eMMHEiHu$7cRi%%a@_9 zt`2V8xPgmpX*-6yjE4^&O1p_CPo7BQSZ{Byw4)dp7?9Z4*C$=a@8ul~?nv(3xdXRu z-GYXO2FWjO>n>ir2xVnuQdcf4EQGy#_d;rFDkLT*!i*U+ASfsZp8#grO1<3N+@D^% zcC8n;R!^Tk1yR)8$w^x<9N^hj52~uF;M}=$P*hYT1)7(a2S<(^k!D<+Z87ld>}=^@ z{6AhtVmZ7qY%M3<7~EyxB-PZ^B#CM?!QhR$efze!dGqFv?4;ia)~!l0yBZrCMHFP` z&Yh5)oGf)Y?5^ytyLH^dbz^vVIK;-r!kRT}aPoi?Cr-fi>(`}>UA}yIt(^`NLcH-L znk~eW9RXcC58P}Q0r4H>Prd9|A72ewX17`RufpI%>V9E(U(Fa!AN|zEPw1(lt$@F; z@GHhYPy@?IR2;DJ?WY!c2HX1rGpm>CXrVf5sSRb+rajbkz2f&{@Gp_Z({Vq(Iu^~i zKp6b}gH?=4!r<>@;qT1gd(Zf)?{3Bqg~7i%!h_FT;$gb>A(hD{n^f|VL_XuGj%cbg zoZ8?kyyUPnW0000+NjA?5IGAHvP4t z54%KWsa~*up#S25g4PyUJ-=B#vU8SfOkVC3u;J1>CCN>xZx>V_Sh(vMyUFU{q&A(T z%a1H=@4r>w>!lpyyYBwP?~T)?JD%6QuQd^xTrI;6v+VaXtCeeiy8Wc6`Rl~%4ZC%_?Pl1m|0#bk z^7R^V?ErQbHRi&f$MXc79yDCv;r+Zw?g6KO{)aj8(mb3yc@;lQyRI|;dChg!RlNKE z2Rz^KOH@NqfTL01M}LIQvs-Etth*oXd|r8f`Q??<_)3?oyAnC+!1AR*FSp!&`>Jlg ze_+iNk^RBzuU~#z^mB@p_ivL;)4i7N+qG`>cNAB`UCr7Rwbo5)mgnY` z%;g)qY$tQOpL?4le&-}t+^m}H?YFCJM3nTCehM|;g7cR zGA+F`RWxmJzeVFD=0;#pu4Yve;?#ZdEzbUm=b{7K&po<#$IEQ?)x!@1Zt*^=Q-AeL z=bfkBqwE`8`967bj@It5w>>Ys`)K2?z~f8Lnb+t}{M^W$ak}{Ubs@{GvO*EfV88O5 ze8_iV_VWU1rp*0s-6soA?ptd4F#E=>dx^Ko-DaPg7dgu!o*9yi7XDzq)Gu?~A%9jq ONWjz8&t;ucLK6U+JX?nV diff --git a/chess/static/chess/img/wB.png b/chess/static/chess/img/wB.png deleted file mode 100644 index 70e0e14088f6ea09b84b728df6aaae6d4776ab4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2374 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 Z{12-kJ&=_`^N#=k002ovPDHLkV1l3JS(E?( diff --git a/chess/static/chess/img/wN.png b/chess/static/chess/img/wN.png deleted file mode 100644 index 237250c164f652f0ea61f5e8f65c9b4cb83489b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 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 V@B7wJo3#J{002ovPDHLkV1iHz`5piO diff --git a/chess/static/chess/img/wQ.png b/chess/static/chess/img/wQ.png deleted file mode 100644 index c3dfc15e556cbbeb546374aa9ee5e6bf121e929d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3812 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 - - - -
Here is some text
-
-
- -{% endblock %} \ No newline at end of file diff --git a/chess/templates/chess/rooms.html b/chess/templates/chess/rooms.html deleted file mode 100644 index de27a12..0000000 --- a/chess/templates/chess/rooms.html +++ /dev/null @@ -1 +0,0 @@ -{% extends 'common/master.html' %} diff --git a/chess/tests.py b/chess/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/chess/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/chess/urls.py b/chess/urls.py deleted file mode 100644 index c3a375a..0000000 --- a/chess/urls.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.urls import path -from . import views - -urlpatterns = [ - path('', views.index, name='chess') -] \ No newline at end of file diff --git a/chess/views.py b/chess/views.py deleted file mode 100644 index bac3a80..0000000 --- a/chess/views.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.shortcuts import render - -# Create your views here. -def index(request): - return render(request, 'chess/board.html', {}) \ No newline at end of file diff --git a/common/templates/signed_in.html b/common/templates/signed_in.html index d628209..b1986c8 100644 --- a/common/templates/signed_in.html +++ b/common/templates/signed_in.html @@ -6,7 +6,7 @@ diff --git a/common/views.py b/common/views.py index 1dbdd64..eea5433 100644 --- a/common/views.py +++ b/common/views.py @@ -20,7 +20,7 @@ from .models import LameUser def index(request): if request.user.is_authenticated: return render(request, "signed_in.html", { - "games": settings.VISIBLE_GAME_LINKS, + "games": settings.GAMES, }) else: return render(request, "index.html") diff --git a/lamegames/routing.py b/lamegames/routing.py index 281718f..9a2d7db 100644 --- a/lamegames/routing.py +++ b/lamegames/routing.py @@ -10,4 +10,4 @@ application = ProtocolTypeRouter({ lamegames.urls.websocket_urlpatterns ) ), -}) \ No newline at end of file +}) diff --git a/lamegames/settings.py b/lamegames/settings.py index f43dcaf..4e2158c 100644 --- a/lamegames/settings.py +++ b/lamegames/settings.py @@ -36,7 +36,6 @@ INSTALLED_APPS = [ "common", "channels", "chat", - "chess", "minesweeper", "rps", "games", @@ -48,27 +47,22 @@ INSTALLED_APPS = [ "django.contrib.staticfiles", ] -VISIBLE_GAME_LINKS = [ +GAMES = [ { - "urls": "minesweeper.urls", - "url": "minesweeper", + "module": "minesweeper", + "url_name": "minesweeper", "name": "Minesweeper (Single-Player)", }, { - "urls": "rps.urls", - "url": "rps", + "module": "rps", + "url_name": "rps", "name": "Rock, Paper, Scissors", }, { - "urls": "chat.urls", - "url": "chat", + "module": "chat", + "url_name": "chat", "name": "Chat", }, - { - "urls": "chess.urls", - "url": "chess", - "name": "Chess", - }, ] MIDDLEWARE = [ diff --git a/lamegames/urls.py b/lamegames/urls.py index 1ebe9ee..697dcd5 100644 --- a/lamegames/urls.py +++ b/lamegames/urls.py @@ -28,11 +28,12 @@ urlpatterns = [ #path('chat/', include('chat.urls')), #path('games/', include('games.urls')), #path('chess/', include('chess.urls')) - *[path(game["url"] + "/", include(game["urls"])) for game in settings.VISIBLE_GAME_LINKS] + *[path(game["url_name"], include(game["module"] + ".urls")) for game in settings.GAMES] ] websocket_urlpatterns = [ - re_path(r'ws/chat/(?P\w+)/$', chat.consumers.ChatConsumer.as_asgi()), - path('rps/', rps.consumers.RPSConsumer.as_asgi()), - path('minesweeper/', minesweeper.consumers.MinesweeperConsumer.as_asgi()) + *[x for game in settings.GAMES for x in __import__(game["module"] + ".urls").urls.websocket_urlpatterns], + #re_path(r'ws/chat/(?P\w+)/$', chat.consumers.ChatConsumer.as_asgi()), + #path('rps/', rps.consumers.RPSConsumer.as_asgi()), + #path('minesweeper/', minesweeper.consumers.MinesweeperConsumer.as_asgi()), ] diff --git a/minesweeper/urls.py b/minesweeper/urls.py index f928a47..b99c5a3 100644 --- a/minesweeper/urls.py +++ b/minesweeper/urls.py @@ -1,6 +1,11 @@ from django.urls import path from . import views +from . import consumers urlpatterns = [ path('minesweeper/', views.minesweeper, name='minesweeper') ] + +websocket_urlpatterns = [ + path('minesweeper/', consumers.MinesweeperConsumer.as_asgi()), +] diff --git a/rps/urls.py b/rps/urls.py index 3d85bed..f545989 100644 --- a/rps/urls.py +++ b/rps/urls.py @@ -1,10 +1,14 @@ from django.urls import path from . import views +from . import consumers urlpatterns = [ path('rps/', views.rps, name="rps"), path('rps/select', views.rps_select, name="rps/select"), path('rps/create', views.rps_create, name="rps/create"), path('rps/join/', views.rps_join, name='rps/join'), - path('minesweeper/', views.minesweeper, name='minesweeper') -] \ No newline at end of file +] + +websocket_urlpatterns = [ + path("rps/", consumers.RPSConsumer.as_asgi()), +]