xcpcio 0.63.6__py3-none-any.whl → 0.63.7__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.

Potentially problematic release.


This version of xcpcio might be problematic. Click here for more details.

@@ -5,14 +5,14 @@ Business logic layer for Contest API operations.
5
5
  Handles file reading, data validation, and business operations.
6
6
  """
7
7
 
8
+ import bisect
8
9
  import json
10
+ from collections import defaultdict
9
11
  from pathlib import Path
10
12
  from typing import Any, Dict, List, Optional, Union
11
13
 
12
14
  from fastapi import HTTPException
13
15
 
14
- from xcpcio.__version__ import __version__
15
-
16
16
 
17
17
  class ContestService:
18
18
  """Service class for contest-related operations"""
@@ -31,26 +31,61 @@ class ContestService:
31
31
  # Initialize data indexes for faster lookups
32
32
  self._load_indexes()
33
33
 
34
+ def _create_index_by_id(self, data: List[Dict[str, Any]], id_name: str) -> Dict[str, List[Dict]]:
35
+ res = defaultdict(list)
36
+ for item in data:
37
+ res[item[id_name]].append(item)
38
+ return res
39
+
34
40
  def _load_indexes(self) -> None:
35
41
  """Load and index commonly accessed data for faster lookups"""
36
- # Load contest data
37
- self.contest_data = self.load_json_file("contest.json")
42
+ self.access = self.load_json_file("access.json")
43
+
44
+ self.accounts = self.load_json_file("accounts.json")
45
+ self.accounts_by_id = {account["id"] for account in self.accounts}
46
+
47
+ self.api_info = self.load_json_file("api.json")
48
+
49
+ self.awards = self.load_json_file("awards.json")
50
+ self.awards_by_id = {award["id"] for award in self.awards}
51
+
52
+ self.clarifications = self.load_json_file("clarifications.json")
53
+ self.clarifications_by_id = {clarification["id"] for clarification in self.clarifications}
54
+
55
+ self.contest = self.load_json_file("contest.json")
56
+ self.contest_state = self.load_json_file("state.json")
57
+
58
+ self.groups = self.load_json_file("groups.json")
59
+ self.groups_by_id = {group["id"]: group for group in self.groups}
60
+
61
+ self.judgement_types = self.load_json_file("judgement-types.json")
62
+ self.judgement_types_by_id = {judgement_type["id"] for judgement_type in self.judgement_types}
63
+
64
+ self.judgements = self.load_json_file("judgements.json")
65
+ self.judgements_by_id = {judgement["id"] for judgement in self.judgements}
66
+ self.judgements_by_submission_id = self._create_index_by_id(self.judgements, "submission_id")
67
+
68
+ self.languages = self.load_json_file("languages.json")
69
+ self.languages_by_id = {language["id"] for language in self.languages}
38
70
 
39
- # Load organizations and create index
40
- organizations_data = self.load_json_file("organizations.json")
41
- self.organizations_by_id = {org["id"]: org for org in organizations_data}
71
+ self.organizations = self.load_json_file("organizations.json")
72
+ self.organizations_by_id = {org["id"]: org for org in self.organizations}
42
73
 
43
- # Load teams and create index
44
- teams_data = self.load_json_file("teams.json")
45
- self.teams_by_id = {team["id"]: team for team in teams_data}
74
+ self.problems = self.load_json_file("problems.json")
75
+ self.problems_by_id = {problem["id"]: problem for problem in self.problems}
46
76
 
47
- # Load problems and create index
48
- problems_data = self.load_json_file("problems.json")
49
- self.problems_by_id = {problem["id"]: problem for problem in problems_data}
77
+ self.runs = self.load_json_file("runs.json")
78
+ self.runs_by_id = {run["id"] for run in self.runs}
79
+ self.runs_by_judgement_id = self._create_index_by_id(self.runs, "judgement_id")
50
80
 
51
- # Load submissions and create index
52
- submissions_data = self.load_json_file("submissions.json")
53
- self.submissions_by_id = {submission["id"]: submission for submission in submissions_data}
81
+ self.submissions = self.load_json_file("submissions.json")
82
+ self.submissions_by_id = {submission["id"]: submission for submission in self.submissions}
83
+
84
+ self.teams = self.load_json_file("teams.json")
85
+ self.teams_by_id = {team["id"]: team for team in self.teams}
86
+
87
+ self.event_feed = self.load_ndjson_file("event-feed.ndjson")
88
+ self.event_feed_tokens = [event["token"] for event in self.event_feed]
54
89
 
55
90
  def load_json_file(self, filepath: str) -> Union[Dict[str, Any], List[Any]]:
56
91
  """
