@SuppressWarnings({"PMD.UnusedPrivateField", "PMD.CommentRequired"})
public class ProcessResult {
  private int exitCode;
  private String stdout;
  private String stderr;

  public ProcessResult(final int exitCode, final String stdout, final String stderr) {
    this.exitCode = exitCode;
    this.stdout = stdout;
    this.stderr = stderr;
  }

  public int getExitCode() {
    return exitCode;
  }

  public String getStdout() {
    return stdout;
  }

  public String getStderr() {
    return stderr;
  }
} @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"})
public final class CppCodeGenerator {

  private CppCodeGenerator() {}

  /**
   * Generate a  main.cpp to call solution.h.
   *
   * @param function the function type info
   * @param fromFile read testcases from file or stdin
   * @return source code of main.cpp
   */
  public static String generateMain(final Function function, boolean fromFile) {
    final StringBuilder result = new StringBuilder();
    result.append("#include <algohub/serialize.h>\n#include <algohub/deserialize.h>\n#include "
        + "<algohub/judge_result.h>\nusing namespace std;\n#include \"solution.cpp\"\n\n\n");

    Indentation.append(result, "int main(int argc, char* argv[]) {\n", 0);
    Indentation.append(result, "signal(SIGSEGV, sigsegv_handler);\n", 1);
    Indentation.append(result, "signal(SIGABRT, sigabrt_handler);\n\n", 1);
    if(fromFile) {
      Indentation.append(result, "ifstream ifs(\"testcases.json\");\n", 1);
      Indentation.append(result, "string testcases_text((istreambuf_iterator<char>(ifs)), (istreambuf_iterator<char>()));\n", 1);
    } else {
      Indentation.append(result, "string testcases_text;\n", 1);
      Indentation.append(result, "getline(cin, testcases_text);\n", 1);
    }
    Indentation.append(result, "rapidjson::Document testcases_json;\n", 1);
    Indentation.append(result, "rapidjson::Document::AllocatorType& allocator = testcases_json.GetAllocator();\n", 1);
    Indentation.append(result, "testcases_json.Parse(testcases_text.c_str());\n", 1);
    Indentation.append(result, "assert (testcases_json.IsArray());\n\n", 1);

    Indentation
        .append(result, "for (rapidjson::SizeType i = 0; i < testcases_json.Size(); i++) {\n", 1);
    Indentation.append(result, "const rapidjson::Value& input = testcases_json[i][\"input\"];\n", 2);
    Indentation.append(result, "assert (input.IsArray());\n\n", 2);

    // deserialize expected output
    Indentation.append(result,
        generateTypeDeclaration(function.getReturn_().getType()) + " expected_output;\n", 2);
    Indentation.append(result, "from_json(testcases_json[i][\"output\"], expected_output);\n\n", 2);

    // Deserialize arguments
    final Function.Parameter[] parameters = function.getParameters();
    for (int i = 0; i < parameters.length; ++i) {
      Indentation.append(result,
          generateTypeDeclaration(parameters[i].getType()) + " algohub_" + parameters[i].getName()
              + ";\n", 2);
      Indentation
          .append(result, "from_json(input[" + i + "], algohub_" + parameters[i].getName() + ");\n",
              2);
    }
    result.append('\n');

    Indentation.append(result, "const auto result = " + function.getName() + "(", 2);

    for (final Function.Parameter parameter : parameters) {
      result.append("algohub_").append(parameter.getName()).append(", ");
    }

    // delete the last unnecessary " ,"
    if (parameters.length > 0) {
      result.delete(result.length() - 2, result.length());
    }
    result.append(");\n\n");

    Indentation.append(result, "if (expected_output == result) {\n", 2);
    Indentation.append(result, "judge_result.testcase_passed_count += 1;\n", 3);
    Indentation.append(result, "} else {\n", 2);
    Indentation.append(result, "judge_result.input = rapidjson::Value(input, allocator).Move();\n", 3);
    Indentation.append(result, "judge_result.expected_output = testcases_json[i][\"output\"];\n", 3);
    Indentation.append(result, "judge_result.output = to_json(result, allocator);\n", 3);
    Indentation.append(result, "break;\n", 3);
    Indentation.append(result, "}\n", 2);
    Indentation.append(result, "}\n\n", 1);

    Indentation
        .append(result, "if (judge_result.testcase_passed_count < testcases_json.Size()) {\n", 1);
    Indentation.append(result, "judge_result.status_code = StatusCode::WRONG_ANSWER;\n", 2);
    Indentation.append(result, "} else {\n", 1);
    Indentation.append(result, "judge_result.status_code = StatusCode::ACCEPTED;\n", 2);
    Indentation.append(result, "}\n\n", 1);

    Indentation.append(result, "std::cout << std::endl << judge_result.to_string();\n", 1);
    Indentation.append(result, "return 0;\n}\n", 1);
    return result.toString();
  }

