rbx.cp 0.5.50__py3-none-any.whl → 0.5.51__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.
@@ -0,0 +1,336 @@
1
+ import os
2
+ import pathlib
3
+ import tempfile
4
+ from typing import Any, Dict, Optional
5
+
6
+ import rich
7
+ import rich.progress
8
+ import typer
9
+
10
+ from rbx import console
11
+ from rbx.box import header, package
12
+ from rbx.box.generators import get_all_built_testcases
13
+ from rbx.box.packaging.polygon import polygon_api as api
14
+ from rbx.box.packaging.polygon.packager import code_to_langs, is_valid_lang_code
15
+ from rbx.box.schema import CodeItem, ExpectedOutcome, Solution, TaskType, Testcase
16
+ from rbx.box.statements.build_statements import get_relative_assets
17
+ from rbx.box.statements.builders import (
18
+ StatementBlocks,
19
+ StatementBuilderProblem,
20
+ render_jinja_blocks,
21
+ )
22
+ from rbx.box.statements.schema import Statement, StatementType
23
+ from rbx.box.testcase_utils import get_alternate_interaction_texts, parse_interaction
24
+
25
+ _API_URL = 'https://polygon.codeforces.com/api'
26
+
27
+ POLY = api.Polygon(
28
+ _API_URL,
29
+ os.environ.get('POLYGON_API_KEY', '').strip(),
30
+ os.environ.get('POLYGON_API_SECRET', '').strip(),
31
+ )
32
+
33
+
34
+ def _get_source_type(code: CodeItem):
35
+ return None
36
+
37
+
38
+ def _get_solution_tag(solution: Solution, is_first: bool = False) -> api.SolutionTag:
39
+ if solution.outcome == ExpectedOutcome.ACCEPTED:
40
+ return api.SolutionTag.OK if not is_first else api.SolutionTag.MA
41
+ if solution.outcome == ExpectedOutcome.ACCEPTED_OR_TLE:
42
+ return api.SolutionTag.TO
43
+ if solution.outcome == ExpectedOutcome.WRONG_ANSWER:
44
+ return api.SolutionTag.WA
45
+ if solution.outcome == ExpectedOutcome.TIME_LIMIT_EXCEEDED:
46
+ return api.SolutionTag.TL
47
+ if solution.outcome == ExpectedOutcome.MEMORY_LIMIT_EXCEEDED:
48
+ return api.SolutionTag.ML
49
+ if solution.outcome == ExpectedOutcome.RUNTIME_ERROR:
50
+ return api.SolutionTag.RE
51
+ return api.SolutionTag.RJ
52
+
53
+
54
+ def _find_or_create_problem(problem_name: str) -> api.Problem:
55
+ results = POLY.problems_list(name=problem_name)
56
+ for result in results:
57
+ if result.name == problem_name:
58
+ console.console.print(
59
+ f'Found already existing problem [item]{problem_name}[/item].'
60
+ )
61
+ return result
62
+ console.console.print(f'Creating new problem [item]{problem_name}[/item].')
63
+ return POLY.problem_create(problem_name)
64
+
65
+
66
+ def _update_problem_info(problem: api.Problem):
67
+ pkg = package.find_problem_package_or_die()
68
+
69
+ problem.update_info(
70
+ api.ProblemInfo(
71
+ interactive=pkg.type == TaskType.COMMUNICATION,
72
+ time_limit=pkg.timeLimit,
73
+ memory_limit=pkg.memoryLimit,
74
+ )
75
+ )
76
+
77
+
78
+ def _get_checker_name() -> str:
79
+ checker = package.get_checker()
80
+ return checker.path.with_stem('checker').name
81
+
82
+
83
+ def _get_interactor_name() -> str:
84
+ interactor = package.get_interactor()
85
+ return interactor.path.with_stem('interactor').name
86
+
87
+
88
+ def _get_validator_name() -> str:
89
+ validator = package.get_validator()
90
+ return validator.path.with_stem('validator').name
91
+
92
+
93
+ def _update_rbx_header(problem: api.Problem):
94
+ console.console.print('Uploading rbx.h...')
95
+ rbx_header = header.get_header()
96
+ problem.save_file(
97
+ type=api.FileType.RESOURCE,
98
+ name='rbx.h',
99
+ file=rbx_header.read_bytes(),
100
+ source_type=None,
101
+ )
102
+
103
+
104
+ def _update_checker(problem: api.Problem):
105
+ console.console.print('Uploading checker...')
106
+ checker = package.get_checker()
107
+ problem.save_file(
108
+ type=api.FileType.SOURCE,
109
+ name=_get_checker_name(),
110
+ file=checker.path.read_bytes(),
111
+ source_type=_get_source_type(checker),
112
+ )
113
+
114
+ problem.set_checker(_get_checker_name())
115
+
116
+
117
+ def _update_interactor(problem: api.Problem):
118
+ console.console.print('Uploading interactor...')
119
+ interactor = package.get_interactor()
120
+ problem.save_file(
121
+ type=api.FileType.SOURCE,
122
+ name=_get_interactor_name(),
123
+ file=interactor.path.read_bytes(),
124
+ source_type=_get_source_type(interactor),
125
+ )
126
+
127
+ problem.set_interactor(_get_interactor_name())
128
+
129
+
130
+ def _upload_validator(problem: api.Problem):
131
+ console.console.print('Uploading validator...')
132
+ validator = package.get_validator()
133
+ problem.save_file(
134
+ type=api.FileType.SOURCE,
135
+ name=_get_validator_name(),
136
+ file=validator.path.read_bytes(),
137
+ source_type=_get_source_type(validator),
138
+ )
139
+
140
+ problem.set_validator(_get_validator_name())
141
+
142
+
143
+ def _save_skip_coinciding_testcases(problem: api.Problem, *args, **kwargs) -> bool:
144
+ try:
145
+ problem.save_test(*args, **kwargs)
146
+ except api.PolygonRequestFailedException as e:
147
+ if 'test coincides with' in e.comment.lower():
148
+ return False
149
+ raise
150
+ return True
151
+
152
+
153
+ def _get_test_params_for_statement(
154
+ testcase: Testcase, is_sample: bool
155
+ ) -> Dict[str, Any]:
156
+ if not is_sample:
157
+ return {}
158
+ res: Dict[str, Any] = {'test_use_in_statements': True}
159
+ if testcase.outputPath is not None:
160
+ res['test_output_for_statements'] = testcase.outputPath.read_text()
161
+ else:
162
+ return res
163
+
164
+ pio_path = testcase.outputPath.with_suffix('.pio')
165
+ if pio_path.is_file():
166
+ interaction = parse_interaction(pio_path)
167
+ res['test_input_for_statements'], res['test_output_for_statements'] = (
168
+ get_alternate_interaction_texts(interaction)
169
+ )
170
+ else:
171
+ pin_path = testcase.outputPath.with_suffix('.pin')
172
+ if pin_path.is_file():
173
+ res['test_input_for_statements'] = pin_path.read_text()
174
+ pout_path = testcase.outputPath.with_suffix('.pout')
175
+ if pout_path.is_file():
176
+ res['test_output_for_statements'] = pout_path.read_text()
177
+ return res
178
+
179
+
180
+ def _upload_testcases(problem: api.Problem):
181
+ pkg = package.find_problem_package_or_die()
182
+ testcases = get_all_built_testcases()
183
+ i = 0
184
+
185
+ with rich.progress.Progress(speed_estimate_period=5) as progress:
186
+ total_len = 0
187
+ for group in pkg.testcases:
188
+ total_len += len(testcases[group.name])
189
+ task_id = progress.add_task('Uploading testcases...', total=total_len)
190
+ for group in pkg.testcases:
191
+ for testcase in testcases[group.name]:
192
+ is_sample = group.name == 'samples'
193
+ saved = _save_skip_coinciding_testcases(
194
+ problem,
195
+ testset='tests',
196
+ test_index=i + 1,
197
+ test_input=testcase.inputPath.read_text(),
198
+ **_get_test_params_for_statement(testcase, is_sample),
199
+ )
200
+ progress.update(task_id, advance=1)
201
+ if saved:
202
+ i += 1
203
+
204
+
205
+ def _upload_solutions(problem: api.Problem):
206
+ console.console.print('Uploading main solution...')
207
+ pkg = package.find_problem_package_or_die()
208
+ main_solution = pkg.solutions[0]
209
+ if main_solution is None or main_solution.outcome != ExpectedOutcome.ACCEPTED:
210
+ return
211
+ problem.save_solution(
212
+ main_solution.path.name,
213
+ main_solution.path.read_bytes(),
214
+ source_type=_get_source_type(main_solution),
215
+ tag=api.SolutionTag.MA,
216
+ )
217
+
218
+ for i, solution in enumerate(pkg.solutions):
219
+ console.console.print(
220
+ f'Uploading solution [item]{solution.path.name}[/item] (tag: [item]{_get_solution_tag(solution, is_first=i == 0)}[/item])...'
221
+ )
222
+ problem.save_solution(
223
+ solution.path.name,
224
+ solution.path.read_bytes(),
225
+ source_type=_get_source_type(solution),
226
+ tag=_get_solution_tag(solution, is_first=i == 0),
227
+ )
228
+
229
+
230
+ def _get_statement_for_language(language: str) -> Optional[Statement]:
231
+ pkg = package.find_problem_package_or_die()
232
+ for statement in pkg.statements:
233
+ if statement.language == language:
234
+ return statement
235
+ return None
236
+
237
+
238
+ def _get_statement_blocks(statement: Statement) -> StatementBlocks:
239
+ # TODO: actually try to convert to rbxTeX
240
+ assert statement.type == StatementType.rbxTeX
241
+ builder_problem = StatementBuilderProblem(
242
+ package=package.find_problem_package_or_die(),
243
+ statement=statement,
244
+ )
245
+ with tempfile.TemporaryDirectory() as temp_dir:
246
+ return render_jinja_blocks(
247
+ pathlib.Path(temp_dir),
248
+ statement.path.read_bytes(),
249
+ **builder_problem.build_inner_jinja_kwargs(),
250
+ )
251
+
252
+
253
+ def _upload_statement_resources(problem: api.Problem, statement: Statement):
254
+ assets = get_relative_assets(statement.path, statement.assets)
255
+ for asset, relative_asset in assets:
256
+ console.console.print(
257
+ f'Uploading statement resource [item]{relative_asset}[/item]...'
258
+ )
259
+ resource_bytes = asset.read_bytes()
260
+ if len(resource_bytes) >= 1024 * 1024: # >= 1mb
261
+ console.console.print(
262
+ f'[error]Statement resource [item]{relative_asset}[/item] is too large to upload (more than 1MB).[/error]'
263
+ )
264
+ raise typer.Exit(1)
265
+ problem.save_statement_resource(
266
+ name=str(relative_asset),
267
+ file=resource_bytes,
268
+ )
269
+
270
+
271
+ def _upload_statement(problem: api.Problem):
272
+ pkg = package.find_problem_package_or_die()
273
+
274
+ languages = set()
275
+ for statement in pkg.statements:
276
+ if not is_valid_lang_code(statement.language):
277
+ continue
278
+ languages.add(statement.language)
279
+ for language in languages:
280
+ statement = _get_statement_for_language(language)
281
+ if statement is None:
282
+ continue
283
+ if statement.type != StatementType.rbxTeX:
284
+ continue
285
+ console.console.print(
286
+ f'Uploading statement for language [item]{language}[/item] (polygon language: [item]{code_to_langs([language])[0]}[/item])...'
287
+ )
288
+ blocks = _get_statement_blocks(statement)
289
+ polygon_statement = api.Statement(
290
+ encoding='utf-8',
291
+ name=statement.title,
292
+ legend=blocks.blocks.get('legend'),
293
+ input=blocks.blocks.get('input'),
294
+ output=blocks.blocks.get('output'),
295
+ interaction=blocks.blocks.get('interaction'),
296
+ notes=blocks.blocks.get('notes'),
297
+ )
298
+ problem.save_statement(
299
+ lang=code_to_langs([language])[0], problem_statement=polygon_statement
300
+ )
301
+
302
+ _upload_statement_resources(problem, statement)
303
+
304
+
305
+ def _normalize_problem_name(name: str) -> str:
306
+ return name.replace(' ', '-').replace('_', '-').lower()
307
+
308
+
309
+ async def upload_problem(name: str):
310
+ pkg = package.find_problem_package_or_die()
311
+ name = _normalize_problem_name(name)
312
+ problem = _find_or_create_problem(name)
313
+ _update_problem_info(problem)
314
+ _update_checker(problem)
315
+ _update_rbx_header(problem)
316
+
317
+ if (
318
+ pkg.type == TaskType.COMMUNICATION
319
+ and package.get_interactor_or_nil() is not None
320
+ ):
321
+ _update_interactor(problem)
322
+
323
+ # if pkg.validator is not None:
324
+ # _upload_validator(problem)
325
+
326
+ _upload_solutions(problem)
327
+ _upload_testcases(problem)
328
+ _upload_statement(problem)
329
+
330
+ # Commit.
331
+ console.console.print('Committing changes...')
332
+ problem.commit_changes()
333
+
334
+ console.console.print(
335
+ f'[success]Problem [item]{name}[/item] uploaded successfully![/success]'
336
+ )
@@ -65,6 +65,10 @@ class Checker(BaseXmlModel):
65
65
  testset: Optional[Testset] = element(default=None)