@@ -65,6 +100,7 @@ class ContestService:
65
100
  Raises:
66
101
  HTTPException: If file not found or invalid JSON
67
102
  """
103
+
68
104
  full_path = self.contest_package_dir / filepath
69
105
  try:
70
106
  with open(full_path, "r", encoding="utf-8") as f:
@@ -74,6 +110,19 @@ class ContestService:
74
110
  except json.JSONDecodeError as e:
75
111
  raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filepath}: {e}")
76
112
 
113
+ def load_ndjson_file(self, filepath: str) -> List[Dict[str, Any]]:
114
+ full_path = self.contest_package_dir / filepath
115
+ try:
116
+ data = list()
117
+ with open(full_path, "r", encoding="utf-8") as f:
118
+ for line in f.readlines():
119
+ data.append(json.loads(line))
120
+ return data
121
+ except FileNotFoundError:
122
+ raise HTTPException(status_code=404, detail=f"File not found: {filepath}")
123
+ except json.JSONDecodeError as e:
124
+ raise HTTPException(status_code=500, detail=f"Invalid JSON in file {filepath}: {e}")
125
+
77
126
  def get_contest_id(self) -> str:
78
127
  """
79
128
  Get contest ID from contest.json.
@@ -100,309 +149,177 @@ class ContestService:
100
149
 
101
150
  # API Information
102
151
  def get_api_info(self) -> Dict[str, Any]:
103
- """Get API information"""
104
- return {
105
- "version": "2023-06",
106
- "version_url": "https://ccs-specs.icpc.io/2023-06/contest_api",
107
- "name": "XCPCIO",
108
- "provider": {
109
- "name": "XCPCIO",
110
- "version": __version__,
111
- },
112
- }
113
-
114
- def get_access_info(self, contest_id: str) -> Dict[str, Any]:
115
- """Get access information for current client"""
152
+ return self.api_info
153
+
154
+ def get_access(self, contest_id: str) -> Dict[str, Any]:
155
+ self.validate_contest_id(contest_id)
156
+ return self.access
157
+
158
+ # Account operations
159
+ def get_accounts(self, contest_id: str) -> List[Dict[str, Any]]:
160
+ self.validate_contest_id(contest_id)
161
+ return self.accounts
162
+
163
+ def get_account(self, contest_id: str, account_id: str) -> Dict[str, Any]:
116
164
  self.validate_contest_id(contest_id)
117
- return {
118
- "capabilities": [],
119
- "endpoints": [
120
- {
121
- "type": "contest",
122
- "properties": [
123
- "id",
124
- "name",
125
- "formal_name",
126
- "start_time",
127
- "duration",
128
- "scoreboard_type",
129
- "penalty_time",
130
- ],
131
- },
132
- {
133
- "type": "problems",
134
- "properties": ["id", "label", "name", "ordinal", "color", "rgb", "time_limit", "test_data_count"],
135
- },
136
- {"type": "teams", "properties": ["id", "name", "label", "organization_id", "group_ids", "hidden"]},
137
- {"type": "organizations", "properties": ["id", "name", "formal_name"]},
138
- {"type": "groups", "properties": ["id", "name"]},
139
- {"type": "judgement-types", "properties": ["id", "name", "penalty", "solved"]},
140
- {"type": "languages", "properties": ["id", "name", "extensions"]},
141
- {
142
- "type": "state",
143
- "properties": ["started", "ended", "frozen", "thawed", "finalized", "end_of_updates"],
144
- },
145
- {
146
- "type": "submissions",
147
- "properties": ["id", "team_id", "problem_id", "language_id", "time", "contest_time"],
148
- },
149
- {
150
- "type": "judgements",
151
- "properties": ["id", "submission_id", "judgement_type_id", "start_time", "start_contest_time"],
152
- },
153
- {
154
- "type": "runs",
155
- "properties": [
156
- "id",
157
- "judgement_id",
158
- "ordinal",
159
- "judgement_type_id",
160
- "time",
161
- "contest_time",
162
- "run_time",
163
- ],
164
- },
165
- {
166
- "type": "clarifications",
167
- "properties": ["id", "from_team_id", "to_team_id", "problem_id", "text", "time", "contest_time"],
168
- },
169
- {"type": "awards", "properties": ["id", "citation", "team_ids"]},
170
- ],
171
- }
165
+ if account_id not in self.accounts_by_id:
166
+ raise HTTPException(status_code=404, detail=f"Account {account_id} not found")
167
+ return self.accounts_by_id[account_id]
172
168
 
173
169
  # Contest operations
