From 00cc143d6e45def675a5ec13e66f8c267ccf6127 Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Wed, 14 Oct 2020 11:04:30 -0400 Subject: [PATCH] 2 many templates --- .gitignore | 2 +- src/app.py | 150 ++++++++++++++++++++++++++------ src/host.py | 3 +- src/join.py | 3 +- src/logger.json | 15 ++++ src/sec.py | 4 + src/static/buzz.mp3 | Bin 0 -> 42683 bytes src/static/game.js | 75 +++++++++++++++- src/static/host.js | 90 +++++++++++++++++++ src/static/index.css | 57 ++++++++++++ src/templates/badname.html | 14 +++ src/templates/gamehost.html | 21 +++++ src/templates/gamenotfound.html | 9 ++ src/templates/games.json | 3 +- src/templates/host.html | 72 ++++++++------- src/templates/join.html | 69 ++++++--------- src/templates/kick.html | 10 +++ src/templates/nametaken.html | 10 +++ src/templates/play.html | 49 +++++++++-- src/templates/please.html | 9 ++ 20 files changed, 542 insertions(+), 123 deletions(-) create mode 100644 src/logger.json create mode 100644 src/static/buzz.mp3 create mode 100644 src/static/host.js create mode 100644 src/templates/badname.html create mode 100644 src/templates/gamehost.html create mode 100644 src/templates/gamenotfound.html create mode 100644 src/templates/kick.html create mode 100644 src/templates/nametaken.html create mode 100644 src/templates/please.html diff --git a/.gitignore b/.gitignore index ae2d4a0..684c562 100644 --- a/.gitignore +++ b/.gitignore @@ -133,5 +133,5 @@ dmypy.json # jetbrains folder .idea/ qbBuzzer.iml -.env test/ + diff --git a/src/app.py b/src/app.py index 3906df4..d4d4211 100644 --- a/src/app.py +++ b/src/app.py @@ -2,43 +2,38 @@ from flask import * from random import randint as rint from src.config import Config from src.host import HostForm -from src.sec import gencode, dohash +from src.join import JoinForm +from src.sec import gencode, dohash, whitelist from logging.config import dictConfig -import logging -from flask_socketio import SocketIO +from flask_socketio import SocketIO, emit, join_room, leave_room import json -dictConfig({ - 'version': 1, - 'formatters': {'default': { - 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', - }}, - 'handlers': {'wsgi': { - 'class': 'logging.StreamHandler', - 'stream': 'ext://flask.logging.wsgi_errors_stream', - 'formatter': 'default' - }}, - 'root': { - 'level': 'INFO', - 'handlers': ['wsgi'] - } -}) +# Loading logging preferences +with open("logger.json", "r") as f: + dconf = json.load(f) +# Establishing logger +dictConfig(dconf) + +# Loading flask app app = Flask(__name__) app.logger.info("Flask app loaded at " + __name__) app.config.from_object(Config) -app.logger.setLevel(logging.DEBUG) - +# Version allows css / js to load instead of taking hours to update even on run smh version = rint(0, 300000000) + +# games games = {} +# home @app.route('/') def home(): return render_template('index.html', version=str(version)) +# creating a room for players to join @app.route("/host", methods=["GET", "POST"]) def host(): form = HostForm() @@ -46,7 +41,7 @@ def host(): hostcode = gencode(64) hash = dohash(hostcode) resp = redirect(url_for("play", hash=hash)) - resp.set_cookie("_gid", str(hostcode), httponly=True, secure=True) + resp.set_cookie("_gid", str(hostcode)) with open("src/templates/games.json", "r") as f: tmp = json.load(f) games[hash] = tmp @@ -55,7 +50,6 @@ def host(): games[hash]["bonus"] = form.bonus.data games[hash]["power"] = form.power.data games[hash]["negs"] = form.negs.data - games[hash]["teams"] = form.teams.data app.logger.debug("Game host at %s", hostcode) app.logger.info("Game created at %s", hash) return resp @@ -63,32 +57,136 @@ def host(): return render_template('host.html', title="Host Game", version=str(version), form=form, default=default) +# Inside the room itself @app.route("/play/") def play(hash): if hash in games.keys(): - return render_template('play.html', version=str(version)) + if dohash(request.cookies.get('_gid')) == hash: + return render_template('gamehost.html', version=str(version), gamecode=hash) + else: + if "name" in request.cookies: + name = request.cookies.get("name") + return render_template('play.html', version=str(version), gamecode=hash, username=name) + else: + return render_template('please.html', version=str(version)) else: abort(404) -@app.route("/join") +@app.route("/kick") +def kick(): + return render_template('kick.html', version=str(version)) + + +# When players attempt to join a room +@app.route("/join", methods=["GET", "POST"]) def join(): - return "In progress!" + form = JoinForm() + if form.validate_on_submit(): + wlist = whitelist() + if not all([a in wlist for a in form.name.data]): + return render_template('badname.html', title='Join Game', version=str(version)) + hash = form.roomcode.data + if hash in games.keys(): + if form.name.data in games[hash]["players"].keys(): + return render_template('nametaken.html', title='Join Game', version=str(version)) + games[hash]["players"][form.name.data] = 0 + resp = redirect(url_for("play", hash=hash)) + resp.set_cookie("_gid", "") + resp.set_cookie("name", form.name.data) + return resp + else: + return render_template('gamenotfound.html', title="Join Game", version=str(version)) + return render_template('join.html', title="Join Game", version=str(version), form=form) +# If someone visits somethin stupid @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 +# Connecting socketio for all socketio functions below socketio = SocketIO(app) +# | +# V + + @socketio.on('json') def handle_json(json): print('received message: ' + str(json)) + emit('json', json) +# Checks when a player / host joins the room +@socketio.on('join') +def on_join(data): + room = data['room'] + username = "" + if "username" in data.keys(): + username = data['username'] + else: + gid = data["_gid"] + if dohash(gid) == room: + username = "host" + join_room(str(room)) + emit('player_join_event', games[room]["players"], room=room) + + +# When the host sends data to server +@socketio.on('host') +def host_msg(data): + room = data["room"] + gid = data["_gid"] + if dohash(gid) != room: # Check if the host is really the host + return + msg = data["data"] + if "lock" in msg.keys(): + pass # lock buzzers + elif "kick" in msg.keys(): + msg["url"] = url_for('kick') + username = msg["kick"] + del games[room]["players"][username] + emit("player_kick_event", msg, room=room) + elif "tossup" in msg.keys(): + pass # give player points + elif "bonus" in msg.keys(): + pass # give player points + elif "power" in msg.keys(): + pass # give player points + elif "negs" in msg.keys(): + pass # give player points + elif "amount" in msg.keys(): + pass # give player points + + +# When the player buzzes +@socketio.on('buzz') +def buzz(data): + room = data["room"] + emit("buzz", data, room=room) # Just send it back + + +# When a player / host leaves +@socketio.on('leave') +def on_leave(data): + print("player leave") + room = data['room'] + username = "" + if "username" in data.keys(): + username = data['username'] + else: + gid = data["_gid"] + if dohash(gid) == room: + username = "host" + del games[room]["players"][username] + leave_room(room) + emit('player_leave_event', {"player": username}, room=room) + + +# Run the thing lol if __name__ == "__main__": - socketio.run(app) + socketio.run(app, host="0.0.0.0", port=25565) # app.run(host="127.0.0.1", port=25565) diff --git a/src/host.py b/src/host.py index d0ebf4b..2785535 100644 --- a/src/host.py +++ b/src/host.py @@ -1,10 +1,9 @@ from flask_wtf import FlaskForm -from wtforms import IntegerField, SubmitField, BooleanField +from wtforms import IntegerField, SubmitField from wtforms.validators import DataRequired class HostForm(FlaskForm): tossup = IntegerField('Tossup Points', validators=[DataRequired()]) bonus = IntegerField('Bonus Points', validators=[DataRequired()]) power = IntegerField('Power Points', validators=[DataRequired()]) negs = IntegerField('Neg Points [Positive]', validators=[DataRequired()]) - teams = BooleanField('Teams? ') create = SubmitField('Create Room') \ No newline at end of file diff --git a/src/join.py b/src/join.py index ba0f6b4..731e613 100644 --- a/src/join.py +++ b/src/join.py @@ -1,6 +1,7 @@ from flask_wtf import FlaskForm -from wtforms import StringField, SubmitField, BooleanField +from wtforms import StringField, SubmitField from wtforms.validators import DataRequired class JoinForm(FlaskForm): roomcode = StringField('Room Code', validators=[DataRequired()]) + name = StringField('Name', validators=[DataRequired()]) create = SubmitField('Join Room') \ No newline at end of file diff --git a/src/logger.json b/src/logger.json new file mode 100644 index 0000000..51382b8 --- /dev/null +++ b/src/logger.json @@ -0,0 +1,15 @@ +{ + "version": 1, + "formatters": {"default": { + "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s" + }}, + "handlers": {"wsgi": { + "class": "logging.StreamHandler", + "stream": "ext://flask.logging.wsgi_errors_stream", + "formatter": "default" + }}, + "root": { + "level": "DEBUG", + "handlers": ["wsgi"] + } +} \ No newline at end of file diff --git a/src/sec.py b/src/sec.py index 1bfb7c5..fd5564f 100644 --- a/src/sec.py +++ b/src/sec.py @@ -20,6 +20,10 @@ def sha3256(val): return ho.digest() +def whitelist(): + return list(ascii_letters + digits) + + def hexdigest(val): return hexlify(val).decode('utf-8') diff --git a/src/static/buzz.mp3 b/src/static/buzz.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..cc4b0241dc6e3e73405d093689e531c4ca29043b GIT binary patch literal 42683 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 OR2hoJ+v-{O2D)!hK~;g z`&wsDtoS_z!WhHzgRx_h(v!XtkJW3JbIv=evvLpWX-B@lkUJ0_goyKu(EPi?m;GUb>I zW)1gdL_tC5fV)dHCG8Yo84qPts5j|<*aOreQ6NI}hciOq={ZjR{e?gm^0gR&Fk$4Z z1Kgoks~MwrGRxz~fT#O<@=}~1_`fVn|wqbIhmVU2Uy@j*IxA0RKCmRnrRx5?Nd+i{^@I3;zjY+sm3Zn zaHTejyMA1kFb%Q1ad3L?bkfA-SX=kJ-t5q#Qh4g`yNHO;#Tu~>@Sxy#&o<|bcM?4; zY$P+CT7CkN5C8>=0jRe2Pr6T!yGlNH0K`X5l$3GPjd{uv$95p$bh5vbDAcqT&97zZ1 z2AQ`0*6qWQ;v$>|`KtnyFT9mYTxwELv&1^j~kV$rEs-eW%JhRcH()Ax;vAi~4oGW3EHF_}7oX0GBt$H4+r(3T^O(kJToV|?=L`_4DP(07SUV~J2(4aKa!ahyWDh!Z zC=LXu{)*@1F-vlInEgt76`6JNDZ3nY&sjOY~zl-Wo-TKl|-zjcwLAX6tX5gcARpj|b7-7Ff$xU?n-uXn~RrLE~ znQG3H-g#1=jFIA zX4bwkS?I~YAwgu7F~<(2gz1aH@r(25b8n-#OHBX2snjqX?H13@@K(NPLQB-64CjV7{X9^3KiM z!5+ikUz!D$%GAibHT@0ZXEug6N^i&B@P%BV|2gHGee504WUuY}^8WjSfF`W_XCQLR zu_)*}c9(bWwXQ?$Ngo46 zz6y(6o%^P*Yqy>(v?SmFFb)6#vWyp*gj2$0^Tnh^YZQ*e)9Q=FE`zS|uIfy-b&4qG z%|zt#-Hm(gH@su$4B_LVZMaijROgpJ^>P*e@RLc?i*1axv(Zl%u_wOtKLIBGqefXCJZaqs#)+5Yy!nN1Y7Uk01f6JV0bxgE8yn&qXR~KH`>dy8Z1-g z{7*-}-c5iAm*ci7Cg_etOT44?AI*0SNADAs6gpOZoW2@y+VarNl))ESgwIxoHEG_+ z%g>wKN2)QH&%Vv7w@m4}_~439lP_YH4}5ED{H4D1)t^~QFotMhK$IGzO$ueCq@oc7 zfl9Q3xpl-ka(?Kp2wMjiM1}U$(Yysya{OXhFo^UQxg!e%aw?`_E=gcd;Hx86k&zDV ze6AzJJVBb7H{P;-?O^kwsP>SqMEELfY5~gwS{wVl-k31|SyGxFCMG+5c#5wv!Bcw3 ziID&DNh5Kn+S&DinsGQ6X(!MJGwC!6HfVo44&HI+$$=j%r33&$e zZ)RfqS(`k+yb$miuAazT=cKfMyDlHqg3;mZMQc_lEDQ+XR$^FGM^=>ePxyFcCyg03 zso$i6)olwQ4zY7w&nW;j(xu_|R(N5NIoFE^@xNS_7^w@!{%pK{^el~Hxqs?mZ(dew zTg}?>y~h+F(Dht4!U0I)U3U0zw8in$2(QFv2O_6my;=I!6;=fk3S4}6g6<9#jILaf z#}Q>Ei@JGXt){18YO7o6iMI*WrpA|Zo7|c8-LhZUZ%s7tH=>Oy_0VF8vzxA&blEfM zIZq{mAMkbjPOu~lL)-vx;9`u!#jFkLMbfX_O9S;TQ?XYoU6Mcz)ktwQzw9S4l>M)t zuvKYVzs`)(1Vk?fmQ4wp@@!?PN_Gab=4QO|Opk}Ko*X*cRb`cFv+qNEQS3EY4?HyF zb#>EjYr0}4R8|uBC%hcPy;UjJ{p-GBdN_E#3YYV59j>*}T%Saca9I6f(P*L!M2xB3 zFvbfk{q?L>9g~xIJ#KY5u=dHYT~`0cgqID`t05C}6MAxPwx zdjw_77JbF?vN-U|yN_2$+ReFI-B_hdirGWMXtU@Ch4Je1PcgWg`_6!6G6_Hx@9>PF zW#xg&B2smRZ3e5{D%F678o5Ez=rvFDzqhDED2Lz5sMn(# zYwsACf~s;x_;OToR_#8i3Re7+Vs&Y#Wh_Uyz31Oto0=A>k)bkSbEucgkiKzPFToo3 z=8vCs__rCXUUJCQh3t1mAHB-^*$Mw3#-PP}DunZEgfu~+vgN$Vv*CW5jeqsG9ws!m zY-jzPw$n=0ADhzJ6CVr3p#kXIrQmPGkf&tYeXc(}9TJE8&*tuZeB?MdkD4g6sLRsK zBoFyp+xfp{f+BYwQ^o^tA50x_m}0Z^CEP|`FG*mALWAu8BLVrpNf#Scs%gC&%jOD` z&>aMO+WR4?*<0h-kInq~fFQL`9H%p60|g62#wwDU@(4@J?!6Jz3BLR`_IwWVewbr3ps8~9QvBIcHO3Z9#1;t&}`vtf*3s1<8;(K~f z36-6|I~!Z5B#*f&Y~jGI?7YT4Ns2O7Z+W2t?W))M3Nm^wgr6MWFm17N&vGh}8=Bvo z8!P;*Maqh~&EVSVtizG*%n8CZTx*C$rantD@tBx?TVfV8to3($hR;U9+IH6iI9g}Y zOr}DMZ@4@o%yl1{H1ECFaXE3*)O_zhW87e+qf$3#n=;$^(>IBbu8nMD^9-PeK>-q? zwdGS(UL7C}A1!WL-yGr4ZPK`2SHbv~XY7udPy8rvm41CSde5)!!R<#Rmpx{}3|$=N zk`YCu+HTQPET|656{M$d*}$OaCLm1?PW;0Kn9* zO28?qpd?kx;Fh+=b2wvld3Du#v`t7aor!i2n_{YHZrnhzfQRziGS0m1F7qrJ(k#YC zd6j&1PlIvFJw@vc2d9#(Fd`}jA_ zZhj-+kBRtr)q4@`ThZB%9*-g2yf)05KWU~*<)7qu3^*f@sLMo|Bw8=|Frch-HGFQ> z(oF74Uq&g7@~E0J^J$7V={sRXroCF9{B3;3=o^bzO~*n4A>v%AV@v=KkoQp;79j=! z6IdVqo9a__J{5@AzhG9^6<+aByte^s<3&n^bkoeuhaCoBnVv)%CQmr;FVEDEojSri zcB0AoJZ!Z(A8`|Knm|vAzcr=hxvCz@eOEVP+q1P$p5zrGE)v#4?*&y%SjY@2_5G@z z%`!p-`7!R=(e~K7wkpwf()q)}7|uZ`E=i{5_={-HQs&p8Z66zX*O}g@wJ^Ll{k57+6<5Bc7Qv{h%$=pVu) z7s^7MEMO2vvR0lI8Ew~19eeZF;y<6lu<`qk{k{YZdP+eY{;69fZ92XStLl2bcGuC; zs+s3L-qrtE!%u}8G0yi4tS{Hzz2WXI9D}GJxqmTv5lRVfGHF~>!c~^s-rQ*QkF-~` zQ1g8D4A~K4NY=Ks;_p*^|0x@egN-OS60jlO)g^RT63eZN+rO5wU?|GB1(H3%>P`q= z6nFms3eHRWu!sZwuL=C#IC5^wsjSh6kc{driSs7OL7TS^WuO0xrI%$n?rie6IoJ`t zr-`SOgp+0`hP*c5t~qyqUT1t)IN?Ex-+1hF$9uE3Eae}NXNk*2jaJ&s(mdkAoBoir z4#)KFrbpS|Uj}7iH?Q>}22Tc`?ZNhkcv5)$3Gbrr zM1LV3c;)v_0T$_~Me0Yjzji)6cKB+4rExF0;Nd~-XH@L7D@bjzW%uVcg$ zR#uT%YJAD-wM!DNB|=NFGd|WbIyC=_LM-Z~#^c1k#aiC>q49ma2=3KFo@VEP4LeuY zq@=;DryYr}(q~+IE9$s1ltyZ()W9#;X@ofaX2r7Aau{DwnR0`r>M}+h{Qo%T)r*Q& z?^Dv}Y|tlu$@y#d`8jL2t4<|!RG`j3L#rye`xD!9CBmO>!ojbU@Is9U8Se(4@8R_a z^-f)mo^2Xmc)A2`qzR6vsZfBHF-Q67+zRw0JuJ=G6)nH?hHTxlIJhj zOe`1@P0*x5)fV16)zXIINSfH#fr5?$Xs3?RLHT$WR)?d>ToT~aq4}S)EWMyOKza{)kr(!n%mf!*1&Jq z=GG3qPi8HVkgM_23W#Es8T>~Phv~tx>krXe1b!~jmdb-BMIUC|Pn7I_0sh|2j?#;~ zXh|`yK0JNkO!mGRo>OW&F{_eH%_jYswSngF{GAR>^Y#M3^0NI50PI@@*4@Y2CtkIr z^|YIN?fgE+`#KlQbj>@=bI8~16jXJd9AJLLZTq=zL@GWLT6MaU{(I2CX)ckBB$Zl$ z3xUN810=O(JS@54rLUGp;uQ45uYRtCa>}I8KnM}GHy%$HV7^P!RHtX|hClD|=r_XmFYz(zHx%`MiD@76Uvt+pQ zNb?}`J2~^T(|Dg|FdtV2h=aG$uvtx3DV35pn0t3NTNqh8x$a1p@Z0-Qd|i1>(2D2b z@Hmr>LKr@!()Zy)F5#u2TXQj7^4pwp88zi|LRQ+h!%TYJcYC2id* zBOSfajgFe^H@(!-g{v)A|4B?#R=!?!YV?pc>c#zrR&}ad@4kl{2bHWbbUZ@eu95xC zQWGb2hDRzTXoXyq!EFY`u9_2-c4T`PVd)0D!i09iQ~)YzC}U&Ffw{SW?DG^2rj|AO z3HIy5(>RVmpnr(nzh``hE5G$H)OGKKc1HYVH7`$uYS~R8?){Sh3qi1>cYKFp(|U@0 z6M>ghTG;JhU#iMx&$gqc*LO8UaiPHD;gVB>2-5lca&0YNkJu>w%BE9+zCH5y8k?Ju zx9{+;uU47*B*W;Z=*{=!vqr~Ha~{!-VYbl=MP_oc)H~xR(fLY63h#`^-PJ9|+84cJ zkD^V-9(+Z2^v_bllU z!UP;%7(R0~e=yP$wOIMG@uPL2i)4s-PmNGY_Zfe!4$Diz^8(1K#p$={KW--rT_-oY zq;GD9r_)ATp0SEP(l;u3`VYU~FX!G= z!TB_ArDdIGO{wgyvonNL$NnAUy8W~$wSAo8$kG#3T)zP?*=){=f!-wvA_+1!9y6wf znkD=L?TcU%7q+TO-TL(?6oEw$VVtr6B#sNci$8T6@#F;aaDtl{X_#CEw9KK!5@Flp zGvbc80(q4sg1XREhHFLR~-2MP{V;;A8cMG*#S2cvI}lc2lNrO(68ei0Vf zKairl0zTAq1r6Vvv7^O{n&*9f|RoF1kCh=~^rJ+YR?)e;_Z(iSW>~<}d zGf)We6X<#bQ zwXynn@8oTCAeNj5m-3dzoaKECu2_?ii*x`WEmJ|LVFd(uxD05qaajH93vw~>Nf;vr z6C5O!ez}26fZU!FP)L3WmJ6o8VLoLMdkCB7FM~^VSSaw5+^3rZNsp)}4D=MBD_+n> ze7;5>@s7+BK3lFPh%wlVLkbtm+Z6uBv9N@HO7ybrZnUgmf*w(+B`I^ev{2O@))Hp- zPgZ2OI;MYsWjl%^7UlSB>b7dfZYo%}via0(m)?KVuGIJ~!lE^W*rUHLMtdIKsyx3I z{*r#}_8|-1SL5CxP4K&+F?3c&3OXncy4T|?Up0olG3BMeVk!D)k>~oeoZ|zs{>r z2KjM{4o!{1B-KZ0z?57n$c4N$vn?7Kk*C+Y_>(&n-}pE|yix9GTq{niUk!GjHSEdkwWM z32(y)BJ&lV=?leDCo)oV#D+dpG5T3*>(4=jtUsTuMPfd zt-3UBw>E8r^G@U%{CR&^AFZ-=BQQi`Q)`s-XZ~nnVS!lACcKhwjZe|s(@niqFT&+4 z!13=k?PhIDiq3UvlXx5{0GZ=r7>f1fqG6mQ`qceHtMq``v&&6Lg32p^6)rwA1ie)j znx8IJKon^b*J-khq*-!$N89W9O4AF@v^7V|Nx#Xfsx)OnfpiwIze%ssR!q9g?@GDy z^Gi6MR`2}-HEiGStf$PT5mrtsDd_5q?Rm{Yy+{&bjne2U36L>jXUu&t6m%%cZ)E_8 zvtG{VcsvVag4}ur%>s%QYCb+~kEdWtdPkloF>F)&92X-XJNbE?tzAk1s^-x4)tvoP z-cOpuDpSGStXn^QNqYVE@BP!_EKM^{e&3(ZdVDuyS^Xw-qx5`{5KToK8DAj~en5U$ z^dFV3XUcUR-L{`Uicq4ycU*^l^(LUO)$#86j!@V7NcXcP{J|4|*cR=<0#?6}e7*LVTP*%vlhj4+A7YWD9^e{9Ce+@=SRdg&~7z+hAH7-{t zIUWJ@GPS(R+IfC@Cdz@vIjm~4jr`!as;TU$p&aPEgHQJ3u7+vbdUlibjQKLY*RW)n zs5aHp2i_cmN{fTGFAmrfHlAA@+mGnvS&DpW)s1J5?)Wg;Jyz!JH{adyS>E%ug8;|s zo(TEE@icH!J@lV4h<7S(E>YLebHFO5g0-s~57N8%2=}KRC@@acQCBPeZcU%L^1h2U z!uM>rBz9=mD7Hw~p7rxL{;-?OaGYj%1PUTVR z)gN?sC1^viP?7;^l%WhTJu|>RU_Gq>zKnLFWH2_jsrdjb1ru>zvqY?lXG<@A9RIsw z!9xW3K)71$qA`MwiA9_wxgz9iY4Tc&o)yZ>3^g1gxjsr3tK3hndWEysITBQuuR7L( z>{qA3z7}n%nL{KsOmThs`!)ZsAcPziOHn+vTBvF=gU}hF%8|J;>&3FD9l??7PkgoNWn*^Qm z_;p$9e38nz2pCd*SKPJctCY!F3*+vo#C#0EtJ$WHEUuTnho=LQsZPbrAONjvr(S0y zxUBwO7#hXrayMW@$BG86+`tDW-@j_t`jVZ0?5dCN1;krsFPPAiMQy2MoAd|}a#-nJ z{Z$-&&ZO^f!+HE^M`~#vzWql_*c17zC@w+tsc-PuHrDb*$Y1e8T`0J14_dTfgo58WkoUVJEd}N*z9ea;X(-W?_hXU_=UFLx)P^$x@hyjs6$I#Mi&i?{Nq_xxvROV zQF7c9k8wl6DdPE~q0xjpkeuI9d028@)Aa2y`Y?LOwVx5~3X5k(83n!6h2S|jV^=XG zw`#-DFvR2OE<|A-%Lg1Z6HOBXf-}2PH)b@Ek*b>y##>&85Ab{_ICQ%=hBxf*UTHy$l7>nKb{(yD{_YUD#)vdNWy1djI@tqtsEuk=>xm z1d2YF#+zCY_joGD{ej@tA?UVUr^!7F4b7$stNnX1^*z`BJU_k#_~jGk70$NjFOugZ z@fwYvo^{+Ij2?J~b+;mO{su6VwLMymgM$Mv_T6#FOAbIYopN2#=ys(JLE}91kH<3P zd!{bAaj+L_8i_rI6olJ_{nVCEBY!5*_TNnGCh{OC8+-X2py-5wfaIXSL|_FXiQbL= zl?J>w_lLds($h}O(MgFqPvb0Xc*(+-HlXJwz`@Qe|ykU-dTYbqEg&$A7H;~ zr(!ZFyFk4b7ZtYR7LxAW+YbYXUlTr}5r(3=34yt%evW?@?wu4&zSCB?^TA#)?UnD^ z7pA690@9{5bRMXGLkm6f7=Ry8jrZ4YVLK0hHxCugH))6EGBP1K#lOJhC;pO~`Hxh5%&W7bhA~M!&>iC`h z*%=Mxx7yHuTwpB1s$)L&AJ#k7l%Z~k2ulmTDZKK+&13)m#F(}|)15qDiJo7*|0qK0 z5t%p>9e-9VD>t{QyUGXYiQn%A5O;g|SQ;9$rE;wP4AMe?q|GmX!vkbW|A;^65B+l> zmyyg`5Uk@gn3F#8zRMy0|Zp@%!0En;rYE$3~2Fku{cBVan;#NCMEF;HiACXFDkyo z;u^GD{gHEZwuUbnM_l#klfC?8RC;R*pU7_b$D7Yx`r2pyV$Iotx_MY58+O4Xp-OX$5M(;O$k%RuF?TwMErT zqvxA>n533AyPqtNX*ymAE6A$O%-uiKBpyn&Ki!Y)HCBtPHBfRMC)qU@S z+DnzU*R3D^1N{Vz99)c9v7_2AF7rZvmPZ#hKJap^cCOBTYf3Alw)RdrzP|V~+m_q# zzOpVAQIdlAxk(fDb=_Xrn30(T=QcGuH8YEY`Z!rIXK%Cs{ z#^Q)S54x|25yFN>B$9+*Apr`3OuNp`T8RrWIk1Hhk-&z{GBQ|WLD}H$Jtod;NMcZ% z;}U{4_k;ry(8D23vs1nfe>7m8xUm?nASn~f+_E^cm4YFe0tq>{0c~`_U=jEl-A7?w zT^^YRtjB7tT@*Vr=<*KKP20kzpG^5JM_K9hZaNBH4VkZ>OLV0`)%(#Rt8( z?DRCuvY~}=Z-Maf{YZda$Sj?zw950*gCZuJRE>?EQgNLI`=T-8QYBIMD;#yr$I<;5dS^UJaov}PJa ztcY|8&ytY1mPp)(i6t#keXd@pnU<6#p6kuSSKe3(dW+`dzgT_l;-?X577Ln+s@Nm_ zW)a~~5J1JJU%7?Yk;o)?2nM zi!o{Ue6_P3=A=T=(>AZti^)E{W8<{l1wcuS+rMIfnU)O+q4l>^>Ihhs5h45)_lh{y zcS-<281<1GDG!sbY83Kl$d>c$wzZhHn9JgKa50`Oj>r=sPV@DNY(*jxod_=T@+bz6p{@>Tm2pYtSLN5I?f%XXxXIOsN9U$9`|_H% zi%SK1_yAX;a>&dE-s}5THv5UWiOh1t5a!rk%#Tfh`|a;N77ZR0;Fsc4{Q+u~>_OS) zWzBtsE2?~T(nl7}mM9!}j~VgiE_GY=gHGHx572vQ0A>a0GZVVgJ4dCe6IFBGc>AYC z*!}Alwtjm-+n$*bP=-y3wr(Sm(l@`6djly6#k^YY_FcUEESxDz81GrJoB)6rKr8WJ z+_*7+k=sL@Q(nX4uFwH6y2Ndi%Dz5}QZ zgC_$f%i$tY+&26Wb8^jDS|xq1GDhlmc}0;ii6d0TiLXd-h%AQD+l^LmD+~{x6Fz1! zkrO6%`^xuRhmgH+pY;yb>{I}c_mGp~S@3ygbxW^MPJsV*&%@z|Zmw0l(RUmknL#8v zGFdi+@E{ER8ZL*Vb&9RHgR~IsCj+B;ugioJlJ}LbMRXf}IQLy~q3j09=`DH*@sj)= zvJVZVT3mM6%)ZraI#IPqB^^smfJ8*7-VsHNryS#q6Pp%pnNnEpS*kQL5(%4~caru=-E|E!u>y1%bHg9!N34C(f;5oRZIx|D8AlC3H0j5i>J&b{;B`WIx|n`u<+WLQ@F&aLV8B z!|5=D*ca+~hX6-EKv_(@ArN{GSq{|(twJXejr1ZHty0?%T)ZS#rJXO#Ba1QH%<6h? zuQt_Q=x1S)Rw^t#lQ142>RkUt*uI9fnK#I@#wH4NdTrJ&{vKfSRZ9{+) zuMez(*rVo@AkI!TL1&YS@?P&3&N^r$O~!1`35pIkS{_B*drT4ciM31f`|pP7m0!1x zXLpdJB^~?Zj!l9oI&=n$Xn)EdTOQm?0Cr%IXi=}~^KZLf-d?D5e>d5!A)H#=`7inS z14l+8dwX*}PD#d!@{l2Jy3srtEz_L^Gun>+;UaY(rUfa&v@-)x(bVwwc{jZx1h0_5 z4uSk2_GUvwPU(8tuU$oK3CmcT1QjFP6LDJE>?3vK)3bj#IvfD-1wf+lvyFI? z{`v){BO(B#v+Sz069CMH2sICGl2@k)iLGref4mTD!jaBn#R$#P=%7UAH(^lt%vaj} z4r10xpq4`8N*r+2dUTb`6xze3M+#P{9m5zK&rws1X&HvG9{SiyZuGc!qj^A*`WT14yaN=n zMkDk*70pG;Bg;NcPfSgLG#BzgefIAITRkKx-t^5eWNE(fr%1LGb#f{bRWp>$s-G`G zNQYiHpNW39ypk!Yd1%UyBbtbK8eTx45M!C%X#5u_J_|fhxwO_~wSN_bsH5E}iM`oi zF>TK9&m3UT4fd!KqpK*i`l9*}kZyO3rgP-!MG6Z$rSrW+tCuX?08rBbXWI_vTtU~} z3q4slDXVp9sA3ICMg}#VH8%LYrnsY7I%9DW8~=0>ZCdL0>9w>iJd(A+5!i^rHeHqC zYD`k_YOD>UO5E=4+w#;7k&lDCKZ<`@Sd?LkvUwPAPRXvSMLS>@W=2To)M?@2&I^;; zBcXHv4FCO|^~ju0O&D)p(s=kG>q14t_Op)8DUlWR742W!38>-(`l10XZbVc{6oUCD zo#1=UV&Du#u~P|gIga=kO4n?NUnsIQ3<;?DePz{gSLn&VEFjFJ18@SIjBrxgSmtD4 z6h4yKI1c+#B3asqvM7a_xpGFBpPkIH!M4z$W<=-(5Tbwh*v|}GpBZ`b$Ix^B+a|s^O1UX)8!wc<@^hM# zvlB!s&MBj%zJ_tzX}#8U^^-o;{c?JKSDD$vM=xl9I?sFoGNcc45|b_b*wQH~;nZTsNJrmG+K*{-mi)l+VP4v#U5^YkXPqw5Fh=`1Iw;;E`sJ z$7}+7)9zjvfe>~y&mD>T&v-U)6V)pqR}1`WG<_fBRsIu zKbXk!oC~xM6F<2(fPW}z|Ku*A^?TS?SGn!Go~AC&s`V`y`Og(*UrnZJg^reH@YTtA zxn2BYw~fjiM*r6*fGRwE_gZgFo9*a{A0@-1FUo4;v-!xVoz|h+Cy~6T&0W5sgfr47 z!qfb6b6)*KpLE3d{cuAFj3dj|&ItnysA8j`Fh`(%BdZ}0#13+z)a5X~55rQs-L6v2 zrGYYgnCg#Z^KlL84#EJ;ZeFSjkgw-9jt_4SP$Q z#zsQo?6IoIKW719>PYy5yruq?$!B28r#vAMRr>&H9I5`T^;lUu{l;e|n8Pr?4Z1>K zuW&SY+Ueiw(+F&O>ZWJcGkKlr_Z*o`kL>+16ap%0=Rq5v5(IvSRqQLOv$sBQt`1Cg zU(EgIbs8q)QdO#zuQ|*WFP8L9G*Q9~rZi7oMU^DttktxTS{-daq#fKA&5Np7r0+88x}U zPo>5QKG=)<_PgIz58l&_Xd>6-cj8z)90I9viDlF5T5Yi+^p#k|Ns#b?7!t{N~e11}_VI5ur9ov)Zb^44@@=mE?QEwG%1*D zzOt~PZiS8$oN}YL2^T6C3_{WW8B!Uiin|Xb*Isrggj2Rs+_UmWw$tySWnmVqx5~P=ACg5rjRDF#Ihhpo z_Wokb2z<300mLP|i0@CFMZH|6rK3Oy`xLFw=#NY*`VE;OfR2W0$~~j;=MiRc1%cgf zFtI64F9RgkUsIbuBlyZ>w>-qt?B)^WcC&9(Vkk3Cfea9fukTF)EzN zQv6r7e_tt}y9&qpe>9N+?5|)#Ak-7-wuVqnv~MqfxmTVX03@$>BcXujz!;-Ft@Jsh zkZX6ikgpJuTySBz{XF8=rfx!k|^>G8qk@%HL4PjV>X9v_1$xYt3v zj_@Ol(5W;)c3eLDMsh57E@1@QRY2a_GBukwuH!AXly9?DAU=3Pi=v5Nhi zcTlNP+gXuC+Jzq;R-8lq*NZ?no40}!%>vwm$1WK|nPZ!1Nn@Xvkn#9tM70=p)+wTj zd2e3%9t1>-&5fwnp?<1dy44L{yU$)%U}WeqyP=M|_nKIJ$H>y^SGaKlxTECO%7A20 z0W%)#ytjmB4svScUxezs2B6%e4TEvkSzdGWNeHz{SM_+8WmM$QX8*_8RZNrE&R)gD z00E83G1{mnyU~>?w>nA|(*LsGa#WJ|b?8w{Wfu$=35?^x-U)Eu)hv5)mR zI+!uYXSldst0p1^9+CMn9Ax5PA`?PRpS^Kb4I<_}Adod18HR-}wxicnw-x1L%&rDZvA*|G z9NMd<>C{epp_ozYC~-mxq}>T^7fQ*59_tA%2XZ@V&~8%uT;4q5c*rN_zFA@w>Wu(~ z*_~Wx4J^rIIX5qAVhzrpm@PP%h*}rl^>^lZ5tN%+j}7O5ijkthgR~sRqZU*C%@o=I zP%IdbOh&TPWAyN$=DXb;qDRqC2RZaYeH(k11mwgc9psF$o_Rbg_a%Z@+0js35MJE( zxf?8P9Z1a%nBWR$2*E?27B#~of63r<#f-TgSaLB5Z@{Wv$X#NyE zLR9Hx{ifd^v3J6*BT4D%eB=@K5P0leDH7qXcQNrL*%C&Ugpx1&?miwhLGSi z4Fn-JQ-wnEUK(9G$cbcnuFIuAHB1VBEZQ0O2M-7lUw-8^4h7a-hDocizd?^-OSor` z^Xh|Z&z+4wq<0lnI8BPh-N>Jp#JsQ^um)HGDA-h9p0!o{4IL)FX_4RmCpw0X;UHB_ zG!qF3N15?p0&p#T62CBU(^sE&FuM(FUm@pTi0ZX@7eL;S0ulCd5M6WzLqfq^B2-_3 z5*#p{BJ@-!RUacH65Lm=RJ{;k2QFYBEPuL)c+e>>1Usb2(ji z4s9mh3K}&>m^HJ8@=g7s|FAS1aZf&&(s43dSLE!E`YrQ2?>=AjhI3C-fODfy%3Nk5 z)*0r^`(skMKhzj$=az7hX=JM#dpvg@Tz@DPFF`TkkpwsfKx(Nb0B^uCRUf@uXW%;; z?F7R7+F6)dWn(1ZdW}geWwtL1AlM2_TcIf=zmwTLZiV{1;6SlMWx+y67L6$FWio;; zSpi4Q^~x0T(0@)-IG|dYj|*$kX@}EYyI7Ts&#Pt*-_e2{^2%lCJ3a6IL5I7g0j0m{ zGs_t}0tA!!iP3`07VbAz*l2{}B`f-3g=nToQ;2F#_m8p@U(XTEY?#!tyj^d{CD|BO z)8auMMsSs}*F~@Vv%FLyd($j4mbFO`Vf{Qjzxe&+;vs=`R>ha$%je5_(HfSgU59?p zWiXEtOMGk-49#c_<;7>NeFFe&g8kI-Ni5rc9p=?|A1<;Q0b&^>!a6&Exh|7tfZbkuiNXCfDOmG{U7n6*OCb~m?@Tl3jV?C z_ZYhBW|9truhoP$ovKGpx`&WF_h$B^(o!`UW{$CiYj=3a`szlK4zLsF1AJL`b}kgR zReli&TYeA#T?_(>OGWpo#zXaC3{fn`HBeEf-HcXpWAu{tCanCtl@;kDO2f1o-!JO4h+deQz{;vRMUFT~Mn*K6ZDkHXpEXDvDT ziyXP7NLSq*E_cF3LGgvXs?`-_fCpe;dVy|V5opcYxAyJ}o$Q?kX2?I>L_b#JZjKR@ z3kBn(ldY7Mo0s9bx1 zd{6T_q{{?z4S;2JGGpmtXe=H&@u$S7#^E^wv9h}pN)>2s?WbHsC90pU-lDXEBskKp zMo*ty%*r<2@lz**sLVMYah*Pt6z2Hg*q+fmd0f%Be%`+~EynGkFKex9 zDE&RB8IRtbeV~X{`t$a+SPv=Pz-8E{7Q*|Z1H#su>jPEO&;I2cT&x`h>Hb^T)yC-Y z#ffFq=dX9O+>8F zOGk0OI_Z>wmU#-rAi^nH=%(G<*S^FJI%^j8b7-|O zw7pM5!9L9v-dqyBDk^)Q^)$EVGcg9aR$pbNfEfNxx7qCw_S0)b!8R}`g_WzoFlnP@ z;}>gnD_w>iu@gvqlyUdLRBCk8r072j6#a?j!$8b+#wW$U4pp~Mpbs~x)IJJ1F*^jG zQ8FXR(R*m!c^AEGRUlh`=C0O~ySD-CF=*b#7Pn-?e`QsbU_Fz&6Eu;*%2_9oWTh z4QGO5QxLhYrv-C%WT)6Zgc)Q(s%m?-u4@1!Mtc^+-ViQnE?>(w*4t06Ec|+3te_Kt z=S!V^zPaMO%B;Br;DzFd??o3*xXrh(a>)E*_UJhE>xjayd)t@0m(3f*&8+ABk-&lY za;L(rdM24nDunplvL&26hUS?-AKVEufb~U}6isjy(g)o^i%A`o(<)RT6IIihG<0g9 z{3q?IWPLPwolWY-&x7@g{oZq541GxSz@V*~lf#`8M9ZWCR#g>|2k3+@F=l$*14~n~ z-!CBSF6n@QozAu2yK4LMdi6^xW;tP$wS_g_a2LI!aoD%NQ%A{^MS5&vtJ;0Tkt4YQ5%|8&YGo26TH z!;$O$$%$3Z)XRKl9dI!gyyGMV8)@9$rMSU#TBbP3j#lguKPr5!t?$4>OP!86`$v#e zzO()813cFztDPiknyYCO?X+C(?nvQrtUAMJk5FXiT$P&JPo?Va=4x&EzenEel>0p= zJKNs{2*bBJ`^Sc=o0b25_EmWFBA$==<`$V8Nu2vNo>?1FN{+UllId4AV8r1600^_6 zFRl@cj?^QOEQ7o$v&@XPE*gzyMpBIcyd?7F#fz?K?tb)?T7aHb-+{d*NcUk;R0}t$ zk(CI}% z=m!52lp@(>i?FKlF~j4(YS*u*90jes zFHatk4G^8%1Y7BD;);B^*RB`qRAXUSE6ZFns8Ti)d8gDWnjVy&6xq%+iIolTL^~Fj zyui+z{0i}zxIzLS#LeH;Y?ipOB)B^M6;Le7wo_nW=5dRB{D#am5TQo*fa{QNn1ww`PJQ)kbr5$d ztP7HYA=)0GKBpU1Iz3-$PDxtz@9$^W3(6{zzn5ga{91&0!kgz|NgS8%CT8!y+xzAR z&c$glwvRNHQCG$=RhiH4klm}qkX(Iwfb;yDf@I0Mb^rPZfqt#ShOca2pD85=TK#CS%sTOHB_RAbs3zw|;!Oo_s8tyj=eoa&GeRzjcIK9+^Lt<%h41H@tX=bPZDDq9irtB~_X@wcee z@@|s+3JHwSnmMks-XThhDr@8U;I&|uoG@aI!sHP|xqS{NPb~aL)dzymQ!L@b=V!1a ziB=Nf6kS^xxD@(i^9qE;$@JT;=e{Oo;f&P2j8aS{x7#pH4*hrVk7SZR7l7;MU1%4F z(9f_Csp@Wv^cs#fVStssI>y|QR-b?h&sIszb^j^MXX3jl$oyI57yPhuidM8cY;y6b z-oW0^L6<-Jchkf>j-Hc#`Cj(Ka#QQ?-24Wi>~B}@_z1&O=BSiJwME@5YY|3W3;=WW z-U1p&-@M>+W+ny}l1X<=0JC-KLBPZwUtK z6vcQRkxXW&I+OtxO}m!!i~_o(naG=w(LHzg^kWQ=xaof@em4?kQS?ASr2Dw+dG#(W zoIP>D{2lH-{5q4j$Av{|vPhrP;Jfcl$8$GR(gO4H4L>}=vMFqnEEIdtw%y|RaCUJk zfB&cS?fK7tga5thUlMdyIryeB%P{<%f$DaX0H*2X_4d@m@K*PQzs}W_4y(#T=WqBr zwWX(;`id|B9DpZAL*aac;Dfrc!&H&@#1)};gK+%h8lkB4YPpHntEWc7Q)6hdgAizS zrfXM7pooT)5GRBoqKjzW@gC@k5lcW3aaQ~fNz^2|n%4j|7@t^ioT$N!mqDgY8rgbE zb~@SCjmi=+5hxpyZx)pFn2P^7f>D4t}wVJrSf z4XY9P6b85@Ni3yMGO#!CHoZhk|C}?%)IMP*eN$TGao?pZ?Z%Hv!ly#>8 ze5Tek(DR2Yf&-3rR`+i&_;6K7?tU8a7wOr%r_DSN>K#^5$mcP_?iBZsvmzsTv_*Db zQR0royWdE&=7fxSDXqIExMT?NtwF?pvh~{nTLdB1-EU{ca+YJ&LA5DdVwPWb(ha2l3Br5Z^z1#wvk4S@49Q)&UT8=G^OKW+^HUXUx^4dK6NGWygzfzYW*$^HA~C zV;FzG{@%M5awE*wfL&M3`P#n#5KR1_LGN;4_v<$Lk8e0O!X`*_kgoIw08=zd1NJi* zf$%V7XGuIdZX3FW_PGftyn6eNhZW~^p#_x_e=0)@H%~kL7k0E1?i8OCSrw(T-M@9A za+&`33BxjZ%(L8+s?3D!Y?d?}3*59XJ6M&fr|JNZ3AmfgRgrr`s{NYl7Vms^3 zt*}}-n;ZOR!@CrS1dP6r{945;07M8$D^(w2`j+kiL;fNs$)i6+f$Ek(ai;KwF~0cg zC=aEV|Ae9*P)m)*5_8Ps-kzs6+4T-0rVg!XNFMpUAq+jz@LWPT_7x42{I)aM4_b#z$9Yf4JSr(Bn%aibXWDJ)DX zDerAO?JMFF`$XFuD+r1g%#=bcSgYxV>A#LEl?=xT`p4JxI*--hNOelS>?jE~;;4Bi z+?vB@j#Jk=>;&L;+4d(CpmlY?SZ7&w;>Bxs;?Dv&bPA_GT~rW_2mfCs`krUmwo4eO1qxO>7NaAp|&dx_y3Q(Wo!3C-pi% z`Gu%!6_D!CxBH8uOu?KPaXsKLtnDvbo2nREOeD7Yt~Hf0I4r97y&FglB?7s z^3CW9nveI^_nZIrO^MfYDLQ6qPjs%40^Q3d5}Gq^@&i)TbCbt&=PG%#TuBRpJM2I& zy#2EDZukqsY@KP(&Ms%vBY}(MZMzI!)|&y(-qA3Z7&NRtwmiA)Igigi7m$x-Q!}?3 z)NfFzi7j$veGnK?dSP?d>D9T%32!{LzIrb)={VZf`1jz4Mi0$)|A_sdbJ{BE&GS>q z+}}>S`iSXEW7)4DvlBu>%c%;HIMJZm^xqmR;I;$LI+&TA)d}m=r}Lf;T?jFKA@!^8 zg(5B)>#$(l>qINP;OJIylbzT&Ssl!g{0(3F_J*cJ0cY)W<$JgwkYsnF&WXqgec^w+ zVz#&fle(qOjjxPehkl%Q_INh%#ZK<^7~|>iJPHyf8o{?Q8?yM-s&ASWh$q~_g~@(} zoE~hgNK>Au-w$ZHK~5>^g&Zc~KP|pJ!CFiqP`@$$KWiOcg-lnhh6HAkdAz0G={eP1 zf{Tv$o^T)REP9DqmNUzdg><}6B@}YIIu@#tS*^rts#V4zqN(SWB;mvdymJLlBGBBaSwi!Egzo+?WkPXUlIt%^O6)-=LulAO#ueRChA*x zG^$bxqv55!me2Z+;#xs~eI);YsN00!O=hg@|1(p_y(=Uro)Yg|AP|otE4IMQV3~E} zBzLRz0pqGcecxI!OUMKX|kyZU0tHrAl7a|N#OtEg4u3} z8;Bqi5Y>*=)1$6u7cJLf#EmjsMIoAK{#Iuq(@Ikpfn@6@B7yB6ahHDel^{#*)&nz2 z{Z<~kM2cK$bCFlTbux(`rV|5k;|y`a-+x$fSeBmIJQ0zcYUbKpcIH)|_fdG0=VsBb zby!uF0?;AJ83%**k41D?0CI|A>Tau3&CNT4S{*$Ui`XgzJ9l%&tOpdnd4ORm4- zF2tScLi@vODO0O?`XaQbPqlxvreGpkqa)%xY0HI9D4vhSk==KaY(Lub&B*qslz4lg z*0{)m-J^C_;7*#}*GT-*h(xJ}R<;y~R(;`?(+MGaK0dte60)8g$-sG&%S(GDfs@;K zyJ_l|6r&2cOEKUos+=`gY%_m{#!$SqBDXP?ca*C}USmal&6k<WOHyNIo$M4}_y#vj zh~j{8st*stjag`?h{LXYk9f>OdH0!F;^gk8TeTTExes$rgdtItbK{J8^Te+J_7|#7 z4GZaY)V>|#F>#5eAfZdPf@n|+&2K2#*f9SpndP;TZp`t9(VO!ITcb^Q-)Xi{>ze>v zih5ee2S>zbgre_#*1Bh%dQ%Z$d(yhbVdW)wx#bn=^vwKA&V6GQ+Otr?Z#jczid@Sk z4suJ=@qzI|#~&lfk7P?YpYFmr%QUdu`Qy>(t0^|wwY_WcG7BfXT-I+&HLH@ENqR-J zjyzcn&H+1*UM#O>YR*kpp|X?aIY~Zs*ldaEp@__)ul-WfIg2M=ebXF-b zonl|?F@tCJGzRns5CE$c(u@M(^w4aj?w0T0l^hgD3|keV&Wo;n4)mJGr%#G#c?3y3 z%+uk4U!O0S*^4I)8^W|XjxG;_O(W`5YJ%x{i}0v5x5>qq?uMg-sA*m_D_#Ctc} z0{{$*u}|-5Ln5LX{aOIBJFF7UD8hB9Yp#D z0MZK>UbekZp#|Wl0?Oll2Rx2BdXpL>x#-oBV(p;!z?#H|%*y)ZIYQD^!8D z>iS-7+QxHTnL-3A*Aw?|^4r(y@ia=@(vCl=nU8qB5-#~~O=_)L`gI%Btj!~@ejE29 zGa2CV%JnN$SX8HzBnDLUh#Z8k9%^?eE?mpJ{j=gVYye-U>1Mc`M$*i+R6ISvKi;m+ z$}7x}q45)oTe?CVcZ^%F>r5B1<}%Z?aRx(4m^IS$s2qbfA*`N}W4NFBv^W zgz_k-F*9+sfWya8Ux}MK8Q?hhM)JoH_f5v!-hoIY5E-HvsGRY%eL{wS< zLtXWAcnZgM=$^th+}LJhsX@MWoU-$LEV0QUS4Hn#!DZ!U<=IHe6aV+02-^Wlpr->{ zj9xU*D2iN?GNb#fnQ_tZN1e2hZu)@c-aVd%e`nl12*+@#1>aw}e0=%0VY-}QW^=56 z?k%R?BxR4DHWa#1_N4qeo;~bmjGC|s-j371bmh=pXkjteWy}+?=@`S>b9>zpD48os z$75TX{r)qg40B{$3oGF=K6Pu3H>I_C#(&9qF0^q+cHwu}w*JxUz>>cxpNkCedup;; z1oR}f=h^x#%dvOc|6ctKJ5sqY``S(|6ryZ2YnhvHpL{AqSN@Jg{e#)V-R0e?%~#uh z3LQ0i0VIcIj0FXTuz(}VrWa-XgIz7LGr`%J@dt%dbU(FV-^O_kuG=oeO1-cpoZ@G| zj2^lI4!+r09pucbw#V)ZkmxH&0&XkTCKs!s9?}BPjR6djxIqTZQPEU>whatYUuuW6 zm(Ak>ov07FP0gKL`3ulO7yC(@BwQ6>*HLQG#0VrIOXQ{Z^6M+~`AUn^f&2X`&p&di z(l7l?uTkFiao{T2NkYmIcC+61m~vHzE?6N%diXj7vz`LuD4 zb^qFf2+Z#i+Kgr}Ume!id@ldo8u7;=K`l}#=%KrDNAp|BSC1z$)Za{%_2p;SGWdxJ z9}rAb2!!5G4BBQ1B7fCVI7~~tzm1x(p^Xj3>uv?KI^6~W0O+f;bGP%<@{f5$KqNz` zcdWR&71@5(rw>O13c60&?o*!M3qPj&r#28yYxygGz7h=X@0TOYLaF#A(9j^f252BW9dCt@&|^tPw`luX{0g`|tYCZL$w4|g>i4PFf&x6xJE z3$J^9Ny$dTe@*?ap&}cg%?j?9Uim68W4c!Drr%X_yG;%Lu=s=D#l(-9<1RfpvD~LU z4Zjrp7yN({io7Mri&b2qVA}L(Ecib7C{-XPD2wjyS1)%-LEdu0(VP0~Q^kd-;*tKR zS_s`78>SoJGq&O)^)`;CufpBA?Na0+=RIT_@arG%+UhSb!2eQ^5(wi%g!AvlcRv3< zdCA}N@EJOWQ-6J!_rb5?f0d!-X~J<){G)t51LIH zO#TYC&tK?O&J93F=NmVs2sNtsNQ5gELbRf?FmMr4GXC&S97fa(v3ez^4p4IR3_s<^ z;IGg04aceIt}bO4i_|c+nc4Q?>{KD4FavDdVze&NscQ{c+Dh1LrHvc3c@y`b)63<< zw~${o_1pf-LI}r53AwCPaAHvVF)suXwpCq(aSS6&K21bBN_|Afez$V;XnZ#3zb~!X z$1PL^h%isc<4&ZCI*ipF?L`0^-XF$;Zr=87``o1q6PH$f#-}|G%=|!07-0QAab6N- z&=kk-NM-FLh`OPH&wQ%Mr#+HtZl!puHy06-TZ98R*e))|l4PS;kP-+efWvlxasq&m znLY}%l12DCN-a*I32AwhUYmkvUSIbHFe2YO_%JSH#GeHw4u|Y;yjp#PyblJ?^P>B z#!0ryU%Em?d9y3HJ(x+q2x#OWUf3soJ!jazbdC-N>e5dRKyP^eX#XgqbXfn03=0In z5HHDs@An^9YTG=-h|d&G)k%eHe4*UbhqJ?oY7U^^r2P13Xi6L{ zjPZjNuohm!{gf^7P`ZRfR-VVyZai>-*|?4*{lP1dR2tkOJ-tVPg4i4bY3oD5?BZB_ za0Jlw76ZP}joC@FZ6iN#u|j)%ZLNz}VpvtMXyL0)D$P$F<3{DujRFdMPI0w_Jm=Gr zFTI_T^fA>J2i&tf*A?hTcvKwf%gf!^{lXU;8w0=zdR8^ejq1)UAC2d?!JdtW?MuSz z$;6m}+eo{Ph zykU;%CcC;3Q_+N90w51pjQW_WN*giQ+t2N`8gldc%@^eSe%4k-S;_rTbIL8fOo z;z&L*Va)!%qog>m*FnT(-uX^1x;fV(|U_C7l=Z|}7U`8epLD#fjCF>V-3Jmch`OGiLiI|?R_#^k-O=11u}0^&XTkhfbT z5Nu>wS5BK2tU*h>4%dgXL&oXU3=ATntNRZLn`D%m58w=uDoL8AqcH|J2hXoJR7l!` z=!1b)^WOhpT7q+aS*ghgpsurjT-KmErz@Uf@8>x>CF1~CYfN{GGkvZjT z#571AYhioA_y+5+z+(vbJ6TwV$-U*s%Z6X)UB@jI8c*d=f2ozH9hd`ty(%$HzgZ2s zaXYh#irV58wb~a9K%MPm*;m4S^+7fg$khY|kid-#k&N~_@LY9Zi7_u7iRYatt)wkm zUlE^=cb>k&Gnc0xM=$lr$EmCH(~rH$@)vovz=h-NCJL2TT?-fCtxZ8BKXzf5yU>o4 zD{1(JS#;x4^#D)i z%>{|gA(TUnRoScMDV&RH_+}xm{u#NcD=$us_;JBpK7$~!X)N7i4!a2#wycRcioub!ikQ*U;V?v+fX-S+iq#C36@fyvQ6x|R=M3t zdPj5Rv<1QHoi;OPqC}rix_Apr>POp_r}yjmA0xS){#VymhDFtWUmqAchlT-> zen_RebLeh_L6DM=mJkN%4rxR}I;A89NofITrMs1uI{)!^yzIs4x0-g}+3 z*S!P&odhPi`r&1D9}kf|rG3x8X=A7Qyr^N=j`&r}pokttd;P;k5w?rRuaQI}0zJg! zg(*J4E=}W2K`>s6^Kc{N(KT0p45Z-1E+a$G#LQ~#&@$V(ppn2z@rPQ1hS@B1v+Byz zM*W!J;L8~jJDaxglt?woZXGaN(5-wyIo~7b)yl5;5}hiOdug?ZxV3`zN4h3IH5;x$#aR6aR$jTL4tdRGj!+}`hVBxalw+HWOjVx9X z0d6LQ>2^XNJHCTzZMyW0(W1ki+z zaf#IW7C`mC9lhvhbZs4qh|62Ur$0-qa4WHc`G%#-Ii58WLkt4{YOYWv+@piL{5&6Z z+-3Bh4&LM7B|H+3v+Xq;Ph6mA;FVn~BZavt7rU6)^$_A*gj~J!w4k36j!R`TdA{~P z{uP4eyR&&ud-i|}RtAB!S9g&-^aSz^Il(APL@;@{;lF_neWo?r3O;&7THgZm$BdTv zpY=}?1ggrE!$ngGV201**&1~fF_xaY8dtI*cI!Al-)aBR(YZ!i=7N33{@HsXc_ z!A}`k8$=fn@T2(_T3lK>qB->L>Na7&X+c@yU2jg@lj zw@}gO>2z~9hv}&GutH46nZ+bVxwrJi5BVb}3rL?FbSVy740EYD2!M`pA0#u->GlT{ zu!{X14BnyIb}JB!)(xIaGJW~b6x9<{)fOXWRQTa~+nlCi=Z@3p&ig#fOOFjvhzc46 z&8;WGngvR(BM!j}3i*encwve)wo|uw!fo;;!>9m#Bb7>2t)}zeJ&Q(RDQ;hY;Iu85 z(^C!)WTsK+2K{nL$Xm;?FtCRH-CFE^jsVa5Hn#)(oeWr6X3OV4bvU zCNkZjU)wT#MxkAaw9~H_o6v`!t_R3u{^~)4AI~aN&@`Jak12aDkXp1Zuq;Rz?R|7M z@PgLAnp5enwHM7pd)>_krwf!!pYr~K&+I2Q zj}I~);i+D&@XUk4t0-l=9r63Hc^ZZSmvxiy*@%=K(WWu$2>|K37Ot$8kMqjZPaR{A zV0Cj#qvUOYUK^qVSWlvzKa_d;b?}oOd+$XmF_tU~riE=snykn&94k!?53}z`-!N5= z40F!cDR0SyYPHlpZEH_1FBO>GE#z}C6QxnPiI624_EY8>fASY;hx88@ zal?F)34sW*VrE0~W7B@ruEGZ-KLVf zyZd+Gs}}XS!K<<;)3-Ga44iE#B_D)Sl#g_1G~ijIL^CpYvH-x2_kh5PVIN?QLl{6C zW$`&2GF-Hj0Am4T*fzZ{M`1M-Nru27MW42GiqhGA)SRwooT@WL!0=wr$;@)_C-ZmD zfE%abG1r;AS=)Ts|6yqaM%9a{m;XKHl(5Eo1~B20@))aEeW7+lN6q{*;D>`{5Yu-1 z;hwiAx~osr*JvK6QkL#=+y!^XM+hIhm+jqdtcdqADuTaA2(B2z8(k7@8QHOrc6VSu;O+Ko0iYv&ICO?m;JWx$t`HegS z**SwBdTIhKzQ?i{`-mPFIac#{jSIJ%n^>hw>lDB7lly4KZuZ{xkh@p)-Ev@o%eL&}#1v|2C-W=E4Y67l)1TYj~b`+9VxL8a}UG zxnJx#>nlEzSSMp14`sjCKjLqQ`U(I^_(9I(>6kXM(DNc?k>0LhRHQ&&T)mk%Fob zC3{CRZ|9D_yhwj7^7863q{W9^Jjmr`q#JzF?Z*1?*36T<2Zgi3Edlkyz+jzYKL|kO zX_-x@!2VnB<&v7-qMc`_&wJsSB7>Tr=XxRNH`Y>Z08#+L=GJXf(83VP z+RO5r)Qee*?;n;D02txMQ@2kQoFs5jSc?8fw>m)e@C)JY8S|bX6u-|bZfAq9I}DO_ zAZg(2r*lVzzx3UZnA?%09*d z3@1ikVMa1# z8DRF(Q&ks&M8$0);PNhb4rLzF{7>Ywx4*IlZvJo|7M5Msmr1Dh}@=i=8 zaC(2_p($+s(TQBjmmF#|0J_TdU>hf>8>d%BzYQ@a2}9Em!#N!Ys;}Ztk}7B7SI_vG z`-Tb@cUKhj@T4KSimAqQ_Q8PJ<^C*NiYg}KkbikF9UEnc0zRle0tX#GKHvxM{%~p; z=>qRx_iNT3?>{wEhu5#`QoFIs=k+ToAABPwGT(&p|5-`}jrO2&q?N5%$ygCo%t$B_ zpe3_xq53P6aR%0cc^Ba6t#k9#@m@*#3(racsgx6@27-#JTi!qRU3~ zxwS^#f^zY5;OLG4vhmEwGUi)l)X6bNNrlw~<%ZtD?ezCCfS`%ASO5tZ%AR-)HYPco z_$bkD1_*VbWGOG+jxC{s_jed{>#Ee^@|38iqV7o1>&ssOt@0yfO69Fft0Kh7c%rV6 zsy|18*}J4=So526B-5ldY3hqD^=3GkgSSP6kSKUezcxFkTHY4*!Bj}E$obxMSX+V% z$|=#(v3Bhb-LnLf!9Ujk!nheFta(z`nGz{uCilrmF9 zM#aLAydZ3H6h>-a<7dAJkhwrrSr4B%o4^0U!i-JDS;c((W<)g-ErkS65JwQ97!4Vg zC(-L6HgB%O6RQ8m{*f@f>G>23IAd6aaA4Rp%I5Rrs-)fK(3GlAA=@uSa(q<4FDRF( zBwGq32B)cB0JmbB6k=E#g9)32CQr4B+q-NN$svep0=VZ-{F>cNyQ}gfM55l}@Hi%Z z+)8_VM_m2d^wtty+^kI&eEl8lzE|n677z9^*;#Cdj)`_x3AqjiWE%?lR@D|itI+gG zgU=k_-+w1B9?|s?dJM)$)VNXfQ7?u8xJYvIi`hd4)2B0T#~|n+&=_8wdvH!GOo{d$ zj_(oAUS9CE;FBCTIwe6C_GLYNhV6uD#iGNB*IVZ%}B z6>V5TF7W1q#h19rpz_X{%B$?~3LE3+=Z}?Z*jyFs8#)zLJ2|K6sy3IL6GXQ;a+sz$ zBCfihT;=$ey=V6t2uZUtC?8%}M@M>@w#{o5ecH~vlbRn*J9;d8jNi-lCg+*Z`OcS*>q16SdquidWqns#Q#4Bn{W#g`TVQYdLY*cM{g%#o(Xm$#H zXtn45hJ9h!PxhR5sha5pmgbQz-6ga4;}jWqjeMi=_2lGzEBKq;OlNML>~m9F;)Ah) z{ghqAw6XV9@pScM(igs7`-H0JJ%+s$Qr{mt)mtSZF?f+g$0Zg9q5+fV#`k$3sNfG> zc0d$YI4T?Q+2}p%o}*#wzU&q!=FV2a>?s_ET`%Z4V7@{J&=ZSQ?27OvQU)kyu$Ny`WN=zmFK^blRwP*mey5FCiN%JrTfCBDd_!! z@1L8D#jfP_Z)SS9%1Ii1o0ex4wh& zk1;PRku#~)3iih#=vv23I~H9}PnyAON9IyEVEacw&0F6hul)k7A~0?cYh)W+5Ce`ydOv6T1BT-N_yTu9`p`Z?JZ6^sH3R7q2*m#JO(563sm zOs6(H+$kgKMS0usSB2Kv4#SrfKuK`b7#e(HY1UoLqidf1;gEVryd6QXJN6fcE>z{0k5vk_DnO z6+kSnCXZ)^g1B0p5LAGw+*f;n|LrH~tNzSQ2U3=?qi%*8L~V>E3t9}{$sCXa=kJ&Z zIg*W;nnveO*NzVz@~`1sA+*~aZrT?(8Ofx*1F+B}#rBvrj9oL>9|5&w!m5s0Z?jV@Au@xQ+-dOBACwM|? z+_#s`yv#JctRv1w$4B@69{wR>Tp=8|__Z0y2mD*cEdXWtNcGMAB zECohNnU5YuL~TB zYw>8?Bl+?K>4?e=+Ft1SdP4-MbQdIsh1M43p>wjPcA!vu--TLg579=f70Vknyc{1*5D55WimKm+{a06|&|bCA zGSQ3Y1DuY%c4z=oj>b_RIaWTsT)K5wi0=)z+3edzeZ!^n^of4~Lhb387E=KnbZz1c z{@MTnLYyX}dYJ0Dhex+3$w1r}OuX`3lW5L$odQ08MVO8dUwPr6#4FSsT*b+@v&w`e z1R-hVE6i8TMGj!6Q!7*F>+4ur)q+_h;5G1^T-}86gz>4S%N{JFyrvn$<-4AkPxzY_ z?@X#-@<3Aug>eBS4?8adIv|Me=0iF{-n9T8o2B}aTIqoo{;#84eisPf>yt~l5=N+e zQe1QQsjKvONdY8haBsytEw;yt;yCm1bOtV_? z^ZwjarJE}Lx+f`IH0rwFJi?{NV>y9+8fIs*lZ!=KqyUL*=^j1wQow8d3DbQj+X@cD zW8vhLob;-3`^BwMM~IU;q~4uRhZ)xALNiovw%tYMM(xvCb5>vw_Z3N~Nbs@?b^aa2 zBZ=Vs8B|AzveVZF2kZ<94NV5Sp_A6`BUb(%5;H z98)vM(8)J+pN+|JV%+dYgsg^TV~`Yk2)9pIQoK*El`!`GSCNq*6=rRw0&uzZ#a8h& zQJ<2ak33Nj=d#-~pct>{8amD7QKD{kZ^R)$E)0YG;9x zs;6&6X^A@k{2TO-Q*QbP1B_+zXhXAIR;Y#d*VKZD&q7y|ikR@Va8rmjnl&Q7UIfRS z(orGwgY`t;FIHX{8b(fHkke2vvhM4)e09|6BMOJ#*#r=yja5>QNDh`bi~y3UYzK-2dLj9*FggT^E zV{zGOk3rl}ceqA8^%KqnB`UfsmKgdM1bWF#C9rwV5hsV@?$QR?`(Iw)3>&q*?|hAS z$+Fk8e~jdK3Fmp4QSa!fr_~ow(ts>k@MK{FQHttH-yG{yjfDCd)YoYwP6qj~EMT8H zx)uzAbN1jit(uGV=Q;^eRwh=5Cr#Kr>%B=N?)=Az4p&rAUJXIc;&Kjm1zry2+<6Q2 zqPia;Dq;LY)z&NvcKY#fNCDc6p`jvXuJClVf)Ia49W|X4tRo~cZhRcQ&?E`K%@m81 z#gk{xhfo&CRsGB?EwuJ|RK~cgQ-Fn-BAc)l?+(d?X*7*zfPd52YAB0&l}L4!0By`h zk(WxK!Z}9T{Q63-&2fCe!XjGHSG1unzN$^Tw2TFE#K}Y6RNHb_azL((%V}yVvv(TZ z82#>&m@MY6WJm0+NjPU0?b7K?t!L2XonTCO6d5VX%0I~#0+4OW=mrqL_T~4@WN^@% zbxf^P4!OTGY$6>cQCJqMdJuJP5;cf{V1Usq5vf_QNT|FNoj;{<|4E{3$x`h)+exg| zE1+g0yBYj99SJdIVsoeu)8%eSeM3j>TBOWbDA%GwIJ7?1;vgO&Cl|*pna~tr&0|ua zDJs$*@0K;d)=$&c4q|b1ys^K(yS7}BDfmfF+wTxrf&gUEDDIty&mLjY*t>xjS8p1b zoer%~$7|RO-UxgYLiL@=c-x#=F^4}=hd$y9Vm0iRU(N<@MPBaxB;}QH(I?7ZmCa62 zZ)Zr1%k=FXc+SE0Ot`jLoG;-6R@u^Fr|I5yPr-M)7a?*Xo{WkHkm|7vQ$-l$9-+ zCUq8jLrTi;5s2)CJ3`L!1qU(_SFGo|nz`;`$o#B*yQ+=W%*dywf4!F6U~5ToHXxBnQsLFK?Q)1Vy)&j zq(-bjqYMx{MPbDF%z5?6d9*$BwM66ruW5Q=c&i9Qe;Cmm8#gV|0A16U(&<|az$=*Q zveeCw$nT^<+KNW-lkS#47N_Zh+S*P1BQIwOw6FtyKZU$hQ+t*MHrZAl*i|` z44NFYD{m`WO~ihoeM=G0*|#lc>|04fw87G;7_U!R(&c?7hX+n?Du?W}W8~=wXqt)ySN$>2?#~;@A7&8yO`!8&T zez`o1xzA>}KQ0itX{aYxZErgA<(_zy4Uj;vfPkwJhTD#UmFi^_WdtT_-}Dp_#8EOi zP-&P%y*GJ62aT8@d>etmjI@ixX2;BA&`BG|ksle!!=T zzriNNq161G_l5n8J9VQ6is8MH^wLRk-SpqfrUW3{m<*~)Aa+zxI^@>g zT>%{KP`LPte$G`(a4>dDL1;wrOvu6{BQjW-!Jd^Kk+ohEvCPFN``WfsYTs6*Od7YC z=j!QQ&6_qIpH1O@@MsRm}oX{b>fbLC$aEjm&ALLhi} z7Ym~d>O4yTXN%~l6qA}%{hE1>1E4rrks0EG#N4vdy9}A1@_R~g>BbcSWVDiS?RHbE zJvljdnnSu}NRc?Y z@7_W2HDqN;*L&b_BOO_;f{Yqm^;p-6vNk>wsmkeigP{Zz)uZ3_Yvua89M` z2K8%Fs~ng_3a0~UZ(}4(WWogQ7wkt#j{z(kv=CsWulU{M9BK^xRt9yd9F)%117M!> z`&@!X9216}0^}e{p1@BJ#dXSkiUKDM6b7Sl-u}`LV!K#GFBGA=&g|Baal_a1OR=0Y zg_jI>SSye=SJ8R3&;DLD@6=OLbEx<_+s_pjBy+5@5oVhIpeQ#smt(LPbbrg=I~cc_ zx5337K=@Fiqb63jSerCtoM6{V&EAB^=?yi{AaxY{_&4`&cFk?8cTB{F?}yhdC(?dV ztA0@cfR&C`1C}M}f#AWV1;#z-*d}C|jHnM{5Z8m05S!rv+YjUMLE zg~fm-yM&iY&V#Y*iOv3fHj&Pm_cg=At=Ot4V5422sWce-rS2`XZK3oP@y~V*Jcrk9 zghIPIYrSO3j8Rb%U17~b{##cGUbP?R)AP0pAMex>8A)63uU#G$2)YJDg|FA{eYi<; zy6oB}Ey-=lZrxwIZu;}3m9wEr79EKO)CSo`GxddnRv_wcqJB#&wpNZ>ZbqQ?LX3T- zR&hbRojrg0k(f@;!m_sjNf|+Mw@*qPsa^KMVgSwJe%xegiK*`ASri%W%q@kOLOPxv z^GBHXk_S$vlX^MAG0|v%J^1-k*31n)W9})IE!d%GS56kfn&|U~K0D?9#%86v=q$JJG+58~reCVymU$9ec<{MC(Jh{Z?FWn$hK=xx_RXV%L zEJH8M{YYD*BozIjc}^@*sP_J@afa0>GR?^9Y6Zaw&;B!nmsQP3-ir9d65XvzsYF@j zRH#@PVCb8|0zVkt&>ea~TJ4tw-a>6@h)*+xwSrl`;s5~g?^OULTtq8EakLBoAc#b5 zLbc$j*M@Os~~o+;r)|cQ6e(O(lURVxmv@4gY`F{{cc# Bs+Rx& literal 0 HcmV?d00001 diff --git a/src/static/game.js b/src/static/game.js index 9f392de..dc2b6ae 100644 --- a/src/static/game.js +++ b/src/static/game.js @@ -1,7 +1,74 @@ var socket = io(); -test = function() { - console.log("h"); - socket.emit('json', {data: 'I\'m connected!'}); + +code = document.getElementById("code").value; +name = document.getElementById("name").value; +kickurl = document.getElementById("kick").value; + +function removeAllChildren(e) { + var child = e.lastElementChild; + while (child) { + e.removeChild(child); + child = e.lastElementChild; + } +} + +socket.on("connect", function() { + // when client first connects to a game + socket.emit("join", {"username": name, "room": code, "_gid": ""}); +}) + +socket.on("player_join_event", function(data) { + div = document.getElementById("sidebar"); + removeAllChildren(div); + if (Object.keys(data).length == 0) { + var keepSidebarOpen = document.createElement("input"); + keepSidebarOpen.setAttribute("type", "hidden"); + div.appendChild(keepSidebarOpen); + return + } + var keys = Object.keys(data); + for (var key in keys) { + var playerDisplay = document.createElement("div"); + playerDisplay.setAttribute("id", keys[key]); + playerDisplay.setAttribute("class", "playertag"); + var playerLink = document.createElement("p"); + playerLink.appendChild(document.createTextNode(keys[key])); + playerDisplay.appendChild(playerLink); + playerDisplay.appendChild(document.createElement("br")); + div.appendChild(playerDisplay); + } +}); + +socket.on("player_leave_event", function(data) { + var element = document.getElementById(data["player"]); + element.parentNode.removeChild(element); +}); + +socket.on("player_kick_event", function(data) { + if (data["kick"] == name) { + window.location = kickurl; + } else { + var element = document.getElementById(data["kick"]); + element.parentNode.removeChild(element); + } + +}) + +function buzz() { + // when client hits buzz + socket.emit("buzz", {"username": name, "room": code, "_gid": ""}); +} + +$(document).on('keypress', function(e) { + if (e.key === ' ' || e.key === 'Spacebar') { + e.preventDefault(); + buzz(); + } +}) + +window.onbeforeunload = function leave() { + // when client leaves + console.log("leave") + socket.emit("leave", {"username": name, "room": code, "_gid": ""}); } -// div id = game (that's where the game goes) \ No newline at end of file diff --git a/src/static/host.js b/src/static/host.js new file mode 100644 index 0000000..a87678e --- /dev/null +++ b/src/static/host.js @@ -0,0 +1,90 @@ +var socket = io(); + +code = document.getElementById("copycode").value; + +function readCookie(name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i=0;i < ca.length;i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + return null; +} + +gid = readCookie("_gid"); + +copycode = function() { + var copyText = document.getElementById("copycode") + copyText.select(); + copyText.setSelectionRange(0, 99999); + document.execCommand("copy") +} + +function send(data) { + socket.emit("host", {"room": code, "_gid": gid, "data": data}); +} + +function removeAllChildren(e) { + var child = e.lastElementChild; + while (child) { + e.removeChild(child); + child = e.lastElementChild; + } +} + +socket.on("connect", function() { + socket.emit("join", {"room": code, "_gid": gid}); +}); +window.onbeforeunload = function leave() { + socket.emit("leave", {"room": code, "_gid": gid}); +} + + +socket.on("player_join_event", function(data) { + div = document.getElementById("sidebar"); + removeAllChildren(div); + if (Object.keys(data).length == 0) { + var keepSidebarOpen = document.createElement("input"); + keepSidebarOpen.setAttribute("type", "hidden"); + div.appendChild(keepSidebarOpen); + return + } + var keys = Object.keys(data); + for (var key in keys) { + var playerDisplay = document.createElement("div"); + playerDisplay.setAttribute("id", keys[key]); + playerDisplay.setAttribute("class", "playertag"); + var playerLink = document.createElement("p"); + playerLink.appendChild(document.createTextNode(keys[key])); + var removeLink = document.createElement("a"); + removeLink.setAttribute("onclick", "removePlayer('" + keys[key] + "');"); + removeLink.appendChild(document.createTextNode("Kick")); + playerDisplay.appendChild(playerLink); + playerDisplay.appendChild(removeLink); + playerDisplay.appendChild(document.createElement("br")); + div.appendChild(playerDisplay); + } +}); + +socket.on("player_leave_event", function(data) { + var element = document.getElementById(data["player"]); + element.parentNode.removeChild(element); +}); + +socket.on("player_kick_event", function(data) { + var element = document.getElementById(data["kick"]); + element.parentNode.removeChild(element); + +}) + +function removePlayer(playername) { + send({"kick": playername}); +} + +socket.on("buzz", function(message) { + var audio = new Audio('/static/buzz.mp3'); + audio.play(); +}) + diff --git a/src/static/index.css b/src/static/index.css index 7570866..e75e556 100644 --- a/src/static/index.css +++ b/src/static/index.css @@ -92,6 +92,63 @@ body { margin-left: 5px; } +.copycode { + text-align: center; +} + +.form { + text-align: center; +} + +.form input { + text-align: center; +} + +.sidebar { + height: 100%; /* Full-height: remove this if you want "auto" height */ + font-size: 25px; + position: fixed; /* Fixed Sidebar (stay in place on scroll) */ + z-index: 1; /* Stay on top */ + top: 0; /* Stay at the top */ + left: 0; + background-color: #e2e27c; + padding-top: 20px; + padding-left: 10px; + padding-right: 20px; +} + +/* The navigation menu links */ +.sidebar a { + padding: 6px 8px 6px 8px; + text-decoration: none; + font-size: 14px; + color: #ea2a2d; + display: inline; +} + +.sidebar p { + padding: 6px 8px 6px 6px; + text-decoration: none; + font-size: 25px; + color: #818181; + display: inline; +} + +/* When you mouse over the navigation links, change their color */ +.sidebar a:hover { + color: #f1f1f1; +} + +/* Style page content */ +.game { + padding: 0px 10px; +} + +/* On smaller screens, where height is less than 450px, change the style of the sidebar (less padding and a smaller font size) */ +@media screen and (max-height: 450px) { + .sidebar {padding-top: 15px;} + .sidebar a {font-size: 18px;} +} @font-face { font-family: 'Abberancy-Regular'; diff --git a/src/templates/badname.html b/src/templates/badname.html new file mode 100644 index 0000000..7fcaba0 --- /dev/null +++ b/src/templates/badname.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% block content %} +
+ Back +
+
+

