@jutge.org/toolkit 4.4.28 → 4.4.29

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.
package/dist/index.js CHANGED
@@ -930,7 +930,7 @@ The new message will be saved as award.html in the problem directory, overriding
930
930
 
931
931
  This command will run the quiz problem and print the resulting object to stdout.
932
932
  A random seed will be generated if not provided.
933
- `).option("-d, --directory <directory>","problem directory",".").option("-s, --seed <seed>","random seed").option("-f, --format <format>","output format (json|yaml)","json").action(async({directory:q,seed:$,format:w})=>{let f=$?parseInt($,10):Ak(1e6,9999999),K=await zu(q,f);if(w==="json")u.json(K);else u.yaml(K)});oD.command("play").summary("Play a quiz problem").description("Play an interactive quiz test. Questions are shown in sequence; you can review and change answers before submitting.\nInput is a JSON file from `quiz run`; if --input is omitted, a run is generated with a random seed from the given directory.\nIf --output is given, the results (your answers, correct answers, and score per question) are written to that file.").option("-i, --input <input>","input JSON file from quiz run").option("-o, --output <output>","output file for results").option("-d, --directory <directory>","problem directory (used when --input is not provided)",".").option("-s, --seed <seed>","random seed (used when --input is not provided)").action(async({input:q,output:$,directory:w,seed:f})=>{let K=f!==void 0?parseInt(f,10):void 0,z=await dA_(q,w,K),P=await lA_(z);if($!==void 0)await rA_($,P)});var pA_=new h6("upgrade").description("Upgrade to the latest version").action(async()=>{await QZ_()});import{exists as A88,glob as u88,mkdir as C88}from"fs/promises";import{basename as gy_,join as nO,normalize as V88,resolve as M88,sep as N88}from"path";var Ey_=z6(hy_(),1);import{createWriteStream as G88}from"fs";async function iO(q,$){let w=G88($),f=Ey_.default("zip",{zlib:{level:9}}),K=new Promise((z,P)=>{w.on("close",()=>z()),w.on("error",P),f.on("error",P),f.on("warning",(D)=>{if(D.code==="ENOENT")console.warn(D);else P(D)})});f.pipe(w);for(let z of q)f.file(z.sourcePath,{name:z.archivePath});await f.finalize(),await K}async function by_(q){function $(D){let Y=[".exe",".o",".hi","~",".bak",".class",".pyc",".pyo"],J=[C8()+"-","__MACOSX",".DS_Store",".","__pycache__"];for(let k of Y)if(D.endsWith(k))return!1;let Z=V88(D).split(N88);for(let k of Z)for(let W of J)if(k.startsWith(W))return!1;return!0}let w=M88(q);if(!w.endsWith(".pbm"))throw Error(`Directory ${q} is not a problem directory (missing .pbm suffix)`);let f=nO(q,C8()+"-zip",wq()),K=gy_(w),z=nO(f,`${K}.zip`);await C88(f,{recursive:!0}),await u.section(`Zipping problem to ${z}`,async()=>{let D=[],Y=await Array.fromAsync(u88("**/*",{cwd:q}));for(let J of Y)if($(J)){let Z=nO(q,J),k=nO(gy_(w),J);u.print(`adding ${k}`),D.push({sourcePath:Z,archivePath:k})}u.print("Creating zip file..."),await iO(D,z)});let P=await h88(q,z);E88(P)}async function h88(q,$){let w=nO(q,"problem.yml");if(await A88(w)){let f=V$.parse(await X3(w));return await b88(q,f,$)}else return await g88(q,$)}function E88(q){u.yaml(q),u.url(`https://jutge.org/problems/${q.problem_nm}`)}async function g88(q,$){return await u.section("Creating problem in Jutge.org",async()=>{let w=await a4(),z={problem_nm:"",email:(await w.student.profile.get()).email,passcode:jP(),shared_testcases:!1,shared_solutions:!1,created_at:"",updated_at:""};return await u.section("Creating problem in Jutge.org",async()=>{let P=await dH($,"application/zip"),{id:D}=await w.instructor.problems.create(z.passcode,P),Y=await Iy_(D);if(!Y)throw Error("Failed to get problem name");z.problem_nm=Y,z.created_at=new Date().toISOString(),z.updated_at=new Date().toISOString()}),await Ry_(q,z,"Created"),u.print(""),u.success(`Problem ${z.problem_nm} created successfully`),z})}async function b88(q,$,w){return await u.section("Updating problem in Jutge.org",async()=>{let f=await a4();return await u.section("Updating problem in Jutge.org",async()=>{let K=await dH(w,"application/zip"),{id:z}=await f.instructor.problems.update($.problem_nm,K);await Iy_(z),$.updated_at=new Date().toISOString()}),await Ry_(q,$,"Updated"),u.print(""),u.success(`Problem ${$.problem_nm} updated successfully`),$})}async function Ry_(q,$,w){await u.section(`${w==="Created"?"Creating":"Updating"} problem.yml`,async()=>{await w1(q,"problem.yml",$),u.success(`${w} problem.yml`)})}async function Iy_(q){let $=new wK,w=await fetch(`${$.JUTGE_API_URL}/webstreams/${q}`);if(w.body===null)return null;let f=void 0,K=w.body.getReader();while(!0){let{done:z,value:P}=await K.read();if(z)return f||null;let D=new TextDecoder().decode(P);u.print(D.trim());let Y=D.match(/Problem ([A-Z]\d{5}) created\./);if(Y)f=Y[1];let J=D.match(/Problem ([A-Z]\d{5}) updated\./);if(J)f=J[1]}}var yy_=new h6("upload").summary("Upload problem to Jutge.org").description(`Upload problem to Jutge.org
933
+ `).option("-d, --directory <directory>","problem directory",".").option("-s, --seed <seed>","random seed").option("-f, --format <format>","output format (json|yaml)","json").action(async({directory:q,seed:$,format:w})=>{let f=$?parseInt($,10):Ak(1e6,9999999),K=await zu(q,f);if(w==="json")u.json(K);else u.yaml(K)});oD.command("play").summary("Play a quiz problem").description("Play an interactive quiz test. Questions are shown in sequence; you can review and change answers before submitting.\nInput is a JSON file from `quiz run`; if --input is omitted, a run is generated with a random seed from the given directory.\nIf --output is given, the results (your answers, correct answers, and score per question) are written to that file.").option("-i, --input <input>","input JSON file from quiz run").option("-o, --output <output>","output file for results").option("-d, --directory <directory>","problem directory (used when --input is not provided)",".").option("-s, --seed <seed>","random seed (used when --input is not provided)").action(async({input:q,output:$,directory:w,seed:f})=>{let K=f!==void 0?parseInt(f,10):void 0,z=await dA_(q,w,K),P=await lA_(z);if($!==void 0)await rA_($,P)});var pA_=new h6("upgrade").description("Upgrade to the latest version").action(async()=>{await QZ_()});import{exists as A88,glob as u88,mkdir as C88}from"fs/promises";import{basename as gy_,join as nO,normalize as V88,resolve as M88,sep as N88}from"path";var Ey_=z6(hy_(),1);import{createWriteStream as G88}from"fs";async function iO(q,$){let w=G88($),f=Ey_.default("zip",{zlib:{level:9}}),K=new Promise((z,P)=>{w.on("close",()=>z()),w.on("error",P),f.on("error",P),f.on("warning",(D)=>{if(D.code==="ENOENT")console.warn(D);else P(D)})});f.pipe(w);for(let z of q)f.file(z.sourcePath,{name:z.archivePath});await f.finalize(),await K}async function by_(q){function $(P){let D=[".exe",".o",".hi","~",".bak",".class",".pyc",".pyo"],Y=[C8()+"-","__MACOSX",".DS_Store",".","__pycache__"];for(let Z of D)if(P.endsWith(Z))return!1;let J=V88(P).split(N88);for(let Z of J)for(let k of Y)if(Z.startsWith(k))return!1;return!0}let w=M88(q);if(!w.endsWith(".pbm"))throw Error(`Directory ${q} is not a problem directory (missing .pbm suffix)`);let f=nO(q,C8()+"-zip",wq()),K=gy_(w),z=nO(f,`${K}.zip`);await C88(f,{recursive:!0}),await u.section(`Zipping problem to ${z}`,async()=>{let P=[],D=await Array.fromAsync(u88("**/*",{cwd:q}));for(let J of D)if($(J)){let Z=nO(q,J),k=nO(gy_(w),J);u.print(`adding ${k}`),P.push({sourcePath:Z,archivePath:k})}u.print("Creating zip file..."),await iO(P,z);let Y=await h88(q,z);E88(Y)})}async function h88(q,$){let w=nO(q,"problem.yml");if(await A88(w)){let f=V$.parse(await X3(w));return await b88(q,f,$)}else return await g88(q,$)}function E88(q){let $={"problem.yml":q};u.yaml($),u.url(`https://jutge.org/problems/${q.problem_nm}`)}async function g88(q,$){return await u.section("Creating problem in Jutge.org",async()=>{let w=await a4(),z={problem_nm:"",email:(await w.student.profile.get()).email,passcode:jP(),shared_testcases:!1,shared_solutions:!1,created_at:"",updated_at:""};return await u.section("Creating problem in Jutge.org",async()=>{let P=await dH($,"application/zip"),{id:D}=await w.instructor.problems.create(z.passcode,P),Y=await Iy_(D);if(!Y)throw Error("Upload failed");z.problem_nm=Y,z.created_at=new Date().toISOString(),z.updated_at=new Date().toISOString()}),await Ry_(q,z,"Created"),u.print(""),u.success(`Problem ${z.problem_nm} created successfully`),z})}async function b88(q,$,w){return await u.section("Updating problem in Jutge.org",async()=>{let f=await a4();return await u.section("Updating problem in Jutge.org",async()=>{let K=await dH(w,"application/zip"),{id:z}=await f.instructor.problems.update($.problem_nm,K);if(!await Iy_(z))throw Error("Upload failed");$.updated_at=new Date().toISOString()}),await Ry_(q,$,"Updated"),u.print(""),u.success(`Problem ${$.problem_nm} updated successfully`),$})}async function Ry_(q,$,w){await u.section(`${w==="Created"?"Creating":"Updating"} problem.yml`,async()=>{await w1(q,"problem.yml",$),u.success(`${w} problem.yml`)})}async function Iy_(q){let $=new wK,w=await fetch(`${$.JUTGE_API_URL}/webstreams/${q}`);if(w.body===null)return null;let f=void 0,K=w.body.getReader();while(!0){let{done:z,value:P}=await K.read();if(z)return f||null;let D=new TextDecoder().decode(P);u.print(D.trim());let Y=D.match(/Problem ([A-Z]\d{5}) created\./);if(Y)f=Y[1];let J=D.match(/Problem ([A-Z]\d{5}) updated\./);if(J)f=J[1]}}var yy_=new h6("upload").summary("Upload problem to Jutge.org").description(`Upload problem to Jutge.org
934
934
 
935
935
  If problem.yml exists, the problem will be updated at Jutge.org using that information (which includes its problem id).
936
936
  If problem.yml does not exist, a new problem will be created at Jutge.org and problem.yml will be generated.
@@ -89,7 +89,7 @@ Problem statements are stored in LaTeX files named `problem.lang.tex`, where `la
89
89
 
90
90
  ### Demo problem
91
91
 
92
- The clonable `demo` problem contains an example of a problem statement with many features that can be used in your own problem statements; see [demo.tex](demo.tex) for examples and inspiration.
92
+ The clonable `demo` problem contains an example of a problem statement with many features that can be used in your own problem statements; see [demo.tex](../assets/problems/demo/demo.pbm/problem.en.tex) for examples and inspiration.
93
93
 
94
94
  ### Structure
95
95
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jutge.org/toolkit",
3
3
  "description": "Toolkit to prepare problems for Jutge.org",
4
- "version": "4.4.28",
4
+ "version": "4.4.29",
5
5
  "homepage": "https://jutge.org",
6
6
  "author": {
7
7
  "name": "Jutge.org",