ó
     ïÒj}‡  ã                   ó�  • S SK r S SKrS SKrS SKrS SKJr  S SKJr  S SKJ	r	J
r
JrJrJrJrJrJrJr  \" 5         S SKJrJr  S SKrS SKrS SKrS SKrS SKJr  \	" \5      r\ R>                  RA                  S5      =(       d    S\l!        \RD                  RG                  S	S
\" SS9SS9  SSSS.r$\ RJ                  RM                  \ RJ                  RO                  \ RJ                  RQ                  \)5      5      S5      r*\ R>                  RA                  SS5      RW                  S5      r,\,(       a  \,R[                  S5      (       d  S\,-   r,S r.\." 5       r/\R`                  S 5       r1S r2S r3S r4S r5/ SQr6S r7S r8SoS jr9S r:S  r;S! r<S" r=\R}                  S#5      S$ 5       r?\R}                  S5      S% 5       r@\R}                  S&5      \5" S'S(5      S) 5       5       rA\R}                  S*5      \5" S'S(5      S+ 5       5       rB\R}                  S5      \5" S(5      S, 5       5       rC\R}                  S-5      S. 5       rD\R}                  S/5      S0 5       rE\R}                  S1S2/S39S4 5       rF\R}                  S5S2/S39S6 5       rG\R}                  S75      \5" 5       S8 5       5       rH\R}                  S95      \5" 5       S: 5       5       rI\R}                  S;5      \5" S<5      S= 5       5       rJ\R}                  S>S2/S39\5" S<5      S? 5       5       rK\R}                  S@5      \5" S<5      SA 5       5       rL\R}                  SBS2/S39\5" S<5      SC 5       5       rM\R}                  SD5      \5" S'S(5      SE 5       5       rN\R}                  SFS2/S39\5" S'S(5      SG 5       5       rOSH rPSpSI jrQSJ rRSK rSSL rT\R«                  SM5      \5" S'S(5      SN 5       5       rV\R«                  SO5      \5" S'S(5      SP 5       5       rW\RA                  SQ5      \5" S'S(5      SR 5       5       rX\R«                  SQ5      \5" S'S(5      SS 5       5       rY\R«                  ST5      \5" S'S(5      SU 5       5       rZ\R«                  SV5      \5" S'S(5      SW 5       5       r[\R«                  SX5      \5" S'S(5      SY 5       5       r\SZ r]\RA                  S[5      \5" S(5      S\ 5       5       r^\RA                  S]5      \5" S(5      S^ 5       5       r_\R«                  S]5      \5" S(5      S_ 5       5       r`\R«                  S`5      \5" S(5      Sa 5       5       ra\R«                  Sb5      \5" S(5      Sc 5       5       rb\R«                  Sd5      \5" S(5      Se 5       5       rcSf rd\Sg:X  aZ  \d" 5         \e" \ R>                  RA                  ShSi5      5      rf\ R>                  RA                  SjSk5      Sl:H  rg\RÑ                  \g\fSmSn9  gg)qé    N©Úwraps)Úload_dotenv)	ÚFlaskÚrequestÚjsonifyÚsessionÚrender_templateÚredirectÚurl_forÚsend_from_directoryÚg)ÚDB_PATHÚget_db)Ú	timedeltaÚ
SECRET_KEYÚscience_gr2_secret_key_2026TÚLaxé   )ÚdaysF)ÚSESSION_COOKIE_HTTPONLYÚSESSION_COOKIE_SAMESITEÚPERMANENT_SESSION_LIFETIMEÚJSON_AS_ASCIIÚ/ú/admin)ÚkidÚparentÚadminÚassetsÚ	BASE_PATHÚ c                  ó@  • SSK n U R                  " 5       n[        R                  " [        R                  R                  [        R                  S5      5       H±  u  p#n[        U5       Hœ  nUR                  S5      (       d  M  UR                  UR                  5       5        UR                  [        [        R                  R                  [        R                  R                  X%5      5      5      R                  5       5        Mž     M³     UR                  5       SS $ )zgChanges whenever a script or stylesheet changes, so phones never run an old cached copy after a deploy.r   NÚstatic)z.jsz.cssé   )ÚhashlibÚmd5ÚosÚwalkÚpathÚjoinÚappÚ	root_pathÚsortedÚendswithÚupdateÚencodeÚstrÚgetmtimeÚ	hexdigest)r&   ÚhÚrootÚ_ÚfilesÚfs         Úapp.pyÚ_asset_versionr;      sµ   € ãØ�Š‹€AÜŸ'š'¤"§'¡'§,¡,¬s¯}©}¸hÓ"GÖH‰ˆ�Ü˜–ˆAØ�z‰z˜/×*Ó*Ø—‘˜Ÿ™›Ô$ a§h¡h¬s´2·7±7×3CÑ3CÄBÇGÁGÇLÁLÐQUÓDYÓ3ZÓ/[×/bÑ/bÓ/dÖ&eó ñ Ið �;‰;‹=˜˜!ÐÐó    c                  ó   • [         [        S.$ )N)Ú	base_pathÚv)r!   ÚASSET_V© r<   r:   Úinject_base_pathrB   +   s   € ä"¬Ñ1Ð1r<   c                 ó*   • [        [        U 5      5      $ ©N)r   r   )Úendpoints    r:   Úbp_redirectrF   0   s   € Ü”G˜HÓ%Ó&Ð&r<   c                 ó:   • [        [        R                  U -   5      $ )zlRedirect to an app path under the prefix the request came through (/science behind the proxy, none locally).)r   r   Úscript_root)r*   s    r:   ÚgorI   4   s   € ä”G×'Ñ'¨$Ñ.Ó/Ð/r<   c                  ó"  • S[         ;  av  [        R                  " S5      (       a*  [        R                  " [        R                  " S5      5      OS n U (       a  [        R                  " U 5      (       a  U OS [         l        [         R
                  $ )NÚcuÚuser_id)r   r	   ÚgetÚACCÚ	can_loginrK   ©Úus    r:   Úcurrent_userrR   9   sR   € Ø”1ƒ}Ü/6¯{ª{¸9×/EÑ/EŒC�GŠG”G—K’K 	Ó*Ô+È4ˆÞœ#Ÿ-š-¨×*Ñ*‰q°ŒŒÜ�4‰4€Kr<   c                  ó8   ^ • [        S T  5       5      m U 4S jnU$ )z]login_required() any account; login_required("kid") / ("parent", "admin") restrict the roles.c              3   ó6   #   • U  H  o(       d  M  Uv •  M     g 7frD   rA   )Ú.0Úrs     r:   Ú	<genexpr>Ú!login_required.<locals>.<genexpr>B   s   é € Ð(šU˜£a—!‘!šUùs   ‚
�	c                 ó4   >^ • [        T 5      U U4S j5       nU$ )Nc                  ó¶  >• [        5       n[        R                  =(       d    [        R                  R	                  S5      nU(       d6  [
        R                  " 5         U(       a  [        SS05      S4$ [        S5      $ T(       a4  US   T;  a+  U(       a  [        SS05      S4$ [        [        US      5      $ US   US	   s[
        S'   [
        S	'   T" U 0 UD6$ )
Nz/api/ÚerrorÚnot_logged_iné‘  Ú
login_pageÚroleÚ
wrong_roleé“  Údisplay_name)rR   r   Úis_jsonr*   Ú
startswithr	   Úclearr   rF   rI   ÚHOME)ÚargsÚkwargsrQ   Úapir9   Úroless       €€r:   ÚwrapperÚ2login_required.<locals>.decorator.<locals>.wrapperD   s½   ø€ ä“ˆAÜ—/‘/×E¤W§\¡\×%<Ñ%<¸WÓ%EˆCÞÜ—’”ÞEHœ ¨/Ð :Ó;¸SÐAÐgÌkÐZfÓNgÐgÞ˜˜6™¨%Ó/ÞBEœ ¨,Ð 7Ó8¸#Ð>Ð^Ì2ÌdÐSTÐU[ÑS\ÉoÓK^Ð^Ø78¸±yÀ!ÀNÑBSÐ4ŒG�F‰OœW ^Ñ4Ù�dÐ%˜fÑ%Ð%r<   r   )r9   rk   rj   s   ` €r:   Ú	decoratorÚ!login_required.<locals>.decoratorC   s    ù€ Ü	ˆq‹õ		&ó 
ð		&ð ˆr<   )Útuple)rj   rm   s   ` r:   Úlogin_requiredrp   @   s    ø€ äÑ(™UÓ(Ó(€Eõð Ðr<   ))Ú
flashcardsÚ
Flashcardsé
   )Úquizz
Quiz Time!é   )Ú	truefalsezTrue or Falsers   )Úmatchingz	Match It!ru   )ÚsortingzSort & Classifyru   )ÚmemoryzMemory Gameru   )ÚlabelingzLabel the Diagramru   c                 ó  • US:X  a  SOSnUS:X  a  SOSu  pVU R                  SU S3U45      R                  5       n0 nU HO  n	U	S   U;   a9  U R                  S	U S
U S3U	S   45        U R                  S	U S3U	S   45        ME  U	S   X‰S   '   MQ     [        U5       HŽ  u  p«X¨;   aG  U R                  SU SSR                  S UR	                  S5       5       5       S3/ UQXŠ   P75        MQ  U R                  SU SU SSR                  S[        U5      -  5       S3U/UQU
P75        M�     UR                  5        HG  u  pÍU[        U5      :¼  d  M  U R                  S	U S
U S3U45        U R                  S	U S3U45        MI     g)uå   Write a section's activities / experiments in order, UPDATING the rows that exist so their ids â€” and the kids'
attempts that point to them â€” survive a restart. Only rows beyond the new count are deleted (with their attempts).Ú
activitiesz$activity_type,title,data_json,pointsztitle,data_json,points)Úactivity_attemptsÚactivity_id)Úexperiment_completionsÚexperiment_idzSELECT id, sort_order FROM z+ WHERE section_id=? ORDER BY sort_order, idÚ
sort_orderzDELETE FROM z WHERE ú=?Úidz WHERE id=?zUPDATE z SET z, c              3   ó*   #   • U  H	  oS -   v •  M     g7f)r‚   NrA   )rU   Úxs     r:   rW   Ú_sync_rows.<locals>.<genexpr>e   s   é € Ð5XÊÀ1¸$¶hÊùó   ‚Ú,zINSERT INTO z (section_id,z,sort_order) VALUES (?,Ú?z,?)N)ÚexecuteÚfetchallÚ	enumerater+   ÚsplitÚlenÚitems)ÚcÚtableÚ
section_idÚrowsÚcolsÚ
done_tableÚdone_colÚoldÚby_orderrV   ÚkÚvalsÚorderÚrids                 r:   Ú
_sync_rowsr�   W   s  € ð 6;¸lÓ5JÑ1ÐPh€DØCHÈLÓCXÑ?ð  _JÑ€JØ
�)‰)Ð1°%°Ð8cÐdÐgqÐfsÓ
t×
}Ñ
}Ó
€CØ€HÛˆØˆ\‰?˜hÓ&Ø�I‰I˜ Z L°¸°zÀÐDÀqÈÁwÀjÔQÐST×S\ÑS\Ð_kÐlqÐkrÐr}Ð]~ð  BCð  DHñ  BIð  AKö  TLà()¨$©ˆH�|‘_Ó%ñ	 ô
 ˜T–?‰ˆØ‹=Ø�I‰I˜ ˜w e¨D¯I©IÑ5XÈÏ
É
ÐSVÌÓ5XÓ,XÐ+YÐYdÐeÐg{ÐimÐg{ÐowÑozÑg{Ö|à�I‰I˜ U G¨=¸¸Ð>UÐVY×V^ÑV^Ð_bÔehÐimÓenÑ_nÓVoÐUpÐpsÐtð  xBð  wMð  EIð  wMð  KLñ  wMö  Nñ	 #ð
 —n‘nÖ&‰
ˆØ”C˜“IÕØ�I‰I˜ Z L°¸°zÀÐDÀsÀfÔMÈqÏyÉyÐ[gÐhmÐgnÐnyÐYzð  ~Að  }Cö  PDò 'r<   c                  óX  • [        5       n U R                  5       n[        [        R                  5       GHÀ  u  p#UR                  S[        R                  5      nUR                  SUS   45        UR                  5       nU(       a&  US   nUR                  SUS   US   US   X$U45        O/UR                  S	US   US   US   US   X$45        UR                  n[        US
   5       GH  u  pxUR                  SUS   U45        UR                  5       nU(       a  US   n	O'UR                  SXhS   US   U45        UR                  n	[        US   5       GH‘  u  p«UR                  SUS   U	45        UR                  5       nU(       a  US   nO'UR                  SX›S   US   U
45        UR                  n[         VVVs/ s H8  u  pÞoûR                  U5      (       d  M  XÞ[        R                  " X½   5      U4PM:     nnnn[        R                  " US   5       Hp  nUR!                  5        VVs0 s H  u  nnUS;  d  M  UU_M     nnnUR#                  US   US   [        R                  " U5      UR                  SS5      45        Mr     [%        USUU5        [%        USXËR                  S/ 5       Vs/ s H  nUS   [        R                  " U5      S4PM!     sn5        GM”     GM     GMÃ     U R'                  5         U R)                  5         g s  snnnf s  snnf s  snf )NÚlevelz!SELECT id FROM units WHERE code=?Úcoderƒ   zJUPDATE units SET name=?, color=?, icon=?, sort_order=?, level=? WHERE id=?ÚnameÚcolorÚiconzNINSERT INTO units (code,name,color,icon,sort_order,level) VALUES (?,?,?,?,?,?)Úchaptersz2SELECT id FROM chapters WHERE code=? AND unit_id=?zDINSERT INTO chapters (unit_id,code,name,sort_order) VALUES (?,?,?,?)Úsectionsz5SELECT id FROM sections WHERE code=? AND chapter_id=?zGINSERT INTO sections (chapter_id,code,name,sort_order) VALUES (?,?,?,?))ÚtypeÚtitleÚpointsr¦   r§   r¨   ru   r|   Úexperimentsé   )r   ÚcursorrŒ   Ú
curriculumÚUNITSrM   ÚLVÚDEFAULTrŠ   ÚfetchoneÚ	lastrowidÚ	ACT_TYPESÚjsonÚdumpsÚ
games_dataÚ	get_gamesr�   Úappendr�   ÚcommitÚclose)Úconnr�   ÚuiÚunitÚlvlÚrowÚunit_idÚciÚchapterÚ
chapter_idÚsiÚsectionr’   Útr§   ÚptsÚactsÚgamer™   r?   ÚgdataÚexps                         r:   Úbuild_curriculum_in_dbrË   m   s#  € Ü‹8€DØ�‰‹€AÜœj×.Ñ.×/‰ˆØ�h‰h�w¤§
¡
Ó+ˆØ	�	‰	Ð5¸¸V¹°ÔGØ�j‰j‹lˆÞØ˜$‘iˆGØ�I‰IÐbÐeiÐjpÑeqÐswÐxñ  tAð  CGð  HNñ  COð  QSð  Zað  ebõ  cà�I‰IÐfØ˜F‘| T¨&¡\°4¸±=À$ÀvÁ,ÐPRÐXôZà—k‘kˆGä$ T¨*Ñ%5×6‰KˆBØ�I‰IÐJÈWÐU[É_Ð^eÐLfÔgØ—*‘*“,ˆCÞØ  ™Y‘
à—	‘	Ð`Ø"¨F¡O°W¸V±_ÀbÐIôKàŸ[™[�
ä(¨°Ñ)<×=‘�Ø—	‘	ÐQÐT[Ð\bÑTcÐeoÐSpÔqØ—j‘j“l�ÞØ!$ T¡‘Jà—I‘IÐgØ)°6©?¸GÀF¹OÈRÐPôRà!"§¡�JåU^ÕqÒU^ÁMÀAÈc×bmÑbmÐno×bpÓ?˜¤4§:¢:¨g©jÓ#9¸3Ó?ÑU^�ÒqÜ&×0Ò0°¸±ÖA�DØ.2¯j©j¬lÔcªl¡d a¨¸aÐGbÑ>b›T˜Q šT©l�EÑcØ—K‘K  f¡¨t°G©}¼d¿jºjÈÓ>OÐQU×QYÑQYÐZbÐdfÓQgÐ hÖiñ Bô ˜1˜l¨J¸Ô=Ü˜1˜m¨Z×itÑitð  vCð  EGô  jHó  :Iò  jHÐbe¸3¸w¹<ÌÏÊÐTWËÐZ\Ó:]ñ  jHñ  :I÷  Jô  >ô 7ñ 0ðN 	‡K�K„MØ‡J�J…Lùô rùãcùò :Is   ÇLÇ$LÈ6L!ÉL!Ê=&L'c                 óh   • U R                  SU S3U45      R                  5       nU(       a  US   $ S $ )NzSELECT u.level FROM z{ a JOIN sections s ON a.section_id=s.id JOIN chapters ch ON s.chapter_id=ch.id JOIN units u ON ch.unit_id=u.id WHERE a.id=?rŸ   )rŠ   r°   )r�   r~   r‘   rV   s       r:   Úunit_level_of_activityrÍ   ›   sF   € Ø	�	‰	Ð(¨¨ð 0Að BØDOÀ>ó	SßS[ÑS[ÓS]ð æˆ1ˆW‰:Ð$ Ð$r<   c                 óL  • [        5       nUR                  5       nUR                  SU 45        UR                  5       nU(       dF  UR                  SU 45        UR	                  5         UR                  SU 45        UR                  5       nUR                  5         [        U5      $ )Nú(SELECT * FROM user_stats WHERE user_id=?z+INSERT INTO user_stats (user_id) VALUES (?))r   r«   rŠ   r°   r¸   r¹   Údict)rL   rº   r�   r¾   s       r:   Úget_user_statsrÑ   ¡   s|   € Ü‹8€DØ�‰‹€AØ‡I�IÐ8¸7¸*ÔEØ
�*‰*‹,€CÞØ	�	‰	Ð?À'ÀÔLØ�‰ŒØ	�	‰	Ð<¸w¸jÔIØ�j‰j‹lˆØ‡J�J„LÜ�‹9Ðr<   c                 óª  • [        5       nUR                  5       nSS KnUR                  R	                  5       R                  5       nUR                  SU 45        UR                  5       nU(       d  UR                  SXU45        O¥US   U-   nUS-  nUS   n	US   n
X•:w  at  SS Kn UR                  R                  U	S5      R                  5       nUR                  R                  US5      R                  5       nXË-
  R                  S	:X  a  U