174
170
  def get_contests(self) -> List[Dict[str, Any]]:
175
- """Get all contests"""
176
- contest_data = self.load_json_file("contest.json")
177
- return [contest_data]
171
+ return [self.contest]
178
172
 
179
173
  def get_contest(self, contest_id: str) -> Dict[str, Any]:
180
- """Get specific contest"""
181
174
  self.validate_contest_id(contest_id)
182
- return self.load_json_file("contest.json")
175
+ return self.contest
183
176
 
184
177
  def get_contest_state(self, contest_id: str) -> Dict[str, Any]:
185
- """Get contest state"""
186
178
  self.validate_contest_id(contest_id)
187
- return self.load_json_file("state.json")
179
+ return self.contest_state
188
180
 
189
181
  # Problem operations
190
182
  def get_problems(self, contest_id: str) -> List[Dict[str, Any]]:
191
- """Get all problems"""
192
183
  self.validate_contest_id(contest_id)
193
- return self.load_json_file("problems.json")
184
+ return self.problems
194
185
 
195
186
  def get_problem(self, contest_id: str, problem_id: str) -> Dict[str, Any]:
196
- """Get specific problem"""
197
187
  self.validate_contest_id(contest_id)
198
- problems = self.load_json_file("problems.json")
199
- for problem in problems:
200
- if problem["id"] == problem_id:
201
- return problem
202
- raise HTTPException(status_code=404, detail=f"Problem {problem_id} not found")
188
+ if problem_id not in self.problems_by_id:
189
+ raise HTTPException(status_code=404, detail=f"Problem {problem_id} not found")
190
+ return self.problems_by_id[problem_id]
203
191
 
204
192
  # Team operations
205
- def get_teams(self, contest_id: str, group_id: Optional[str] = None) -> List[Dict[str, Any]]:
206
- """Get all teams, optionally filtered by group"""
193
+ def get_teams(self, contest_id: str) -> List[Dict[str, Any]]:
207
194
  self.validate_contest_id(contest_id)
208
- teams = self.load_json_file("teams.json")
209
-
210
- if group_id:
211
- filtered_teams = []
212
- for team in teams:
213
- if group_id in team.get("group_ids", []):
214
- filtered_teams.append(team)
215
- return filtered_teams
216
-
217
- return teams
195
+ return self.teams
218
196
 
219
197
  def get_team(self, contest_id: str, team_id: str) -> Dict[str, Any]:
220
- """Get specific team"""
221
198
  self.validate_contest_id(contest_id)
222
- teams = self.load_json_file("teams.json")
223
- for team in teams:
224
- if team["id"] == team_id:
225
- return team
226
- raise HTTPException(status_code=404, detail=f"Team {team_id} not found")
199
+ if team_id not in self.teams_by_id:
200
+ raise HTTPException(status_code=404, detail=f"Team {team_id} not found")
201
+ return self.teams_by_id[team_id]
227
202
 
228
203
  # Organization operations
229
204
  def get_organizations(self, contest_id: str) -> List[Dict[str, Any]]:
230
- """Get all organizations"""
231
205
  self.validate_contest_id(contest_id)
232
- return self.load_json_file("organizations.json")
206
+ return self.organizations
233
207
 
234
208
  def get_organization(self, contest_id: str, organization_id: str) -> Dict[str, Any]:
235
- """Get specific organization"""
236
209
  self.validate_contest_id(contest_id)
237
- organizations = self.load_json_file("organizations.json")
238
- for org in organizations:
239
- if org["id"] == organization_id:
240
- return org
241
- raise HTTPException(status_code=404, detail=f"Organization {organization_id} not found")
210
+ if organization_id not in self.organizations_by_id:
211
+ raise HTTPException(status_code=404, detail=f"Organization {organization_id} not found")
212
+ return self.organizations_by_id[organization_id]
242
213
 
243
214
  # Group operations
244
215
  def get_groups(self, contest_id: str) -> List[Dict[str, Any]]:
245
- """Get all groups"""
246
216
  self.validate_contest_id(contest_id)
247
- return self.load_json_file("groups.json")
217
+ return self.groups
248
218
 
249
219
  def get_group(self, contest_id: str, group_id: str) -> Dict[str, Any]:
250
- """Get specific group"""
251
220
  self.validate_contest_id(contest_id)
252
- groups = self.load_json_file("groups.json")
253
- for group in groups:
254
- if group["id"] == group_id:
255
- return group
256
- raise HTTPException(status_code=404, detail=f"Group {group_id} not found")
221
+ if group_id not in self.groups_by_id:
222
+ raise HTTPException(status_code=404, detail=f"Group {group_id} not found")
223
+ return self.groups_by_id[group_id]
257
224
 