Bad Name

+
+
+
+

Names can only be alphanumeric.

+
+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/gamehost.html b/src/templates/gamehost.html new file mode 100644 index 0000000..2540558 --- /dev/null +++ b/src/templates/gamehost.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block content %} +
+

Game!

+
+ + +
+
+

Click to copy the game code:

+ +
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/src/templates/gamenotfound.html b/src/templates/gamenotfound.html new file mode 100644 index 0000000..e2caa98 --- /dev/null +++ b/src/templates/gamenotfound.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% block content %} +
+ Back +
+
+

Game not found

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/games.json b/src/templates/games.json index a9f90e3..40cc82e 100644 --- a/src/templates/games.json +++ b/src/templates/games.json @@ -4,5 +4,6 @@ "bonus": 20, "power": 15, "negs": 5, - "teams": false + "teams": false, + "players": {} } \ No newline at end of file diff --git a/src/templates/host.html b/src/templates/host.html index 3575e0c..5f24cce 100644 --- a/src/templates/host.html +++ b/src/templates/host.html @@ -7,41 +7,39 @@

Host Game

-
- {{ form.csrf_token }} - {{ form.hidden_tag() }} -

- {{ form.tossup.label }}
- {{ form.tossup(size=32, value=default[0]) }}
- {% for error in form.tossup.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.bonus.label }}
- {{ form.bonus(size=32, value=default[1]) }}
- {% for error in form.bonus.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.power.label }}
- {{ form.power(size=32, value=default[2]) }}
- {% for error in form.power.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.negs.label }}
- {{ form.negs(size=32, value=default[3]) }}
- {% for error in form.negs.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.teams() }} {{ form.teams.label }}
- {% for error in form.negs.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.create() }} -
-

