Interactive mode
diff --git a/judger-v2/Config.cpp b/judger-v2/Config.cpp
index 48f9e66..dfb5617 100644
--- a/judger-v2/Config.cpp
+++ b/judger-v2/Config.cpp
@@ -14,13 +14,14 @@
         dispatcher_port = atoi(ini.top()["dispatcher_port"].c_str());
         low_privilege_uid = atoi(ini.top()["low_privilege_uid"].c_str());
         general_compile_time = atoi(ini.top()["general_compile_time"].c_str());
-        generator_run_time = atoi(ini.top()["generator_run_time"].c_str());
+//        generator_run_time = atoi(ini.top()["generator_run_time"].c_str());
         generator_run_memory = atoi(ini.top()["generator_run_memory"].c_str());
         vmlang_multiplier = atoi(ini.top()["vmlang_multiplier"].c_str());
         max_output_limit = atoi(ini.top()["max_output_limit"].c_str());
         extra_runtime = atoi(ini.top()["extra_runtime"].c_str());
         checker_run_time = atoi(ini.top()["checker_run_time"].c_str());
         checker_run_memory = atoi(ini.top()["checker_run_memory"].c_str());
+        interactive_max_run_time = atoi(ini.top()["interactive_max_run_time"].c_str());
         tmpfile_path = ini.top()["tmpfile_path"];
     } catch (runtime_error & e) {
         cerr << e.what();
diff --git a/judger-v2/Config.h b/judger-v2/Config.h
index 37084be..230a093 100644
--- a/judger-v2/Config.h
+++ b/judger-v2/Config.h
@@ -135,6 +135,15 @@
         this->vmlang_multiplier = vmlang_multiplier;
     }
 
+    int GetInteractive_max_run_time() const {
+        return interactive_max_run_time;
+    }
+
+    void SetInteractive_max_run_time(int interactive_max_run_time) {
+        this->interactive_max_run_time = interactive_max_run_time;
+    }
+
+
 
 
 protected:
@@ -151,6 +160,7 @@
     int extra_runtime;
     int checker_run_time;
     int checker_run_memory;
+    int interactive_max_run_time;
     string judge_connect_string;
     string tmpfile_path;
 