  /**
   * Generate a type declaration.
   *
   * <p>post order, recursive.</p>
   *
   * @param type the type
   * @return type declaration
   */
  static String generateTypeDeclaration(final TypeNode type) {
    if (!type.isContainer()) {
      return TypeMap.TYPE_MAP.get(LanguageType.CPLUSPLUS).get(type.getValue());
    }

    final String containerTypeStr =
        TypeMap.TYPE_MAP.get(LanguageType.CPLUSPLUS).get(type.getValue());
    if (type.getKeyType().isPresent()) {
      return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get()) + ", "
          + generateTypeDeclaration(type.getElementType().get()) + ">";
    } else {
      final String typeDeclaration =
          containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get()) + ">";
      return addSharedPtr(type, typeDeclaration);
    }
  }

  /**
   * Generate an empty function with comments.
   * @param function Function prototype
   * @return source code of a empty function
   */
  public static String generateEmptyFunction(final Function function) {
    return FunctionGenerator.generateFunction(function, LanguageType.CPLUSPLUS, 0);
  }

  private static String addSharedPtr(TypeNode type, String elemType) {
    if (type.getValue() == IntermediateType.BINARY_TREE_NODE
        || type.getValue() == IntermediateType.LINKED_LIST_NODE) {
      return "shared_ptr<" + elemType + ">";
    } else {
      return elemType;
    }
  }
} @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"})
public final class PythonCodeGenerator {

  private PythonCodeGenerator() {}

