rbx.cp 0.11.1__py3-none-any.whl → 0.12.0__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.
- rbx/box/builder.py +3 -3
- rbx/box/contest/build_contest_statements.py +19 -2
- rbx/box/contest/statements.py +1 -16
- rbx/box/generators.py +54 -12
- rbx/box/package.py +56 -4
- rbx/box/packaging/polygon/upload.py +2 -3
- rbx/box/schema.py +3 -3
- rbx/box/solutions.py +8 -12
- rbx/box/statements/build_statements.py +0 -1
- rbx/box/statements/latex.py +11 -0
- rbx/grading/caching.py +1 -0
- rbx/grading/judge/sandbox.py +1 -0
- rbx/grading/steps.py +1 -0
- rbx/resources/presets/default/contest/.gitignore +15 -0
- rbx/resources/presets/default/contest/contest.rbx.yml +2 -2
- rbx/resources/presets/default/problem/.gitignore +15 -0
- rbx/resources/presets/default/problem/validator.cpp +2 -1
- rbx/resources/presets/default/shared/icpc.sty +1 -1
- rbx/utils.py +13 -0
- {rbx_cp-0.11.1.dist-info → rbx_cp-0.12.0.dist-info}/METADATA +1 -1
- {rbx_cp-0.11.1.dist-info → rbx_cp-0.12.0.dist-info}/RECORD +24 -24
- {rbx_cp-0.11.1.dist-info → rbx_cp-0.12.0.dist-info}/LICENSE +0 -0
- {rbx_cp-0.11.1.dist-info → rbx_cp-0.12.0.dist-info}/WHEEL +0 -0
- {rbx_cp-0.11.1.dist-info → rbx_cp-0.12.0.dist-info}/entry_points.txt +0 -0
rbx/box/builder.py
CHANGED
@@ -96,10 +96,10 @@ async def verify(verification: environment.VerificationParam) -> bool:
|
|
96
96
|
|
97
97
|
tracked_solutions = None
|
98
98
|
if verification < VerificationLevel.ALL_SOLUTIONS.value:
|
99
|
-
pkg = package.find_problem_package_or_die()
|
100
|
-
|
101
99
|
tracked_solutions = {
|
102
|
-
str(solution.path)
|
100
|
+
str(solution.path)
|
101
|
+
for solution in package.get_solutions()
|
102
|
+
if is_fast(solution)
|
103
103
|
}
|
104
104
|
|
105
105
|
with utils.StatusProgress('Running solutions...') as s:
|
@@ -12,7 +12,7 @@ from rbx.box.contest.contest_package import get_problems
|
|
12
12
|
from rbx.box.contest.schema import Contest, ContestProblem, ContestStatement
|
13
13
|
from rbx.box.formatting import href
|
14
14
|
from rbx.box.schema import Package, Testcase
|
15
|
-
from rbx.box.statements import build_statements
|
15
|
+
from rbx.box.statements import build_statements, latex
|
16
16
|
from rbx.box.statements.build_statements import (
|
17
17
|
get_builders,
|
18
18
|
get_environment_languages_for_statement,
|
@@ -211,8 +211,12 @@ def build_contest_only(
|
|
211
211
|
input_type: StatementType,
|
212
212
|
output_type: Optional[StatementType] = None,
|
213
213
|
custom_vars: Optional[Dict[str, Any]] = None,
|
214
|
+
install_tex: bool = False,
|
214
215
|
) -> Tuple[bytes, StatementType]:
|
215
216
|
console.console.print('Building contest-level statement.')
|
217
|
+
if install_tex:
|
218
|
+
output_type = StatementType.TeX
|
219
|
+
|
216
220
|
bdrs = get_builders(
|
217
221
|
contest.name,
|
218
222
|
statement.steps,
|
@@ -243,6 +247,15 @@ def build_contest_only(
|
|
243
247
|
item=get_statement_builder_contest(statement, extracted_problems),
|
244
248
|
verbose=False,
|
245
249
|
)
|
250
|
+
|
251
|
+
if install_tex and bdr.output_type() == StatementType.TeX:
|
252
|
+
console.console.log(
|
253
|
+
f'Installing LaTeX packages for [item]{statement.name} {statement.language}[/item]...'
|
254
|
+
)
|
255
|
+
tmp_file = pathlib.Path(td) / '__tmp_install__.tex'
|
256
|
+
tmp_file.write_bytes(output)
|
257
|
+
latex.install_tex_packages(tmp_file, pathlib.Path(td))
|
258
|
+
|
246
259
|
last_content = output
|
247
260
|
last_output = bdr.output_type()
|
248
261
|
|
@@ -256,6 +269,7 @@ def build_statement_rooted(
|
|
256
269
|
output_type: Optional[StatementType] = None,
|
257
270
|
use_samples: bool = True,
|
258
271
|
custom_vars: Optional[Dict[str, Any]] = None,
|
272
|
+
install_tex: bool = False,
|
259
273
|
) -> Tuple[bytes, StatementType]:
|
260
274
|
# Validate.
|
261
275
|
if not statement.path.is_file():
|
@@ -290,9 +304,10 @@ def build_statement_rooted(
|
|
290
304
|
statement.type,
|
291
305
|
output_type=joiner.joined_type() if joiner is not None else output_type,
|
292
306
|
custom_vars=custom_vars,
|
307
|
+
install_tex=install_tex,
|
293
308
|
)
|
294
309
|
|
295
|
-
if joiner is None or
|
310
|
+
if joiner is None or install_tex:
|
296
311
|
return last_content, last_output
|
297
312
|
assert statement.joiner is not None
|
298
313
|
|
@@ -335,6 +350,7 @@ def build_statement(
|
|
335
350
|
output_type: Optional[StatementType] = None,
|
336
351
|
use_samples: bool = True,
|
337
352
|
custom_vars: Optional[Dict[str, Any]] = None,
|
353
|
+
install_tex: bool = False,
|
338
354
|
) -> pathlib.Path:
|
339
355
|
with tempfile.TemporaryDirectory() as td:
|
340
356
|
root = pathlib.Path(td)
|
@@ -345,6 +361,7 @@ def build_statement(
|
|
345
361
|
output_type=output_type,
|
346
362
|
use_samples=use_samples,
|
347
363
|
custom_vars=custom_vars,
|
364
|
+
install_tex=install_tex,
|
348
365
|
)
|
349
366
|
|
350
367
|
statement_path = (pathlib.Path('build') / statement.name).with_suffix(
|
rbx/box/contest/statements.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import subprocess
|
2
1
|
from typing import Annotated, List, Optional
|
3
2
|
|
4
3
|
import syncer
|
@@ -50,7 +49,6 @@ async def build(
|
|
50
49
|
vars: Annotated[
|
51
50
|
Optional[List[str]],
|
52
51
|
typer.Option(
|
53
|
-
'-v',
|
54
52
|
'--vars',
|
55
53
|
help='Variables to be used in the statements.',
|
56
54
|
),
|
@@ -102,9 +100,6 @@ async def build(
|
|
102
100
|
|
103
101
|
built_statements = []
|
104
102
|
|
105
|
-
if install_tex:
|
106
|
-
output = StatementType.TeX
|
107
|
-
|
108
103
|
for statement in valid_statements:
|
109
104
|
built_statements.append(
|
110
105
|
build_statement(
|
@@ -112,23 +107,13 @@ async def build(
|
|
112
107
|
contest,
|
113
108
|
output_type=output,
|
114
109
|
use_samples=samples,
|
110
|
+
install_tex=install_tex,
|
115
111
|
custom_vars=expand_any_vars(annotations.parse_dictionary_items(vars)),
|
116
112
|
)
|
117
113
|
)
|
118
114
|
|
119
115
|
console.console.rule(title='Built statements')
|
120
116
|
for statement, built_path in zip(valid_statements, built_statements):
|
121
|
-
if install_tex:
|
122
|
-
subprocess.run(
|
123
|
-
[
|
124
|
-
'texliveonfly',
|
125
|
-
built_path,
|
126
|
-
]
|
127
|
-
)
|
128
|
-
console.console.log(
|
129
|
-
f'Installing LaTeX packages for [item]{statement.name} {statement.language}[/item]...'
|
130
|
-
)
|
131
|
-
continue
|
132
117
|
console.console.print(
|
133
118
|
f'[item]{statement.name} {statement.language}[/item] -> {href(built_path)}'
|
134
119
|
)
|
rbx/box/generators.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import functools
|
1
2
|
import pathlib
|
2
3
|
import shutil
|
3
4
|
from typing import Dict, List, Optional, Set
|
@@ -40,12 +41,44 @@ def _compile_generator(generator: CodeItem) -> str:
|
|
40
41
|
return compile_item(generator, sanitized=SanitizationLevel.PREFER)
|
41
42
|
|
42
43
|
|
44
|
+
@functools.cache
|
45
|
+
def _warn_once_about_crlf():
|
46
|
+
console.console.print(
|
47
|
+
'[warning]It seems a few files have CRLF (\\r\\n) line endings.[/warning]'
|
48
|
+
)
|
49
|
+
console.console.print(
|
50
|
+
'[warning]This usually happens when the file is created on Windows. Please convert the file to LF (\\n) line endings.[/warning]'
|
51
|
+
)
|
52
|
+
console.console.print(
|
53
|
+
'[warning]If you are in VSCode, you can make sure LF (\\n) line endings are used by changing the [item]"files.eol"[/item] setting.[/warning]'
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
@functools.cache
|
58
|
+
def _warn_about_crlf(path: pathlib.Path):
|
59
|
+
_warn_once_about_crlf()
|
60
|
+
console.console.print(
|
61
|
+
f'[warning]Testcase file [item]{path}[/item] has CRLF (\\r\\n) line endings, converting to LF (\\n).[/warning]'
|
62
|
+
)
|
63
|
+
|
64
|
+
|
65
|
+
def _check_crlf(path: pathlib.Path):
|
66
|
+
with open(path, 'rb') as f:
|
67
|
+
for line in f:
|
68
|
+
if line.endswith(b'\r\n') or line.endswith(b'\n\r'):
|
69
|
+
_warn_about_crlf(path)
|
70
|
+
break
|
71
|
+
|
72
|
+
path.write_text(path.read_text().replace('\r', ''))
|
73
|
+
|
74
|
+
|
43
75
|
def _copy_testcase_over(
|
44
76
|
testcase: Testcase,
|
45
77
|
dest: Testcase,
|
46
78
|
):
|
47
79
|
testcase = fill_output_for_defined_testcase(testcase)
|
48
80
|
dest.inputPath.parent.mkdir(parents=True, exist_ok=True)
|
81
|
+
_check_crlf(testcase.inputPath)
|
49
82
|
shutil.copy(
|
50
83
|
str(testcase.inputPath),
|
51
84
|
str(dest.inputPath),
|
@@ -55,6 +88,7 @@ def _copy_testcase_over(
|
|
55
88
|
and testcase.outputPath.is_file()
|
56
89
|
and dest.outputPath is not None
|
57
90
|
):
|
91
|
+
_check_crlf(testcase.outputPath)
|
58
92
|
dest.outputPath.parent.mkdir(parents=True, exist_ok=True)
|
59
93
|
shutil.copy(
|
60
94
|
str(testcase.outputPath),
|
@@ -71,6 +105,8 @@ def _copy_testcase_output_over(
|
|
71
105
|
if not src_path.is_file():
|
72
106
|
return False
|
73
107
|
|
108
|
+
_check_crlf(src_path)
|
109
|
+
|
74
110
|
shutil.copy(str(src_path), str(dest_output_path.with_suffix(suffix)))
|
75
111
|
return True
|
76
112
|
|
@@ -84,6 +120,7 @@ def _copy_testcase_outputs_over(
|
|
84
120
|
has_copied = False
|
85
121
|
|
86
122
|
if testcase.outputPath is not None and testcase.outputPath.is_file():
|
123
|
+
_check_crlf(testcase.outputPath)
|
87
124
|
shutil.copy(str(testcase.outputPath), str(dest.outputPath))
|
88
125
|
has_copied = True
|
89
126
|
|
@@ -120,35 +157,42 @@ def get_call_from_string(call_str: str) -> GeneratorCall:
|
|
120
157
|
async def _get_necessary_generators_for_groups(
|
121
158
|
groups: Optional[Set[str]] = None,
|
122
159
|
) -> Set[str]:
|
123
|
-
pkg = package.find_problem_package_or_die()
|
124
|
-
existing_generators = set(generator.name for generator in pkg.generators)
|
125
160
|
necessary_generators = set()
|
126
161
|
|
127
162
|
class NecessaryGeneratorsVisitor(TestcaseGroupVisitor):
|
128
163
|
async def visit(self, entry: GenerationTestcaseEntry):
|
129
164
|
if entry.metadata.generator_call is not None:
|
165
|
+
if (
|
166
|
+
package.get_generator_or_nil(entry.metadata.generator_call.name)
|
167
|
+
is None
|
168
|
+
):
|
169
|
+
console.console.print(
|
170
|
+
f'[error]Generator [item]{entry.metadata.generator_call.name}[/item] is not present in the package.[/error]'
|
171
|
+
)
|
172
|
+
if entry.metadata.generator_script is not None:
|
173
|
+
console.console.print(
|
174
|
+
f'[error]This generator is referenced from [item]{entry.metadata.generator_script}[/item].[/error]'
|
175
|
+
)
|
176
|
+
raise typer.Exit(1)
|
130
177
|
necessary_generators.add(entry.metadata.generator_call.name)
|
131
178
|
|
132
179
|
await run_testcase_visitor(NecessaryGeneratorsVisitor(groups))
|
133
180
|
|
134
|
-
return
|
181
|
+
return necessary_generators
|
135
182
|
|
136
183
|
|
137
184
|
def compile_generators(
|
185
|
+
tracked_generators: Set[str],
|
138
186
|
progress: Optional[StatusProgress] = None,
|
139
|
-
tracked_generators: Optional[Set[str]] = None,
|
140
187
|
) -> Dict[str, str]:
|
141
188
|
def update_status(text: str):
|
142
189
|
if progress is not None:
|
143
190
|
progress.update(text)
|
144
191
|
|
145
|
-
pkg = package.find_problem_package_or_die()
|
146
|
-
|
147
192
|
generator_to_compiled_digest = {}
|
148
193
|
|
149
|
-
for
|
150
|
-
|
151
|
-
continue
|
194
|
+
for generator_name in tracked_generators:
|
195
|
+
generator = package.get_generator(generator_name)
|
152
196
|
update_status(f'Compiling generator [item]{generator.name}[/item]')
|
153
197
|
try:
|
154
198
|
generator_to_compiled_digest[generator.name] = _compile_generator(generator)
|
@@ -267,9 +311,7 @@ async def generate_testcases(
|
|
267
311
|
|
268
312
|
compiled_generators = compile_generators(
|
269
313
|
progress=progress,
|
270
|
-
tracked_generators=await _get_necessary_generators_for_groups(groups)
|
271
|
-
if groups is not None
|
272
|
-
else None,
|
314
|
+
tracked_generators=await _get_necessary_generators_for_groups(groups),
|
273
315
|
)
|
274
316
|
|
275
317
|
testcase_utils.clear_built_testcases()
|
rbx/box/package.py
CHANGED
@@ -229,13 +229,45 @@ def get_build_testgroup_path(
|
|
229
229
|
|
230
230
|
|
231
231
|
@functools.cache
|
232
|
-
def
|
232
|
+
def get_generator_or_nil(
|
233
|
+
name: str, root: pathlib.Path = pathlib.Path()
|
234
|
+
) -> Optional[Generator]:
|
233
235
|
package = find_problem_package_or_die(root)
|
234
236
|
for generator in package.generators:
|
235
237
|
if generator.name == name:
|
236
238
|
return generator
|
237
|
-
|
238
|
-
|
239
|
+
|
240
|
+
path = pathlib.Path(root / name)
|
241
|
+
if path.is_file():
|
242
|
+
return Generator(name=name, path=path)
|
243
|
+
|
244
|
+
path_pattern = path.with_suffix('.*')
|
245
|
+
matching_files = list(
|
246
|
+
file.relative_to(root) for file in root.glob(str(path_pattern))
|
247
|
+
)
|
248
|
+
|
249
|
+
if len(matching_files) > 1:
|
250
|
+
console.console.print(
|
251
|
+
f'[error]Multiple candidate generators found for [item]{name}[/item]: {matching_files}[/error]'
|
252
|
+
)
|
253
|
+
console.console.print(
|
254
|
+
'[info]Please specify the generator path explicitly, including the extension, or rename the conflicting files.[/info]'
|
255
|
+
)
|
256
|
+
raise typer.Exit(1)
|
257
|
+
|
258
|
+
if matching_files:
|
259
|
+
return Generator(name=name, path=matching_files[0])
|
260
|
+
|
261
|
+
return None
|
262
|
+
|
263
|
+
|
264
|
+
@functools.cache
|
265
|
+
def get_generator(name: str, root: pathlib.Path = pathlib.Path()) -> Generator:
|
266
|
+
generator = get_generator_or_nil(name, root)
|
267
|
+
if generator is None:
|
268
|
+
console.console.print(f'[error]Generator [item]{name}[/item] not found[/error]')
|
269
|
+
raise typer.Exit(1)
|
270
|
+
return generator
|
239
271
|
|
240
272
|
|
241
273
|
@functools.cache
|
@@ -292,7 +324,27 @@ def get_interactor(root: pathlib.Path = pathlib.Path()) -> CodeItem:
|
|
292
324
|
@functools.cache
|
293
325
|
def get_solutions(root: pathlib.Path = pathlib.Path()) -> List[Solution]:
|
294
326
|
package = find_problem_package_or_die(root)
|
295
|
-
|
327
|
+
seen_paths = set()
|
328
|
+
res = []
|
329
|
+
|
330
|
+
def add_solution(entry: Solution):
|
331
|
+
if entry.path in seen_paths:
|
332
|
+
return
|
333
|
+
seen_paths.add(entry.path)
|
334
|
+
res.append(entry)
|
335
|
+
|
336
|
+
for entry in package.solutions:
|
337
|
+
if '*' in str(entry.path):
|
338
|
+
for file in root.glob(str(entry.path)):
|
339
|
+
relative_file = file.relative_to(root)
|
340
|
+
add_solution(
|
341
|
+
Solution.model_copy(
|
342
|
+
entry, update={'path': relative_file}, deep=True
|
343
|
+
)
|
344
|
+
)
|
345
|
+
continue
|
346
|
+
add_solution(entry)
|
347
|
+
return res
|
296
348
|
|
297
349
|
|
298
350
|
@functools.cache
|
@@ -214,8 +214,7 @@ def _upload_testcases(problem: api.Problem):
|
|
214
214
|
|
215
215
|
def _upload_solutions(problem: api.Problem):
|
216
216
|
console.console.print('Uploading main solution...')
|
217
|
-
|
218
|
-
main_solution = pkg.solutions[0]
|
217
|
+
main_solution = package.get_main_solution()
|
219
218
|
if main_solution is None or main_solution.outcome != ExpectedOutcome.ACCEPTED:
|
220
219
|
return
|
221
220
|
problem.save_solution(
|
@@ -225,7 +224,7 @@ def _upload_solutions(problem: api.Problem):
|
|
225
224
|
tag=api.SolutionTag.MA,
|
226
225
|
)
|
227
226
|
|
228
|
-
for i, solution in enumerate(
|
227
|
+
for i, solution in enumerate(package.get_solutions()):
|
229
228
|
console.console.print(
|
230
229
|
f'Uploading solution [item]{solution.path.name}[/item] (tag: [item]{_get_solution_tag(solution, is_first=i == 0)}[/item])...'
|
231
230
|
)
|
rbx/box/schema.py
CHANGED
@@ -9,7 +9,7 @@ from pydantic import AfterValidator, BaseModel, ConfigDict, Field, model_validat
|
|
9
9
|
from pydantic_core import PydanticCustomError
|
10
10
|
|
11
11
|
from rbx.autoenum import AutoEnum, alias
|
12
|
-
from rbx.box.fields import
|
12
|
+
from rbx.box.fields import NameField
|
13
13
|
from rbx.box.statements.expander import expand_statements
|
14
14
|
from rbx.box.statements.schema import Statement
|
15
15
|
from rbx.grading.steps import Outcome
|
@@ -257,7 +257,7 @@ class Testcase(BaseModel):
|
|
257
257
|
class GeneratorCall(BaseModel):
|
258
258
|
model_config = ConfigDict(extra='forbid')
|
259
259
|
|
260
|
-
name: str =
|
260
|
+
name: str = Field(description='The name of the generator to call.')
|
261
261
|
|
262
262
|
args: Optional[str] = Field(
|
263
263
|
default=None, description='The arguments to pass to the generator.'
|
@@ -355,7 +355,7 @@ problems that have points.
|
|
355
355
|
class Generator(CodeItem):
|
356
356
|
model_config = ConfigDict(extra='forbid')
|
357
357
|
|
358
|
-
name: str =
|
358
|
+
name: str = Field(description="""The name of the generator.""")
|
359
359
|
|
360
360
|
|
361
361
|
class Solution(CodeItem):
|
rbx/box/solutions.py
CHANGED
@@ -158,12 +158,10 @@ def compile_solutions(
|
|
158
158
|
tracked_solutions: Optional[Set[str]] = None,
|
159
159
|
sanitized: bool = False,
|
160
160
|
) -> Dict[pathlib.Path, str]:
|
161
|
-
pkg = package.find_problem_package_or_die()
|
162
|
-
|
163
161
|
compiled_solutions = {}
|
164
162
|
|
165
163
|
if tracked_solutions is None:
|
166
|
-
tracked_solutions = set(str(sol.path) for sol in
|
164
|
+
tracked_solutions = set(str(sol.path) for sol in package.get_solutions())
|
167
165
|
|
168
166
|
for solution in expand_solutions(list(tracked_solutions)):
|
169
167
|
if progress:
|
@@ -232,9 +230,8 @@ async def convert_list_of_solution_evaluations_to_dict(
|
|
232
230
|
skeleton: SolutionReportSkeleton,
|
233
231
|
items: Iterable[EvaluationItem],
|
234
232
|
) -> List[Dict[str, List[Evaluation]]]:
|
235
|
-
pkg = package.find_problem_package_or_die()
|
236
233
|
res: List[Dict[str, List[Evaluation]]] = [
|
237
|
-
collections.defaultdict(list) for _ in
|
234
|
+
collections.defaultdict(list) for _ in package.get_solutions()
|
238
235
|
]
|
239
236
|
|
240
237
|
for item in items:
|
@@ -250,10 +247,9 @@ def _get_solutions_for_skeleton(
|
|
250
247
|
tracked_solutions: Optional[Iterable[str]] = None,
|
251
248
|
verification: VerificationLevel = VerificationLevel.NONE,
|
252
249
|
) -> List[Solution]:
|
253
|
-
pkg = package.find_problem_package_or_die()
|
254
250
|
solutions = [
|
255
251
|
sol
|
256
|
-
for sol in
|
252
|
+
for sol in package.get_solutions()
|
257
253
|
if verification.value >= VerificationLevel.ALL_SOLUTIONS.value or is_fast(sol)
|
258
254
|
]
|
259
255
|
if tracked_solutions is not None:
|
@@ -739,8 +735,7 @@ def _get_solution_repr(sol: Solution) -> List[Tuple[str, str]]:
|
|
739
735
|
|
740
736
|
|
741
737
|
def expand_solutions_with_source(sols: List[str]) -> List[Tuple[Solution, bool]]:
|
742
|
-
|
743
|
-
pkg_sols = {str(sol.path): sol for sol in pkg.solutions}
|
738
|
+
pkg_sols = {str(sol.path): sol for sol in package.get_solutions()}
|
744
739
|
|
745
740
|
# Download remote sols.
|
746
741
|
path_sols = remote.expand_files(sols)
|
@@ -777,20 +772,21 @@ async def pick_solutions(
|
|
777
772
|
tracked_solutions: Optional[OrderedSet[str]],
|
778
773
|
extra_solutions: Optional[List[str]] = None,
|
779
774
|
) -> List[str]:
|
780
|
-
pkg = package.find_problem_package_or_die()
|
781
775
|
# Store in a separate list to maintain order with the package declaration.
|
782
776
|
import questionary
|
783
777
|
|
778
|
+
solutions = package.get_solutions()
|
779
|
+
|
784
780
|
choices = [
|
785
781
|
questionary.Choice(
|
786
782
|
title=_get_solution_repr(sol),
|
787
783
|
value=str(sol.path),
|
788
784
|
checked=tracked_solutions is None or str(sol.path) in tracked_solutions,
|
789
785
|
)
|
790
|
-
for sol in
|
786
|
+
for sol in solutions
|
791
787
|
]
|
792
788
|
|
793
|
-
seen_sols = set(str(sol.path) for sol in
|
789
|
+
seen_sols = set(str(sol.path) for sol in solutions)
|
794
790
|
|
795
791
|
if extra_solutions is not None:
|
796
792
|
# Add only new solutions.
|
rbx/box/statements/latex.py
CHANGED
@@ -5,6 +5,8 @@ from typing import Optional
|
|
5
5
|
|
6
6
|
import chardet
|
7
7
|
|
8
|
+
from rbx.utils import command_exists
|
9
|
+
|
8
10
|
MAX_PDFLATEX_RUNS = 3
|
9
11
|
|
10
12
|
|
@@ -45,3 +47,12 @@ class Latex:
|
|
45
47
|
return LatexResult(result=completed, pdf=None)
|
46
48
|
|
47
49
|
return LatexResult(result=completed, pdf=output_path.read_bytes())
|
50
|
+
|
51
|
+
|
52
|
+
def install_tex_packages(path: pathlib.Path, cwd: pathlib.Path):
|
53
|
+
if not command_exists('texliveonfly'):
|
54
|
+
return
|
55
|
+
subprocess.run(
|
56
|
+
['texliveonfly', path],
|
57
|
+
cwd=cwd,
|
58
|
+
)
|
rbx/grading/caching.py
CHANGED
@@ -241,6 +241,7 @@ def _copy_hashed_files(artifact_list: List[GradingArtifacts], cacher: FileCacher
|
|
241
241
|
) is not None:
|
242
242
|
# Use a symlink to the file in the persistent cache, if available.
|
243
243
|
output.dest.unlink(missing_ok=True)
|
244
|
+
output.dest.parent.mkdir(parents=True, exist_ok=True)
|
244
245
|
output.dest.symlink_to(path_to_symlink)
|
245
246
|
else:
|
246
247
|
# Otherwise, copy it.
|
rbx/grading/judge/sandbox.py
CHANGED
rbx/grading/steps.py
CHANGED
@@ -355,6 +355,7 @@ def _process_output_artifacts(
|
|
355
355
|
):
|
356
356
|
# File is in the persistent cache, store a symlink to it.
|
357
357
|
dst.unlink(missing_ok=True)
|
358
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
358
359
|
dst.symlink_to(path_to_symlink)
|
359
360
|
else:
|
360
361
|
# File is not in the persistent cache, copy it.
|
@@ -1,13 +1,13 @@
|
|
1
1
|
---
|
2
2
|
# yaml-language-server: $schema=https://rsalesc.github.io/rbx/schemas/Contest.json
|
3
|
-
# Add problems by running `rbx contest add
|
3
|
+
# Add problems by running `rbx contest add`
|
4
4
|
name: "new-contest"
|
5
5
|
statements:
|
6
6
|
- name: "statement-en"
|
7
7
|
title: "New contest"
|
8
8
|
language: "en"
|
9
9
|
path: "statement/contest.rbx.tex"
|
10
|
-
type:
|
10
|
+
type: JinjaTeX
|
11
11
|
assets:
|
12
12
|
- "statement/icpc.sty"
|
13
13
|
- "statement/*.png"
|
@@ -1,3 +1,4 @@
|
|
1
|
+
#include "rbx.h"
|
1
2
|
#include "testlib.h"
|
2
3
|
|
3
4
|
using namespace std;
|
@@ -6,7 +7,7 @@ int main(int argc, char *argv[]) {
|
|
6
7
|
registerValidation(argc, argv);
|
7
8
|
prepareOpts(argc, argv);
|
8
9
|
|
9
|
-
int MAX_N =
|
10
|
+
int MAX_N = getVar<int>("MAX_N"); // Read from package vars.
|
10
11
|
|
11
12
|
inf.readInt(1, MAX_N, "A");
|
12
13
|
inf.readSpace();
|
rbx/utils.py
CHANGED
@@ -6,6 +6,7 @@ import os
|
|
6
6
|
import os.path
|
7
7
|
import pathlib
|
8
8
|
import resource
|
9
|
+
import subprocess
|
9
10
|
from typing import Any, Optional, Type, TypeVar
|
10
11
|
|
11
12
|
import rich
|
@@ -145,6 +146,18 @@ def get_open_fds():
|
|
145
146
|
return fds
|
146
147
|
|
147
148
|
|
149
|
+
def command_exists(command):
|
150
|
+
try:
|
151
|
+
subprocess.run(
|
152
|
+
[command], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
153
|
+
)
|
154
|
+
return True
|
155
|
+
except FileNotFoundError:
|
156
|
+
return False
|
157
|
+
except subprocess.CalledProcessError:
|
158
|
+
return True
|
159
|
+
|
160
|
+
|
148
161
|
@contextlib.contextmanager
|
149
162
|
def new_cd(x: pathlib.Path):
|
150
163
|
d = os.getcwd()
|
@@ -2,7 +2,7 @@ rbx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
rbx/annotations.py,sha256=qcJGL_INONSirH7LTrEma5RsweAIbO6QlRHVvRvb9ao,3521
|
3
3
|
rbx/autoenum.py,sha256=cusv8ClXRlDVvhZ8eDrtYcL_2peXlHugAey_ht8roXk,12025
|
4
4
|
rbx/box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
rbx/box/builder.py,sha256=
|
5
|
+
rbx/box/builder.py,sha256=umrTdVAwvsOosBDVvDZ6kq1yWg3Z2Lxp2o1zK-V7BBk,3594
|
6
6
|
rbx/box/cd.py,sha256=_XAzb3kV1NUaaRs8hc9SGDo10O1yh2_gr1EiAKzfUjI,2711
|
7
7
|
rbx/box/checkers.py,sha256=wjS64fDrEkTjU6f80strt4QEBHPo4FQDh9ijELhOQT0,13016
|
8
8
|
rbx/box/cli.py,sha256=a_tjWct-pin60cZ3OIg3SsyCjIoSWR0m6_lepFxDbDE,29778
|
@@ -10,12 +10,12 @@ rbx/box/code.py,sha256=4GChCeUaHjT7stvtPAURbCL1_V238geG3xmXQjbdV20,26708
|
|
10
10
|
rbx/box/compile.py,sha256=Kzn5mEQu4vb91W9vjyt0DS6cfPJzFLTUoowFj7uHLUo,2539
|
11
11
|
rbx/box/conftest.py,sha256=sEmciXSeDC-wmrZ1JSxbsUenKNP_VWW32mrCun2pY3I,1070
|
12
12
|
rbx/box/contest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
rbx/box/contest/build_contest_statements.py,sha256=
|
13
|
+
rbx/box/contest/build_contest_statements.py,sha256=OKf7BQ6DxtY65TpzjhNbY5Bu3wByrxZt7qCqWDXBaNQ,12693
|
14
14
|
rbx/box/contest/contest_package.py,sha256=r6BGq3S4Ezj3Ep7pCmtvz3SN44npb2_rKJEoT5lSOqk,2985
|
15
15
|
rbx/box/contest/contest_utils.py,sha256=fsWHG1e65wq9zvRY3tdf32VF0nU1yzGTOBX5yjXiNk4,1102
|
16
16
|
rbx/box/contest/main.py,sha256=e_DjbrwpXTFZQaVWJO7prJyehJ702GkVEAGEraRK6h4,8352
|
17
17
|
rbx/box/contest/schema.py,sha256=eb7xtyq078YYWYHueximNhyHFINzwgLMFm1j9U3LxBQ,7461
|
18
|
-
rbx/box/contest/statements.py,sha256=
|
18
|
+
rbx/box/contest/statements.py,sha256=dI3AmaTYfOzyB1uh75ST9se9o_QqXzar4pNkIdC-_G8,3956
|
19
19
|
rbx/box/creation.py,sha256=oTAC11XV2Pw2YAlF_d11Eo7A1fD6ItlpFMpLEzMLyFI,1331
|
20
20
|
rbx/box/deferred.py,sha256=II3X9e87JCOZtmspnHh-n4PFqh-FsH_oc0XJHZ9ZYVQ,691
|
21
21
|
rbx/box/download.py,sha256=tLW5gLVeLk0gHMEMwScSoHIXQPkXuPsqXzItsrsnUZY,3070
|
@@ -24,7 +24,7 @@ rbx/box/environment.py,sha256=iR-VTNvbW8iNienWKYVnd1xxCuhWml7bYa5FTIZCOY0,13574
|
|
24
24
|
rbx/box/extensions.py,sha256=Von8kIeXvNFTkGlMRMTvL2HIHPwlkuiMswr-ydbGV1w,519
|
25
25
|
rbx/box/fields.py,sha256=lc1OHpo_AC8RxzNasipULGkRmToAiXBGzWDeb14L_ss,1092
|
26
26
|
rbx/box/formatting.py,sha256=i3vXHpo_L_VpVPxOe4wHlai1WhlDJlfxUexS9DC0Szg,1249
|
27
|
-
rbx/box/generators.py,sha256=
|
27
|
+
rbx/box/generators.py,sha256=yu1CAW-u3M1EhfSZldhIcPTwIFBGC8OzWxVGR-kufTk,15366
|
28
28
|
rbx/box/generators_test.py,sha256=J7aBfuJhU84MWDWzgReRoOuQw_hVa09B8gTKAvL2XVo,1987
|
29
29
|
rbx/box/git_utils.py,sha256=VlUgzuHOCnrjjiJQnDB32qDHbHw_zkwgA7wm4bloibc,750
|
30
30
|
rbx/box/global_package.py,sha256=OMnvqY8VQlP9YVSZwH5LCVkTsE7zNIhhRcslIWktkQc,2016
|
@@ -35,7 +35,7 @@ rbx/box/lazy_importing_test.py,sha256=B0-b3y_DkxEmtVfu4NfmVsgVdFl6kRCsEL6GLMHJIS
|
|
35
35
|
rbx/box/linting.py,sha256=wRE0hKCduTBHZYBFmmis_d9AMTsDu0Q-AjByCeTnkrY,3187
|
36
36
|
rbx/box/main.py,sha256=a8CYi77kOywPFly4-ucEIJLXQW-1NFp91kK2fA42YTE,86
|
37
37
|
rbx/box/naming.py,sha256=pOG37X_wQM9CCSYwJIUf-b-ZHEs_nchO7wQEdP_quJg,1367
|
38
|
-
rbx/box/package.py,sha256=
|
38
|
+
rbx/box/package.py,sha256=VyG7TZKYGeqzilPkLs8rbJDa1kTIXfrZADequnJvyE4,15110
|
39
39
|
rbx/box/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
40
|
rbx/box/packaging/boca/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
41
|
rbx/box/packaging/boca/extension.py,sha256=EQALNEOv4zVDXSKs_dk11n92y7cBZVn8TogIK683lE0,890
|
@@ -48,7 +48,7 @@ rbx/box/packaging/pkg/packager.py,sha256=4pt4cZa_MU9gsWNVvh5Um1KEIh_axBHlXmPf6rp
|
|
48
48
|
rbx/box/packaging/polygon/packager.py,sha256=K8WKYO-HBDx_z4R43Ko7YBs1bbFjhFPx8IUkvY0jM0I,11190
|
49
49
|
rbx/box/packaging/polygon/polygon_api.py,sha256=mPKEqiwANJ1nr-JhOgzGMaDhnbljsAgzzPHW6kkf7R4,41016
|
50
50
|
rbx/box/packaging/polygon/test.py,sha256=bgEju5PwudgyfwxXJagm8fM6CJVlWM6l_-2q1V-oKaQ,3069
|
51
|
-
rbx/box/packaging/polygon/upload.py,sha256=
|
51
|
+
rbx/box/packaging/polygon/upload.py,sha256=tymodSg5Bv1pnG5q6b_LYvRBs-m3PcyXL4TS0UmZwEk,12875
|
52
52
|
rbx/box/packaging/polygon/xml_schema.py,sha256=ZgcLyvxggMUccbTNdzflue5G-FTN2_ZmOGGF7FD0Y5A,2851
|
53
53
|
rbx/box/presets/__init__.py,sha256=L6fy_hetXnB8Eo_MO3oadv_ce2hwVW2J-BJm9CooEdA,33432
|
54
54
|
rbx/box/presets/fetch.py,sha256=900aq9S8e12TlgSenG0iHgtF4OWgqavZsptgI_a1YKM,2508
|
@@ -57,17 +57,17 @@ rbx/box/presets/schema.py,sha256=iOGWHqJ9Z-ljQV8ljOjQMuCwqJQLJKm_pYX9cLjZbmE,243
|
|
57
57
|
rbx/box/remote.py,sha256=PsJ4i3suQEr3cxiKk4nCho98QBGs5b2v8_TEvn_nE-o,5204
|
58
58
|
rbx/box/retries.py,sha256=BZsi4sYBjm3VK5zb_pBQSYQuKo3ZntmtEFoVPZHg4QI,4982
|
59
59
|
rbx/box/sanitizers/warning_stack.py,sha256=6-rr3dkMq6MpfjrVZ8lSQjF4RZ5YzZSAPMzHCfm-6h4,2876
|
60
|
-
rbx/box/schema.py,sha256=
|
60
|
+
rbx/box/schema.py,sha256=kOWMe0lrAJBEhU5gBAWvhwMHHzWx17PBwThou4zuo1A,18834
|
61
61
|
rbx/box/setter_config.py,sha256=WHlWjjdHNoBbCdZqYokctTSxvtPqQXGmrgDHyaK4FKk,4985
|
62
|
-
rbx/box/solutions.py,sha256=
|
62
|
+
rbx/box/solutions.py,sha256=CmwLS7EJsZ6_4HqU0bKV8oy2Vd6wKwdQS3R9AH3XNZQ,53696
|
63
63
|
rbx/box/solutions_test.py,sha256=PX1TQoRzNd9mi1SGsG7WFrpqFgNrNX5Kwt0mkwFdoOA,1749
|
64
64
|
rbx/box/state.py,sha256=MMf3DvfQji0jKEliCHct2Tpp_0epL1tvP8HbHNArQIc,166
|
65
65
|
rbx/box/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
66
|
-
rbx/box/statements/build_statements.py,sha256
|
66
|
+
rbx/box/statements/build_statements.py,sha256=-pUQAS8CEnWqHtpKW6wH338rQg3FKmb9qYxilzcwJFA,12693
|
67
67
|
rbx/box/statements/builders.py,sha256=Qb_rfkFOqghFZfEf2zPSEoDPc-lCBNb5CcPoOkV7HMk,13747
|
68
68
|
rbx/box/statements/expander.py,sha256=sdbMtNcJQCbXGIkFIl9h24pGr77vhFLnM31V5AfuduI,1715
|
69
69
|
rbx/box/statements/joiners.py,sha256=jItNXkAbTjFQpPMgfDMW86n3vMTbaE8sgo9I8Yf4Txg,2886
|
70
|
-
rbx/box/statements/latex.py,sha256=
|
70
|
+
rbx/box/statements/latex.py,sha256=ipTGjL4kjAsnqgiH6Pk1PwKFegBumQP4-y0pFAbNN8I,1584
|
71
71
|
rbx/box/statements/latex_jinja.py,sha256=iMx47ynKMjLNcfymzHV24jtWrRVnit0Va9H8yTfgmiA,10379
|
72
72
|
rbx/box/statements/schema.py,sha256=5_qrY1KztCLSe4t-rJ7zdv3cBjcaO-FnFc45ZRUotfs,5127
|
73
73
|
rbx/box/stats.py,sha256=rUAnmp7kTgUvIQ56NLpQaIQkazB37MVcUos5en3xUQw,3258
|
@@ -121,14 +121,14 @@ rbx/console.py,sha256=X8EJy68OROgh6ao3ZcUjZm5Y56VFMzen58ywAuQ7pAU,990
|
|
121
121
|
rbx/create.py,sha256=ezUq9KiSA-88ASd8CtjWXw8UB4LCaQ3Gib3OgvsLK-Q,986
|
122
122
|
rbx/edit.py,sha256=Zqnx_Pt06ijCxV-pZKGCJhjKB-nVO0QCM6xSBwPWGoE,798
|
123
123
|
rbx/grading/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
124
|
-
rbx/grading/caching.py,sha256=
|
124
|
+
rbx/grading/caching.py,sha256=Inu9IYtjO6reg7XGCP44AcaJ5Ax1McfkfNwcpjTCzrw,15376
|
125
125
|
rbx/grading/conftest.py,sha256=820Uw3AE-dwAfwLhXjgq_PixpDI1-JEXsOPYf4VT5H8,971
|
126
126
|
rbx/grading/debug_context.py,sha256=kuAXEI8yRG8xfhS9WKKIRh9X0e5JUD8zvl_cpczJTC8,699
|
127
127
|
rbx/grading/grading_context.py,sha256=TaRyLwPkkxvspQIFUFk8Ok0T8EST2pHMMNoVDx9lbFU,3416
|
128
128
|
rbx/grading/judge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
129
129
|
rbx/grading/judge/cacher.py,sha256=wtRnVE_Es9xcqIgrhn6WzUoB90aihUuKaFyuVsusngg,20323
|
130
130
|
rbx/grading/judge/digester.py,sha256=gtOIe_iL4PEWA7OKelW1gjSI-nBvbOpDPJGV8VQyjSg,912
|
131
|
-
rbx/grading/judge/sandbox.py,sha256=
|
131
|
+
rbx/grading/judge/sandbox.py,sha256=m0Or5UWnKyPuaJNfb-OiVucHT04ZPIb9_QJrkie1Pok,26340
|
132
132
|
rbx/grading/judge/sandboxes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
133
133
|
rbx/grading/judge/sandboxes/isolate.py,sha256=SbzmvjnbMRIHWV68_6jdZ7dZRnC-Hp9ACNyv8OS_Npg,25991
|
134
134
|
rbx/grading/judge/sandboxes/stupid_sandbox.py,sha256=_5p3IFmrDhyky8RCyc6fjUCiBf2SFSJ99O_4sj7xzTE,11342
|
@@ -139,7 +139,7 @@ rbx/grading/judge/testiso.py,sha256=v14DtkWiZFJ9AKMzrb0_vZKPWDt8jz8iIw1Z2O-Advk,
|
|
139
139
|
rbx/grading/limits.py,sha256=ev312UTOo8S4-3AAVibQdXZclWCxS96CdbZxqW4y1kE,770
|
140
140
|
rbx/grading/processing_context.py,sha256=Jg9kNnkH3hi2hiE6Gh23QwS89r9Zj230NMl1CUEHSfo,1866
|
141
141
|
rbx/grading/profiling.py,sha256=OEdtoAzjYjLfi-QI5Ke7tLZzJeqvGpMB2utQBNuH3E4,3369
|
142
|
-
rbx/grading/steps.py,sha256=
|
142
|
+
rbx/grading/steps.py,sha256=JlR72UvEdvJGFZGA0Jd_2qUoEnElhiIOQAzbUrOhidk,30185
|
143
143
|
rbx/grading/steps_with_caching.py,sha256=b6NVZN46IG2r49uQ6u19Jj6AJ_nQFO6_pcKq4dWTwuQ,4579
|
144
144
|
rbx/grading/steps_with_caching_run_test.py,sha256=Ldrs1VS01TWYpqg1x9LeiF7_TejsE_suL3y1MI5pAlU,26599
|
145
145
|
rbx/grading_utils.py,sha256=lL2KtSkOsMElqrRoApQTbFcqVOeHVWUDTMCa3IsLpC4,4484
|
@@ -202,14 +202,14 @@ rbx/resources/packagers/moj/scripts/py2/run.sh,sha256=qshf-K3mKP4c7b45S3D82Wj0Ai
|
|
202
202
|
rbx/resources/packagers/moj/scripts/py3/compile.sh,sha256=XPn8qDR_gPAAZD9h5lVEMdBkrSogRZvpT4MAaNNp9nk,96
|
203
203
|
rbx/resources/packagers/moj/scripts/py3/prep.sh,sha256=it1e07QRpsnku3-rXOO1ovaw-RJlVVPy9R3I6WWwgMM,126
|
204
204
|
rbx/resources/packagers/moj/scripts/py3/run.sh,sha256=LrMi7Tap9no8gh64QNGUXbWauP6ZpSl-wEwXZ2qhPo0,197
|
205
|
-
rbx/resources/presets/default/contest/.gitignore,sha256=
|
206
|
-
rbx/resources/presets/default/contest/contest.rbx.yml,sha256=
|
205
|
+
rbx/resources/presets/default/contest/.gitignore,sha256=CMwGD717vKcbQrXjha2D4LMwjDfQcev8rjFPg0AIi4A,131
|
206
|
+
rbx/resources/presets/default/contest/contest.rbx.yml,sha256=7ifI6vbQg9IOYA94Q6i1toj-S8wNwwDkK-gJLxEaCeU,845
|
207
207
|
rbx/resources/presets/default/contest/statement/contest.rbx.tex,sha256=Jx6op_WdVpQOMekvOAZnBzDxxvBzg1_9ZFWtbzGasLo,793
|
208
208
|
rbx/resources/presets/default/contest/statement/instructions.tex,sha256=JG_eR13ukZgEahrrmrbg40H8cUzpoUE8QLocihN-fZ8,2414
|
209
209
|
rbx/resources/presets/default/contest/statement/logo.png,sha256=RLNYmZoc-BR6AZKkmr4UEg3h01YeFzvy604jMAQC7aA,414485
|
210
210
|
rbx/resources/presets/default/env.rbx.yml,sha256=quSPG5Xs9KroYLATNLPNtORLGRWtrLLt2Fx81T1enAM,1692
|
211
211
|
rbx/resources/presets/default/preset.rbx.yml,sha256=s7OFotxoe3aFFEstJv5QG7LU3UP370dGe5hA9gWRQpg,498
|
212
|
-
rbx/resources/presets/default/problem/.gitignore,sha256=
|
212
|
+
rbx/resources/presets/default/problem/.gitignore,sha256=CMwGD717vKcbQrXjha2D4LMwjDfQcev8rjFPg0AIi4A,131
|
213
213
|
rbx/resources/presets/default/problem/gens/gen.cpp,sha256=rn6sGRjZ1sFE1Rq02r6488iquY9xTrutcvLv4d1sohA,178
|
214
214
|
rbx/resources/presets/default/problem/manual_tests/samples/000.in,sha256=w66OEtCJGqjUNj8cJrqgImgGVm8W_OlIUtF255ds-ow,4
|
215
215
|
rbx/resources/presets/default/problem/manual_tests/samples/001.in,sha256=P4QInDX87xXoDWu4PVIzUeNW5LtTlUKbMCvJ9uZOPGw,20
|
@@ -221,10 +221,10 @@ rbx/resources/presets/default/problem/sols/wa.cpp,sha256=Bj7tejPIlXG_JqUHWY1zi9T
|
|
221
221
|
rbx/resources/presets/default/problem/statement/statement.rbx.tex,sha256=JHdiMN3NQQsysDA1w3RfOGmDFobCc68YCB6SURy2hHo,360
|
222
222
|
rbx/resources/presets/default/problem/testplan/random.py,sha256=-iPorU24QHfp39EYRJX9jMKcTIxxz5ejKoAzPLIuu1g,98
|
223
223
|
rbx/resources/presets/default/problem/testplan/random.txt,sha256=2BA_AM8IAKEcrUTJhnzWnNJN8whDN82E2137NhFkt2U,137
|
224
|
-
rbx/resources/presets/default/problem/validator.cpp,sha256=
|
224
|
+
rbx/resources/presets/default/problem/validator.cpp,sha256=I_Vs12xQnJnwkRtCu4EjazdaERms4GktZhME7zGaQjU,337
|
225
225
|
rbx/resources/presets/default/problem/wcmp.cpp,sha256=gbjJe3Vf9-YzHCEqBUq30aI3jMZXhqBDn3jjecYOn-w,902
|
226
226
|
rbx/resources/presets/default/shared/contest_template.rbx.tex,sha256=-sExA0H7vo08I6P0dT78_xNN5Q9wiu6KZzB75s12Xm4,1293
|
227
|
-
rbx/resources/presets/default/shared/icpc.sty,sha256=
|
227
|
+
rbx/resources/presets/default/shared/icpc.sty,sha256=04feEwL7LRRvUFopwVAVjxdTvzE5gQtFsSkm6iJ5hLo,8042
|
228
228
|
rbx/resources/presets/default/shared/problem_template.rbx.tex,sha256=AjziXNWluAGsQiPQ2r477RkrMpNQJ1kcgidU8T_C4KA,1281
|
229
229
|
rbx/resources/templates/rbx.h,sha256=Iwtmr2gdDYmZ2VlIurmleBb_uEpriWd4EX0dJta8xUA,2179
|
230
230
|
rbx/resources/templates/template.cpp,sha256=xXWpWo7fa7HfmPNqkmHcmv3i46Wm0ZL-gPmkRfGvLn4,317
|
@@ -238,9 +238,9 @@ rbx/test.py,sha256=lrjIWESMedaDLX_knikPsJT322oI2nvy8weCslEuHLU,11810
|
|
238
238
|
rbx/testcase.py,sha256=yKOq3CAJZ1YTmInvnoIs0u1iJnRj_X85XiWbLI-p9d8,1951
|
239
239
|
rbx/testcase_rendering.py,sha256=nfmv6dSEqd4aR3TsaODwkKGK6AXty_DDKtWf_ejiQpI,2084
|
240
240
|
rbx/testing_utils.py,sha256=x_PqD8Zd2PkN91NxVHUnSTs044-1WK5KKtttKQBXpFs,2083
|
241
|
-
rbx/utils.py,sha256=
|
242
|
-
rbx_cp-0.
|
243
|
-
rbx_cp-0.
|
244
|
-
rbx_cp-0.
|
245
|
-
rbx_cp-0.
|
246
|
-
rbx_cp-0.
|
241
|
+
rbx/utils.py,sha256=SZW_bqU33CkHRrInnGN36QfQA0dQx2zdWO32fxlDy-w,5264
|
242
|
+
rbx_cp-0.12.0.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
243
|
+
rbx_cp-0.12.0.dist-info/METADATA,sha256=moF508pqK5J5V43KW2LiDjuxZkjzL0DlHoa_OZvAjpc,4625
|
244
|
+
rbx_cp-0.12.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
245
|
+
rbx_cp-0.12.0.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
|
246
|
+
rbx_cp-0.12.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|