public override ExecutionResult Execute(ExecutionContext executionContext)
        {
            var result = new ExecutionResult();

            // Create a temp file with the submission code
            string submissionFilePath;
            try
            {
                submissionFilePath = this.CreateSubmissionFile(executionContext.Code);
            }
            catch (ArgumentException exception)
            {
                result.IsCompiledSuccessfully = false;
                result.CompilerComment = exception.Message;

                return result;
            }

            // Create a sandbox executor source file in the working directory
            var sandboxExecutorSourceFilePath = $"{this.workingDirectory}\\{SandboxExecutorClassName}";
            File.WriteAllText(sandboxExecutorSourceFilePath, this.SandboxExecutorCode);

            // Compile all source files - sandbox executor and submission file
            var compilerPath = this.getCompilerPathFunc(executionContext.CompilerType);
            var compilerResult = this.CompileSourceFiles(
                executionContext.CompilerType,
                compilerPath,
                executionContext.AdditionalCompilerArguments,
                new[] { submissionFilePath, sandboxExecutorSourceFilePath });

            // Assign compiled result info to the execution result
            result.IsCompiledSuccessfully = compilerResult.IsCompiledSuccessfully;
            result.CompilerComment = compilerResult.CompilerComment;
            if (!result.IsCompiledSuccessfully)
            {
                return result;
            }

            // Prepare execution process arguments and time measurement info
            var classPathArgument = $"-classpath \"{this.workingDirectory}\"";

            var submissionFilePathLastIndexOfSlash = submissionFilePath.LastIndexOf('\\');
            var classToExecute = submissionFilePath.Substring(submissionFilePathLastIndexOfSlash + 1);

            var timeMeasurementFilePath = $"{this.workingDirectory}\\{TimeMeasurementFileName}";

            // Create an executor and a checker
            var executor = new StandardProcessExecutor();
            var checker = Checker.CreateChecker(executionContext.CheckerAssemblyName, executionContext.CheckerTypeName, executionContext.CheckerParameter);

            // Process the submission and check each test
            foreach (var test in executionContext.Tests)
            {
                var processExecutionResult = executor.Execute(
                    this.javaExecutablePath,
                    test.Input,
                    executionContext.TimeLimit,
                    executionContext.MemoryLimit,
                    new[] { classPathArgument, SandboxExecutorClassName, classToExecute, $"\"{timeMeasurementFilePath}\"" });

                UpdateExecutionTime(timeMeasurementFilePath, processExecutionResult, executionContext.TimeLimit);

                var testResult = this.ExecuteAndCheckTest(test, processExecutionResult, checker, processExecutionResult.ReceivedOutput);
                result.TestResults.Add(testResult);
            }

            return result;
        }
        public override ExecutionResult Execute(ExecutionContext executionContext)
        {
            var result = new ExecutionResult();

            // Copy the sandbox executor source code to a file in the working directory
            File.WriteAllText(this.SandboxExecutorSourceFilePath, this.SandboxExecutorCode);

            // Create a temp file with the submission code
            string submissionFilePath;
            try
            {
                submissionFilePath = this.CreateSubmissionFile(executionContext);
            }
            catch (ArgumentException exception)
            {
                result.IsCompiledSuccessfully = false;
                result.CompilerComment = exception.Message;

                return result;
            }

            var compilerResult = this.DoCompile(executionContext, submissionFilePath);

            // Assign compiled result info to the execution result
            result.IsCompiledSuccessfully = compilerResult.IsCompiledSuccessfully;
            result.CompilerComment = compilerResult.CompilerComment;
            if (!result.IsCompiledSuccessfully)
            {
                return result;
            }

            // Prepare execution process arguments and time measurement info
            var classPathArgument = $"-classpath \"{this.WorkingDirectory}\"";

            var classToExecuteFilePath = compilerResult.OutputFile;
            var classToExecute = classToExecuteFilePath
                .Substring(
                    this.WorkingDirectory.Length + 1,
                    classToExecuteFilePath.Length - this.WorkingDirectory.Length - JavaCompiledFileExtension.Length - 1)
                .Replace('\\', '.');

            var timeMeasurementFilePath = $"{this.WorkingDirectory}\\{TimeMeasurementFileName}";

            // Create an executor and a checker
            var executor = new StandardProcessExecutor();
            var checker = Checker.CreateChecker(executionContext.CheckerAssemblyName, executionContext.CheckerTypeName, executionContext.CheckerParameter);

            // Process the submission and check each test
            foreach (var test in executionContext.Tests)
            {
                var processExecutionResult = executor.Execute(
                    this.javaExecutablePath,
                    test.Input,
                    executionContext.TimeLimit * 2, // Java virtual machine takes more time to start up
                    executionContext.MemoryLimit,
                    new[] { classPathArgument, SandboxExecutorClassName, classToExecute, $"\"{timeMeasurementFilePath}\"" });

                UpdateExecutionTime(timeMeasurementFilePath, processExecutionResult, executionContext.TimeLimit);

                var testResult = this.ExecuteAndCheckTest(test, processExecutionResult, checker, processExecutionResult.ReceivedOutput);
                result.TestResults.Add(testResult);
            }

            return result;
        }