  /**
   * Generate the main function.
   *
   * @param function Function type info.
   * @param fromFile read testcases from file or stdin
   * @return the complete source code
   */
  @SuppressWarnings({"PMD.PreserveStackTrace"})
  public static String generateMain(final Function function, boolean fromFile) {
    final StringBuilder result = new StringBuilder();

    result.append("import json\nimport collections\nfrom algohub import *\nimport solution\n\n"
        + "if __name__ == '__main__':\n");

    final Function.Parameter[] parameters = function.getParameters();
    try {
      for (final Function.Parameter parameter : parameters) {
        Indentation.append(result,
            parameter.getName() + "_type = TypeNode.from_json('" + ObjectMapperInstance.INSTANCE
                .writeValueAsString(parameter.getType()) + "')\n", 1);

      }
      Indentation.append(result,
          "output_type = TypeNode.from_json('" + ObjectMapperInstance.INSTANCE
              .writeValueAsString(function.getReturn_().getType()) + "')\n\n", 1);
    } catch (JsonProcessingException e) {  // impossible
      throw new IllegalStateException(e.getMessage());
    }

    if(fromFile) {
      Indentation.append(result, "with open(\"testcases.json\", \"r\") as f:\n", 1);
      Indentation.append(result, "raw_testcases = json.loads(f.read())\n", 2);
    } else {
      Indentation.append(result, "raw_testcases = json.loads(input())\n", 1);
    }
    Indentation.append(result, "assert isinstance(raw_testcases, list)\n\n", 1);

    Indentation.append(result, "judge_result = JudgeResult(StatusCode.ACCEPTED)\n\n", 1);

    Indentation.append(result, "for i in range(len(raw_testcases)):\n", 1);
    Indentation.append(result, "test_case = raw_testcases[i]\n", 2);
    for (int i = 0; i < parameters.length; ++i) {
      final Function.Parameter parameter = parameters[i];
      Indentation.append(result,
          "algohub_" + parameter.getName() + " = from_json(" + "test_case['input'][" + i + "], "
              + parameter.getName() + "_type)\n", 2);
    }

    Indentation
        .append(result, "expected_output = from_json(" + "test_case['output'], output_type)\n\n",
            2);

    Indentation.append(result, "actual_output = solution." + function.getName() + "(", 2);
    for (final Function.Parameter parameter : parameters) {
      result.append("algohub_").append(parameter.getName()).append(", ");
    }
    if (parameters.length > 0) {
      result.delete(result.length() - 2, result.length());
    }
    result.append(")\n\n");

    Indentation.append(result, "if actual_output == expected_output:\n", 2);
    Indentation.append(result, "judge_result.testcase_passed_count += 1\n", 3);
    Indentation.append(result, "else:\n", 2);
    Indentation.append(result, "judge_result.input = test_case['input']\n", 3);
    Indentation.append(result, "judge_result.expected_output = test_case['output']\n", 3);
    Indentation.append(result, "judge_result.output = to_json(actual_output, output_type);\n", 3);
    Indentation.append(result, "break\n\n", 3);

    Indentation.append(result,
        "if judge_result.testcase_passed_count < len(raw_testcases):\n", 1);
    Indentation.append(result, "judge_result.status_code = StatusCode.WRONG_ANSWER\n", 2);
    Indentation.append(result, "else:\n", 1);
    Indentation.append(result, "judge_result.status_code = StatusCode.ACCEPTED\n\n", 2);

    Indentation.append(result, "print(judge_result)\n", 1);
    return result.toString();
  }

  /**
   * Generate a type declaration.
   *
   * <p>post order, recursive.</p>
   *
   * @param type the type
   * @return type declaration
   */
  static String generateTypeDeclaration(final TypeNode type) {
    if (!type.isContainer()) {
      return TypeMap.PYTHON_TYPE_MAP.get(type.getValue());
    }

    if (type.getValue() ==  IntermediateType.ARRAY || type.getValue() ==  IntermediateType.LIST) {
      return generateTypeDeclaration(type.getElementType().get()) + "[]";
    } else {
      final String containerTypeStr = TypeMap.PYTHON_TYPE_MAP.get(type.getValue());
      if (type.getKeyType().isPresent()) {
        return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get())
            + ", " + generateTypeDeclaration(type.getElementType().get())
            + ">";
      } else {
        return containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get()) + ">";
      }
    }
  }

  /**
   * Generate an empty function with comments.
   * @param function Function prototype
   * @return source code of a empty function
   */
  public static String generateEmptyFunction(final Function function) {
    return generateEmptyFunction(function, 0);
  }

  static String generateEmptyFunction(final Function function, final int indent) {
    final StringBuilder result = new StringBuilder();

    // function comment
    for (final Function.Parameter p : function.getParameters()) {
      Indentation.append(result,
          "# @param {" + generateTypeDeclaration(p.getType())
              + "} " + p.getName() + " " + p.getComment() + "\n", indent);
    }

    final Function.Return return_ = function.getReturn_();
    Indentation.append(result, "# @return {" +
        generateTypeDeclaration(return_.getType()) + "} " + return_.getComment() + "\n", indent);

    // function body
    Indentation.append(result, "def " + function.getName() + "(", indent);

    for (final Function.Parameter p : function.getParameters()) {
      result.append(p.getName()).append(", ");
    }
    // delete the last unnecessary " ,"
    result.delete(result.length() - 2, result.length());
    result.append("):\n");
    Indentation.append(result, "# Write your code here\n", indent + 1);

    return result.toString();
  }
} @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"})
public final class RubyCodeGenerator {