S	-  n
OS	n
 UR                  S
XxX¥U 45        UR                  5         UR                  5         g !   S	n
 N<= f)Nr   rÏ   zMINSERT INTO user_stats (user_id,total_points,last_active_date) VALUES (?,?,?)Útotal_pointsé2   Úlast_active_dateÚstreak_daysz%Y-%m-%dé   zfUPDATE user_stats SET total_points=?, total_stars=?, streak_days=?, last_active_date=? WHERE user_id=?)r   r«   ÚdatetimeÚdateÚtodayÚ	isoformatrŠ   r°   Ústrptimer   r¸   r¹   )rL   Ú
points_addrº   r�   rØ   rÚ   r¾   Ú	new_totalÚ	new_starsÚ	last_dateÚstreakÚprevÚcurrs                r:   Úupdate_user_statsrä   ¯   s?  € Ü‹8€DØ�‰‹€AÛØ�M‰M×ÑÓ!×+Ñ+Ó-€EØ‡I�IÐ8¸7¸*ÔEØ
�*‰*‹,€CÞØ	�	‰	ÐaØ¨Ð.õ	0ð ˜Ñ'¨*Ñ4ˆ	Ø ‘Oˆ	ØÐ*Ñ+ˆ	Ø�]Ñ#ˆØÓÛðØ×(Ñ(×1Ñ1°)¸ZÓH×MÑMÓO�Ø×(Ñ(×1Ñ1°%¸ÓD×IÑIÓK�Ø‘K×%Ñ%¨Ó*Ø˜a‘K‘Fà‘Fð 	
�	‰	ÐzØ¨¸Ð@ô	Bà‡K�K„MØ‡J�J…LøðØ’ús   Â'A+E ÄE ÅEc                 ój  • [        5       nUR                  5       n/ nUR                  SU 45        UR                  5       S   S:”  a$  UR                  SU 45        UR	                  S5        UR                  SU 45        UR                  5       S   S:”  a$  UR                  SU 45        UR	                  S5        UR                  S	U 45        UR                  5       S   S
:¼  a$  UR                  SU 45        UR	                  S5        UR                  SU 45        UR                  5       S   S:¼  a$  UR                  SU 45        UR	                  S5        [        U 5      nUS   S:¼  a$  UR                  SU 45        UR	                  S5        UR                  S5        UR                  5       n0 nU H„  nUR                  SUS   45        UR                  5       S   nUR                  SXS   45        UR                  5       S   n	US   n
X¦;  a  SSS.Xj'   Xj   S==   U-  ss'   Xj   S==   U	-  ss'   M†     SSSS S!S"S#.nUR                  5        HM  u  p¬X¦;   d  M  Xj   nUS   S:”  d  M  US   US   :¼  d  M)  UR                  S$X45        UR	                  U5        MO     [        S% UR                  5        5       5      n[        S& UR                  5        5       5      nUS:”  a)  Xþ:¼  a$  UR                  S'U 45        UR	                  S(5        UR                  5         UR                  5         U$ ))NúISELECT COUNT(*) as n FROM activity_attempts WHERE user_id=? AND partial=0Únr   zpINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code='first_steps'))Úfirst_stepsz™SELECT COUNT(DISTINCT a.id) as n FROM activity_attempts aa JOIN activities a ON aa.activity_id=a.id WHERE aa.user_id=? AND aa.score>=100 AND aa.partial=0zrINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code='perfect_score'))Úperfect_scorezqSELECT COUNT(DISTINCT ec.experiment_id) as n FROM experiment_completions ec WHERE ec.user_id=? AND ec.completed=1é   znINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code='scientist'))Ú	scientistz\SELECT COUNT(DISTINCT activity_id) as n FROM activity_attempts WHERE user_id=? AND partial=0é   zpINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code='quiz_master'))Úquiz_masterrÖ   é   zmINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code='streak_7'))Ústreak_7zq
        SELECT s.id, ch.id as ch_id, ch.name FROM sections s
        JOIN chapters ch ON s.chapter_id=ch.id
    ú;SELECT COUNT(*) as total FROM activities WHERE section_id=?rƒ   Útotalú¡SELECT COUNT(DISTINCT activity_id) as done FROM activity_attempts WHERE user_id=? AND partial=0 AND activity_id IN (SELECT id FROM activities WHERE section_id=?)Údoner¡   )rñ   ró   Úplant_expertÚbody_masterÚmatter_geniusÚ