-
+
+
+ {{ form.csrf_token }} +

+

+ {{ form.tossup.label }}
+ {{ form.tossup(size=32, value=default[0]) }}
+ {% for error in form.tossup.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.bonus.label }}
+ {{ form.bonus(size=32, value=default[1]) }}
+ {% for error in form.bonus.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.power.label }}
+ {{ form.power(size=32, value=default[2]) }}
+ {% for error in form.power.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.negs.label }}
+ {{ form.negs(size=32, value=default[3]) }}
+ {% for error in form.negs.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.create() }} +
+
+

+
+
{% endblock %} \ No newline at end of file diff --git a/src/templates/join.html b/src/templates/join.html index b04a1d4..afb233c 100644 --- a/src/templates/join.html +++ b/src/templates/join.html @@ -1,47 +1,30 @@ {% extends "base.html" %} {% block content %} -
- Back -
-
-

Host Game

-
-
- {{ form.csrf_token }} - {{ form.hidden_tag() }} -

- {{ form.tossup.label }}
- {{ form.tossup(size=32, value=default[0]) }}
- {% for error in form.tossup.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.bonus.label }}
- {{ form.bonus(size=32, value=default[1]) }}
- {% for error in form.bonus.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.power.label }}
- {{ form.power(size=32, value=default[2]) }}
- {% for error in form.power.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.negs.label }}
- {{ form.negs(size=32, value=default[3]) }}
- {% for error in form.negs.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.teams() }} {{ form.teams.label }}
- {% for error in form.negs.errors %} - [{{ error }}]
- {% endfor %} -
- {{ form.create() }} -
-