  private RubyCodeGenerator() {}

  /**
   * Generate the main function.
   *
   * @param function Funciton prototype.
   * @param fromFile read testcases from file or stdin
   * @return the complete source code.
   */
  @SuppressWarnings({"PMD.PreserveStackTrace"})
  public static String generateMain(final Function function, boolean fromFile) {
    final StringBuilder result = new StringBuilder();

    result.append("require 'json'\nrequire 'algohub'\nrequire_relative './solution'\n\n\n"
        + "if __FILE__ == $0\n");

    final Function.Parameter[] parameters = function.getParameters();
    try {
      for (final Function.Parameter parameter : parameters) {
        Indentation.append(result, parameter.getName() + "_type = Algohub::TypeNode.from_json('"
            + ObjectMapperInstance.INSTANCE.writeValueAsString(parameter.getType()) + "')\n", 1);

      }
      Indentation.append(result,
          "output_type = Algohub::TypeNode.from_json('" + ObjectMapperInstance.INSTANCE
              .writeValueAsString(function.getReturn_().getType()) + "')\n\n", 1);
    } catch (JsonProcessingException e) {  // impossible
      throw new IllegalStateException(e.getMessage());
    }

    if(fromFile) {
      Indentation.append(result, "raw_testcases = JSON.load(IO.read(\"testcases.json\"))\n\n", 1);
    } else {
      Indentation.append(result, "raw_testcases = JSON.load(STDIN.gets())\n\n", 1);
    }

    Indentation.append(result, "judge_result = Algohub::JudgeResult.new(Algohub::StatusCode::ACCEPTED)\n\n", 1);

    Indentation.append(result, "raw_testcases.size.times do |i|\n", 1);
    Indentation.append(result, "test_case = raw_testcases[i]\n", 2);
    for (int i = 0; i < parameters.length; ++i) {
      final Function.Parameter parameter = parameters[i];
      Indentation.append(result,
          "algohub_" + parameter.getName() + " = Algohub.from_json(" + "test_case['input'][" + i
              + "], " + parameter.getName() + "_type)\n", 2);
    }

    Indentation.append(result,
        "expected_output = Algohub.from_json(" + "test_case['output'], output_type)\n\n", 2);

    Indentation.append(result, "actual_output = " + function.getName() + "(", 2);
    for (final Function.Parameter parameter : parameters) {
      result.append("algohub_").append(parameter.getName()).append(", ");
    }
    if (parameters.length > 0) {
      result.delete(result.length() - 2, result.length());
    }
    result.append(")\n\n");

    Indentation.append(result, "if actual_output == expected_output\n", 2);
    Indentation.append(result, "judge_result.testcase_passed_count += 1\n", 3);
    Indentation.append(result, "else\n", 2);
    Indentation.append(result, "judge_result.input = test_case['input']\n", 3);
    Indentation.append(result, "judge_result.expected_output = test_case['output']\n", 3);
    Indentation.append(result, "judge_result.output = Algohub.to_json(actual_output, output_type)\n", 3);
    Indentation.append(result, "break\n", 3);
    Indentation.append(result, "end\n", 2);
    Indentation.append(result, "end\n\n", 1);

    Indentation.append(result,
        "if(judge_result.testcase_passed_count < raw_testcases.size)\n", 1);
    Indentation.append(result, "judge_result.status_code = Algohub::StatusCode::WRONG_ANSWER\n", 2);
    Indentation.append(result, "else\n", 1);
    Indentation.append(result, "judge_result.status_code = Algohub::StatusCode::ACCEPTED\n", 2);
    Indentation.append(result, "end\n\n", 1);

    Indentation.append(result, "print(judge_result)\n", 1);
    result.append("end\n");
    return result.toString();
  }

