rapid-router 7.5.10__py2.py3-none-any.whl → 7.5.12__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
game/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "7.5.10"
1
+ __version__ = "7.5.12"
@@ -488,3 +488,38 @@ class LevelEditorTestCase(TestCase):
488
488
  # Teacher shouldn't see any shared levels now
489
489
  response = self.client.get(levels_url)
490
490
  assert len(response.context["directly_shared_levels"]) == 0
491
+
492
+ def test_level_cannot_be_created_with_invalid_fields(self):
493
+ email, password = signup_teacher_directly()
494
+ create_organisation_directly(email)
495
+ _, _, access_code = create_class_directly(email)
496
+ create_school_student_directly(access_code)
497
+
498
+ level_data = self.LEVEL_DATA1
499
+ level_data["subtitle"] = "<a>invalid subtitle</a>"
500
+
501
+ self.login(email, password)
502
+ url = reverse("save_level_for_editor")
503
+ response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
504
+
505
+ assert response.status_code == 401
506
+
507
+ level_data["subtitle"] = "valid subtitle"
508
+ level_data["lesson"] = "<a>invalid lesson</a>"
509
+
510
+ response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
511
+
512
+ assert response.status_code == 401
513
+
514
+ level_data["lesson"] = "valid lesson"
515
+ level_data["hint"] = "<a>invalid hint</a>"
516
+
517
+ response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
518
+
519
+ assert response.status_code == 401
520
+
521
+ level_data["hint"] = "valid hint"
522
+
523
+ response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
524
+
525
+ assert response.status_code == 200
@@ -221,80 +221,88 @@ def save_level_for_editor(request, levelId=None):
221
221
  if not permissions.can_save_level(request.user, level):
222
222
  return HttpResponseUnauthorized()
223
223
 
224
- pattern = re.compile("^(\w?[ ]?)*$")
224
+ name_pattern = re.compile("^(\w?[ ]?)*$")
225
+ fields_pattern = re.compile("^[\w.?!', ]*$")
226
+
227
+ name_is_safe = name_pattern.match(data["name"])
228
+ fields_are_safe = all(
229
+ [
230
+ field not in data or fields_pattern.match(data[field])
231
+ for field in ["subtitle", "lesson", "hint"]
232
+ ]
233
+ )
225
234
 
226
- if pattern.match(data["name"]):
227
- level_management.save_level(level, data)
235
+ if not (name_is_safe and fields_are_safe):
236
+ return HttpResponseUnauthorized()
228
237
 
229
- is_user_school_student = (
230
- hasattr(level.owner, "student")
231
- and not level.owner.student.is_independent()
232
- )
233
- is_user_independent = (
234
- hasattr(level.owner, "student") and level.owner.student.is_independent()
235
- )
236
- is_user_teacher = hasattr(level.owner, "teacher")
237
-
238
- # when level is created
239
- if levelId is None:
240
- teacher = None
241
-
242
- # if level owner is a school student, share with teacher automatically if they aren't an admin
243
- if is_user_school_student:
244
- teacher = level.owner.student.class_field.teacher
245
- if not teacher.is_admin:
246
- level.shared_with.add(teacher.new_user)
247
-
248
- if not data["anonymous"]:
249
- level_management.email_new_custom_level(
250
- teacher.new_user.email,
251
- request.build_absolute_uri(reverse("level_moderation")),
252
- request.build_absolute_uri(
253
- reverse("play_custom_level", kwargs={"levelId": level.id})
254
- ),
255
- str(level.owner.student),
256
- level.owner.student.class_field.name,
257
- )
238
+ level_management.save_level(level, data)
258
239
 
259
- elif is_user_teacher:
260
- teacher = level.owner.teacher
240
+ is_user_school_student = (
241
+ hasattr(level.owner, "student") and not level.owner.student.is_independent()
242
+ )
243
+ is_user_independent = (
244
+ hasattr(level.owner, "student") and level.owner.student.is_independent()
245
+ )
246
+ is_user_teacher = hasattr(level.owner, "teacher")
261
247
 
262
- # if level owner is a teacher or an indy user, approval isn't needed
263
- if not is_user_school_student:
264
- level.needs_approval = False
248
+ # when level is created
249
+ if levelId is None:
250
+ teacher = None
265
251
 
