private void ApplyMacros(ProblemContext context) { foreach (var macro in context.Macros) { if (context.Spec.Text.NotEmpty() && context.Spec.Text.Contains(macro.Key)) { context.Spec.Text = context.Spec.Text.Replace(macro.Key, macro.Value); } if (context.Flag.GradeInputData.NotEmpty() && context.Flag.GradeInputData.Contains(macro.Key)) { context.Flag.GradeInputData = context.Flag.GradeInputData.Replace(macro.Key, macro.Value); } } if (context.Flag.Workspace == null) { return; } foreach (var vm in context.Flag.Workspace.Vms) { if (vm.Replicas < 0) { vm.Replicas = context.Problem.Team?.Players?.Count() ?? 1; } } }
/// <summary> /// Save submitted flag /// </summary> /// <param name="context"></param> /// <param name="flag"></param> private void SaveFlag(ProblemContext context, ProblemFlag flag) { string fn = Path.Combine(context.ProblemFolder, flag.SubmissionId + ".json"); string data = JsonConvert.SerializeObject(flag); File.WriteAllText(fn, data); }
private void FetchTemplates(ProblemContext context) { if (context.Flag.Workspace?.CustomizeTemplates ?? false) { string templates = Mojo.Templates(context.Flag.Workspace.Id).Result; File.WriteAllText(Path.Combine(context.ProblemFolder, "_templates.json"), templates); } }
private void Deploy(ProblemContext context) { // TODO: check max-concurrent-problems if (context.Flag.Workspace == null) { return; } if (context.Flag.Iso.NotEmpty()) { context.Flag.Workspace.Iso = context.Flag.Iso; } string fn = Path.Combine(context.ProblemFolder, "_templates.json"); if (File.Exists(fn)) { context.Flag.Workspace.Templates = File.ReadAllText(fn); } // temp transition mapping var spec = JsonConvert.DeserializeObject <TopoMojo.Models.GamespaceSpec>( JsonConvert.SerializeObject(context.Flag.Workspace) ); spec.WorkspaceId = context.Flag.Workspace.Id; spec.IsolationId = context.Problem.IsolationId; var state = Mojo.Start(spec).Result; string consoleMarkdown = "> Gamespace Resources: " + String.Join( " | ", state.Vms .Select(v => $"[{v.Name.Untagged()}](/console/{v.Id}/{v.Name.Untagged()}/{spec.IsolationId})") ); context.ProblemState.GamespaceText = consoleMarkdown; string markdownMarker = "<!--tm doc-->"; if ( spec.AppendMarkdown && state.Markdown.NotEmpty() && !context.ProblemState.Text.Contains(markdownMarker)) { context.ProblemState.Text += $"{state.Markdown}\n{markdownMarker}"; } context.ProblemState.GamespaceReady = true; context.Flag.Workspace.Templates = null; Data.SaveContext(context); }
public ProblemController(ProblemContext context) { _context = context; if (_context.ProblemItems.Count() == 0) { _context.ProblemItems.Add(new ProblemItem { Name = "Проблема" }); _context.SaveChanges(); } }
private void HydrateFlagFiles(ProblemContext context) { if (context.Flag.Files.IsEmpty() || !Directory.Exists(context.ChallengeFolder)) { return; } string[] files = Directory.GetFiles(context.ChallengeFolder, "*", SearchOption.AllDirectories); var selectedFiles = new List <string>(); foreach (string target in context.Flag.Files) { if (files.Contains(target)) { selectedFiles.Add(target); continue; } string match = files.FirstOrDefault(f => Path.GetFileName(f) == target); if (match.NotEmpty()) { selectedFiles.Add(match); continue; } var rule = target.Split(":"); if (int.TryParse(rule[0], out int count)) { for (int i = 0; i < count; i++) { string[] pool = files .Where(f => f.LikeGlob(rule[1])) .Except(selectedFiles) .ToArray(); if (pool.Length > 0) { selectedFiles.Add(pool[new Random().Next(pool.Length)]); } else { break; } } } } context.Flag.Files = selectedFiles.ToArray(); Array.Sort(context.Flag.Files); }
public Form1() { InitializeComponent(); Bitmap data = (Bitmap)Bitmap.FromFile("map.jpg"); ProblemContext.LoadFromImage((Bitmap)Bitmap.FromFile("map.jpg")); this.BackgroundImage = data; this.Width = this.BackgroundImage.Width; this.Height = this.BackgroundImage.Height; this.Paint += new PaintEventHandler(Form1_Paint); this.MouseMove += new MouseEventHandler(Form1_MouseMove); this.MouseClick += new MouseEventHandler(Form1_MouseClick); this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); this.UpdateStyles(); this.button1.Text = "Compute EST path"; }
private void BuildIso(ProblemContext context) { if (context.Flag.Iso.NotEmpty() || context.Flag.Files.IsEmpty()) { return; } string path = Path.Combine(context.IsoFolder, context.Problem.Id + ".iso"); try { var builder = new CDBuilder { UseJoliet = true, VolumeIdentifier = "VOL" + new Random().Next().ToString("X") }; foreach (string file in context.Flag.Files) { builder.AddFile(Path.GetFileName(file), file); } if (context.Spec.Document.NotEmpty()) { string docpath = Path.Combine(context.ChallengeFolder, context.Spec.Document); if (!File.Exists(docpath)) { docpath = Path.Combine(context.IsoFolder, context.Spec.Document); } if (File.Exists(docpath)) { builder.AddFile(Path.GetFileName(docpath), docpath); } } builder.Build(path); context.Flag.Iso = Path.GetFileName(path); } catch (Exception ex) { Logger.LogError(ex, $"Error building iso file for {context.Spec.Title}."); } }
private void ResolveText(ProblemContext context) { var links = new List <string>(); if (context.Spec.Document.NotEmpty()) { links.Add($"[PDF File]({Options.DownloadUrl}/{context.Spec.Document})"); } if (context.Flag.Iso.NotEmpty() && !context.Flag.IsoRestricted) { // try get filesize string fsize = ""; string path = Path.Combine(Options.IsoPath, context.Flag.Iso); if (File.Exists(path)) { var info = new FileInfo(path); fsize = info.Length.ToDisplayBytes(); } links.Add($"[ISO File {fsize}]({Options.DownloadUrl}/{context.Flag.Iso})"); } if (links.Count > 0) { var linkText = "> Download Resources: " + string.Join(" | ", links); context.Spec.Text = string.Join("\n\n", linkText, context.Spec.Text); } context.Spec.Text = string.IsNullOrWhiteSpace(context.Spec.Text) ? string.Empty : Regex.Replace(context.Spec.Text, "]\\(img/", $"]({Options.DownloadUrl}/img/"); context.Flag.Text = string.IsNullOrWhiteSpace(context.Flag.Text) ? string.Empty : Regex.Replace(context.Flag.Text, "]\\(img/", $"]({Options.DownloadUrl}/img/"); context.ProblemState.Text = string.Join("\n", context.Spec.Text, context.Flag.Text); }
private void Generate(ProblemContext context) { if (context.Flag != null) { return; } SelectFlag(context); ApplyMacros(context); FetchTemplates(context); HydrateFlagFiles(context); ExecuteScript(context); BuildIso(context); ResolveText(context); Data.SaveContext(context); }
private void SelectFlag(ProblemContext context) { if (context.Flag != null) { return; } if (!context.Problem.FlagIndex.HasValue) { context.Problem.FlagIndex = new Random().Next(context.Spec.Flags.Length); } context.FlagIndex = context.Problem.FlagIndex.Value; context.Flag = context.Spec.Flags[context.FlagIndex].Map <FlagSpec>(); if (context.Flag.Workspace == null && context.Spec.Workspace != null) { context.Flag.Workspace = context.Spec.Workspace; } context.ProblemState.HasGamespace = context.Flag.Workspace != null; context.ProblemState.Tokens = GetTokens(context.Flag); }
public ProblemsController(ProblemContext context) { _context = context; }
public MatchAlphaNumeric(Options options, ILogger logger, ProblemContext problemContext) : base(options, logger, problemContext) { }
/// <summary> /// Save a ProblemContext to a file /// </summary> /// <param name="context"></param> public void SaveContext(ProblemContext context) { string contextPath = Path.Combine(Data.RootPath, Options.ProblemPath, context.Problem.Id, "_context.json"); File.WriteAllText(contextPath, JsonConvert.SerializeObject(context, Formatting.Indented)); }
/// <summary> /// Grades a flag submitted for a problem /// </summary> /// <param name="flag"></param> /// <returns></returns> public GradedSubmission Grade(ProblemFlag flag) { ProblemContext context = null; GradingResult result = null; Logger.LogDebug($"grading {flag.Id}"); var submissionStatus = SubmissionStatus.Submitted; try { context = Data.LoadContext(flag.Id); if (context == null || context.Flag == null) { throw new NotFoundException(); } if (context.ProblemState.Status == ProblemStatus.Complete) { throw new ProblemCompleteException(); } SaveFlag(context, flag); IGradingStrategy strategy = null; switch (context.Flag.Type) { case FlagType.MatchOutput: strategy = new MatchOutput(Options, Logger, context); break; case FlagType.MatchAll: strategy = new MatchAll(Options, Logger, context); break; case FlagType.MatchAny: strategy = new MatchAny(Options, Logger, context); break; case FlagType.Match: strategy = new Match(Options, Logger, context); break; case FlagType.MatchAlphaNumeric: default: strategy = new MatchAlphaNumeric(Options, Logger, context); break; } result = strategy.GradeTokens(flag); } catch (Exception ex) { Logger.LogError(ex, "Had a problem with grading"); } finally { if (context != null && result != null) { submissionStatus = result.Success ? SubmissionStatus.Passed : SubmissionStatus.Failed; var check = false; // if max submissions <= 0 then we accept // unlimited submissions if unsuccessful if (context.Problem.Settings.MaxSubmissions > 0) { if (context.Spec.IsMultiStage) { // if multi stage we only consider the // last graded token incorrect count check = result.GradedTokens.Last().Status != TokenStatusType.Correct && flag.Count >= context.Problem.Settings.MaxSubmissions; } else { check = flag.Count >= context.Problem.Settings.MaxSubmissions; } } var isFinal = result.Success || check; if (isFinal) { //_ = Mojo.Stop(flag.Id); context.ProblemState.End = DateTime.UtcNow; //context.ProblemState.GamespaceReady = false; context.ProblemState.Status = result.Success ? ProblemStatus.Success : ProblemStatus.Failure; } context.ProblemState.Percent = result.CorrectPercent; // map TokenSpec detail along with correct answers var problemStateTokens = new List <Token>(); int index = 0; foreach (var tokenSpec in context.Flag.Tokens) { var correct = result.GradedTokens.SingleOrDefault(t => t.Index == index && t.Status == TokenStatusType.Correct); problemStateTokens.Add(new Token { Index = index, Label = tokenSpec.Label, Percent = context.Flag.Tokens.Length == 1 ? 100 : tokenSpec.Percent, Status = correct?.Status ?? TokenStatusType.Pending, Timestamp = correct?.Timestamp, Value = correct?.Value }); index++; } context.ProblemState.Tokens = problemStateTokens; Data.SaveContext(context); } } Logger.LogDebug($"returning {flag.Id}"); return(new GradedSubmission { ProblemId = flag.Id, SubmissionId = flag.SubmissionId, Status = submissionStatus, State = context?.ProblemState, Timestamp = DateTime.UtcNow, Tokens = result?.GradedTokens }); }
/// <summary> /// Create a new instance of a problem for a team /// </summary> /// <param name="problem"></param> /// <returns></returns> public ProblemState Spawn(Problem problem) { var context = new ProblemContext { Problem = problem, ProblemState = new ProblemState { Id = problem.Id, ChallengeLink = problem.ChallengeLink } }; try { Logger.LogDebug($"initializing {problem.Id}"); context = Initialize(problem); if (!Stats.ClaimSession(context.ProblemState.TeamId, "adhoc", 0)) { throw new Exception($"All {Options.MaxSessions} sessions are in use. Please try again later."); } var start = DateTime.UtcNow; var reportStat = context.Flag == null; Logger.LogDebug($"generating {problem.Id} [index: {problem.FlagIndex ?? -1}]"); Generate(context); Logger.LogDebug($"deploying {problem.Id}"); Deploy(context); if (reportStat) { Stats.ReportStat(new ChallengeStat { Id = problem.ChallengeLink.Id, Sum = (int)DateTime.UtcNow.Subtract(start).TotalSeconds, Count = 1 }); } if (context.ProblemState.Start.IsEmpty()) { context.ProblemState.Start = DateTime.UtcNow; } if (context.ProblemState.Status != ProblemStatus.Failure && context.ProblemState.Status != ProblemStatus.Success && context.ProblemState.Status != ProblemStatus.Complete ) { context.ProblemState.Status = ProblemStatus.Ready; } Data.SaveContext(context); } catch (Exception ex) { context.ProblemState.Status = ProblemStatus.Error; context.ProblemState.Text = ex.Message; Logger.LogError(ex, $"Failed to spawn problem {problem.Id}"); } finally { } return(context.ProblemState); }
public GradingResult(ProblemContext context) { ProblemContext = context; }
public MatchOutput(Options options, ILogger logger, ProblemContext problemContext) : base(options, logger, problemContext) { }
protected GradingStrategy(Options options, ILogger logger, ProblemContext problemContext) { Options = options; Logger = logger; ProblemContext = problemContext; }
private void ExecuteScript(ProblemContext context) { if (context.Flag.GenerateCommand.IsEmpty()) { return; } var process = Process.Start( new ProcessStartInfo { FileName = Options.Command, Arguments = string.Format( Options.CommandArgs, context.ChallengeFolder, context.ProblemFolder, context.Flag.GenerateImage, context.Flag.GenerateCommand ) } ); Logger.LogInformation(process.StartInfo.Arguments); process.WaitForExit(Options.MaxScriptSeconds * 1000); if (!process.HasExited) { process.Kill(); throw new ProblemGenerationTimeoutException(); } if (process.ExitCode > 0) { throw new ProblemGenerationException(); } string fileName = Path.Combine(context.ProblemFolder, context.Flag.GenerateOutputFlag); if (File.Exists(fileName)) { string data = File.ReadAllText(fileName); try { context.Flag.Tokens = Deserializer.Deserialize <TokenSpec[]>(data); } catch { context.Flag.Tokens = new TokenSpec[] { new TokenSpec { Value = data } }; } } fileName = Path.Combine(context.ProblemFolder, context.Flag.GenerateOutputText); if (File.Exists(fileName)) { context.Spec.Text = string.Join("\n\n", context.Spec.Text, File.ReadAllText(fileName)); } fileName = Path.Combine(context.ProblemFolder, context.Flag.GenerateOutputFileList); if (File.Exists(fileName)) { string[] files = File.ReadAllLines(fileName); var additionalFiles = new List <string>(); foreach (string file in files) { string target = file .Replace("/src", context.ChallengeFolder) .Replace("/dst", context.ProblemFolder); if (File.Exists(target)) { additionalFiles.Add(target); } } if (additionalFiles.Count > 0) { context.Flag.Files = context.Flag.Files .Union(additionalFiles) .ToArray(); } } }