  /**
   * Generate a type declaration.
   *
   * <p>post order, recursive.</p>
   *
   * @param type the type
   * @return type declaration
   */
  static String generateTypeDeclaration(final TypeNode type) {
    if (!type.isContainer()) {
      return TypeMap.RUBY_TYPE_MAP.get(type.getValue());
    }

    if (type.getValue() ==  IntermediateType.ARRAY || type.getValue() ==  IntermediateType.LIST) {
      return generateTypeDeclaration(type.getElementType().get()) + "[]";
    } else {
      final String containerTypeStr = TypeMap.RUBY_TYPE_MAP.get(type.getValue());
      if (type.getKeyType().isPresent()) {
        return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get())
            + ", " + generateTypeDeclaration(type.getElementType().get())
            + ">";
      } else {
        return containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get()) + ">";
      }
    }
  }

  /**
   * Generate an empty function with comments.
   * @param function Function prototype
   * @return source code of a empty function
   */
  public static String generateEmptyFunction(final Function function) {
    final StringBuilder result = new StringBuilder();

    // function comment
    for (final Function.Parameter p : function.getParameters()) {
      result.append("# @param {" + generateTypeDeclaration(p.getType())+ "} " +
              p.getName() + " " + p.getComment() + "\n");
    }

    final Function.Return return_ = function.getReturn_();
    result.append("# @return {" + generateTypeDeclaration(return_.getType()) + "} " +
        return_.getComment() + "\ndef " + function.getName() + "(");
    for (final Function.Parameter p : function.getParameters()) {
      result.append(p.getName()).append(", ");
    }
    // delete the last unnecessary " ,"
    result.delete(result.length() - 2, result.length());
    result.append(")\n    # Write your code here\nend");

    return result.toString();
  }
} @SuppressWarnings("PMD.CommentRequired")
public final class JudgeResult {
  @JsonProperty(value = "status_code", required = true) private StatusCode statusCode;
  @JsonProperty("error_message") private String errorMessage;
  private ArrayNode input;
  private JsonNode output;
  @JsonProperty("expected_output") private JsonNode expectedOutput;
  @JsonProperty("testcase_passed_count") private int testcasePassedCount;
  @JsonProperty("testcase_total_count") private int testcaseTotalCount;
  @JsonProperty("elapsed_time") private long elapsedTime; // milliseconds
  @JsonProperty("consumed_memory") private long consumedMemory;  // bytes

  /**
   * Since some fields are immutable, need to provide a method for Jackson.
   */
  @JsonCreator public JudgeResult(@JsonProperty(value = "status_code", required = true) final StatusCode statusCode,
      @JsonProperty("error_message") final String errorMessage,
      @JsonProperty("input") final ArrayNode input, @JsonProperty("output") final JsonNode output,
      @JsonProperty("expected_output") final JsonNode expectedOutput,
      @JsonProperty("testcase_passed_count") final int testcasePassedCount,
      @JsonProperty("testcase_total_count") final int testcaseTotalCount,
      @JsonProperty("elapsed_time") final long elapsedTime,
      @JsonProperty("consumed_memory") final long consumedMemory) {
    this.statusCode = statusCode;
    this.errorMessage = errorMessage;
    this.input = input;
    this.output = output;
    this.expectedOutput = expectedOutput;
    this.testcasePassedCount = testcasePassedCount;
    this.testcaseTotalCount = testcaseTotalCount;
    this.elapsedTime = elapsedTime;
    this.consumedMemory = consumedMemory;
  }

  /**
   * Constructor.
   */
  public JudgeResult(final String compileErrorMsg) {
    this.statusCode = StatusCode.COMPILE_ERROR;
    this.errorMessage = compileErrorMsg;
  }

  // PENDING or RUNNING
  public JudgeResult(final StatusCode statusCode) {
    this.statusCode = statusCode;
  }

  public StatusCode getStatusCode() {
    return statusCode;
  }

  public String getErrorMessage() {
    return errorMessage;
  }