diff --git a/judger-v2/Interactive.cpp b/judger-v2/Interactive.cpp
new file mode 100644
index 0000000..06ef692
--- /dev/null
+++ b/judger-v2/Interactive.cpp
@@ -0,0 +1,446 @@
+/* 
+ * File:   Interactive.cpp
+ * Author: payper
+ * 
+ * Created on 2014年4月24日, 下午5:41
+ */
+
+#include "Interactive.h"
+#include "Logger.h"
+
+extern bool syscalls_other[500];
+extern bool syscalls_java[500];
+extern bool syscalls_csharp[500];
+extern int GENERAL_COMPILE_TIME,GENERATOR_RUN_TIME,GENERATOR_RUN_MEMORY,VMLANG_MULTIPLIER,MAX_OUTPUT_LIMIT,EXTRA_RUNTIME;
+extern int lowprivid;
+extern string tmpnam();
+
+Interactive::Interactive() : Program()  {
+    validator_compiled = false;
+}
+
+Interactive::~Interactive() {
+    if (validator_base_filename!="") Deletefile(validator_base_filename+"*");
+    if (Checkfile(validator_src_filename)) Deletefile(validator_src_filename);
+    if (Checkfile(validator_exc_filename)) Deletefile(validator_exc_filename);
+    if (Checkfile(validator_err_filename)) Deletefile(validator_err_filename);
+}
+
+int Interactive::Excution() {
+    system(((string)"chmod +x "+exc_filename).c_str());
+    system(((string)"chmod +x "+validator_exc_filename).c_str());
+    res_filename=tmpnam();
+    struct rlimit runtime;
+    runtime.rlim_max=runtime.rlim_cur=CONFIG->GetInteractive_max_run_time()+EXTRA_RUNTIME;
+    pid_t wid;
+    if ((wid=fork())==0) {
+        pid_t pgrp = getpid();
+        pid_t vpid;
+        int vtorPipe[2];
+        int rtovPipe[2];
+        pipe(vtorPipe);
+        pipe(rtovPipe);
+        if ((vpid = fork()) == 0) {
+            setpgid(0, pgrp);
+            LOGGER->addIdentifier(getpid(), "Sandbox");
+            dup2(vtorPipe[0], STDIN_FILENO);
+            dup2(rtovPipe[1], STDOUT_FILENO);
+            close(vtorPipe[0]);
+            close(vtorPipe[1]);
+            close(rtovPipe[0]);
+            close(rtovPipe[1]);
+            
+            string exc_command;
+            pid_t pid;
+            int runstat;
+            bool excuted=false;
+            struct rusage rinfo;
+            setrlimit(RLIMIT_CPU,&runtime);
+            struct user_regs_struct reg;
+            struct rlimit time_limit,output_limit;
+
+            time_limit.rlim_cur=case_time_limit<total_time_limit-time_used?case_time_limit:total_time_limit-time_used;
+            time_limit.rlim_cur=(time_limit.rlim_cur+999)/1000;
+            if (time_limit.rlim_cur<=0) time_limit.rlim_cur=1;
+            time_limit.rlim_max=time_limit.rlim_cur+1;
+            if ((pid=fork())==0) {
+                LOGGER->addIdentifier(getpid(), "Runner");
+                setpgid(0, pgrp);
+                LOG((string)"Time limit for this program is "+Inttostring(time_limit.rlim_cur));
+                setrlimit(RLIMIT_CPU,&time_limit);
+
+                setuid(lowprivid);
+                ptrace(PTRACE_TRACEME,0,NULL,NULL);
+
+                switch (language) {
+                    case CPPLANG:
+                    case CLANG:
+                    case FORTLANG:
+                    case FPASLANG:
+                    case SMLLANG:
+                    case ADALANG:
+                        exc_command=(string)"./"+exc_filename;
+                        execl(exc_command.c_str(),exc_command.c_str(),NULL);
+                        break;
+                    case JAVALANG:
+                        execl("/usr/bin/java","java","-Djava.security.manager","-Djava.security.policy=java.policy","-client","-cp",CONFIG->GetTmpfile_path().c_str(),"Main",NULL);
+                        break;
+                    case CSLANG:
+                        execl("/usr/bin/mono","mono",exc_filename.c_str(),NULL);
+                        break;
+                    case PERLLANG:
+                        execl("/usr/bin/perl","perl",src_filename.c_str(),"-W",NULL);
+                    case RUBYLANG:
+                        execl("/usr/bin/ruby","ruby",src_filename.c_str(),"-W",NULL);
+                        break;
+                    case PYLANG:
+                        execl("/usr/bin/python","python",exc_filename.c_str(),NULL);
+                        break;
+                }
+                exit(0);
+            }
+            else {
+                if (language<MIN_LANG_NUM||language>MAX_LANG_NUM||language==VCLANG||language==VCPPLANG) {
+                    result="Invalid Language";
+                    LOG("Invalid Language Detected");
+                    result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                    Savetofile(res_filename,result);
+                    exit(0);
+                }
+                LOG("Program Child Process: "+Inttostring(pid));
+                LOG("Running program");
+                runstat=0;
+                struct timeval case_startv;
+                struct timezone case_startz;
+                gettimeofday(&case_startv,&case_startz);
+                while (1) {
+                    wait4(pid,&runstat,0,&rinfo);
+                    time_used=(rinfo.ru_utime.tv_sec+rinfo.ru_stime.tv_sec)*1000+(rinfo.ru_utime.tv_usec+rinfo.ru_stime.tv_usec)/1000;
+                    if (total_time_limit<time_used) {
+                        LOG("Dectect TLE, type:1, LOOP found. Time used: "+Inttostring(time_used)+", Limit: "+Inttostring(total_time_limit));
+                        ptrace(PTRACE_KILL,pid,NULL,NULL);
+                        result="Time Limit Exceed";
+                        result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                        Savetofile(res_filename,result);
+                        break;
+                    }
+                    if (memory_used<getpagesize()*rinfo.ru_minflt) memory_used=getpagesize()*rinfo.ru_minflt;
+                    if (WIFEXITED(runstat)) {
+                        LOG((string)"Used time: "+Inttostring(time_used));
+                        LOG((string)"Used Memory: "+Inttostring(memory_used));
+                        LOG((string)"Run status: "+Inttostring(WEXITSTATUS(runstat)));
+                        if (check_exit_status&&WEXITSTATUS(runstat)!=0) result="Runtime Error";
+                        else result="Normal";
+                        result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                        Savetofile(res_filename,result);
+                        break;
+                    }
+                    if (WIFSIGNALED(runstat)&&WTERMSIG(runstat)!=SIGTRAP) {
+                        int signal=WTERMSIG(runstat);
+                        LOG((string)"Used time: "+Inttostring(time_used));
+                        LOG((string)"Used Memory: "+Inttostring(memory_used));
+                        LOG((string)"Run status: "+Inttostring(runstat));
+                        switch (signal)
+                        {
+                            case SIGXCPU:
+                                LOG("Dectect TLE, type:2, signaled");
+                                result="Time Limit Exceed";
+                                time_used=time_limit.rlim_cur*1000+4;
+                                break;
+                            case SIGXFSZ:
+                                result="Output Limit Exceed";
+                                break;
+                            default:
+                                result="Runtime Error";
+                        }
+                        result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                        Savetofile(res_filename,result);
+                        ptrace(PTRACE_KILL,pid,NULL,NULL);
+                        break;
+                    }
+                    else if (WIFSTOPPED(runstat)&&WSTOPSIG(runstat)!=SIGTRAP) {
+                        int signal=WSTOPSIG(runstat);
+                        LOG((string)"Used time: "+Inttostring(time_used));
+                        LOG((string)"Used Memory: "+Inttostring(memory_used));
+                        LOG((string)"Run status: "+Inttostring(runstat));
+                        switch (signal)
+                        {
+                            case SIGXCPU:
+                                result="Time Limit Exceed";
+                                LOG("Dectect TLE, type:2, signaled");
+                                time_used=time_limit.rlim_cur*1000+4;
+                                break;
+                            case SIGXFSZ:
+                                result="Output Limit Exceed";
+                                break;
+                            default:
+                                result="Runtime Error";
+                        }
+                        result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                        Savetofile(res_filename,result);
+                        ptrace(PTRACE_KILL,pid,NULL,NULL);
+                        break;
+                    }
+                    else if ((runstat>>8)!=5&&(runstat>>8)>0) {
+                        LOG((string)"Used time: "+Inttostring(time_used));
+                        LOG((string)"Used Memory: "+Inttostring(memory_used));
+                        LOG((string)"Run status: "+Inttostring(runstat));
+                        result="Runtime Error";
+                        result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                        Savetofile(res_filename,result);
+                        ptrace(PTRACE_KILL,pid,NULL,NULL);
+                        break;
+                    }
+                    ptrace(PTRACE_GETREGS,pid,NULL,&reg);
+                    #ifdef __i386__
+                    //printf("System call:%ld\n",reg.orig_eax);
+                    if (reg.orig_eax==SYS_execve&&!excuted) excuted=true;
+                    else {
+                        if (language==JAVALANG) {
+                            if (syscalls_java[reg.orig_eax]) {
+                                LOG((string)"Invalid system call: "+ Inttostring(reg.orig_eax));
+                                result="Restricted Function";
+                                result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                                Savetofile(res_filename,result);
+                                ptrace(PTRACE_KILL,pid,NULL,NULL);
+                                exit(0);
+                            }
+                        }
+                        else if (language==CSLANG) {
+                            if (syscalls_csharp[reg.orig_eax]) {
+                                LOG((string)"Invalid system call: "+ Inttostring(reg.orig_eax));
+                                result="Restricted Function";
+                                result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                                Savetofile(res_filename,result);
+                                ptrace(PTRACE_KILL,pid,NULL,NULL);
+                                exit(0);
+                            }
+                        }
+                        else if (syscalls_other[reg.orig_eax]) {
+                            LOG((string)"Invalid system call: "+ Inttostring(reg.orig_eax));
+                            result="Restricted Function";
+                            result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                            Savetofile(res_filename,result);
+                            ptrace(PTRACE_KILL,pid,NULL,NULL);
+                            exit(0);
+                        }
+                    }
+                    #else
+                    //printf("System call:%ld\n",reg.orig_rax);
+                    if (reg.orig_rax==SYS_execve&&!excuted) excuted=true;
+                    else {
+                        if (language==JAVALANG) {
+                            if (syscalls_java[reg.orig_rax]) {
+                                LOG((string)"Invalid system call: "+ Inttostring(reg.orig_rax));
+                                result="Restricted Function";
+                                result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                                Savetofile(res_filename,result);
+                                ptrace(PTRACE_KILL,pid,NULL,NULL);
+                                break;
+                            }
+                        }
+                        else if (language==CSLANG) {
+                            if (syscalls_csharp[reg.orig_rax]) {
+                                LOG((string)"Invalid system call: "+ Inttostring(reg.orig_rax));
+                                result="Restricted Function";
+                                result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                                Savetofile(res_filename,result);
+                                ptrace(PTRACE_KILL,pid,NULL,NULL);
+                                break;
+                            }
+                        }
+                        else if (syscalls_other[reg.orig_rax]) {
+                            LOG((string)"Invalid system call: "+ Inttostring(reg.orig_rax));
+                            result="Restricted Function";
+                            result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                            Savetofile(res_filename,result);
+                            ptrace(PTRACE_KILL,pid,NULL,NULL);
+                            break;
+                        }
+                    }
+                    #endif
+                    if (memory_used/1024>memory_limit) {
+                        LOG((string)"Used time: "+Inttostring(time_used));
+                        LOG((string)"Used Memory: "+Inttostring(memory_used));
+                        LOG((string)"Run status: "+Inttostring(runstat));
+                        result="Memory Limit Exceed";
+                        result+="\n"+Inttostring(time_used)+"\n"+Inttostring(memory_used);
+                        Savetofile(res_filename,result);
+                        ptrace(PTRACE_KILL,pid,NULL,NULL);
+                        break;
+                    }
+                    ptrace(PTRACE_SYSCALL,pid,NULL,NULL);
+                }
+                exit(0);
+            }
+            exit(0);
+        } else {
+            pid_t pvid;
+            if ((pvid = fork()) == 0) {
+                LOGGER->addIdentifier(getpid(), "Validator");
+                setpgid(0, pgrp);
+                dup2(rtovPipe[0], STDIN_FILENO);
+                dup2(vtorPipe[1], STDOUT_FILENO);
+                close(vtorPipe[0]);
+                close(vtorPipe[1]);
+                close(rtovPipe[0]);
+                close(rtovPipe[1]);
+
+                string exc_command;
+                setuid(lowprivid);
+
+                switch (language) {
+                    case CPPLANG:
+                    case CLANG:
+                    case FORTLANG:
+                    case FPASLANG:
+                    case SMLLANG:
+                    case ADALANG:
+                        exc_command=(string)"./"+exc_filename;
+                        execl(exc_command.c_str(),exc_command.c_str(),NULL);
+                        break;
+                    case JAVALANG:
+                        execl("/usr/bin/java","java","-Djava.security.manager","-Djava.security.policy=java.policy","-client","-cp",CONFIG->GetTmpfile_path().c_str(),"Main",NULL);
+                        break;
+                    case CSLANG:
+                        execl("/usr/bin/mono","mono",exc_filename.c_str(),NULL);
+                        break;
+                    case PERLLANG:
+                        execl("/usr/bin/perl","perl",src_filename.c_str(),"-W",NULL);
+                    case RUBYLANG:
+                        execl("/usr/bin/ruby","ruby",src_filename.c_str(),"-W",NULL);
+                        break;
+                    case PYLANG:
+                        execl("/usr/bin/python","python",exc_filename.c_str(),NULL);
+                        break;
+                }
+                exit(0);
+            } else {
+                LOGGER->addIdentifier(getpid(), "ValidatorRunner");
+                int rstat, cstat, waitcnt;
+                while (1) {
+                    usleep(50000);
+                    waitpid(pvid, &rstat, WNOHANG);
+                    if (WIFEXITED(rstat)) {
+                        waitpid(pvid, &rstat, 0);
+                        LOG("Validator runned.");
+                        waitcnt = 10;
+                        while (waitcnt--) {
+                            usleep(50000);
+                            waitpid(vpid, &cstat, WNOHANG);
+                            if (WIFEXITED(cstat)) {
+                                waitpid(vpid,&cstat,0);
+                                LOG("User program runned.");
+                                exit(WEXITSTATUS(rstat));
+                            }
+                        }
+                        kill(-pgrp, SIGKILL);
+                        exit(1);
+                    }
+                    
+                    waitpid(vpid, &cstat, WNOHANG);
+                    if (WIFEXITED(cstat)) {
+                        waitpid(vpid,&cstat,0);
+                        LOG("User program runned.");
+                        waitcnt = 10;
+                        while (waitcnt--) {
+                            usleep(50000);
+                            waitpid(pvid, &rstat, 0);
+                            if (WIFEXITED(rstat)) {
+                                waitpid(pvid, &rstat, 0);
+                                LOG("Validator runned.");
+                                exit(WEXITSTATUS(rstat));
+                            }
+                        }
+                        kill(-pgrp, SIGKILL);
+                        exit(1);
+                    }
+                }
+                exit(0);
+            }
+        }
+        exit(0);
+    }
+    else {
+        LOG("Watch Child Process: "+Inttostring(wid));
+        int rstat,tused;
+        struct timeval case_startv,case_nowv;
+        struct timezone case_startz,case_nowz;
+        gettimeofday(&case_startv,&case_startz);
+        int cnt=-1;
+        while (1) {
+            usleep(50000);
+            cnt++;
+            gettimeofday(&case_nowv,&case_nowz);
+            tused=case_nowv.tv_sec-case_startv.tv_sec;
+            if (cnt%20==0) LOG("Running Used: "+Inttostring(tused));
+            if (waitpid(wid,&rstat,WNOHANG)==0) {
+                if (tused>runtime.rlim_max) {
+                    result="Judge Error";
+                    LOG("Time too much!");
+                    LOG("kill `pstree -p "+Inttostring(wid)+" | sed 's/(/\\n(/g' | grep '(' | sed 's/(\\(.*\\)).*/\\1/' | tr \"\\n\" \" \"`");
+                    system(("kill `pstree -p "+Inttostring(wid)+" | sed 's/(/\\n(/g' | grep '(' | sed 's/(\\(.*\\)).*/\\1/' | tr \"\\n\" \" \"`").c_str());
+                    waitpid(wid,&rstat,0);
+                    return 1;
+                }
+            }
+            else if (WIFSIGNALED(rstat) && WTERMSIG(rstat)!=0) {
+                result="Judge Error";
+                LOG("Something is wrong.");
+                LOG("kill `pstree -p "+Inttostring(wid)+" | sed 's/(/\\n(/g' | grep '(' | sed 's/(\\(.*\\)).*/\\1/' | tr \"\\n\" \" \"`");
+                system(("kill `pstree -p "+Inttostring(wid)+" | sed 's/(/\\n(/g' | grep '(' | sed 's/(\\(.*\\)).*/\\1/' | tr \"\\n\" \" \"`").c_str());
+                waitpid(wid,&rstat,0);
+                return 1;
+            }
+            if (WIFEXITED(rstat)) {
+                waitpid(wid,&rstat,0);
+                LOG("Runned.");
+                break;
+            }
+        }
+        string res="";
+        fstream fin(res_filename.c_str(),fstream::in);
+        while (fin.fail()) fin.open(res_filename.c_str(),fstream::in);
+        //system(("kill -9 "+Inttostring(wid)).c_str());
+        int case_time_used,case_memory_used;
+        getline(fin,result);
+        fin>>case_time_used>>case_memory_used;
+        time_used+=case_time_used;
+        memory_used=max(memory_used,case_memory_used);
+        fin.close();
+        if (result==""||result==" ") {
+            result="Judge Error";
+            LOG("Failed to get result.");
+        } else if (result == "Normal") {
+            if (WEXITSTATUS(rstat) == 0) result = "Accepted";
+            else result = "Wrong Answer";
+        }
+        system(("rm "+res_filename).c_str());
+    }
+    return 0;
+}
+
+void Interactive::Run() {
+    if (!validator_compiled) {
+        Setresult("");
+        // reuse compile function
+        Trytocompile(validator_source, validator_language);
+        if (Getresult() != "") {
+            Setresult("Judge Error");
+            return;
+        }
+        
+        // copy compile result of validator
+        validator_base_filename = Getbase_filename();
+        validator_src_filename = Getsrc_filename();
+        validator_exc_filename = Getexc_filename();
+        validator_err_filename = Geterr_filename();
+    }
+    if (!Getcompiled()) {
+        Setresult("");
+        Trytocompile(source, language);
+        if (Getresult() != "") return;
+    }
+    Excution();
+    if (total_time_limit<time_used) result="Time Limit Exceed";
+}
diff --git a/judger-v2/Interactive.h b/judger-v2/Interactive.h
new file mode 100644
index 0000000..25fe880
--- /dev/null
+++ b/judger-v2/Interactive.h
@@ -0,0 +1,86 @@
+/* 
+ * File:   Interactive.h
+ * Author: payper
+ *
+ * Created on 2014年4月24日, 下午5:41
+ */
+
+#ifndef INTERACTIVE_H
+#define	INTERACTIVE_H
+
+#include "Program.h"
+
+class Interactive : public Program {
+public:
+    Interactive();
+    virtual ~Interactive();
+
+    string GetValidator_base_filename() const {
+        return validator_base_filename;
+    }
+
+    void SetValidator_base_filename(string validator_base_filename) {
+        this->validator_base_filename = validator_base_filename;
+    }
+
+    bool IsValidator_compiled() const {
+        return validator_compiled;
+    }
+
+    void SetValidator_compiled(bool validator_compiled) {
+        this->validator_compiled = validator_compiled;
+    }
+
+    string GetValidator_exc_filename() const {
+        return validator_exc_filename;
+    }
+
+    void SetValidator_exc_filename(string validator_exc_filename) {
+        this->validator_exc_filename = validator_exc_filename;
+    }
+
+    int GetValidator_language() const {
+        return validator_language;
+    }
+
+    void SetValidator_language(int validator_language) {
+        this->validator_language = validator_language;
+    }
+
+    string GetValidator_source() const {
+        return validator_source;
+    }
+
+    void SetValidator_source(string validator_source) {
+        this->validator_source = validator_source;
+    }
+
+    string GetValidator_src_filename() const {
+        return validator_src_filename;
+    }
+
+    void SetValidator_src_filename(string validator_src_filename) {
+        this->validator_src_filename = validator_src_filename;
+    }
+    
+    void Run();
+
+private:
+    int Excution();
+    
+    string validator_base_filename;
+    string validator_src_filename;
+    string validator_exc_filename;
+    string validator_in_filename;
+    string validator_out_filename;
+    string validator_err_filename;
+    string validator_res_filename;
+    
+    bool validator_compiled;
+    
+    string validator_source;
+    int validator_language;
+};
+
+#endif	/* INTERACTIVE_H */
+
diff --git a/judger-v2/PConfig.cpp b/judger-v2/PConfig.cpp
index 92b6c83..50b82e9 100644
--- a/judger-v2/PConfig.cpp
+++ b/judger-v2/PConfig.cpp
@@ -22,6 +22,8 @@
         data_checker_language = atoi(ini.top()["data_checker_language"].c_str());
         solution_filename = basedir + ini.top()["solution_filename"];
         solution_language = atoi(ini.top()["solution_language"].c_str());