66
66
 
67
67
 
68
+ class Interactor(BaseXmlModel):
69
+ source: File = element()
70
+
71
+
68
72
  class Problem(BaseXmlModel, tag='problem'):
69
73
  names: List[Name] = wrapped('names', element(tag='name'), default_factory=list)
70
74
 
@@ -84,6 +88,8 @@ class Problem(BaseXmlModel, tag='problem'):
84
88
 
85
89
  checker: Checker = wrapped('assets', element(tag='checker'))
86
90
 
91
+ interactor: Optional[Interactor] = wrapped('assets', element(tag='interactor'))
92
+
87
93
 
88
94
  class ContestProblem(BaseXmlModel):
89
95
  index: str = attr()
rbx/box/solutions.py CHANGED
@@ -889,29 +889,37 @@ def _print_solution_header(
889
889
  console.print(f'({solution_testdir})')
890
890
 
891
891
 
892
+ @dataclasses.dataclass
893
+ class SolutionTiming:
894
+ time: int
895
+ solution: Solution
896
+
897
+
892
898
  @dataclasses.dataclass
893
899
  class TimingSummary:
894
- slowest_good: Optional[int] = None
895
- fastest_slow: Optional[int] = None
900
+ slowest_good: Optional[SolutionTiming] = None
901
+ fastest_slow: Optional[SolutionTiming] = None
896
902
 
897
- def add_good(self, time: int):
898
- if self.slowest_good is None or time > self.slowest_good:
899
- self.slowest_good = time
903
+ def add_good(self, time: int, solution: Solution):
904
+ if self.slowest_good is None or time > self.slowest_good.time:
905
+ self.slowest_good = SolutionTiming(time, solution)
900
906
 
901
- def add_slow(self, time: int):
902
- if self.fastest_slow is None or time < self.fastest_slow:
903
- self.fastest_slow = time
907
+ def add_slow(self, time: int, solution: Solution):
908
+ if self.fastest_slow is None or time < self.fastest_slow.time:
909
+ self.fastest_slow = SolutionTiming(time, solution)
904
910
 
905
911
  def print(self, console: rich.console.Console, tl: Optional[int] = None):
906
912
  if self.slowest_good is not None:
907
913
  console.print(
908
- f'Slowest [success]OK[/success] solution: {self.slowest_good} ms'
914
+ f'Slowest [success]OK[/success] solution: {self.slowest_good.time} ms, [item]{self.slowest_good.solution.path}[/item]'
909
915
  )
910
916
  if self.fastest_slow is not None:
911
- fastest_slow = self.fastest_slow
912
- if tl is not None and self.fastest_slow > tl:
917
+ fastest_slow = self.fastest_slow.time
918
+ if tl is not None and self.fastest_slow.time > tl:
913
919
  fastest_slow = f'>{tl}'
914
- console.print(f'Fastest [error]slow[/error] solution: {fastest_slow} ms')
920
+ console.print(
921
+ f'Fastest [error]slow[/error] solution: {fastest_slow} ms, [item]{self.fastest_slow.solution.path}[/item]'
922
+ )
915
923
 
916
924
 
917
925
  async def _print_timing(
@@ -953,11 +961,11 @@ async def _print_timing(
953
961
 
954
962
  # Get solution timings.
955
963
  if solution.outcome.match(Outcome.ACCEPTED):
956
- summary.add_good(solution_time)
957
- summary_per_language[solution.language].add_good(solution_time)
964
+ summary.add_good(solution_time, solution)
965
+ summary_per_language[solution.language].add_good(solution_time, solution)
958
966
  if solution.outcome.is_slow():
959
- summary.add_slow(solution_time)
960
- summary_per_language[solution.language].add_slow(solution_time)
967
+ summary.add_slow(solution_time, solution)
968
+ summary_per_language[solution.language].add_slow(solution_time, solution)
961
969
 
962
970
  if summary.slowest_good is None and summary.fastest_slow is None:
963
971
  return
rbx/box/testcase_utils.py CHANGED
@@ -213,6 +213,21 @@ def parse_interaction(file: pathlib.Path) -> TestcaseInteraction:
213
213
  )
214
214
 
215
215
 
216
+ def get_alternate_interaction_texts(
217
+ interaction: TestcaseInteraction,
218
+ ) -> Tuple[str, str]:
219
+ interactor_entries = []
220
+ solution_entries = []
221
+ for entry in interaction.entries:
222
+ if entry.pipe == 1:
223
+ solution_entries.append(entry.data)
224
+ interactor_entries.extend(['\n'] * entry.data.count('\n'))
225
+ else:
226
+ interactor_entries.append(entry.data)
227
+ solution_entries.extend(['\n'] * entry.data.count('\n'))
228
+ return ''.join(interactor_entries), ''.join(solution_entries)
229
+
230
+
216
231
  def print_interaction(interaction: TestcaseInteraction):
217
232
  for entry in interaction.entries:
218
233
  text = rich.text.Text(entry.data)
rbx/box/unit.py CHANGED
@@ -103,7 +103,7 @@ async def run_validator_unit_tests(progress: StatusProgress):
103
103
 
104
104
  console.console.rule('Validator tests', style='info')
105
105
  if not entries:
106
- console.console.print(']No validator unit tests found.')
106
+ console.console.print('No validator unit tests found.')
107
107
  return
108
108
 
109
109
  compiled_validators = validators.compile_validators(vals, progress=progress)
@@ -14,11 +14,16 @@ read -r -d '' TestlibContent <<"EOF"
14
14
  {{testlib_content}}
15
15
  EOF
16
16
 
17
+ read -r -d '' RbxHeaderContent <<"EOF"
18
+ {{rbx_header_content}}
19
+ EOF
20
+
17
21
  read -r -d '' CheckerContent <<"EOF"
18
22
  {{checker_content}}
19
23
  EOF
20
24
 
21
25
  printf "%s" "${TestlibContent}" >testlib.h
26
+ printf "%s" "${RbxHeaderContent}" >rbx.h
22
27
  printf "%s" "${CheckerContent}" >$CHECKER_PATH
23
28
 
24
29
  checker_hash=($(md5sum $CHECKER_PATH))
@@ -0,0 +1,90 @@
1
+ #include <optional>
2
+ #include <stdexcept>
3
+ #include <string>
4
+
5
+ #ifndef _RBX_H
6
+ #define _RBX_H
7
+
8
+ std::optional<std::string> getStringVar(std::string name) {
9
+ //<rbx::string_var>
10
+ return std::nullopt;
11
+ }
12
+
13
+ std::optional<int> getIntVar(std::string name) {
14
+ //<rbx::int_var>
15
+ return std::nullopt;
16
+ }
17
+
18
+ std::optional<float> getFloatVar(std::string name) {
19
+ //<rbx::float_var>
20
+ return std::nullopt;
21
+ }
22
+
23
+ std::optional<bool> getBoolVar(std::string name) {
24
+ //<rbx::bool_var>
25
+ return std::nullopt;
26
+ }
27
+
28
+ template <typename T> T getVar(std::string name);
29
+
30
+ template <> int getVar<int>(std::string name) {
31
+ auto opt = getIntVar(name);
32
+ if (!opt.has_value()) {
33
+ throw std::runtime_error("Variable " + name +
34
+ " is not an integer or could not be found");
35
+ }
36
+ return opt.value();
37
+ }
38
+
39
+ template <> float getVar<float>(std::string name) {
40
+ auto opt = getFloatVar(name);
41
+ if (!opt.has_value()) {
42
+ auto intOpt = getIntVar(name);
43
+ if (intOpt.has_value()) {
44
+ opt = (float)intOpt.value();
45
+ }
46
+ }
47
+ if (!opt.has_value()) {
48
+ throw std::runtime_error("Variable " + name +
49
+ " is not a float or could not be found");
50
+ }
51
+ return opt.value();
52
+ }
53
+
54
+ template <> double getVar<double>(std::string name) {
55
+ return getVar<float>(name);
56
+ }
57
+
58
+ template <> std::string getVar<std::string>(std::string name) {
59
+ auto opt = getStringVar(name);
60
+ if (!opt.has_value()) {
61
+ auto intOpt = getIntVar(name);
62
+ if (intOpt.has_value()) {
63
+ opt = std::to_string(intOpt.value());
64
+ }
65
+ }
66
+ if (!opt.has_value()) {
67
+ auto floatOpt = getFloatVar(name);
68
+ if (floatOpt.has_value()) {
69
+ opt = std::to_string(floatOpt.value());
70
+ }
71
+ }
72
+ if (!opt.has_value()) {
73
+ throw std::runtime_error("Variable " + name +
74
+ " is not a string or could not be found");
75
+ }
76
+ return opt.value();
77
+ }
78
+
79
+ template <> bool getVar<bool>(std::string name) {
80
+ auto opt = getBoolVar(name);
81
+ if (!opt.has_value()) {
82
+ opt = getIntVar(name) != 0;
83
+ }
84
+ if (!opt.has_value()) {
85
+ throw std::runtime_error("Variable " + name +
86
+ " is not a boolean or could not be found");
87
+ }
88
+ return opt.value();
89
+ }
90
+ #endif
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.50
3
+ Version: 0.5.51
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9,<4.0
@@ -5,8 +5,8 @@ rbx/box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  rbx/box/builder.py,sha256=MDm2qqmhedAbhn3rWP6cDwbBsGhV6sz_2sg1zLkPDw0,3613
6
6
  rbx/box/cd.py,sha256=9a_SOnzoJBXxxffp4Wbf3UKXIwKuN3Hvj7K6SocALwE,1194
7
7
  rbx/box/checkers.py,sha256=eb4tqtVUJYlme_Vkj2TGkUABM7EMS0P1EswhMYjN7BI,11459
8
- rbx/box/cli.py,sha256=0JeJSVTK_5coijsm1b1zKQzuv7RBgexoM3klDeveabY,26487
9
- rbx/box/code.py,sha256=Cnts7noJaaoM35DZ9xcJAKXLwsKB4oBebMidqmMMO4M,18795
8
+ rbx/box/cli.py,sha256=lGyAa5WrK8h61QWC2OrOWuC8Va0VOZedQnY-_0uOp3k,26703
9
+ rbx/box/code.py,sha256=g2e3PPGQFNRnMBkTuqw3D4nFS8hnvzNCDc4vVSYGugY,18846
10
10
  rbx/box/compile.py,sha256=OJLthDQ921w9vyoE6Gk1Df54i5RwtRJ2YG-8XEfefcs,2489
11
11
  rbx/box/conftest.py,sha256=sEmciXSeDC-wmrZ1JSxbsUenKNP_VWW32mrCun2pY3I,1070
12
12
  rbx/box/contest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -18,26 +18,29 @@ rbx/box/contest/schema.py,sha256=JMAig5WpaOahNgAHxA9vX4zYeVYDxpjKP_PFGvmmkE0,495
18
18
  rbx/box/contest/statements.py,sha256=Or8gFb6P_oViGdeiVgepXsvd_W84mA7LRaVmiAXWWSg,2977
19
19
  rbx/box/creation.py,sha256=Evz7K6JoarD-4JJQsZsgoxU9FgCF9Z7-LfuroG4Cqls,2444
20
20
  rbx/box/deferred.py,sha256=II3X9e87JCOZtmspnHh-n4PFqh-FsH_oc0XJHZ9ZYVQ,691
21
- rbx/box/download.py,sha256=MFP-R26JiYGAP89I0TK-0fYc69Fsd20tsBqgtRCy5AE,2234
21
+ rbx/box/download.py,sha256=DxAiAk4lDYWEz1C9UTvZzHTq6hgm4fxGezApm2IkCTM,2601
22
22
  rbx/box/environment.py,sha256=S-OLvR2_Nac8m923b9AtDhOY3goRJXlPA_I3s7BeDqQ,11162
23
23
  rbx/box/extensions.py,sha256=Von8kIeXvNFTkGlMRMTvL2HIHPwlkuiMswr-ydbGV1w,519
24
24
  rbx/box/formatting.py,sha256=3phFRHzqVXj4Ok1yDhCq6Clbw6KlqwJNpMhs--oTWFI,405
25
25
  rbx/box/generators.py,sha256=5-3K0JSLR9GbV0LmOkvNsWiQaMvhFBrI56ZaV1WgodQ,13472
26
26
  rbx/box/generators_test.py,sha256=J7aBfuJhU84MWDWzgReRoOuQw_hVa09B8gTKAvL2XVo,1987
27
+ rbx/box/header.py,sha256=ifErXcIxG5lM5AyRiHDr7JE401vR4ORNXCNpHXxN_ls,2001
27
28
  rbx/box/lazy_importing_main.py,sha256=6Z8As7qVFFT619xHH9Xt8VCH57NjC4aDxfAgkWiUwT8,116
28
29
  rbx/box/lazy_importing_test.py,sha256=B0-b3y_DkxEmtVfu4NfmVsgVdFl6kRCsEL6GLMHJISo,628
29
30
  rbx/box/main.py,sha256=Imwc0ZkheOpa5r8S0Xpb8RLQzJgxb9vyuSR4_wab11g,43
30
- rbx/box/naming.py,sha256=n3Nvw2MuWtAjywDxYDV5gg22Upf8Ap1lYavo0o46SRA,612
31
+ rbx/box/naming.py,sha256=OiaiLe0k1sBx4vIXemUqnzfdNte79rrCgOvBze9XaTw,940
31
32
  rbx/box/package.py,sha256=YuX_FS6yKx6FaFz0NF0cx3v6jzhqwvsLr3Oprx_TTJA,13645
32
33
  rbx/box/packaging/boca/extension.py,sha256=EQALNEOv4zVDXSKs_dk11n92y7cBZVn8TogIK683lE0,890
33
- rbx/box/packaging/boca/packager.py,sha256=CUMoQICrkQQBFElmI9SrvXlFFnpwkTiJ9qbOSJOy6AE,12512
34
- rbx/box/packaging/contest_main.py,sha256=nMdgPE4OK_tsnUMdRI1cJwLpgxGrwW_mJjox0oOALWw,2757
35
- rbx/box/packaging/main.py,sha256=WOW0JRYcZRuWOEsfd4AKX5wLqu8Br1TYaEfHjqWmu9Q,3070
36
- rbx/box/packaging/moj/packager.py,sha256=Ro_TO3RVCCRAxNcCio0u42TLfW8FnX9IohMChmGlrvo,8499
34
+ rbx/box/packaging/boca/packager.py,sha256=XPCauwbemjWNNnfIocJ8pxnlsxRjst4wYXJsVDyMQlM,12632
35
+ rbx/box/packaging/contest_main.py,sha256=UsRfIdNmOf0iLUbzgjxzyECfMuCQINstG1SCClGHaUQ,2808
36
+ rbx/box/packaging/main.py,sha256=qltqDncaxtvP3xXyUZGqWampBvh340JJjLru0h8XTPI,3476
37
+ rbx/box/packaging/moj/packager.py,sha256=tk0S0hayPnbGrFQsw1Ht_mYOriRlzYHgrkXLO-0ZknY,8724
37
38
  rbx/box/packaging/packager.py,sha256=da2haC1L9cG30myneMrRIAdGubtid0Xmy38BHKPCZZ4,3633
38
- rbx/box/packaging/polygon/packager.py,sha256=qTGOUckevdOCt_ES63pN3uhmhDl9JuNcZ1XEnGNq-tU,10833
39
+ rbx/box/packaging/polygon/packager.py,sha256=GfZ-Dc2TDKkb3QNnfOy8yxldho2L401Ao06oWg--Gcs,11714
40
+ rbx/box/packaging/polygon/polygon_api.py,sha256=mPKEqiwANJ1nr-JhOgzGMaDhnbljsAgzzPHW6kkf7R4,41016
39
41
  rbx/box/packaging/polygon/test.py,sha256=bgEju5PwudgyfwxXJagm8fM6CJVlWM6l_-2q1V-oKaQ,3069
40
- rbx/box/packaging/polygon/xml_schema.py,sha256=-r24bCeRMGLrGGoT9FIgmqr87xHL-JzrFaR6bztbYtw,2703
42
+ rbx/box/packaging/polygon/upload.py,sha256=2WyEXlfprLUDbq-9AMB5hXOQVvvmsT1-stO60MHrEo0,11182
43
+ rbx/box/packaging/polygon/xml_schema.py,sha256=ZgcLyvxggMUccbTNdzflue5G-FTN2_ZmOGGF7FD0Y5A,2851
41
44
  rbx/box/presets/__init__.py,sha256=BwmjBw8wF8yiZFjCYBjMk-HGMZaRwhlfszbWAj3B0vw,18689
42
45
  rbx/box/presets/fetch.py,sha256=F-BCOlvEBEyDqtOhiDuGPn4EDtA4Bwm-fqHJ7zZGlW8,1975
43
46
  rbx/box/presets/lock_schema.py,sha256=6sRPnyePOC8yy-5WcD5JRZdDJHf8loqbvpQ1IPiOU9s,349
@@ -46,7 +49,7 @@ rbx/box/retries.py,sha256=tRk2K1bXw2xnwkAj2CsktRHTEhw7YKcPxMQTT6mCy-E,4707
46
49
  rbx/box/sanitizers/warning_stack.py,sha256=RI97_GJgdjTKIXY_r0EKp5h0qQQSDSdNDh5K7zINrqs,2861
47
50
  rbx/box/schema.py,sha256=tOQ1tLHqc_5V-UgrzM44aS8ULAkq-IkeErxjLCFVA8I,16778
48
51
  rbx/box/setter_config.py,sha256=s53talhwM6FTGDCcBhY7IlZ6_6mJ3PMp6V4kTtaSs50,4262
49
- rbx/box/solutions.py,sha256=eTMpxIvhU3IUF1gfR_y20o_6NZ4hDtMGhTi4ookG9TY,43766
52
+ rbx/box/solutions.py,sha256=zv6jYdJG8cLFe0rNO3f7pgGYnXQaeECYXOo5CQ90VBs,44155
50
53
  rbx/box/solutions_test.py,sha256=TCowbxBG3SvDlFO5-qtBj_M_HrAHe0IJaI1XwoQ1d00,1718
51
54
  rbx/box/state.py,sha256=MMf3DvfQji0jKEliCHct2Tpp_0epL1tvP8HbHNArQIc,166
52
55
  rbx/box/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -62,7 +65,7 @@ rbx/box/stressing/finder_parser.py,sha256=jXpYNa4FyugzmHi3r96Uv4rU1krRQJc5Ihr9jf
62
65
  rbx/box/stressing/generator_parser.py,sha256=oHZryjR3YohgaSO9WEirQ7b2e-98WgZStF0N99W4Thw,7380
63
66
  rbx/box/tasks.py,sha256=oyWtgZvIEIkVV6e-GcJx7x8Z3T5tIDFBZbp0638sLeY,10036
64
67
  rbx/box/testcase_extractors.py,sha256=T5vCW5qERlqitGrFP6RuITEVr9o8XQozNa4AsxfuV_Y,11871
65
- rbx/box/testcase_utils.py,sha256=Ppg_P1Nq48cuKo1XiIi4b8FZkMW8IBp_4Wf1Yf42YuI,7019
68
+ rbx/box/testcase_utils.py,sha256=31rvCpLi681R6Xm1WpG8HPDOkTtF0bRWa8IsmdWGLCk,7556
66
69
  rbx/box/testcases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
70
  rbx/box/testcases/main.py,sha256=_I7h_obRcpNLRQ6dDJDIE5NAvTyn5nBOhdsBhRA_PvU,5442
68
71
  rbx/box/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -70,7 +73,7 @@ rbx/box/ui/captured_log.py,sha256=ptICDPViVnz-_2NfrcB0SSBXNW5L74zI-vAZNN7kSok,11
70
73
  rbx/box/ui/css/app.tcss,sha256=apd5PkPEvl5jK3kE2qrxPyVED1VnvSsj08QQwzUPwEA,786
71
74
  rbx/box/ui/main.py,sha256=b0rHcBF42W4AOCv7WhtiGf_rUnY0yxpqO5oj3wfR4R4,984
72
75
  rbx/box/ui/run.py,sha256=wMEXrEFdQvMHz2hRKAFIithTnTtaL0kNQZu0jKmb8jI,7060
73
- rbx/box/unit.py,sha256=ySnosNg-b50mJU_9jEpRYm5wiiZxkdhKR9AVQXbtTOE,6478
76
+ rbx/box/unit.py,sha256=PY96t8qnsHLsoJVanbDnrIx-s8Dada9Fj_v375MhvTw,6477
74
77
  rbx/box/validators.py,sha256=oqlNhw7jivbbH5l8g3xwihPRy76AM7MA3G4A8nyI_V0,10416
75
78
  rbx/box/validators_test.py,sha256=WY4Ho-wlsPHc0YNuz0KFVd6KQ9ouuiou3w5_zMOZ4Fs,362
76
79
  rbx/checker.py,sha256=pj1jO3my48ru-qugbER5onccANCjoR0-PaFe3H3VGEY,4118
@@ -111,7 +114,7 @@ rbx/resources/default_setter_config.mac.yml,sha256=i28xwAUDg-kuxx19knCiYkh-NR7Qe
111
114
  rbx/resources/default_setter_config.yml,sha256=oy6fbuQyYaJS2Cw2zcbYcBBGt6138CyB3-bLl45_QqY,1000
112
115
  rbx/resources/envs/default.rbx.yml,sha256=8gl4DXc5mVISx__1libPQfmuHYdW32xjysfqpNESIAo,853
113
116
  rbx/resources/envs/isolate.rbx.yml,sha256=VZAJ-Mu-A5Rt4m0VtMygOXA7eLLvCCmoorv_0acDmXQ,870
114
- rbx/resources/packagers/boca/checker.sh,sha256=sjJBj0IUG3U5pRPMIqiSER8Ktuy8Ff1SAi1GMmLR0GA,1088
117
+ rbx/resources/packagers/boca/checker.sh,sha256=q34ZS2clnctOj_8XPUxUGc-qm0kGgUG9ThDm-WZRz3I,1196
115
118
  rbx/resources/packagers/boca/compare.sh,sha256=a6AmQqwrIq616DHjp_S2l95wO7UiMVy0LQ9EajZKDDk,1201
116
119
  rbx/resources/packagers/boca/compile/c,sha256=lHLvxzkG_he5jmxWrix0WT80ipMWWUZdOgOQMSpj8oo,4507
117
120
  rbx/resources/packagers/boca/compile/cc,sha256=B_18QkUGcjUg6yrTFlTQuMWnHpTWUKPZmFuk7Y0l1VA,4561
@@ -176,6 +179,7 @@ rbx/resources/presets/default/problem/tests/samples/000.in,sha256=w66OEtCJGqjUNj
176
179
  rbx/resources/presets/default/problem/tests/samples/001.in,sha256=P4QInDX87xXoDWu4PVIzUeNW5LtTlUKbMCvJ9uZOPGw,20
177
180
  rbx/resources/presets/default/problem/validator.cpp,sha256=VwZZUVq8GZHB07eOb6AoQirrYttPfTpF6P5m6I9nsLI,333
178
181
  rbx/resources/presets/default/problem/wcmp.cpp,sha256=gbjJe3Vf9-YzHCEqBUq30aI3jMZXhqBDn3jjecYOn-w,902
182
+ rbx/resources/templates/rbx.h,sha256=7v-dm4cwP6trsJR-Ixk3_JNfaG1dwM_Lm8FcVPaA0YA,2180
179
183
  rbx/resources/templates/template.cpp,sha256=xXWpWo7fa7HfmPNqkmHcmv3i46Wm0ZL-gPmkRfGvLn4,317
180
184
  rbx/run.py,sha256=8WsEAdj7FwYSc9itfJ977n5HN5CYN63T__HRYI6IB1A,1515
181
185
  rbx/schema.py,sha256=qcxuuxUJ0KwHR03CEYvdoP1SYW7yes3QyuI_0lnVMl0,1494
@@ -188,8 +192,8 @@ rbx/testcase.py,sha256=yKOq3CAJZ1YTmInvnoIs0u1iJnRj_X85XiWbLI-p9d8,1951
188
192
  rbx/testcase_rendering.py,sha256=nfmv6dSEqd4aR3TsaODwkKGK6AXty_DDKtWf_ejiQpI,2084
189
193
  rbx/testing_utils.py,sha256=ZXMysGXpTtvS1lfLL38FuD5iSIyxi3ARjQePDrUmEtc,2067
190
194
  rbx/utils.py,sha256=6e1eXRzNE-52D0UVtqclePxqR4Haiqt8qWCrSVjnGuE,4585
191
- rbx_cp-0.5.50.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
192
- rbx_cp-0.5.50.dist-info/METADATA,sha256=ScwTLSdZ7ISYKsmPKdWkq1hT0AOfAm25GBzQT9c4u-E,3261
193
- rbx_cp-0.5.50.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
194
- rbx_cp-0.5.50.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
195
- rbx_cp-0.5.50.dist-info/RECORD,,
195
+ rbx_cp-0.5.51.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
196
+ rbx_cp-0.5.51.dist-info/METADATA,sha256=wALvGgPfDA7gajXxA98TcHv67w54c_zWxRH7uXIMo_4,3261
197
+ rbx_cp-0.5.51.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
198
+ rbx_cp-0.5.51.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
199
+ rbx_cp-0.5.51.dist-info/RECORD,,