  public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
  }

  public ArrayNode getInput() {
    return input;
  }

  public JsonNode getOutput() {
    return output;
  }

  public JsonNode getExpectedOutput() {
    return expectedOutput;
  }

  public int getTestcasePassedCount() {
    return testcasePassedCount;
  }

  public int getTestcaseTotalCount() {
    return testcaseTotalCount;
  }

  public void setTestcaseTotalCount(int n) {
    this.testcaseTotalCount = n;
  }

  public long getElapsedTime() {
    return elapsedTime;
  }

  public long getConsumedMemory() {
    return consumedMemory;
  }

  public void setElapsedTime(long elapsedTime) {
    this.elapsedTime = elapsedTime;
  }
} @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "PMD.UnusedPrivateField", "PMD.SingularField",
    "PMD.ArrayIsStoredDirectly", "PMD.CommentRequired"})
@JsonIgnoreProperties(ignoreUnknown = true)
public class Problem {
  @JsonProperty(required = true) private final Map<String, String> title;
  @JsonProperty(required = true) private final Map<String, String> description;
  @JsonProperty(required = true) private final Function function;
  @JsonProperty(value = "test_cases", required = true) private final TestCase[] testCases;
  private final String category;
  private final String[] tags;
  private final int difficulty;
  @JsonProperty("time_limit") private final int timeLimit;
  @JsonProperty("memory_limit") private final int memoryLimit;
  @JsonProperty("related_problems") private final String[] relatedProblems;
  private final Map<String, String> author;
  @JsonProperty("test_cases_generator") private final String testCasesGenerator;

  /**
   * Since some fields are immutable, need to provide a method for Jackson.
   */
  @SuppressWarnings({"PMD.ExcessiveParameterList", "PMD.ShortVariable"}) @JsonCreator
  public Problem(
      @JsonProperty(value = "title", required = true) final Map<String, String> title,
      @JsonProperty(value = "description", required = true) final Map<String, String> description,
      @JsonProperty(value = "function", required = true) final Function function,
      @JsonProperty(value = "test_cases", required = true) final TestCase[] testCases,
      @JsonProperty("category") final String category,
      @JsonProperty("tags") final String[] tags,
      @JsonProperty("difficulty") final int difficulty,
      @JsonProperty("time_limit") final int timeLimit,
      @JsonProperty("memory_limit") final int memoryLimit,
      @JsonProperty("related_problems") final String[] relatedProblems,
      @JsonProperty("author") final Map<String, String> author,
      @JsonProperty("test_cases_generator") final String testCasesGenerator) {
    this.title = title;
    this.description = description;
    this.category = category;
    this.tags = tags;
    this.difficulty = difficulty;
    this.timeLimit = timeLimit;
    this.memoryLimit = memoryLimit;
    this.relatedProblems = relatedProblems;
    this.function = function;
    this.author = author;
    this.testCases = testCases;
    this.testCasesGenerator = testCasesGenerator;
  }

  /**
   * Test cases.
   */
  @JsonIgnoreProperties(ignoreUnknown = true) public static class TestCase {
    @JsonProperty(required = true) private final ArrayNode input;
    @JsonProperty(required = true) private final JsonNode output;

    @JsonCreator public TestCase(
        @JsonProperty(value = "input", required = true) final ArrayNode input,
        @JsonProperty(value = "output", required = true) final JsonNode output) {
      this.input = input;
      this.output = output;
    }

    public ArrayNode getInput() {
      return input;
    }

    public JsonNode getOutput() {
      return output;
    }
  }

  public String getId() {
    return this.title.get("en").replaceAll("\\s+", "-").replaceAll("['\\(\\),]+", "").toLowerCase();
  }

  public Map<String, String> getTitle() {
    return title;
  }

  public Map<String, String> getDescription() {
    return description;
  }

  public String getCategory() {
    return category;
  }

  public String[] getTags() {
    return tags;
  }

  public int getDifficulty() {
    return difficulty;
  }