force_heroÚearth_guardianÚsky_explorer)ÚPlantsÚPeoplezStates of MatterzMotion and Forcesz#Earth Materials & Natural ResourceszThe SkyzdINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code=?))c              3   ó*   #   • U  H	  oS    v •  M     g7f)rñ   NrA   ©rU   r?   s     r:   rW   Úcheck_badges.<locals>.<genexpr>
  s   é € ÐDÒ(C 1�g–JÒ(Cùr‡   c              3   ó*   #   • U  H	  oS    v •  M     g7f)ró   NrA   rý   s     r:   rW   rþ     s   é € ÐBÒ&A �V–9Ò&Aùr‡   zqINSERT OR IGNORE INTO user_badges (user_id,badge_id) VALUES (?,(SELECT id FROM badges WHERE code='all_complete'))Úall_complete)r   r«   rŠ   r°   r·   rÑ   r‹   r�   ÚsumÚvaluesr¸   r¹   )rL   rº   r�   ÚawardedÚstatsr¥   Úchapter_completionÚsecÚ	total_actÚdone_actÚch_nameÚ	badge_mapÚ
badge_codeÚinfoÚ	total_allÚdone_alls                   r:   Úcheck_badgesr  Ï   s¨  € Ü‹8€DØ�‰‹€AØ€Gà‡I�IÐYÐ\cÐ[eÔfØ‡z�zƒ|�CÑ˜1ÓØ	�	‰	ð  Eð  HOð  GQô  	RØ�‰�}Ô%à‡I�Ið  jð  mtð  lvô  wØ‡z�zƒ|�CÑ˜1ÓØ	�	‰	ð  Gð  JQð  ISô  	TØ�‰�Ô'à‡I�Ið  Bð  ELð  DNô  OØ‡z�zƒ|�CÑ˜AÓØ	�	‰	ð  Cð  FMð  EOô  	PØ�‰�{Ô#à‡I�IÐlÐovÐnxÔyØ‡z�zƒ|�CÑ˜BÓØ	�	‰	ð  Eð  HOð  GQô  	RØ�‰�}Ô%ä˜7Ó#€EØˆ]Ñ˜qÓ Ø	�	‰	ð  Bð  ELð  DNô  	OØ�‰�zÔ"à‡I�Ið ô 	ð �z‰z‹|€HØÐÛˆØ	�	‰	ÐOÐRUÐVZÑR[ÐQ]Ô^Ø—J‘J“L Ñ)ˆ	Ø	�	‰	ð  vð  y@ð  FJñ  BKð  xLô  	MØ—:‘:“< Ñ'ˆØ�f‘+ˆØÓ,Ø45¸qÑ*AÐÑ'ØÑ# GÓ,°	Ñ9Ó,ØÑ# FÓ+¨xÑ7Õ+ñ ð !¨MØ+À,Ø/?ÈNñ€Ið
  )Ÿ™Ö0ÑˆØÕ(Ø%Ñ.ˆDØ�G‰}˜qÕ  T¨&¡\°T¸'±]Õ%BØ—	‘	ð  Að  DKð  CXô  YØ—‘˜zÖ*ñ  1ô ÑDÐ(:×(AÑ(AÔ(CÓDÓD€IÜÑBÐ&8×&?Ñ&?Ô&AÓBÓB€HØ�1ƒ}˜Ó.Ø	�	‰	ð  Fð  IPð  HRô  	SØ�‰�~Ô&à‡K�K„MØ‡J�J„LØ€Nr<   c           	      óÀ  • [        5       nUR                  5       nUR                  SX45        UR                  5       nU(       d  UR                  SXSX#S45        Oc[	        US   U5      nUS   U-   nUS   S-   n	UR                  SU45        UR                  5       S	   n
Xš:¼  a  S
OSnUR                  SXxX›X45        UR                  5         UR                  5         g )Nz?SELECT * FROM section_progress WHERE user_id=? AND section_id=?z¤INSERT INTO section_progress (user_id,section_id,status,best_score,total_points,activities_completed,last_accessed) VALUES (?,?,?,?,?,?,datetime('now','localtime'))Úin_progressr×   Ú
best_scorerÓ   Úactivities_completedrð   rñ   Ú	completedz¢UPDATE section_progress SET best_score=?,total_points=?,activities_completed=?,status=?,last_accessed=datetime('now','localtime') WHERE user_id=? AND section_id=?)r   r«   rŠ   r°   Úmaxr¸   r¹   )rL   r’   Úscorer¨   rº   r�   r¾   Únew_bestÚ
new_pointsÚnew_donerñ   Ústatuss               r:   Úupdate_section_progressr    sä   € Ü‹8€DØ�‰‹€AØ‡I�IÐOÐRYÐQfÔgØ
�*‰*‹,€CÞØ	�	‰	ð  yØ¨°uÀaÐHõ	Jô �s˜<Ñ(¨%Ó0ˆØ˜Ñ(¨6Ñ1ˆ
ØÐ-Ñ.°Ñ2ˆØ	�	‰	ÐOÐR\ÐQ^Ô_Ø—
‘
“˜WÑ%ˆØ (Ó 1‘°}ˆØ	�	‰	ð  wØ¨¸7ÐOô	Qà‡K�K„MØ‡J�J…Lr<   z/assets/<path:filename>c                 ó"   • [        [        U 5      $ rD   )r   Ú
ASSETS_DIR)Úfilenames    r:   Úserve_assetr  *  s   € äœz¨8Ó4Ð4r<   c                  óÆ   • [        5       n U (       d  [        S5      $ U S   S:X  a  [        S5      $ U S   S:X  a  [        S[        R
                  " U 5      S9$ [        S5      $ )	Nr^   r_   r   r   r   úparent.html©Úmezkid.html)rR   rF   rI   r
   rN   ÚpublicrP   s    r:   Úindexr%  /  sY   € ä‹€AÞÜ˜<Ó(Ð(Øˆ�y�GÓÜ�(‹|ÐØˆ�y�HÓÜ˜}´·²¸A³Ñ?Ð?Ü˜:Ó&Ð&r<   z/parentr   r   c                  óN   • [        S[        R                  " [        5       5      S9$ )Nr!  r"  ©r
   rN   r$  rR   rA   r<   r:   Úparent_pager(  ;  s   € ô ˜=¬S¯ZªZ¼»Ó-GÑHÐHr<   z/reportc                  ó   • [        S5      $ )z=One kid's science report (shown inside the parent dashboard).zreport.html)r
   rA   r<   r:   Úreport_pager*  A  s   € ô ˜=Ó)Ð)r<   c                  óN   • [        S[        R                  " [        5       5      S9$ )Nz
admin.htmlr"  r'  rA   r<   r:   Ú
admin_pager,  H  s   € ô ˜<¬C¯JªJ´|³~Ó,FÑGÐGr<   z/loginc                  ód   • [        5       n U (       a  [        [        U S      5      $ [        S5      $ )Nr_   z
login.html)rR   rI   rf   r
   rP   s    r:   r^   r^   N  s*   € ä‹€AÞÜ”$�q˜‘y‘/Ó"Ð"Ü˜<Ó(Ð(r<   z/logoutc                  óB   • [         R                  " 5         [        S5      $ )Nr^   )r	   re   rF   rA   r<   r:   Úlogout_pager/  V  s   € ä‡M‚M„OÜ�|Ó$Ð$r<   z
/api/loginÚPOST)Úmethodsc                  óð  • [         R                  " SS9=(       d    0 n [        R                  " U R	                  SS5      R                  5       U R	                  SS5      5      u  pU(       a  SU;   a  SOSn[        X2S	.5      S
4$ [        R                  " 5         [        R                  " US   US   US   US   S9  S[        l
        [        US   US   [         R                  [        US      -   S.5      $ )NT©ÚsilentÚusernamer"   Úpasswordu
   Ù…ÙˆÙ‚ÙˆÙ�zThis account is suspended.zInvalid username or password)r[   Úerror_arr]   rƒ   r_   rb   )rL   r5  r_   rb   )r_   rb   Úhome)r   Úget_jsonrN   ÚauthenticaterM   Ústripr   r	   re   r0   Ú	permanentrH   rf   )ÚdatarQ   ÚerrÚmsgs       r:   Ú	api_loginr@  \  sÛ   € ä×Ò 4Ñ(×.¨B€DÜ×Ò˜dŸh™h z°2Ó6×<Ñ<Ó>ÀÇÁÈÐUWÓ@XÓY�F€AÞ
Ø.:¸cÓ.AÑ*ÐGeˆÜ Ñ6Ó7¸Ð<Ð<Ü‡M‚M„OÜ‡N‚N˜1˜T™7¨Q¨z©]ÀÀ6ÁÐYZÐ[iÑYjÒkØ„GÔÜ˜A˜f™I°q¸Ñ7HÔRY×ReÑReÔhlÐmnÐouÑmvÑhwÑRwÑxÓyÐyr<   z/api/logoutc                  óF   • [         R                  " 5         [        SS05      $ )NÚokT)r	   re   r   rA   r<   r:   Ú
api_logoutrC  i  s   € ä‡M‚M„OÜ�D˜$�<Ó Ð r<   z/api/mec                  ó¾  • [        [        S   5      n [        5       nUR                  5       nUR	                  S[        S   45        UR                  5        Vs/ s H  n[        U5      PM     nnUR                  5         [        [        S   [        S   [        S   [        S   [        5       S   [        R                  " [        5       S   5      U US.5      $ s  snf )NrL   úaSELECT b.* FROM user_badges ub JOIN badges b ON ub.badge_id=b.id WHERE ub.user_id=? ORDER BY b.idr5  r_   rb   Úcourse_level)rL   r5  r_   rb   rF  Úcourser  Úbadges)rÑ   r	   r   r«   rŠ   r‹   rÐ   r¹   r   rR   r®   rŸ   )r  rº   r�   rV   rH  s        r:   Úapi_merI  o  sÍ   € ô œ7 9Ñ-Ó.€EÜ‹8€DØ�‰‹€AØ‡I�IÐuÔxð  AJñ  yKð  xMô  NØ Ÿz™zœ|Ó,š|˜!Œd�1Žg™|€FÐ,Ø‡J�J„LÜÜ˜9Ñ%Ü˜JÑ'Ü˜‘Ü Ñ/Ü$› ~Ñ6Ü—(’(œ<›>¨.Ñ9Ó:ØØñ	ó 	ð 	ùò -s   ÁCz/api/curriculumc            	      ó²  • [        5       n U R                  5       n/ n[        5       nUS   S:X  a  UR                  SUS   45        OUR                  S5        UR	                  5       nU GHÅ  n[        U5      nUR                  SUS   45        UR	                  5       n/ US'   U GHs  n[        U5      nUR                  S	US   45        UR	                  5       n	/ US
'   U	 GH  n
[        U
5      nUR                  SU
S   45        UR	                  5        Vs/ s H  n[        U5      PM     snUS'   UR                  SU
S   45        UR	                  5        Vs/ s H  n[        U5      PM     snUS'   [        S   S:X  ah  UR                  S[        S   U
S   45        UR                  5       S   US'   UR                  S[        S   U
S   45        UR                  5       S   US'   US
   R                  U5        GM!     US   R                  U5        GMv     UR                  U5        GMÈ     U R                  5         [        U5      $ s  snf s  snf )Nr_   r   z5SELECT * FROM units WHERE level=? ORDER BY sort_orderrF  z'SELECT * FROM units ORDER BY sort_orderz:SELECT * FROM chapters WHERE unit_id=? ORDER BY sort_orderrƒ   r¤   z=SELECT * FROM sections WHERE chapter_id=? ORDER BY sort_orderr¥   zfSELECT id,activity_type,title,points,sort_order FROM activities WHERE section_id=? ORDER BY sort_orderr|   zYSELECT id,title,points,sort_order FROM experiments WHERE section_id=? ORDER BY sort_orderr©   rò   rL   ró   Úactivities_donez­SELECT COUNT(DISTINCT experiment_id) as done FROM experiment_completions WHERE user_id=? AND completed=1 AND experiment_id IN (SELECT id FROM experiments WHERE section_id=?)Úexperiments_done)r   r«   rR   rŠ   r‹   rÐ   r	   r°   r·   r¹   r   )rº   r�   ÚresultrQ   Úunitsr¼   r¤   ÚchrÁ   r¥   r  rÄ   rV   s                r:   Úapi_curriculumrP  „  s£  € ô ‹8€DØ�‰‹€AØ€FÜ‹€AØˆ�y�EÓØ	�	‰	ÐIÈAÈnÑL]ÐK_Õ`à	�	‰	Ð;Ô<Ø�J‰J‹L€EÜˆÜ�A‹wˆØ	�	‰	ÐNÐQRÐSWÑQXÐPZÔ[Ø—:‘:“<ˆØˆˆZÑÜˆBÜ˜2“hˆGØ�I‰IÐUÐXZÐ[_ÑX`ÐWbÔcØ—z‘z“|ˆHØ"$ˆG�JÑÜ�Ü˜s›)�Ø—	‘	ð  Cð  FIð  JNñ  FOð  EQô  RØ:;¿*¹*¼,Ó(Gº,°Q¬¨a®¹,Ñ(G�˜Ñ%Ø—	‘	ÐuÐx{ð  }Añ  yBð  xDô  EØ;<¿:¹:¼<Ó)Hº<°a¬$¨q®'¹<Ñ)H�˜Ñ&Ü˜6‘? eÓ+Ø—I‘Ið  Bô  ELð  MVñ  EWð  Y\ð  ]añ  Ybð  Dcô  dØ12·±³¸fÑ1E�GÐ-Ñ.Ø—I‘Ið  Nô  QXð  Ybñ  Qcð  ehð  imñ  enð  Poô  pØ23·*±*³,¸vÑ2F�GÐ.Ñ/Ø˜
Ñ#×*Ñ*¨7×3ñ  ð �Ñ×#Ñ# G×,ñ# ð$ 	�‰�d×ñ/ ð0 	‡J�J„LÜ�6‹?Ðùò )Hùâ)Hs   ÄI
ÅI
z/api/activity/<int:activity_id>r   c                 ód  • [        5       nUR                  5       nUR                  SU 45        UR                  5       n[	        X 5      nUR                  5         U(       a  U[        5       S   :w  a  [        SS05      S4$ [        U5      n[        R                  " US   5      US'   [        U5      $ )Nz\SELECT a.*, s.chapter_id FROM activities a JOIN sections s ON a.section_id=s.id WHERE a.id=?rF  r[   Ú	not_foundé”  Ú	data_json©r   r«   rŠ   r°   rÍ   r¹   rR   r   rÐ   r³   Úloads)r~   rº   r�   r¾   r½   Úds         r:   Úapi_get_activityrX  ¬  s–   € ô ‹8€DØ�‰‹€AØ‡I�IÐlÐozÐn|Ô}Ø
�*‰*‹,€CÜ
  Ó
0€CØ‡J�J„LÞ�#œ›¨Ñ7Ó7Ü˜ Ð-Ó.°Ð3Ð3ÜˆS‹	€AÜ—Z’Z  +¡Ó/€A€k�NÜ�1‹:Ðr<   z&/api/activity/<int:activity_id>/submitc           
      óL  • [         R                  " 5       nUR                  SS5      n[        S[	        UR                  SS5      =(       d    S5      5      nUR                  S0 5      n[        [        [	        UR                  SS5      =(       d    S5      S5      S5      nUR                  S5      (       a  SOSn[        5       nUR                  5       nUR                  S	U 45        UR                  5       n	U	(       a  [        X€5      [        5       S
   :w  a  UR                  5         [        SS05      S4$ [        X9S   S-   5      nUR                  S[        S   XU[        R                   " U5      XV45        UR#                  5         UR                  5         [%        [        S   U5        U(       d  ['        [        S   U	S   X#5        [)        [        S   5      n
[+        [        S   5      n/ nU
(       a‘  [        5       nUR                  5       nSR-                  S[/        U
5      -  5      nUR                  SU S3[        S   /U
-   5        UR1                  5        Vs/ s H  n[3        U5      PM     nnUR                  5         [        SUUUS   US   US.5      $ s  snf )Nr  r   Úpoints_earnedÚanswersÚ
time_spenti  Úpartialr×   z#SELECT * FROM activities WHERE id=?rF  r[   rR  rS  r¨   rs   z~INSERT INTO activity_attempts (user_id,activity_id,score,points_earned,answers_json,time_spent,partial) VALUES (?,?,?,?,?,?,?)rL   r’   rˆ   r‰   zcSELECT b.* FROM user_badges ub JOIN badges b ON ub.badge_id=b.id WHERE ub.user_id=? AND b.code IN (Ú)TrÓ   Útotal_stars)rB  r  rZ  rÓ   r_  Ú
new_badges)r   r9  rM   r  ÚintÚminr   r«   rŠ   r°   rÍ   rR   r¹   r   r	   r³   r´   r¸   rä   r  r  rÑ   r+   rŽ   r‹   rÐ   )r~   r=  r  rZ  r[  r\  r]  rº   r�   Úactr`  r  Ú
badge_rowsÚconn2Úc2ÚplaceholdersrV   s                    r:   Úapi_submit_activityrh  ¼  sT  € ô ×ÒÓ€DØ�H‰H�W˜aÓ €EÜ˜œ3˜tŸx™x¨¸Ó;×@¸qÓAÓB€MØ�h‰h�y "Ó%€GÜ”Sœ˜TŸX™X l°AÓ6×;¸!Ó<¸aÓ@À$ÓG€JØ—8‘8˜I×&Ñ&‰a¨A€Gä‹8€DØ�‰‹€AØ‡I�IÐ3°k°^ÔDØ
�*‰*‹,€CÞÔ(¨Ó8¼L»NÈ>Ñ<ZÓZØ�
‰
ŒÜ˜ Ð-Ó.°Ð3Ð3Ü˜¨8¡}°rÑ'9Ó:€Mà‡I�Ið  OÜ�yÑ! ;°}ÄdÇjÂjÐQXÓFYÐ[eÐoôqà‡K�K„MØ‡J�J„Lä”g˜iÑ(¨-Ô8ÞÜ¤¨	Ñ 2°C¸Ñ4EÀuÔ\Üœg iÑ0Ó1€Jäœ7 9Ñ-Ó.€EØ€JÞÜ“ˆØ�\‰\‹^ˆØ—x‘x ¤c¨*£oÑ 5Ó6ˆØ
�
‰
Ðxð  zFð  yGð  GHð  IÜ˜IÑ&Ð'¨*Ñ4ô	6à')§{¡{¤}Ó5¢} !”d˜1–g¡}ˆ
Ð5Ø�‰ŒäØØØ&Ø˜nÑ-Ø˜]Ñ+Ø ñó ð ùò 6s   É"J!z#/api/experiment/<int:experiment_id>c                 óf  • [        5       nUR                  5       nUR                  SU 45        UR                  5       n[	        X S5      nUR                  5         U(       a  U[        5       S   :w  a  [        SS05      S4$ [        U5      n[        R                  " US   5      US'   [        U5      $ )Nú$SELECT * FROM experiments WHERE id=?r©   rF  r[   rR  rS  rT  rU  )r€   rº   r�   r¾   r½   rW  s         r:   Úapi_get_experimentrk  î  s—   € ô ‹8€DØ�‰‹€AØ‡I�IÐ4°}Ð6FÔGØ
�*‰*‹,€CÜ
  °=Ó
A€CØ‡J�J„LÞ�#œ›¨Ñ7Ó7Ü˜ Ð-Ó.°Ð3Ð3ÜˆS‹	€AÜ—Z’Z  +¡Ó/€A€k�NÜ�1‹:Ðr<   z,/api/experiment/<int:experiment_id>/completec                 ó2  • [         R                  " 5       nUR                  SS5      n[        5       nUR	                  5       nUR                  SU 45        UR                  5       nU(       a  [        X@S5      [        5       S   :w  a  UR                  5         [        SS05      S4$ UR                  S	[        S
   U 45        UR                  5       nU(       a  UR                  SX&S   45        OUR                  S[        S
   X45        UR                  5         UR                  5         [        [        S
   US   5        [        [        S
   US   SUS   5        [        [        S
   5      n[!        [        S
   5      n[        SUS   US   US   US.5      $ )NÚnotesr"   rj  r©   rF  r[   rR  rS  zHSELECT * FROM experiment_completions WHERE user_id=? AND experiment_id=?rL   ziUPDATE experiment_completions SET completed=1,notes=?,completed_at=datetime('now','localtime') WHERE id=?rƒ   z[INSERT INTO experiment_completions (user_id,experiment_id,completed,notes) VALUES (?,?,1,?)r¨   r’   éd   TrÓ   r_  )rB  rZ  rÓ   r_  r`  )r   r9  rM   r   r«   rŠ   r°   rÍ   rR   r¹   r   r	   r¸   rä   r  r  rÑ   )	r€   r=  rm  rº   r�   rÊ   Úexistingr`  r  s	            r:   Úapi_complete_experimentrp  þ  s‰  € ô ×ÒÓ€DØ�H‰H�W˜bÓ!€EÜ‹8€DØ�‰‹€AØ‡I�IÐ4°}Ð6FÔGØ
�*‰*‹,€CÞÔ(¨¸=ÓIÌ\Ë^Ð\jÑMkÓkØ�
‰
ŒÜ˜ Ð-Ó.°Ð3Ð3à‡I�IÐXÔ[bÐclÑ[mÐo|ÐZ}Ô~Ø�z‰z‹|€HÞØ	�	‰	Ð}ð  AFð  QUñ  HVð  @Wõ  	Xà	�	‰	ÐoÜ˜9Ñ% }Ð<ô	>à‡K�K„MØ‡J�J„Lä”g˜iÑ(¨#¨h©-Ô8ÜœG IÑ.°°LÑ0AÀ3ÈÈHÉÔVÜœg iÑ0Ó1€JÜœ7 9Ñ-Ó.€EäØØ˜X™Ø˜nÑ-Ø˜]Ñ+Ø ñó ð r<   z/api/parent/dashboardc            	      óÀ  • [        5       n U (       d  [        SS05      S4$ [        5       nUR                  5       nUR	                  SU S   45        UR                  5       n/ nU GH  nUS   US   US   US   [        R                  " US   5      US	   US
   S.n[        US   5      nXvS'   UR	                  SUS   45        UR                  5       S   US'   UR	                  SUS   45        UR                  5       nUS   (       a  [        US   S5      OSUS'   UR	                  SUS   45        UR                  5       S   US'   UR	                  SUS   45        UR                  5        V	s/ s H  n	[        U	5      PM     sn	US'   UR	                  SUS   US   45        UR                  5        V	s/ s H  n	[        U	5      PM     sn	US'   UR	                  SUS   45        UR                  5        V	s/ s H  n	[        U	5      PM     sn	US'   UR	                  SUS   45        UR                  5        V	s/ s H  n	[        U	5      PM     sn	US'   UR                  U5        GM	     UR	                  S5        UR                  5        V	s/ s H  n	[        U	5      PM     n
n	UR                  5         [        XJS.5      $ s  sn	f s  sn	f s  sn	f s  sn	f s  sn	f ) Nr[   Úparent_not_foundrS  zJSELECT * FROM users WHERE role='kid' AND parent_id=? ORDER BY display_namerƒ   rb   r5  rF  ÚavatarÚactive)rƒ   rb   r5  rF  rG  rs  rt  r  ræ   rç   Útotal_attemptszSSELECT AVG(score) as avg_score FROM activity_attempts WHERE user_id=? AND partial=0Ú	avg_scorer×   r   zeSELECT COUNT(DISTINCT experiment_id) as n FROM experiment_completions WHERE user_id=? AND completed=1rL  rE  rH  a¦  
            SELECT s.name as section_name, s.code as section_code,
                   ch.name as chapter_name, u.name as unit_name, u.color as unit_color,
                   sp.status, sp.best_score, sp.total_points, sp.activities_completed,
                   (SELECT COUNT(*) FROM activities WHERE section_id=s.id) as total_activities,
                   sp.last_accessed
            FROM sections s
            JOIN chapters ch ON s.chapter_id=ch.id
            JOIN units u ON ch.unit_id=u.id
            LEFT JOIN section_progress sp ON sp.section_id=s.id AND sp.user_id=?
            WHERE u.level=?
            ORDER BY u.sort_order, ch.sort_order, s.sort_order
        Úsection_progressaª  
            SELECT aa.attempted_at, aa.score, aa.points_earned, aa.time_spent, aa.partial,
                   a.title, a.activity_type, s.name as section_name, s.code as section_code
            FROM activity_attempts aa
            JOIN activities a ON aa.activity_id=a.id
            JOIN sections s ON a.section_id=s.id
            WHERE aa.user_id=?
            ORDER BY aa.attempted_at DESC
            LIMIT 50
        Úrecent_activitya=  
            SELECT ec.completed_at, e.title, s.name as section_name
            FROM experiment_completions ec
            JOIN experiments e ON ec.experiment_id=e.id
            JOIN sections s ON e.section_id=s.id
            WHERE ec.user_id=? AND ec.completed=1
            ORDER BY ec.completed_at DESC
        Úexperiments_completedz SELECT * FROM badges ORDER BY id)ÚkidsÚ
all_badges)Ú_parent_scoper   r   r«   rŠ   r‹   r®   rŸ   rÑ   r°   ÚroundrÐ   r·   r¹   )Úprº   r�   rz  rM  r   Úkid_datar  r¾   rV   r{  s              r:   Úapi_parent_dashboardr€  #  s	  € ô 	‹€AÞÜ˜Ð!3Ð4Ó5°sÐ:Ð:Ü‹8€DØ�‰‹€AØ‡I�IÐZÐ]^Ð_cÑ]dÐ\fÔgØ�:‰:‹<€DØ€FÜˆØ˜d™)°S¸Ñ5HÐVYÐZdÑVeÐwzð  |Jñ  xKÜ Ÿhšh s¨>Ñ':Ó;ÀsÈ8Á}Ð`cÐdlÑ`mñoˆä˜s 4™yÓ)ˆØ!�Ñà	�	‰	Ð]Ð`cÐdhÑ`iÐ_kÔlØ%&§Z¡Z£\°#Ñ%6ˆÐ!Ñ"à	�	‰	ÐgÐjmÐnrÑjsÐiuÔvØ�j‰j‹lˆØ>AÀ+×>N¤ c¨+Ñ&6¸Ô :ÐTUˆ�Ñà	�	‰	ÐyÐ|ð  AEñ  }Fð  |Hô  	IØ'(§z¡z£|°CÑ'8ˆÐ#Ñ$à	�	‰	ÐyÐ|ð  AEñ  }Fð  |Hô  	IØ/0¯z©z¬|Ó<ª|¨!œd 1žg©|Ñ<ˆ�Ñà	�	‰	ð ð �$‰i˜˜^Ñ,Ð-ô	/ð :;¿¹¼Ó'Fº°A¬¨Q®¹Ñ'FˆÐ#Ñ$à	�	‰	ð 	ð �$‰iˆ\ô		ð 9:¿
¹
¼Ó&Eº°1¤t¨A¦w¹Ñ&EˆÐ"Ñ#à	�	‰	ð ð �$‰iˆ\ô	ð ?@¿j¹j¼lÓ,Kºl¸¬T°!®W¹lÑ,KˆÐ(Ñ)à�‰�h×ñq ðt ‡I�IÐ0Ô1Ø#$§:¡:¤<Ó0¢<˜a”$�q–'¡<€JÐ0Ø‡J�J„LÜ˜FÑ=Ó>Ð>ùòY =ùò (Gùò 'Fùò -Lùò
 1s   Å2KÆ9KÇ<KÈ?KÊKz/api/parent/resetc                  óÒ   • [         R                  " SS9=(       d    0 n [        U R                  S5      5      nU(       d  [	        SS05      S4$ [        US   5        [	        SS05      $ )	NTr3  Úkid_idr[   õ   ØºÙŠØ± Ù…Ø³Ù…ÙˆØ­ra   rƒ   rB  )r   r9  Úmanaged_kidrM   r   Ú
_reset_kid)r=  r™   s     r:   Úapi_parent_resetr†  n  s`   € ô ×Ò 4Ñ(×.¨B€DÜ�D—H‘H˜XÓ&Ó'€AÞÜ˜Ð!4Ð5Ó6¸Ð;Ð;Üˆq�‰wÔÜ�D˜$�<Ó Ð r<   c                 ó6  • [        5       nUR                  5       nUR                  SU 45        UR                  SU 45        UR                  SU 45        UR                  SU 45        UR                  SU 45        UR                  5         UR	                  5         g )Nz-DELETE FROM activity_attempts WHERE user_id=?z2DELETE FROM experiment_completions WHERE user_id=?z,DELETE FROM section_progress WHERE user_id=?z'DELETE FROM user_badges WHERE user_id=?zRUPDATE user_stats SET total_points=0, total_stars=0, streak_days=0 WHERE user_id=?)r   r«   rŠ   r¸   r¹   )r‚  rº   r�   s      r:   r…  r…  y  s}   € Ü‹8€DØ�‰‹€AØ‡I�IÐ=À¸yÔIØ‡I�IÐBÀVÀIÔNØ‡I�IÐ<¸v¸iÔHØ‡I�IÐ7¸&¸ÔCØ‡I�IÐbÐekÐdmÔnØ‡K�K„MØ‡J�J…Lr<   c                 ó   • [        U S9U4$ )N)r[   )r   )r?  r    s     r:   Úfailr‰  †  s   € Ü˜Ñ˜tÐ#Ð#r<   c                  ó>   • [         R                  " SSS9=(       d    0 $ )NT)Úforcer4  )r   r9  rA   r<   r:   ÚbodyrŒ  Š  s   € Ü×Ò $¨tÑ4×:¸Ð:r<   c                 ó¾   •  [         R                  " [        U 5      5      n[         R
                  " [        5       U5      (       a  U$ S$ ! [        [        4 a     gf = f)zPThe kid the caller may manage (admin: any kid; parent: only its own), else None.N)rN   rM   ra  Ú	TypeErrorÚ
ValueErrorÚcan_manage_kidrR   ©r‚  r™   s     r:   r„  r„  Ž  sS   € ðÜ�GŠG”C˜“KÓ ˆô ×"Ò"¤<£>°1×5Ñ5ˆ1Ð?¸4Ð?øô ”zÐ"ó Ùðús   ‚A	 Á	AÁAc                  ó^  • [        5       n U S   S:X  a  U $ [        R                  R                  S5      =(       d    [	        5       R                  S5      nU(       a=  [        U5      R                  5       (       a  [        R                  " [        U5      5      OSnU(       a  US   S:X  a  U$ S$ )zfThe parent whose kids the request is about: a parent itself, or the admin's ?parent= / body parent_id.r_   r   Ú	parent_idN)	rR   r   rg   rM   rŒ  r2   ÚisdigitrN   ra  )rQ   Úpidr~  s      r:   r|  r|  —  s~   € ä‹€AØˆ�y�HÓØˆÜ
�,‰,×
Ñ
˜8Ó
$×
?¬«¯
©
°;Ó(?€CÞ ¤S¨£X×%5Ñ%5×%7Ñ%7Œ�Š”�C“Ô¸T€AÞ�a˜‘i 8Ó+ˆ1Ð5°Ð5r<   z/api/account/passwordc                  óh  • [        5       n [        5       n[        R                  " XR	                  SS5      5      (       d  [        S5      $  [        R                  " US   U R	                  SS5      5        [        SS9$ ! [        R                   a  n[        [        U5      5      s S nA$ S nAff = f)Nr—   r"   u6   ÙƒÙ„Ù…Ø© Ø§Ù„Ù…Ø±ÙˆØ± Ø§Ù„Ø­Ø§Ù„ÙŠØ© ØºÙŠØ± ØµØ­ÙŠØ­Ø©rƒ   ÚnewT©rB  )
rŒ  rR   rN   Úcheck_pwrM   r‰  Úset_passwordÚAccountErrorr2   r   )rW  rQ   Úes      r:   Úapi_own_passwordr�  ¡  s�   € ô 	‹€AÜ‹€AÜ�<Š<˜Ÿ5™5 ¨Ó+×,Ñ,ÜÐLÓMÐMðÜ×Ò˜˜4™ !§%¡%¨¨rÓ"2Ô3ô �dÑÐøô ×Ñó Ü”C˜“F‹|Õûðús   Á*A? Á?B1ÂB,Â&B1Â,B1z/api/kid/<int:kid_id>/resetc                 ól   • [        U 5      nU(       d  [        SS5      $ [        US   5        [        SS9$ ©Nrƒ  ra   rƒ   Tr˜  )r„  r‰  r…  r   r‘  s     r:   Úapi_kid_resetr   ¯  s6   € ô 	�FÓ€AÞÜÐ'¨Ó-Ð-Üˆq�‰wÔÜ�dÑÐr<   z	/api/kidsc                  ó&  • [        5       n U S   S:X  a†  [        R                  R                  S5      (       db  [	        [
        R                  " 5       [
        R                  " 5        Vs0 s H  oS   U_M
     sn[
        R                  [        R                  S9$ [        5       nU(       d  [        SS5      $ [	        [
        R                  " US   5      [
        R                  " U5      US   [
        R                  [        R                  S	9$ s  snf )
Nr_   r   r   rƒ   )rz  ÚparentsÚavatarsÚlevelsõ#   ÙˆÙ„ÙŠ Ø§Ù„Ø£Ù…Ø± ØºÙŠØ± Ù…ÙˆØ¬ÙˆØ¯rS  Úmax_kids)rz  r   r¦  r£  r¤  )rR   r   rg   rM   r   rN   Úall_kidsr¢  ÚAVATARSr®   ÚLEVELSr|  r‰  Úkids_ofr$  )rQ   r~  s     r:   Úapi_kidsr«  ¹  sÑ   € ô 	‹€AØˆ�y�GÓ¤G§L¡L×$4Ñ$4°X×$>Ñ$>ÜœCŸLšL›NÌÏÊÌÓ4WÊÀA°t±W¸a²ZÉÑ4WÔad×alÑalÔuw×u~Ñu~ÑÐÜ‹€AÞÜÐ9¸3Ó?Ð?ÜœŸš A d¡GÓ,´S·Z²ZÀ³]ÈQÈzÉ]Ôdg×doÑdoÔxz÷  yBñ  yBñ  Cð  Cùò	 5Xs   Á(D
c                  ó"  • [        5       n U (       d  [        S5      $ [        5       nUR                  S5      =(       d    [        R
                  " 5       n [        R                  " SUR                  S5      UR                  S5      X S   UR                  SS5      UR                  S	[        R                  5      S
9n[        S[        R                  " U5      US9$ ! [        R                   a  n[        [        U5      5      s S nA$ S nAff = f)Nu   Ø§Ø®ØªØ± ÙˆÙ„ÙŠ Ø§Ù„Ø£Ù…Ø±r6  r   r5  rb   rƒ   rs  r"   rF  )r“  rs  rF  T)rB  r   r6  )r|  r‰  rŒ  rM   rN   Úgen_passwordÚcreater®   r¯   r›  r2   r   r$  )r~  rW  r6  r™   rœ  s        r:   Úapi_kid_creater¯  Å  sÔ   € ô 	‹€AÞÜÐ0Ó1Ð1Ü‹€AØ�u‰u�ZÓ ×6¤C×$4Ò$4Ó$6€HðÜ�JŠJ�u˜aŸe™e JÓ/°·±°~Ó1FÈÐ^bÑ\cÐlm×lqÑlqÐrzÐ|~ÓlØ$%§E¡E¨.¼"¿*¹*Ó$EñGˆô �d¤§
¢
¨1£¸ÑAÐAøô ×Ñó Ü”C˜“F‹|Õûðús   ÁA(C ÃDÃ0D	ÄDÄ	Dz/api/kids/<int:kid_id>c           
      ón  • [        U 5      nU(       d  [        SS5      $ [        5       n [        R                  " US   40 S Vs0 s H  o3U;   d  M
  X2U   _M     snD6n[        S[        R                  " U5      S9$ s  snf ! [        R
                   a  n[        [        U5      5      s S nA$ S nAff = f)Nrƒ  ra   rƒ   )rb   rs  Ú
unlock_allrt  rF  T)rB  r   )	r„  r‰  rŒ  rN   r0   r›  r2   r   r$  )r‚  r™   rW  r9   rœ  s        r:   Úapi_kid_updater²  Õ  s·   € ô 	�FÓ€AÞÜÐ'¨Ó-Ð-Ü‹€AðÜ�JŠJ�q˜‘wñ  CÑ4vó  #BÒ4v¨qð  @Añ  {A£7 1¨¡d¢7Ñ4vñ  #Bñ  Cˆô �d¤§
¢
¨1£Ñ.Ð.ùò #BøÜ×Ñó Ü”C˜“F‹|Õûðús5   ªB Á	A=Á	A=ÁB Á=B ÂB4ÂB/Â)B4Â/B4z/api/kids/<int:kid_id>/passwordc                 ób  • [        U 5      nU(       d  [        SS5      $ [        5       R                  S5      =(       d    [        R
                  " 5       n [        R                  " US   U5        [        SX!S   S9$ ! [        R                   a  n[        [        U5      5      s S nA$ S nAff = f)Nrƒ  ra   r6  rƒ   Tr5  ©rB  r6  r5  )
r„  r‰  rŒ  rM   rN   r­  rš  r›  r2   r   )r‚  r™   r6  rœ  s       r:   Úapi_kid_passwordrµ  ã  s�   € ô 	�FÓ€AÞÜÐ'¨Ó-Ð-Ü‹v�z‰z˜*Ó%×;¬×)9Ò)9Ó);€HðÜ×Ò˜˜4™ (Ô+ô �d X¸*¹ÑFÐFøô ×Ñó Ü”C˜“F‹|Õûðús   ÁA< Á<B.ÂB)Â#B.Â)B.z/api/kids/<int:kid_id>/deletec                 ó‚   • [        U 5      nU(       d  [        SS5      $ [        R                  " US   5        [	        SS9$ rŸ  )r„  r‰  rN   Údeleter   r‘  s     r:   Úapi_kid_deleter¸  ñ  s:   € ô 	�FÓ€AÞÜÐ'¨Ó-Ð-Ü‡J‚Jˆq�‰wÔÜ�dÑÐr<   c                 óV   • [         R                  " U 5      nU(       a  US   S:X  a  U$ S $ )Nr_   r   )rN   rM   )r•  r~  s     r:   Ú_parentrº  û  s'   € Ü�Š�‹€AÞ�a˜‘i 8Ó+ˆ1Ð5°Ð5r<   z/api/admin/summaryc                  ó>   • [        [        R                  " 5       5      $ rD   )r   rN   ÚsummaryrA   r<   r:   Úapi_admin_summaryr½     s   € ô ”3—;’;“=Ó!Ð!r<   z/api/admin/parentsc                  ó:   • [        [        R                  " 5       S9$ )N)r¢  )r   rN   r¢  rA   r<   r:   Úapi_admin_parentsr¿    s   € ô œ3Ÿ;š;›=Ñ)Ð)r<   c            
      óÀ  • [        5       n U R                  S5      =(       d    [        R                  " 5       n [        R                  " SU R                  S5      U R                  S5      XR                  S[        R
                  5      S9n[        S[        R                  " U5      US9$ ! [        R                   a  n[        [        U5      5      s S nA$ S nAff = f)	Nr6  r   r5  rb   r¦  )r¦  T)rB  r   r6  )rŒ  rM   rN   r­  r®  ÚDEFAULT_MAX_KIDSr›  r‰  r2   r   r$  )rW  r6  r~  rœ  s       r:   Úapi_admin_parent_createrÂ    sµ   € ô 	‹€AØ�u‰u�ZÓ ×6¤C×$4Ò$4Ó$6€HðÜ�JŠJ�x §¡ zÓ!2°A·E±E¸.Ó4IÈ8×^cÑ^cÐdnÔps÷  qEñ  qEó  _Fñ  Gˆô �d¤3§:¢:¨a£=¸8ÑDÐDøô ×Ñó Ü”C˜“F‹|Õûðús   ¹AB+ Â+CÂ?CÃCÃCz/api/admin/parents/<int:pid>c           
      ód  • [        U 5      (       d  [        SS5      $ [        5       n [        R                  " U 40 S Vs0 s H  o"U;   d  M
  X!U   _M     snD6n[        S[        R                  " U5      S9$ s  snf ! [        R
                   a  n[        [        U5      5      s S nA$ S nAff = f)Nr¥  rS  )rb   r¦  rt  T)rB  r   )	rº  r‰  rŒ  rN   r0   r›  r2   r   r$  )r•  rW  r9   r~  rœ  s        r:   Úapi_admin_parent_updaterÄ    s›   € ô �3�<‰<ÜÐ9¸3Ó?Ð?Ü‹€AðÜ�JŠJ�sÑbÑ0VÓaÒ0V¨1Ð_`ÑZ`›w˜q A¡$šwÑ0VÑaÑbˆô �d¤3§:¢:¨a£=Ñ1Ð1ùò bøÜ×Ñó Ü”C˜“F‹|Õûðús4   ¨A= ¿	A8Á	A8ÁA= Á8A= Á=B/ÂB*Â$B/Â*B/z%/api/admin/parents/<int:pid>/passwordc                 óZ  • [        U 5      nU(       d  [        SS5      $ [        5       R                  S5      =(       d    [        R
                  " 5       n [        R                  " X5        [        SX!S   S9$ ! [        R                   a  n[        [        U5      5      s S nA$ S nAff = f)Nr¥  rS  r6  Tr5  r´  )
rº  r‰  rŒ  rM   rN   r­  rš  r›  r2   r   )r•  r~  r6  rœ  s       r:   Úapi_admin_parent_passwordrÆ  %  sˆ   € ô 	�‹€AÞÜÐ9¸3Ó?Ð?Ü‹v�z‰z˜*Ó%×;¬×)9Ò)9Ó);€HðÜ×Ò˜Ô'ô �d X¸*¹ÑFÐFøô ×Ñó Ü”C˜“F‹|Õûðús   ÁA8 Á8B*ÂB%ÂB*Â%B*z#/api/admin/parents/<int:pid>/deletec                 óv   • [        U 5      (       d  [        SS5      $ [        S[        R                  " U 5      S9$ )Nr¥  rS  T)rB  Údeleted)rº  r‰  r   rN   r·  )r•  s    r:   Úapi_admin_parent_deleterÉ  3  s0   € ô �3�<‰<ÜÐ9¸3Ó?Ð?Ü�d¤C§J¢J¨s£OÑ4Ð4r<   c                  óÂ   • SSK Jn   U " 5         [        R                  " [        R
                  5        [        R                  " [        R
                  5        [        5         g )Nr   ©Úinit_db)Údb_initrÌ  rN   Úmigrater(   ÚenvironÚ	bootstraprË   rË  s    r:   Úinit_apprÑ  ;  s0   € ÝÙ„IÜ‡K‚K”—
‘
ÔÜ‡M‚M”"—*‘*ÔÜÕr<   Ú__main__ÚPORTiº  ÚFLASK_DEBUGÚ0Ú1z0.0.0.0)ÚdebugÚportÚhost)r|   )i�  )ir(   r³   r&   Úsqlite3Ú	functoolsr   Údotenvr   Úflaskr   r   r   r	   r
   r   r   r   r   rÍ  r   r   r¬   rµ   ÚaccountsrN   r¤  r®   rØ   r   Ú__name__r,   rÏ  rM   Ú
secret_keyÚconfigr0   rf   r*   r+   ÚdirnameÚabspathÚ__file__r  Úrstripr!   rd   r;   r@   Úcontext_processorrB   rF   rI   rR   rp   r²   r�   rË   rÍ   rÑ   rä   r  r  Úrouter  r%  r(  r*  r,  r^   r/  r@  rC  rI  rP  rX  rh  rk  rp  r€  r†  r…  r‰  rŒ  r„  r|  Úpostr�  r   r«  r¯  r²  rµ  r¸  rº  r½  r¿  rÂ  rÄ  rÆ  rÉ  rÑ  ra  rØ  r×  ÚrunrA   r<   r:   Ú<module>rê     sÚ  ðÛ 	Û Û Û Ý Ý ß n× nÕ ná „ç #Û Û Û Û Ý áˆHƒo€Ø—‘—‘ Ó-×NÐ1N€„Ø ‡
�
× Ñ ¨$ÈÑjsÐy{Ñj|ð  MRÐ ñ  SØ˜c¨HÑ5€Ø�W‰W�\‰\˜"Ÿ'™'Ÿ/™/¨"¯'©'¯/©/¸(Ó*CÓDÀhÓO€
à�J‰J�N‰N˜;¨Ó+×2Ñ2°3Ó7€	Þ�Y×)Ñ)¨#×.Ñ.Ø�i‘€Iòñ Ó
€ð ×Ññ2ó ð2ò'ò0ò
òò&w€	òDò,+ô\%òòò@CòLð* ‡�Ð$Ó%ñ5ó &ð5ð ‡�ˆ3ƒñ'ó ð'ð ‡�ˆ9ÓÙ�˜'Ó"ñIó #ó ðIð ‡�ˆ9ÓÙ�˜'Ó"ñ*ó #ó ð*ð
 ‡�ˆ8ÓÙ�ÓñHó ó ðHð ‡�ˆ8Óñ)ó ð)ð ‡�ˆ9Óñ%ó ð%ð
 ‡�ˆ< & €Ð*ñ	zó +ð	zð ‡�ˆ= 6 (€Ð+ñ!ó ,ð!ð
 ‡�ˆ9ÓÙÓñó ó ðð& ‡�ÐÓÙÓñ#ó ó ð#ðL ‡�Ð,Ó-Ù�Óñó ó .ðð ‡�Ð3¸f¸X€ÐFÙ�Óñ-ó ó Gð-ð` ‡�Ð0Ó1Ù�Óñó ó 2ðð ‡�Ð9ÀFÀ8€ÐLÙ�Óñ ó ó Mð ðF ‡�Ð"Ó#Ù�˜'Ó"ñF?ó #ó $ðF?ðR ‡�Ð¨¨€Ð1Ù�˜'Ó"ñ!ó #ó 2ð!ò	ô$ò;ò@ò6ð ‡�Ð
!Ó"Ù�˜'Ó"ñ	ó #ó #ð	ð ‡�Ð
'Ó(Ù�˜'Ó"ñó #ó )ðð ‡�ˆÓÙ�˜'Ó"ñCó #ó ðCð ‡�ˆ+ÓÙ�˜'Ó"ñBó #ó ðBð ‡�Ð
"Ó#Ù�˜'Ó"ñ	/ó #ó $ð	/ð ‡�Ð
+Ó,Ù�˜'Ó"ñ	Gó #ó -ð	Gð ‡�Ð
)Ó*Ù�˜'Ó"ñó #ó +ðò6ð
 ‡�Ð	ÓÙ�Óñ"ó ó ð"ð ‡�Ð	ÓÙ�Óñ*ó ó ð*ð ‡�Ð
ÓÙ�ÓñEó ó  ðEð ‡�Ð
(Ó)Ù�Óñ2ó ó *ð2ð ‡�Ð
1Ó2Ù�Óñ	Gó ó 3ð	Gð ‡�Ð
/Ó0Ù�Óñ5ó ó 1ð5òð ˆzÓÙ„JÙˆr�z‰z�~‰~˜f dÓ+Ó,€DØ�J‰J�N‰N˜=¨#Ó.°#Ñ5€EØ‡G�G�%˜d¨€GÒ3ð	 r<   