258
225
  # Language operations
259
226
  def get_languages(self, contest_id: str) -> List[Dict[str, Any]]:
260
- """Get all languages"""
261
227
  self.validate_contest_id(contest_id)
262
- return self.load_json_file("languages.json")
228
+ return self.languages
263
229
 
264
230
  def get_language(self, contest_id: str, language_id: str) -> Dict[str, Any]:
265
- """Get specific language"""
266
231
  self.validate_contest_id(contest_id)
267
- languages = self.load_json_file("languages.json")
268
- for lang in languages:
269
- if lang["id"] == language_id:
270
- return lang
271
- raise HTTPException(status_code=404, detail=f"Language {language_id} not found")
232
+ if language_id not in self.languages_by_id:
233
+ raise HTTPException(status_code=404, detail=f"Language {language_id} not found")
234
+ return self.languages_by_id[language_id]
272
235
 
273
236
  # Judgement type operations
274
237
  def get_judgement_types(self, contest_id: str) -> List[Dict[str, Any]]:
275
- """Get all judgement types"""
276
238
  self.validate_contest_id(contest_id)
277
- return self.load_json_file("judgement-types.json")
239
+ return self.judgement_types
278
240
 
279
241
  def get_judgement_type(self, contest_id: str, judgement_type_id: str) -> Dict[str, Any]:
280
- """Get specific judgement type"""
281
242
  self.validate_contest_id(contest_id)
282
- judgement_types = self.load_json_file("judgement-types.json")
283
- for jt in judgement_types:
284
- if jt["id"] == judgement_type_id:
285
- return jt
286
- raise HTTPException(status_code=404, detail=f"Judgement type {judgement_type_id} not found")
243
+ if judgement_type_id not in self.judgement_types_by_id:
244
+ raise HTTPException(status_code=404, detail=f"Judgement type {judgement_type_id} not found")
245
+ return self.judgement_types_by_id[judgement_type_id]
287
246
 
288
247
  # Submission operations
289
- def get_submissions(
290
- self, contest_id: str, team_id: Optional[str] = None, problem_id: Optional[str] = None
291
- ) -> List[Dict[str, Any]]:
292
- """Get all submissions, optionally filtered"""
248
+ def get_submissions(self, contest_id: str) -> List[Dict[str, Any]]:
293
249
  self.validate_contest_id(contest_id)
294
- submissions = self.load_json_file("submissions.json")
295
-
296
- # Apply filters
297
- if team_id:
298
- submissions = [s for s in submissions if s.get("team_id") == team_id]
299
- if problem_id:
300
- submissions = [s for s in submissions if s.get("problem_id") == problem_id]
301
-
302
- return submissions
250
+ return self.submissions
303
251
 
304
252
  def get_submission(self, contest_id: str, submission_id: str) -> Dict[str, Any]:
305
- """Get specific submission"""
306
253
  self.validate_contest_id(contest_id)
307
- submissions = self.load_json_file("submissions.json")
308
- for submission in submissions:
309
- if submission["id"] == submission_id:
310
- return submission
311
- raise HTTPException(status_code=404, detail=f"Submission {submission_id} not found")
254
+ if submission_id not in self.submissions_by_id:
255
+ raise HTTPException(status_code=404, detail=f"Submission {submission_id} not found")
256
+ return self.submissions_by_id[submission_id]
312
257
 
313
258
  # Judgement operations
314
259
  def get_judgements(self, contest_id: str, submission_id: Optional[str] = None) -> List[Dict[str, Any]]:
315
- """Get all judgements, optionally filtered by submission"""
316
260
  self.validate_contest_id(contest_id)
317
- judgements = self.load_json_file("judgements.json")
318
261
 
319
- if submission_id:
320
- judgements = [j for j in judgements if j.get("submission_id") == submission_id]
262
+ if submission_id is not None:
263
+ if submission_id not in self.judgements_by_submission_id:
264
+ raise HTTPException(status_code=404, detail=f"Submission id not found: {submission_id}")
265
+ return self.judgements_by_submission_id[submission_id]
321
266
 
322
- return judgements
267
+ return self.judgements
323
268
 
324
269
  def get_judgement(self, contest_id: str, judgement_id: str) -> Dict[str, Any]:
325
- """Get specific judgement"""
326
270
  self.validate_contest_id(contest_id)