266
- # share with all admins of the school if user is in a school
267
- if not is_user_independent:
268
- if not teacher.school is None:
269
- school_admins = teacher.school.admins()
252
+ # if level owner is a school student, share with teacher automatically if they aren't an admin
253
+ if is_user_school_student:
254
+ teacher = level.owner.student.class_field.teacher
255
+ if not teacher.is_admin:
256
+ level.shared_with.add(teacher.new_user)
257
+
258
+ if not data["anonymous"]:
259
+ level_management.email_new_custom_level(
260
+ teacher.new_user.email,
261
+ request.build_absolute_uri(reverse("level_moderation")),
262
+ request.build_absolute_uri(
263
+ reverse("play_custom_level", kwargs={"levelId": level.id})
264
+ ),
265
+ str(level.owner.student),
266
+ level.owner.student.class_field.name,
267
+ )
270
268
 
271
- [
272
- level.shared_with.add(school_admin.new_user)
273
- for school_admin in school_admins
274
- if school_admin.new_user != request.user
275
- ]
269
+ elif is_user_teacher:
270
+ teacher = level.owner.teacher
276
271
 
277
- # anytime a student edits their level
278
- if is_user_school_student:
279
- if not level.needs_approval:
280
- level.needs_approval = True
281
-
282
- if not data["anonymous"]:
283
- level_management.email_new_custom_level(
284
- level.owner.student.class_field.teacher.new_user.email,
285
- request.build_absolute_uri(reverse("level_moderation")),
286
- request.build_absolute_uri(
287
- reverse("play_custom_level", kwargs={"levelId": level.id})
288
- ),
289
- str(level.owner.student),
290
- level.owner.student.class_field.name,
291
- )
272
+ # if level owner is a teacher or an indy user, approval isn't needed
273
+ if not is_user_school_student:
274
+ level.needs_approval = False
292
275
 
293
- level.save()
294
- response = {"id": level.id}
295
- return HttpResponse(json.dumps(response), content_type="application/json")
296
- else:
297
- return HttpResponseUnauthorized()
276
+ # share with all admins of the school if user is in a school
277
+ if not is_user_independent:
278
+ if not teacher.school is None:
279
+ school_admins = teacher.school.admins()
280
+
281
+ [
282
+ level.shared_with.add(school_admin.new_user)
283
+ for school_admin in school_admins
284
+ if school_admin.new_user != request.user
285
+ ]
286
+
287
+ # anytime a student edits their level
288
+ if is_user_school_student:
289
+ if not level.needs_approval:
290
+ level.needs_approval = True
291
+
292
+ if not data["anonymous"]:
293
+ level_management.email_new_custom_level(
294
+ level.owner.student.class_field.teacher.new_user.email,
295
+ request.build_absolute_uri(reverse("level_moderation")),
296
+ request.build_absolute_uri(
297
+ reverse("play_custom_level", kwargs={"levelId": level.id})
298
+ ),
299
+ str(level.owner.student),
300
+ level.owner.student.class_field.name,
301
+ )
302
+
303
+ level.save()
304
+ response = {"id": level.id}
305
+ return HttpResponse(json.dumps(response), content_type="application/json")
298
306
 
299
307
 
300
308
  @transaction.atomic
@@ -397,9 +405,11 @@ class SharingInformationForEditor(APIView):
397
405
  )