  public int getTimeLimit() {
    return timeLimit;
  }

  public int getMemoryLimit() {
    return memoryLimit;
  }

  public String[] getRelatedProblems() {
    return relatedProblems;
  }

  public Function getFunction() {
    return function;
  }

  public Map<String, String> getAuthor() {
    return author;
  }

  public TestCase[] getTestCases() {
    return testCases;
  }

  public String getTestCasesGenerator() {
    return testCasesGenerator;
  }
} @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "PMD.UnusedPrivateField", "PMD.SingularField",
    "PMD.ArrayIsStoredDirectly"}) @JsonIgnoreProperties(ignoreUnknown = true) public
class Function {

  /**
   * Function name.
   */
   private final String name;
  /**
   * Return metadata.
   */
  @JsonProperty("return") private final Return return_;
  /**
   * Parameters' metadata.
   */
  private final Parameter[] parameters;

  /**
   * Since this class is immutable, need to provide a method for Jackson.
   */
  @JsonCreator public Function(@JsonProperty("name") final String name,
      @JsonProperty("return") final Return return_,
      @JsonProperty("parameters") final Parameter[] parameters) {
    this.name = name;
    this.return_ = return_;
    this.parameters = parameters;
  }


  /**
   * Return type.
   */
  @JsonIgnoreProperties(ignoreUnknown = true) public static class Return {
    /**
     * Return data type.
     */
    private final TypeNode type;
    /**
     * Comment of returned value.
     */
    private final String comment;

    /**
     * Since this class is immutable, need to provide a method for Jackson.
     */
    @JsonCreator public Return(@JsonProperty("type") final TypeNode type,
        @JsonProperty("comment") final String comment) {
      this.type = type;
      this.comment = comment;
    }

    public TypeNode getType() {
      return type;
    }

    public String getComment() {
      return comment;
    }
  }


  /**
   * Function parameters' metadata.
   */
  @JsonIgnoreProperties(ignoreUnknown = true) public static class Parameter {
    /**
     * Parameter name.
     */
    private final String name;
    /**
     * Parameter type.
     */
    private final TypeNode type;
    /**
     * Parameter comment.
     */
    private final String comment;

    /**
     * Since this class is immutable, need to provide a method for Jackson.
     */
    @JsonCreator public Parameter(@JsonProperty("name") final String name,
        @JsonProperty("type") final TypeNode type, @JsonProperty("comment") final String comment) {
      this.name = name;
      this.type = type;
      this.comment = comment;
    }

    public String getName() {
      return name;
    }

    public TypeNode getType() {
      return type;
    }

    public String getComment() {
      return comment;
    }
  }

  public String getName() {
    return name;
  }

  public Return getReturn_() {
    return return_;
  }