327
- judgements = self.load_json_file("judgements.json")
328
- for judgement in judgements:
329
- if judgement["id"] == judgement_id:
330
- return judgement
331
- raise HTTPException(status_code=404, detail=f"Judgement {judgement_id} not found")
271
+ if judgement_id not in self.judgements_by_id:
272
+ raise HTTPException(status_code=404, detail=f"Judgement {judgement_id} not found")
273
+ return self.judgements_by_id[judgement_id]
332
274
 
333
275
  # Run operations
334
276
  def get_runs(self, contest_id: str, judgement_id: Optional[str] = None) -> List[Dict[str, Any]]:
335
- """Get all runs, optionally filtered by judgement"""
336
277
  self.validate_contest_id(contest_id)
337
- runs = self.load_json_file("runs.json")
338
278
 
339
- if judgement_id:
340
- runs = [r for r in runs if r.get("judgement_id") == judgement_id]
279
+ if judgement_id is not None:
280
+ if judgement_id not in self.runs_by_judgement_id:
281
+ raise HTTPException(status_code=404, detail=f"Judgement id not found: {judgement_id}")
282
+ return self.runs_by_judgement_id[judgement_id]
341
283
 
342
- return runs
284
+ return self.runs
343
285
 
344
286
  def get_run(self, contest_id: str, run_id: str) -> Dict[str, Any]:
345
- """Get specific run"""
346
287
  self.validate_contest_id(contest_id)
347
- runs = self.load_json_file("runs.json")
348
- for run in runs:
349
- if run["id"] == run_id:
350
- return run
351
- raise HTTPException(status_code=404, detail=f"Run {run_id} not found")
288
+ if run_id not in self.runs_by_id:
289
+ raise HTTPException(status_code=404, detail=f"Run {run_id} not found")
290
+ return self.runs_by_id[run_id]
352
291
 
353
292
  # Clarification operations
354
293
  def get_clarifications(
355
294
  self,
356
295
  contest_id: str,
357
- from_team_id: Optional[str] = None,
358
- to_team_id: Optional[str] = None,
359
- problem_id: Optional[str] = None,
360
296
  ) -> List[Dict[str, Any]]:
361
- """Get all clarifications, optionally filtered"""
362
297
  self.validate_contest_id(contest_id)
363
- clarifications = self.load_json_file("clarifications.json")
364
-
365
- # Apply filters (empty string means null)
366
- if from_team_id is not None:
367
- if from_team_id == "":
368
- clarifications = [c for c in clarifications if c.get("from_team_id") is None]
369
- else:
370
- clarifications = [c for c in clarifications if c.get("from_team_id") == from_team_id]
371
-
372
- if to_team_id is not None:
373
- if to_team_id == "":
374
- clarifications = [c for c in clarifications if c.get("to_team_id") is None]
375
- else:
376
- clarifications = [c for c in clarifications if c.get("to_team_id") == to_team_id]
377
-
378
- if problem_id is not None:
379
- if problem_id == "":
380
- clarifications = [c for c in clarifications if c.get("problem_id") is None]
381
- else:
382
- clarifications = [c for c in clarifications if c.get("problem_id") == problem_id]
383
-
384
- return clarifications
298
+ return self.clarifications
385
299
 
386
300
  def get_clarification(self, contest_id: str, clarification_id: str) -> Dict[str, Any]:
387
- """Get specific clarification"""
388
301
  self.validate_contest_id(contest_id)
389
- clarifications = self.load_json_file("clarifications.json")
390
- for clarification in clarifications:
391
- if clarification["id"] == clarification_id:
392
- return clarification
393
- raise HTTPException(status_code=404, detail=f"Clarification {clarification_id} not found")
302
+ if clarification_id not in self.clarifications_by_id:
303
+ raise HTTPException(status_code=404, detail=f"Clarification {clarification_id} not found")
304
+ return self.clarifications_by_id[clarification_id]
394
305
 
395
306
  # Award operations
396
307
  def get_awards(self, contest_id: str) -> List[Dict[str, Any]]:
397
- """Get all awards"""
398
308
  self.validate_contest_id(contest_id)
399
- return self.load_json_file("awards.json")
309
+ return self.awards
400
310
 
401
311
  def get_award(self, contest_id: str, award_id: str) -> Dict[str, Any]:
402
- """Get specific award"""
403
312
  self.validate_contest_id(contest_id)