398
406
  valid_recipients["classes"].append(
399
407
  {
400
- "name": f"{class_.name} ({app_tags.make_into_username(class_.teacher.new_user)})"
401
- if teacher.is_admin
402
- else class_.name,
408
+ "name": (
409
+ f"{class_.name} ({app_tags.make_into_username(class_.teacher.new_user)})"
410
+ if teacher.is_admin
411
+ else class_.name
412
+ ),
403
413
  "id": class_.id,
404
414
  "students": [
405
415
  {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rapid-router
3
- Version: 7.5.10
3
+ Version: 7.5.12
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Framework :: Django
@@ -8,11 +8,11 @@ License-File: LICENSE.md
8
8
  Requires-Dist: asgiref==3.8.1; python_version >= "3.8"
9
9
  Requires-Dist: asttokens==3.0.0; python_version >= "3.8"
10
10
  Requires-Dist: certifi==2025.4.26; python_version >= "3.6"
11
- Requires-Dist: cfl-common==8.7.1
11
+ Requires-Dist: cfl-common==8.7.3
12
12
  Requires-Dist: charset-normalizer==3.4.2; python_version >= "3.7"
13
13
  Requires-Dist: decorator==5.2.1; python_version >= "3.8"
14
14
  Requires-Dist: diff-match-patch==20241021; python_version >= "3.7"
15
- Requires-Dist: django==5.1.9; python_version >= "3.10"
15
+ Requires-Dist: django==5.1.10; python_version >= "3.10"
16
16
  Requires-Dist: django-countries==7.6.1
17
17
  Requires-Dist: django-csp==3.8
18
18
  Requires-Dist: django-formtools==2.5.1; python_version >= "3.8"
@@ -25,14 +25,14 @@ Requires-Dist: django-two-factor-auth==1.17.0; python_version >= "3.8"
25
25
  Requires-Dist: djangorestframework==3.16.0; python_version >= "3.9"
26
26
  Requires-Dist: executing==2.2.0; python_version >= "3.8"
27
27
  Requires-Dist: idna==3.10; python_version >= "3.6"
28
- Requires-Dist: ipython==9.2.0; python_version >= "3.11"
28
+ Requires-Dist: ipython==9.3.0; python_version >= "3.11"
29
29
  Requires-Dist: ipython-pygments-lexers==1.1.1; python_version >= "3.8"
30
30
  Requires-Dist: jedi==0.19.2; python_version >= "3.6"
31
31
  Requires-Dist: libsass==0.23.0; python_version >= "3.8"
32
32
  Requires-Dist: matplotlib-inline==0.1.7; python_version >= "3.8"
33
33
  Requires-Dist: more-itertools==8.7.0; python_version >= "3.5"
34
- Requires-Dist: numpy==2.2.5; python_version >= "3.10"
35
- Requires-Dist: pandas==2.2.3; python_version >= "3.9"
34
+ Requires-Dist: numpy==2.2.6; python_version >= "3.10"
35
+ Requires-Dist: pandas==2.3.0; python_version >= "3.9"
36
36
  Requires-Dist: parso==0.8.4; python_version >= "3.6"
37
37
  Requires-Dist: pexpect==4.9.0; sys_platform != "win32" and sys_platform != "emscripten"
38
38
  Requires-Dist: pgeocode==0.4.0; python_version >= "3.8"
@@ -43,17 +43,17 @@ Requires-Dist: pygments==2.19.1; python_version >= "3.8"
43
43
  Requires-Dist: pyhamcrest==2.0.2; python_version >= "3.5"
44
44
  Requires-Dist: pyjwt==2.6.0; python_version >= "3.7"
45
45
  Requires-Dist: pypng==0.20220715.0
46
- Requires-Dist: python-dateutil==2.9.0.post0; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2"
46
+ Requires-Dist: python-dateutil==2.9.0.post0; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3"
47
47
  Requires-Dist: pytz==2025.2
48
48
  Requires-Dist: qrcode==7.4.2; python_version >= "3.7"
49
49
  Requires-Dist: requests==2.32.3; python_version >= "3.8"
50
- Requires-Dist: setuptools==80.3.1; python_version >= "3.9"
51
- Requires-Dist: six==1.17.0; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2"
50
+ Requires-Dist: setuptools==80.9.0; python_version >= "3.9"
51
+ Requires-Dist: six==1.17.0; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3"
52
52
  Requires-Dist: sqlparse==0.5.3; python_version >= "3.8"
53
53
  Requires-Dist: stack-data==0.6.3
54
54
  Requires-Dist: tablib==3.7.0; python_version >= "3.9"
55
55
  Requires-Dist: traitlets==5.14.3; python_version >= "3.8"
56
- Requires-Dist: typing-extensions==4.13.2; python_version >= "3.8"
56
+ Requires-Dist: typing-extensions==4.14.0; python_version >= "3.9"
57
57
  Requires-Dist: tzdata==2025.2; python_version >= "2"
58
58
  Requires-Dist: urllib3==2.4.0; python_version >= "3.9"
59
59
  Requires-Dist: wcwidth==0.2.13
@@ -63,13 +63,13 @@ Requires-Dist: asgiref==3.8.1; python_version >= "3.8" and extra == "dev"
63
63
  Requires-Dist: attrs==25.3.0; python_version >= "3.8" and extra == "dev"
64
64
  Requires-Dist: black==25.1.0; python_version >= "3.9" and extra == "dev"
65
65
  Requires-Dist: certifi==2025.4.26; python_version >= "3.6" and extra == "dev"
66
- Requires-Dist: cfl-common==8.7.1; extra == "dev"
66
+ Requires-Dist: cfl-common==8.7.3; extra == "dev"
67
67
  Requires-Dist: chardet==5.2.0; python_version >= "3.7" and extra == "dev"
68
68
  Requires-Dist: charset-normalizer==3.4.2; python_version >= "3.7" and extra == "dev"
69
69
  Requires-Dist: click==8.2.1; python_version >= "3.10" and extra == "dev"
70
- Requires-Dist: codeforlife-portal==8.7.1; extra == "dev"
70
+ Requires-Dist: codeforlife-portal==8.7.3; extra == "dev"
71
71
  Requires-Dist: diff-match-patch==20241021; python_version >= "3.7" and extra == "dev"
72
- Requires-Dist: django==5.1.9; python_version >= "3.10" and extra == "dev"
72
+ Requires-Dist: django==5.1.10; python_version >= "3.10" and extra == "dev"
73
73
  Requires-Dist: django-classy-tags==4.1.0; python_version >= "3.8" and extra == "dev"
74
74
  Requires-Dist: django-countries==7.6.1; extra == "dev"
75
75
  Requires-Dist: django-csp==3.8; extra == "dev"
@@ -96,45 +96,46 @@ Requires-Dist: isort==6.0.1; python_full_version >= "3.9.0" and extra == "dev"
96
96
  Requires-Dist: libsass==0.23.0; python_version >= "3.8" and extra == "dev"
97
97
  Requires-Dist: more-itertools==8.7.0; python_version >= "3.5" and extra == "dev"
98
98
  Requires-Dist: mypy-extensions==1.1.0; python_version >= "3.8" and extra == "dev"
99
- Requires-Dist: numpy==2.2.5; python_version >= "3.10" and extra == "dev"
99
+ Requires-Dist: numpy==2.2.6; python_version >= "3.10" and extra == "dev"
100
100
  Requires-Dist: outcome==1.3.0.post0; python_version >= "3.7" and extra == "dev"
101
101
  Requires-Dist: packaging==25.0; python_version >= "3.8" and extra == "dev"
102
- Requires-Dist: pandas==2.2.3; python_version >= "3.9" and extra == "dev"
102
+ Requires-Dist: pandas==2.3.0; python_version >= "3.9" and extra == "dev"
103
103
  Requires-Dist: pathspec==0.12.1; python_version >= "3.8" and extra == "dev"
104
104
  Requires-Dist: pgeocode==0.4.0; python_version >= "3.8" and extra == "dev"
105
105
  Requires-Dist: phonenumbers==8.12.12; extra == "dev"
106
106
  Requires-Dist: pillow==11.2.1; python_version >= "3.9" and extra == "dev"
107
107
  Requires-Dist: platformdirs==4.3.8; python_version >= "3.9" and extra == "dev"
108
108
  Requires-Dist: pluggy==1.6.0; python_version >= "3.9" and extra == "dev"
109
+ Requires-Dist: pygments==2.19.1; python_version >= "3.8" and extra == "dev"
109
110
  Requires-Dist: pyjwt==2.6.0; python_version >= "3.7" and extra == "dev"
110
111
  Requires-Dist: pypng==0.20220715.0; extra == "dev"
111
112
  Requires-Dist: pysocks==1.7.1; extra == "dev"
112
- Requires-Dist: pytest==8.3.5; python_version >= "3.8" and extra == "dev"
113
+ Requires-Dist: pytest==8.4.0; python_version >= "3.9" and extra == "dev"
113
114
  Requires-Dist: pytest-django==4.8.0; python_version >= "3.8" and extra == "dev"
114
115
  Requires-Dist: pytest-order==1.3.0; python_version >= "3.7" and extra == "dev"
115
116
  Requires-Dist: pytest-xdist==3.7.0; python_version >= "3.9" and extra == "dev"
116
- Requires-Dist: python-dateutil==2.9.0.post0; (python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2") and extra == "dev"
117
+ Requires-Dist: python-dateutil==2.9.0.post0; (python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3") and extra == "dev"
117
118
  Requires-Dist: pytz==2025.2; extra == "dev"
118
119
  Requires-Dist: pyyaml==6.0.2; python_version >= "3.8" and extra == "dev"
119
120
  Requires-Dist: qrcode==7.4.2; python_version >= "3.7" and extra == "dev"
120
121
  Requires-Dist: reportlab==4.2.5; (python_version >= "3.7" and python_version < "4") and extra == "dev"
121
122
  Requires-Dist: requests==2.32.3; python_version >= "3.8" and extra == "dev"
122
123
  Requires-Dist: selenium==4.29.0; python_version >= "3.9" and extra == "dev"
123
- Requires-Dist: setuptools==80.3.1; python_version >= "3.9" and extra == "dev"
124
- Requires-Dist: six==1.17.0; (python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2") and extra == "dev"
124
+ Requires-Dist: setuptools==80.9.0; python_version >= "3.9" and extra == "dev"
125
+ Requires-Dist: six==1.17.0; (python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3") and extra == "dev"
125
126
  Requires-Dist: sniffio==1.3.1; python_version >= "3.7" and extra == "dev"
126
127
  Requires-Dist: sortedcontainers==2.4.0; extra == "dev"
127
128
  Requires-Dist: sqlparse==0.5.3; python_version >= "3.8" and extra == "dev"
128
129
  Requires-Dist: tablib==3.7.0; python_version >= "3.9" and extra == "dev"
129
130
  Requires-Dist: trio==0.30.0; python_version >= "3.9" and extra == "dev"
130
131
  Requires-Dist: trio-websocket==0.12.2; python_version >= "3.8" and extra == "dev"
131
- Requires-Dist: typing-extensions==4.13.2; python_version >= "3.8" and extra == "dev"
132
+ Requires-Dist: typing-extensions==4.14.0; python_version >= "3.9" and extra == "dev"
132
133
  Requires-Dist: tzdata==2025.2; python_version >= "2" and extra == "dev"
133
134
  Requires-Dist: urllib3==2.4.0; python_version >= "3.9" and extra == "dev"
134
135
  Requires-Dist: websocket-client==1.8.0; python_version >= "3.8" and extra == "dev"
135
136
  Requires-Dist: wheel==0.45.1; python_version >= "3.8" and extra == "dev"
136
137
  Requires-Dist: wsproto==1.2.0; python_full_version >= "3.7.0" and extra == "dev"
137
- Requires-Dist: zipp==3.21.0; python_version >= "3.9" and extra == "dev"
138
+ Requires-Dist: zipp==3.22.0; python_version >= "3.9" and extra == "dev"
138
139
  Dynamic: classifier
139
140
  Dynamic: license-file
140
141
  Dynamic: provides-extra
@@ -3,7 +3,7 @@ example_project/rapid_router_test_settings.py,sha256=3PPkhCEztAn-WGLQ-Bf2hA5n1q_
3
3
  example_project/settings.py,sha256=-Lsw_DJow_LaKaTE4DNfY69o3cclXUHNoWNybPBHIqY,4333
4
4
  example_project/urls.py,sha256=XHug_cpNy21yOef3E1-wWT5VkTuxpl6ZXIlCj6jDjWA,422
5
5
  example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
6
- game/__init__.py,sha256=F_qKRkryDfrCkcPV55mU0KLe6QhfXJyH9Rfx4Yg-Uu0,23
6
+ game/__init__.py,sha256=pFUKWsutX3VUz-kNRAZXm5PflBdJ7dAo_wTAJT9qHdM,23
7
7
  game/admin.py,sha256=BLwwaqQYuqmMdwqnvhdan19iGxdcoBX4CXFk_ROG5-M,1431
8
8
  game/app_settings.py,sha256=mlg-1AiP7AR5JNOHAXXLuCrYWaZMmSihvSYk9c2c8YY,857
9
9
  game/cache.py,sha256=dtOiFl6Z4I2Q9-8Hz24ZI-5C0asXYSQhF2Be5q74N8g,2227
@@ -774,7 +774,7 @@ game/templatetags/game/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
774
774
  game/templatetags/game/utils.py,sha256=quMDcxpoi998hHiOH6CtoxITgpVPo4iWeINFk5AHFPU,406
775
775
  game/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
776
776
  game/tests/test_api.py,sha256=RI2PBnSD2dOGmCdXgH8SsoHuBSRJzUv8zBA3Hzb_ASU,5688
777
- game/tests/test_level_editor.py,sha256=sMTbCUfxjT84fDlxJMS9dIzOIST0f8yKF_JT0FMGv8I,19565
777
+ game/tests/test_level_editor.py,sha256=ttUMFpfpJp1Vc90X15v2i6AOItvPTwnA1BeuZ3sj9m8,20767
778
778
  game/tests/test_level_moderation.py,sha256=OcU8nx0Ih4FCR9b_tp0w4n6zWVdJ3gzftz6fa0iz67U,7057
779
779
  game/tests/test_level_selection.py,sha256=IbrIPKDozvQ-05JAmLxHw9DsTfTwTBF2VJQPU8dn2XI,11800
780
780
  game/tests/test_models.py,sha256=L1F5yHtVdDmVuhw7uGDBiOOTYi9rgZVIjzd248-eqLc,2592
@@ -794,14 +794,14 @@ game/views/api.py,sha256=j5Qwabpj0x9oJJ5iHhgGKeJ1RcHZgR5-eg3VGHPCyjE,8994
794
794
  game/views/helper.py,sha256=SR11w5rpshwSvC7v5dDFazTrH-Vpn9gOe93OLpwrVlE,548
795
795
  game/views/language_code_conversions.py,sha256=oaBqaPd5n1a4XmD1UWacpKrFYZ8Gk6CDII9sTrLDQDM,2590
796
796
  game/views/level.py,sha256=8Z5ZXnspK5Bnhy8-BeVt_Evf2JSSrRklGO7Fw3W78BA,16887
797
- game/views/level_editor.py,sha256=uvR-cYxb6zWUEN2kH6ZfmcaFEb6XilgARFKyRMsyIq4,18130
797
+ game/views/level_editor.py,sha256=qJlHPs85hFCJoXrkwql37UduGs0MKxpAtwm5EpzEwi0,18227
798
798
  game/views/level_moderation.py,sha256=GwnvXlHRxGNjgjr3pcCCmnxCHEX4UCJlsGw2VA6rncA,5303
799
799
  game/views/level_selection.py,sha256=UI345nDv5iTRQ7VttiLKLzezJlaSlaKOnhlALZgMU9Q,9896
800
800
  game/views/level_solutions.py,sha256=lfwLFvw4gFuptTkL2J_ibhnuiysl3Yao15sn2qoQlcE,97194
801
801
  game/views/scoreboard.py,sha256=Lxy7XtoG7VwWpTb-c22BGC6eN8uCmmOnQ2qjY-oXA3k,16914
802
802
  game/views/scoreboard_csv.py,sha256=yx4tOwx5QsHyU1S1BUPUqRBWIh5idq8QVtBID-NqZto,1768
803
- rapid_router-7.5.10.dist-info/licenses/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
804
- rapid_router-7.5.10.dist-info/METADATA,sha256=2kIZfP3y8ldHXPMmau6dSPSI9P5kGK29lwDXRzWK31s,9111
805
- rapid_router-7.5.10.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
806
- rapid_router-7.5.10.dist-info/top_level.txt,sha256=rKP4ryr1t8Wcnx8grJHDViM3T5cMYH_0vygDjC04ArA,21
807
- rapid_router-7.5.10.dist-info/RECORD,,
803
+ rapid_router-7.5.12.dist-info/licenses/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
804
+ rapid_router-7.5.12.dist-info/METADATA,sha256=k3d-4OlAyJnh6YOk_Z4lfUmSSKwfTzjgGMlV3KMydHQ,9209
805
+ rapid_router-7.5.12.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
806
+ rapid_router-7.5.12.dist-info/top_level.txt,sha256=rKP4ryr1t8Wcnx8grJHDViM3T5cMYH_0vygDjC04ArA,21
807
+ rapid_router-7.5.12.dist-info/RECORD,,