-
+
+ Back +
+
+

Join Game

+
+
+
+ {{ form.csrf_token }} +

+ {{ form.roomcode.label }}
+ {{ form.roomcode(size=32) }}
+ {% for error in form.roomcode.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.name.label }}
+ {{ form.name(size=32) }}
+ {% for error in form.name.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.create() }} +

+
+
{% endblock %} \ No newline at end of file diff --git a/src/templates/kick.html b/src/templates/kick.html new file mode 100644 index 0000000..1297a39 --- /dev/null +++ b/src/templates/kick.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +
+ Back +
+
+

You have been kicked.

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/nametaken.html b/src/templates/nametaken.html new file mode 100644 index 0000000..e4d6075 --- /dev/null +++ b/src/templates/nametaken.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +
+ Back +
+
+

Name is already taken.

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/play.html b/src/templates/play.html index b6290ca..9b0a1d4 100644 --- a/src/templates/play.html +++ b/src/templates/play.html @@ -1,9 +1,42 @@ -{% extends "base.html" %} - -{% block content %} - - -
- + + + {% if title %} + + + + + {{ title }} - Buzzer! + + {% else %} + + Buzzer! + + + + {% endif %} + +
+

Play!

-{% endblock %} + +

+
+
+ +
+
+
+ +
+ +
+
+ + + + + + diff --git a/src/templates/please.html b/src/templates/please.html new file mode 100644 index 0000000..e645fcc --- /dev/null +++ b/src/templates/please.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% block content %} +
+ Back +
+
+

Please join using the Join page.

+
+{% endblock %} \ No newline at end of file