+        validator_filename = basedir + ini.top()["validator_filename"];
+        validator_language = atoi(ini.top()["validator_language"].c_str());
         error = false;
     } catch (runtime_error & e) {
         error = true;
diff --git a/judger-v2/PConfig.h b/judger-v2/PConfig.h
index c716aa5..2eb25dc 100644
--- a/judger-v2/PConfig.h
+++ b/judger-v2/PConfig.h
@@ -20,12 +20,31 @@
         void Setsolution_language(int val) { solution_language = val; }
         bool Geterror() { return error; }
         void Seterror(bool val) { error = val; }
+
+        string Getvalidator_filename() const {
+            return validator_filename;
+        }
+
+        void Setvalidator_filename(string validator_filename) {
+            this->validator_filename = validator_filename;
+        }
+
+        int Getvalidator_language() const {
+            return validator_language;
+        }
+
+        void Setvalidator_language(int validator_language) {
+            this->validator_language = validator_language;
+        }
+
     protected:
     private:
         string data_checker_filename;
         string solution_filename;
+        string validator_filename;
         int data_checker_language;
         int solution_language;
+        int validator_language;
         string basedir;
         map <string,string> config;
         bool error;
diff --git a/judger-v2/Program.cpp b/judger-v2/Program.cpp
index fb0e8ac..6fcf7a1 100644
--- a/judger-v2/Program.cpp
+++ b/judger-v2/Program.cpp
@@ -14,6 +14,8 @@
     result="";
     base_filename="";
     time_used=memory_used=0;
+    compile_time_limit=GENERAL_COMPILE_TIME;
+    if (vmlang[language]) compile_time_limit=GENERAL_COMPILE_TIME*3;
     check_exit_status=false;
     if (!para_inited) {
         init_error();
@@ -93,7 +95,7 @@
     return t;
 }
 
-int Program::Compile() {
+int Program::Compile(string source, int language) {
     cinfo_filename = CONFIG->GetTmpfile_path() + tmpnam()+".txt";
     if (language!=JAVALANG) base_filename = CONFIG->GetTmpfile_path() + tmpnam();
     else base_filename = CONFIG->GetTmpfile_path() + "Main";
@@ -512,41 +514,51 @@
     return 0;
 }
 
-void Program::Run()
-{
-    if (!compiled) {
-        compile_time_limit=GENERAL_COMPILE_TIME;
-        if (vmlang[language]) compile_time_limit=GENERAL_COMPILE_TIME*3;
-        int res=Compile();
-        compiled=true;
-        if (res==-1) {
-            //JUDGE ERROR
-            result="Invalid Language";
-            return;
-        }
-        else if (res==2) {
-            //COMPILE ERROR
+void Program::Trytocompile(string source, int language) {
+    if (source == "") {
+        source = this->source;
+    }
+    if (language == -1) {
+        language = this->language;
+    }
+    int res=Compile(source, language);
+    compiled=true;
+    if (res==-1) {
+        //JUDGE ERROR
+        result="Invalid Language";
+        return;
+    }
+    else if (res==2) {
+        //COMPILE ERROR
+        result="Compile Error";
+        return;
+    }
+    int cnt=0;
+    while (res==1) {
+        cnt++;
+        ce_info=Loadallfromfile(cinfo_filename,200);
+        if (ce_info.length()>0||cnt>2) {
             result="Compile Error";
             return;
         }
-        int cnt=0;
-        while (res==1) {
-            cnt++;
-            ce_info=Loadallfromfile(cinfo_filename,200);
-            if (ce_info.length()>0||cnt>2) {
-                result="Compile Error";
-                return;
-            }
-            else {
-                usleep(50000);
-                res=Compile();
-            }
+        else {
+            usleep(50000);
+            res=Compile(source, language);
         }
-        if (vmlang[language]) {
-            total_time_limit*=VMLANG_MULTIPLIER;
-            case_time_limit*=VMLANG_MULTIPLIER;
-            memory_limit*=VMLANG_MULTIPLIER;
-        }
+    }
+    if (vmlang[language]) {
+        total_time_limit*=VMLANG_MULTIPLIER;
+        case_time_limit*=VMLANG_MULTIPLIER;
+        memory_limit*=VMLANG_MULTIPLIER;
+    }
+}
+
+void Program::Run()
+{
+    if (!compiled) {
+        result = "";
+        Trytocompile(source, language);
+        if (result != "") return;
     }
     if (exc_filename!=src_filename) {
         string tmps=CONFIG->GetTmpfile_path() + tmpnam();
diff --git a/judger-v2/Program.h b/judger-v2/Program.h
index cc2d37f..be87f6e 100644
--- a/judger-v2/Program.h
+++ b/judger-v2/Program.h
@@ -46,35 +46,56 @@
         void Setcheck_exit_status(bool val) { check_exit_status = val; }
         string Loadallfromfile(string filename,int limit=-1);
         void Run();
-        int Compile();
+        int Compile(string, int);
+        void Trytocompile(string, int);
         void Savetofile(string filename,string content);
         bool Checkfile(string);
         string Inttostring(int);
+
+        string Getbase_filename() const {
+            return base_filename;
+        }
+
+        void Setbase_filename(string base_filename) {
+            this->base_filename = base_filename;
+        }
+
+        string Geterr_filename() const {
+            return err_filename;
+        }
+
+        void Seterr_filename(string err_filename) {
+            this->err_filename = err_filename;
+        }
+
+
     protected:
-    private:
-        int Excution();
         void Deletefile(string);
-        string base_filename;
-        string src_filename;
-        string exc_filename;
-        string in_filename;
-        string out_filename;
-        string err_filename;
-        string res_filename;
-        bool compiled;
-        string cinfo_filename;
-        string ce_info;
         int total_time_limit;
         int case_time_limit;
         int memory_limit;
         int time_used;
         int memory_used;
-        int language;
-        string source;
+        string exc_filename;
         string result;
+        string res_filename;
+        bool check_exit_status;
+        string source;
+        int language;
+        string src_filename;
+    private:
+        int Excution();
+        string base_filename;
+        string in_filename;
+        string out_filename;
+        string err_filename;
+        bool compiled;
+        string cinfo_filename;
+        string ce_info;
+        
         int compile_time_limit;
         bool has_input;
-        bool check_exit_status;
+        
         static bool para_inited;
 };
 
diff --git a/judger-v2/chaclient.cpp b/judger-v2/chaclient.cpp
index e358ef6..8749b64 100644
--- a/judger-v2/chaclient.cpp
+++ b/judger-v2/chaclient.cpp
@@ -6,6 +6,7 @@
 #include "PConfig.h"
 #include "ini.hpp"
 #include "SocketHandler.h"
+#include "Interactive.h"
 
 map <string,string> config;
 
@@ -377,6 +378,35 @@
     send_result(retbott.Getout_filename());
 }
 
+void dointeractive() {
+    LOG("Runid: "+Inttostring(bott->Getrunid())+" Type: Interactive");
+    
+    retbott.Settype(RESULT_REPORT);
+    retbott.Setrunid(bott->Getrunid());
+    Interactive * usrprogram=new Interactive;
+    usrprogram->Setlanguage(bott->Getlanguage());
+    usrprogram->Setsource(bott->Getsrc());
+    problem=new PConfig(bott->Getpid());
+    usrprogram->SetValidator_source(Loadallfromfile(problem->Getvalidator_filename()));
+    usrprogram->SetValidator_language(problem->Getvalidator_language());
+    
+    usrprogram->Setcase_time_limit(bott->Getcase_limit());
+    usrprogram->Settotal_time_limit(bott->Gettime_limit());
+    usrprogram->Setmemory_limit(bott->Getmemory_limit());
+    
+    usrprogram->Run();
+    retbott.Setce_info(usrprogram->Getce_info());
+    retbott.Settime_used(usrprogram->Gettime_used());
+    retbott.Setmemory_used(usrprogram->Getmemory_used());
+    retbott.Setresult(usrprogram->Getresult());
+    
+    retbott.Setout_filename("results/"+Inttostring(retbott.Getrunid()));
+    retbott.toFile();
+    delete usrprogram;
+    delete problem;
+    send_result(retbott.Getout_filename());
+}
+
 int main(int argc, char *argv[]) {
     init();
     //init_error();
@@ -400,6 +430,7 @@
         parse_bott();
         if (bott->Gettype()==DO_CHALLENGE) dochallenge();
         else if (bott->Gettype()==NEED_JUDGE||bott->Gettype()==DO_TESTALL||bott->Gettype()==DO_PRETEST) dojudge(bott->Gettype());
+        else if (bott->Gettype()==DO_INTERACTIVE) dointeractive();
         delete bott;
     }
     return 0;
diff --git a/judger-v2/chaclient.h b/judger-v2/chaclient.h
index 758ce59..63e96de 100644
--- a/judger-v2/chaclient.h
+++ b/judger-v2/chaclient.h
@@ -48,6 +48,7 @@
 #define DO_CHALLENGE 4
 #define DO_PRETEST 5
 #define DO_TESTALL 6
+#define DO_INTERACTIVE 7
 #define JUDGER_STATUS_REPORT 1
 #define NEED_DATA 2
 #define RESULT_REPORT 3
diff --git a/judger-v2/config.ini b/judger-v2/config.ini
index c5fb32f..c9a97ae 100644
--- a/judger-v2/config.ini
+++ b/judger-v2/config.ini
@@ -10,4 +10,5 @@
 extra_runtime = 10
 checker_run_time = 3
 checker_run_memory = 65536
-tmpfile_path = tmpfile/
\ No newline at end of file
+tmpfile_path = tmpfile/
+interactive_max_run_time = 20