  public Parameter[] getParameters() {
    return parameters;
  }
} public enum StatusCode {
  PENDING(0),
  RUNNING(1),

  COMPILE_ERROR(2),
  RUNTIME_ERROR(3),

  ACCEPTED(4),
  WRONG_ANSWER(5),

  TIME_LIMIT_EXCEEDED(6),
  MEMORY_LIMIT_EXCEEDED(7),
  OUTPUT_LIMIT_EXCEEDED(8),

  RESTRICTED_CALL(9),
  TOO_LONG_CODE(10);


  private final int code;

  StatusCode(int code) {
    this.code = code;
  }

  @JsonCreator
  public static StatusCode fromInt(int code) {
    for (final StatusCode v : StatusCode.values()) {
      if (code == v.code) {
        return v;
      }
    }

    throw new IllegalArgumentException("Unrecognized status code: " + code);
  }

  @JsonValue
  public int toInt() {
    return this.code;
  }
} public enum LanguageType {
  JAVA("Java"),
  PYTHON("Python"),
  CPLUSPLUS("C++"),

  CLOJURE("Clojure"),
  CSHARP("C#"),
  FSHARP("F#"),
  GO("Go"),
  HASKELL("Haskell"),
  JAVASCRIPT("JavaScript"),
  LUA("Lua"),
  OCAML("Ocaml"),
  RACKET("Racket"),
  RUBY("Ruby"),
  RUST("Rust"),
  SCALA("Scala"),
  SWIFT("Swift");

  /**
   * Text for display.
   */
  private final String text;

  LanguageType(final String text) {
    this.text = text;
  }

  /**
   * Return real Enum from string.
   */
  @JsonCreator
  public static LanguageType fromString(String text) {
    if (text != null) {
      for (final LanguageType v : LanguageType.values()) {
        if (text.equalsIgnoreCase(v.text)) {
          return v;
        }
      }
    }
    throw new IllegalArgumentException("Unrecognized language: " + text);
  }

  /**
   * {@inheritDoc}.
   */
  @JsonValue
  @Override public String toString() {
    return text;
  }

  public String getFileSuffix() {
    switch (this) {
      case CPLUSPLUS:
        return "cpp";
      case PYTHON:
        return "py";
      case CLOJURE:
        return "clj";
      case CSHARP:
        return "cs";
      case FSHARP:
        return "fs";
      case HASKELL:
        return "hs";
      case JAVASCRIPT:
        return "js";
      case OCAML:
        return "ml";
      case RACKET:
        return "rkt";
      case RUBY:
        return "rb";
      case RUST:
        return "rs";
      default:
        return text.toLowerCase();
    }
  }
} public final class ObjectMapperInstance {
  public static final ObjectMapper INSTANCE = new ObjectMapper();
  private ObjectMapperInstance() {}

  static {
    INSTANCE.registerModule(new Jdk8Module());
    INSTANCE.setSerializationInclusion(JsonInclude.Include.NON_NULL);
  }
}
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import java.io.File;
import java.util.function.UnaryOperator;
import org.algohub.engine.bo.ProcessResult;
import org.algohub.engine.codegenerator.CppCodeGenerator;
import org.algohub.engine.codegenerator.PythonCodeGenerator;
import org.algohub.engine.codegenerator.RubyCodeGenerator;
import org.algohub.engine.pojo.JudgeResult;
import org.algohub.engine.pojo.Problem;
import org.algohub.engine.pojo.Function;
import org.algohub.engine.bo.StatusCode;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.TimeUnit;
import org.algohub.engine.type.LanguageType;
import org.algohub.engine.util.ObjectMapperInstance;
package org.algohub.engine.judge;




/**
 * Interface of all languages' judges.
 */
public interface JudgeInterface {
  long TIMEOUT = 20;  // 20 seconds
  int N_TTY_BUF_SIZE = 4096;

  /**
   * Read a text file.
   */
  static String readText(final InputStream inputStream) {
    try (final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {

      final StringBuilder sb = new StringBuilder();
      for (String line = br.readLine(); line != null; line = br.readLine()) {
        sb.append(line);
        sb.append('\n');
      }

      if (sb.length() > 0) {
        // delete the last unnecessary newline
        sb.delete(sb.length() - 1, sb.length());
      }
      return sb.toString();
    } catch (IOException ex) {
      return "";
    }
  }

  /**
   * Run a shell command and get the normal output and error output.
   */
  static ProcessResult runCommand(final Process process, final String input, final long seconds)
      throws IOException, InterruptedException {
    if (input != null && !input.isEmpty()) {
      final BufferedWriter bw =
          new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
      bw.write(input);
      bw.flush();
      bw.close();
    }

    final String stdout = readText(process.getInputStream());
    final String stderr = readText(process.getErrorStream());
    final boolean succeeded = process.waitFor(seconds, TimeUnit.SECONDS);
    if (!succeeded) {
      process.destroy(); // timeout, kill the process
    }

    final int exitCode = succeeded ? process.exitValue() : 24;  // SIGXCPU

    return new ProcessResult(exitCode, stdout, stderr);
  }

  static JudgeResult runCode(final String[] command, String input, File cwd) {