404
- awards = self.load_json_file("awards.json")
405
- for award in awards:
406
- if award["id"] == award_id:
407
- return award
408
- raise HTTPException(status_code=404, detail=f"Award {award_id} not found")
313
+ if award_id not in self.awards_by_id:
314
+ raise HTTPException(status_code=404, detail=f"Award {award_id} not found")
315
+ return self.awards_by_id[award_id]
316
+
317
+ # Event Feed operations
318
+ def get_event_feed(self, contest_id: str, since_token: Optional[str] = None) -> List[Dict[str, Any]]:
319
+ self.validate_contest_id(contest_id)
320
+
321
+ if since_token is None:
322
+ return self.event_feed
323
+
324
+ idx = bisect.bisect_left(self.event_feed_tokens, since_token)
325
+ return self.event_feed[idx:]
@@ -59,7 +59,6 @@ class ContestArchiver:
59
59
 
60
60
  # Known endpoints that can be fetched
61
61
  KNOWN_ENDPOINTS = [
62
- "access",
63
62
  "contests",
64
63
  "judgement-types",
65
64
  "languages",
@@ -80,7 +79,6 @@ class ContestArchiver:
80
79
  ]
81
80
 
82
81
  DOMJUDGE_KNOWN_ENDPOINTS = [
83
- "access",
84
82
  "contests",
85
83
  "judgement-types",
86
84
  "languages",
@@ -289,7 +287,7 @@ class ContestArchiver:
289
287
 
290
288
  data = await self.fetch_json("/")
291
289
  if not data:
292
- raise RuntimeError("Failed to fetch API information from root endpoint")
290
+ raise RuntimeError("Failed to fetch API information")
293
291
 
294
292
  self._api_info = data # Store API info for later use
295
293
 
@@ -401,6 +399,7 @@ class ContestArchiver:
401
399
  # Always dump API and contest info
402
400
  await self.dump_api_info()
403
401
  await self.dump_contest_info()
402
+ await self.dump_endpoint_single("access")
404
403
 
405
404
  # Get list of endpoints to dump
406
405
  if self._config.endpoints:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xcpcio
3
- Version: 0.63.6
3
+ Version: 0.63.7
4
4
  Summary: xcpcio python lib
5
5
  Project-URL: homepage, https://github.com/xcpcio/xcpcio
6
6
  Project-URL: documentation, https://github.com/xcpcio/xcpcio
@@ -0,0 +1,34 @@
1
+ xcpcio/__init__.py,sha256=kjd6itqBRSQ-OT83qUJXHt81KQQDRUtaIuykzfaWXLM,121
2
+ xcpcio/__version__.py,sha256=95oCDxj_oHcOcxQzEfotvdWgY-p_3xsHZ2AaFTYVdR4,172
3
+ xcpcio/constants.py,sha256=MjpAgNXiBlUsx1S09m7JNT-nekNDR-aE6ggvGL3fg0I,2297
4
+ xcpcio/types.py,sha256=AkYby2haJgxwtozlgaPMG2ryAZdvsSc3sH-p6qXcM4g,6575
5
+ xcpcio/ccs/__init__.py,sha256=LSoKFblEuSoIVBYcUxOFF8fn2bH2R6kSg9xNrBfzC0g,99
6
+ xcpcio/ccs/contest_archiver.py,sha256=ICogyPzKfFRoO7J5D2Eu-3JwIirC3etMev7hyTjn4z8,16198
7
+ xcpcio/ccs/api_server/__init__.py,sha256=ASvVJ_ibGkXFDSNmy05eb9gESXRS8hjYHCrBecSnaS0,174
8
+ xcpcio/ccs/api_server/dependencies.py,sha256=5nosGVwY-3Mq7eK9C5ZOMEJFozzzw_kLlpCraFbJ9wY,1225
9
+ xcpcio/ccs/api_server/server.py,sha256=3gft3MqDXvKWug5UCLhdV681bcQMRrewDkwQ7qSPtRU,2598
10
+ xcpcio/ccs/api_server/routes/__init__.py,sha256=uz65H4L5Wzef7QPi5PsLQM1xbMdG6FoZ0Np0y039_2k,1537
11
+ xcpcio/ccs/api_server/routes/access.py,sha256=O-RGLmgLNBQ-ccu8rlHOgonTjl02fYOdi3VTsUa-T0w,434
12
+ xcpcio/ccs/api_server/routes/accounts.py,sha256=nAwiIz-y4fGmqHBniMuQifk9jVt4i9YPZWBB7w40q5Q,994
13
+ xcpcio/ccs/api_server/routes/awards.py,sha256=gBPSFlDj6PM6Poys6JbO7VMsfCljKz6QrTjKEqQcS8w,957
14
+ xcpcio/ccs/api_server/routes/clarifications.py,sha256=vvMNMvQkZTOn1VJ8C5U86gpIkN3yNrxBll1VMTJjzQg,1046
15
+ xcpcio/ccs/api_server/routes/contests.py,sha256=o-A5wMDy5UC9wM71K3ruMmP4p4lSoU9B3XmDGPV0M7g,4203
16
+ xcpcio/ccs/api_server/routes/general.py,sha256=xLH-sqyeC4dSd6SUYpjg-w-1ZtmSqZAgIupoVOyYwD4,763
17
+ xcpcio/ccs/api_server/routes/groups.py,sha256=kWKFFty2iWckMN-j6G3NbgMVKCPQ478_mYKrYsHXgMA,949
18
+ xcpcio/ccs/api_server/routes/judgement_types.py,sha256=S3Dt0VYjntVBQBvLYhJGcDNSy7O8Zh7b7NSfrronZSU,1057
19
+ xcpcio/ccs/api_server/routes/judgements.py,sha256=3w0LHYbZazli_v587l98U23r5PuolRs_vtbNLMwgjTU,1127
20
+ xcpcio/ccs/api_server/routes/languages.py,sha256=2BYqTaSBWx0E5XlaTjofElLb7z4HTsVs3rrozdyqz0s,985
21
+ xcpcio/ccs/api_server/routes/organizations.py,sha256=608tPsK2bCUmqSalEFysC1zQf3FDDIeweT6PLLrOyLg,2515
22
+ xcpcio/ccs/api_server/routes/problems.py,sha256=2YFw_ODw-6L015UgpL1p-lLItgCgnqDamni6_9Qmbdk,2458
23
+ xcpcio/ccs/api_server/routes/runs.py,sha256=1L6fo1KPcDeKwOEkTxCwEetmyfNKY_Z0uxATqBJftIs,1046
24
+ xcpcio/ccs/api_server/routes/submissions.py,sha256=UKgDt9yv45Hfpr8P_8-2Po0jF4HvzG87zgkcb1YIKVc,2542
25
+ xcpcio/ccs/api_server/routes/teams.py,sha256=9nWz0tvMnccCNEzSN9DY-ZJtxlgaka9YSPe_5Gykbl8,2282
26
+ xcpcio/ccs/api_server/services/__init__.py,sha256=WQLNrLVomhtICl8HlFYaCoRewIHVZfUiiwrSBUOOWDg,171
27
+ xcpcio/ccs/api_server/services/contest_service.py,sha256=rMbAm7HVw5dHMTwp1tLAP0QhlCKlEMWQ65LZLZzjbfg,13210
28
+ xcpcio/ccs/model/__init__.py,sha256=cZE1q5JY-iHDEKZpsx0UZaMhH-23H4oAHaYOkW7dZ5s,43
29
+ xcpcio/ccs/model/model_2023_06/__init__.py,sha256=OmDQZqmigBpL64LXk5lIOGoQ3Uqis8-2z6qQpOO5aJc,167
30
+ xcpcio/ccs/model/model_2023_06/model.py,sha256=bVMDWpJTwPSpz1fHPxWrWerxCBIboH3LKVZpIZGQ2pY,15287
31
+ xcpcio-0.63.7.dist-info/METADATA,sha256=oWlZ8fA8EO1Ly_wvo8JUlxbeDmlV7PVKPKum4ydxzDk,1079
32
+ xcpcio-0.63.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
+ xcpcio-0.63.7.dist-info/entry_points.txt,sha256=qvzh8oDJxIHqTN-rg2lRN6xR99AqxbWnlAQI7uzDibI,59
34
+ xcpcio-0.63.7.dist-info/RECORD,,
@@ -1,33 +0,0 @@
1
- xcpcio/__init__.py,sha256=kjd6itqBRSQ-OT83qUJXHt81KQQDRUtaIuykzfaWXLM,121
2
- xcpcio/__version__.py,sha256=rmZgql2iMibrRXQ70oij5TmONsjXyGZIxE3EUzW1_1E,172
3
- xcpcio/constants.py,sha256=MjpAgNXiBlUsx1S09m7JNT-nekNDR-aE6ggvGL3fg0I,2297
4
- xcpcio/types.py,sha256=AkYby2haJgxwtozlgaPMG2ryAZdvsSc3sH-p6qXcM4g,6575
5
- xcpcio/ccs/__init__.py,sha256=LSoKFblEuSoIVBYcUxOFF8fn2bH2R6kSg9xNrBfzC0g,99
6
- xcpcio/ccs/contest_archiver.py,sha256=FKpUn1IGfa-UNf63OJ5eff7rxOEqXCvFYRLsvkMbUJc,16203
7
- xcpcio/ccs/api_server/__init__.py,sha256=ASvVJ_ibGkXFDSNmy05eb9gESXRS8hjYHCrBecSnaS0,174
8
- xcpcio/ccs/api_server/dependencies.py,sha256=5nosGVwY-3Mq7eK9C5ZOMEJFozzzw_kLlpCraFbJ9wY,1225
9
- xcpcio/ccs/api_server/server.py,sha256=3gft3MqDXvKWug5UCLhdV681bcQMRrewDkwQ7qSPtRU,2598
10
- xcpcio/ccs/api_server/routes/__init__.py,sha256=imTyDjc9Md3OIr7GniHi3i1vmfzSTKppuUjVREtd8b4,1461
11
- xcpcio/ccs/api_server/routes/access.py,sha256=8f21NmvVLaFopb5q4MnifOHbhadDZuNHr0BIYc9nmqY,579
12
- xcpcio/ccs/api_server/routes/awards.py,sha256=uj56ty2k7N5KXfQuWTvvTXSa7HO29CUfEhO8S85hlM0,1069
13
- xcpcio/ccs/api_server/routes/clarifications.py,sha256=JX7FNbv_4mRdpuV0aSzGwjjmW-4SwTbmAOlm51MNpf4,1644
14
- xcpcio/ccs/api_server/routes/contests.py,sha256=bJeMaGegei59rD-5YE0ptYcNsPdJqc73KnntRpShzZk,2560
15
- xcpcio/ccs/api_server/routes/general.py,sha256=9WsnjlomsU13vvozOVHSRIzgReuLGzPln3xwDb8i-gY,933
16
- xcpcio/ccs/api_server/routes/groups.py,sha256=8hOT_2rz329M_7hcfggRxLU-g8aV2xp6w3aMYlfOPNs,1087
17
- xcpcio/ccs/api_server/routes/judgement_types.py,sha256=pMOFBQ1LqKhCTLNBGzopCOEmTnWsuVg67dTuItJaCsM,1268
18
- xcpcio/ccs/api_server/routes/judgements.py,sha256=9GMaEkD8erhqaSItlZQdLzKz-1XL7MD2SQinnD_CZFg,1339
19
- xcpcio/ccs/api_server/routes/languages.py,sha256=DUNRd3q_Hm5F8-3nCiAMpqqxzG_9zcU5_N8ACefqjOE,1176
20
- xcpcio/ccs/api_server/routes/organizations.py,sha256=fWnKTCmxd3c1leYsRuJHuuTs0CZr-l_-Jl-8_wY_Ojk,2889
21
- xcpcio/ccs/api_server/routes/problems.py,sha256=0Ba3fz09UfTGYmYYYJYFGmIpgIvJaa1Fg-5pcLcxEMY,2774
22
- xcpcio/ccs/api_server/routes/runs.py,sha256=uBPeM5ChI3LxR__pBSyDxsbcE4NyL6eKVdvF4TEOk5g,1248
23
- xcpcio/ccs/api_server/routes/submissions.py,sha256=81-KbQLUKCqgGE-aCTO7-Pg2QyTJc_Mu_Ys8N0oF1tU,3161
24
- xcpcio/ccs/api_server/routes/teams.py,sha256=y_aJykzgewmOQtXOJe2s0s7DQmnKjD3805Q5VTcdlIQ,2725
25
- xcpcio/ccs/api_server/services/__init__.py,sha256=WQLNrLVomhtICl8HlFYaCoRewIHVZfUiiwrSBUOOWDg,171
26
- xcpcio/ccs/api_server/services/contest_service.py,sha256=EbSDrkVg18Th9kAuYAin4InHCOI7hWkkDJR1u1xlEtk,16186
27
- xcpcio/ccs/model/__init__.py,sha256=cZE1q5JY-iHDEKZpsx0UZaMhH-23H4oAHaYOkW7dZ5s,43
28
- xcpcio/ccs/model/model_2023_06/__init__.py,sha256=OmDQZqmigBpL64LXk5lIOGoQ3Uqis8-2z6qQpOO5aJc,167
29
- xcpcio/ccs/model/model_2023_06/model.py,sha256=bVMDWpJTwPSpz1fHPxWrWerxCBIboH3LKVZpIZGQ2pY,15287
30
- xcpcio-0.63.6.dist-info/METADATA,sha256=uEBCmgoTkMCCrO-zLZGdzDjhYb9n51mabFs4lwEV0II,1079
31
- xcpcio-0.63.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
32
- xcpcio-0.63.6.dist-info/entry_points.txt,sha256=qvzh8oDJxIHqTN-rg2lRN6xR99AqxbWnlAQI7uzDibI,59
33
- xcpcio-0.63.6.dist-info/RECORD,,