xalanq / cf-tool

:bar_chart: Codeforces CLI (Submit, Parse, Test, etc.). Support Contests, Gym, Groups, acmsguru, Windows, macOS, Linux, 7 MB
MIT License
1.31k stars 226 forks source link

How can we speed up the submit feedback? #48

Closed Fomalhauthmj closed 4 years ago

Fomalhauthmj commented 4 years ago

I find that when i use "cf submit" command to submit my solution then the cmd need much long time to get feedback about result,sometime it will error because of "net/http: TLS handshake timeout".By the way,I use shadowsocks global proxy mode to open codeforces in China. 我发现在我使用cf submit 命令后 往往需要很长时间才能获得提交的反馈,而且如果不用ss的全局模式无法访问codeforces(我平时使用PAC模式访问),请问有改善的方式吗?

user202729 commented 4 years ago

cf-tool gets the submission info by repeatedly download the /contest/ID/my page, which is slower than the way Codeforces do it (with a WebSocket)

user202729 commented 4 years ago

This is a WIP that implements reading from websocket:

Code ```diff diff --git a/client/submit.go b/client/submit.go index 11a73cf..f2343f0 100644 --- a/client/submit.go +++ b/client/submit.go @@ -83,6 +83,7 @@ func (c *Client) SubmitContest(contestID, problemID, langID, source string) (err } color.Green("Submitted") + // TODO can body be used here? submissions, err := c.WatchSubmission(contestID, "", 1, true) if err != nil { return diff --git a/client/watch.go b/client/watch.go index 5233e9b..23d10ee 100644 --- a/client/watch.go +++ b/client/watch.go @@ -11,7 +11,10 @@ import ( "strconv" "strings" "time" + "net/url" + "encoding/json" + "github.com/gorilla/websocket" "github.com/PuerkitoBio/goquery" "github.com/fatih/color" ansi "github.com/k0kubun/go-ansi" @@ -208,10 +211,12 @@ func parseSubmission(body []byte, cfOffset string) (ret Submission, err error) { fmtReg := regexp.MustCompile(`]+?)["']?>`) colReg := regexp.MustCompile(`]+?)["']?>`) tagReg := regexp.MustCompile(`<[\s\S]*?>`) + status = fmtReg.ReplaceAllString(status, "") status = colReg.ReplaceAllString(status, `${c-$1}`) status = tagReg.ReplaceAllString(status, "") status = strings.TrimSpace(status) + when := get(".format-time") if when != "" { when = parseWhen(when, cfOffset) @@ -241,6 +246,34 @@ func parseSubmission(body []byte, cfOffset string) (ret Submission, err error) { }, nil } +func (c *Client) getSubmissionsFromBody(body []byte, n int) (submissions []Submission, err error) { + if err = checkLogin(c.Username, body); err != nil { + return + } + + cfOffset, err := findCfOffset(body) + if err != nil { + return + } + + submissionsBody, err := findSubmission(body, n) + if err != nil { + return + } + + for _, submissionBody := range submissionsBody { + if submission, err := parseSubmission(submissionBody, cfOffset); err == nil { + submissions = append(submissions, submission) + } + } + + if len(submissions) < 1 { + return nil, errors.New("Cannot find any submission") + } + + return +} + func (c *Client) getSubmissions(myURL string, n int) (submissions []Submission, err error) { resp, err := c.client.Get(myURL) if err != nil { @@ -252,35 +285,212 @@ func (c *Client) getSubmissions(myURL string, n int) (submissions []Submission, return } - if err = checkLogin(c.Username, body); err != nil { - return + return c.getSubmissionsFromBody(body, n) +} + +func findMeta(body []byte, name string) (string, error) { + // name must not contain any regex meta-character + reg := regexp.MustCompile(``) + tmp := reg.FindSubmatch(body) + if len(tmp) < 2 { + return "", errors.New("Cannot find meta property") } + return string(tmp[1]), nil +} - cfOffset, err := findCfOffset(body) +// WatchSubmission n is the number of submissions +func (c *Client) WatchSubmission(contestID, problemID string, n int, line bool) (submissions []Submission, err error) { + // new version + URL := ToGym(fmt.Sprintf(c.Host+"/contest/%v/my", contestID), contestID) + if contestID == "0" { + URL = c.Host+"/problemset/status" // DEBUG + } + + maxWidth := 0 + first := true + + resp, err := c.client.Get(URL) + if err != nil { + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) if err != nil { return } - submissionsBody, err := findSubmission(body, n) + submissions, err = c.getSubmissionsFromBody(body, n) if err != nil { return } + display(submissions, problemID, first, &maxWidth, line) + first = false - for _, submissionBody := range submissionsBody { - if submission, err := parseSubmission(submissionBody, cfOffset); err == nil { - submissions = append(submissions, submission) + ended := func() bool { + endCount := 0 + for _, submission := range submissions { + if submission.end { + endCount++ + } } + return endCount == len(submissions) + } + if ended() { + return } - if len(submissions) < 1 { - return nil, errors.New("Cannot find any submission") + wssrawurl := "wss://pubsub.codeforces.com/ws/" + + /* + for _, x := range []string{"gc","uc","usmc","cc","pc","tc"} { // is it necessary to include all of those channels? + data, _ := findMeta(body, x) // data: pushstream/websocket channel + fmt.Printf("%v = %v\n", x, data) + if err == nil { + wssrawurl += data + '/' + } + } + */ + + for _, x := range []string{"pc","cc","gc"} { // is it necessary to include all of those channels? + data, err := findMeta(body, x) // data: pushstream/websocket channel + if err == nil { + wssrawurl += `s_` + data + `/` + } + } + + wssurl, _ := url.Parse(wssrawurl) + + conn, _, err := websocket.DefaultDialer.Dial(wssurl.String(), nil) + if err != nil { + return + } + defer conn.Close() + + for { + var bytes []byte + _, bytes, err = conn.ReadMessage() + + if err != nil { + return + } + + + var data struct { + Id int + Channel string + Text string + } + json.Unmarshal(bytes, &data) + + //fmt.Println(data.Text) + + var submission struct { + T string + D []interface{} + /* + var a = submission.d[0]; + var id = submission.d[1]; + var contestId = submission.d[2]; + var problemId = submission.d[3]; + var testset = submission.d[4]; + var points = submission.d[5]; + var verdictString = submission.d[6]; + var passedTestCount = submission.d[7]; + var judgedTestCount = submission.d[8]; + var timeConsumed = submission.d[9]; + var memoryConsumed = submission.d[10]; + var participantId = submission.d[11]; + var verdict = preparedVerdictFormats[submission.d[12]]; // https://sta.codeforces.com/s/52452/js/preparedVerdictFormats-en.js + var enCreationTime = submission.d[13]; + var ruCreationTime = submission.d[14]; + var relativeTime = submission.d[15]; + var lang = submission.d[16]; + var diagnostics = submission.d[17]; + */ + } + + json.Unmarshal([]byte(data.Text), &submission) + if submission.T != "s" { + continue + } + + // var a = submission.D[0].(float64); + var id = uint64(submission.D[1].(float64)); + + /* + TESTING + WRONG_ANSWER + TIME_LIMIT_EXCEEDED + RUNTIME_ERROR + OK + MEMORY_LIMIT_EXCEEDED + null + COMPILATION_ERROR + */ + + for i := range submissions { + sub := &submissions[i] + judgedTestCount := uint64(submission.D[8].(float64)) + if sub.id == id && judgedTestCount >= sub.judged { + // NOTE: in Codeforces JS code the "a" property are compared, however Submission struct doesn't have a field for that + sub.passed = uint64(submission.D[7].(float64)) + sub.judged = judgedTestCount + if submission.D[6] == nil { + sub.status = "${c-waiting}Running?" + } else { + verdictString := submission.D[6].(string) + testset := submission.D[4].(string) + + switch verdictString { // TODO could lookup in preparedVerdictFormats + case "OK": + sub.status = "${c-accepted}Accepted" + case "COMPILATION_ERROR": + sub.status = "Compilation error" + case "DENIAL_OF_JUDGEMENT": // ??? TODO + sub.status = "${c-failed}Denial of judgement" + default: + //fmt.Printf("verdictString = %v, testset = %v, passed = %v, judged = %v", + // verdictString, testset, sub.passed, sub.judged) + sub.status = fmt.Sprintf("%v on %v %v", map[string]string{ + "TESTING": "${c-waiting}Running", + "WRONG_ANSWER": "${c-rejected}Wrong answer", + "TIME_LIMIT_EXCEEDED": "${c-rejected}Time limit exceeded", + "RUNTIME_ERROR": "${c-rejected}Runtime error", + "MEMORY_LIMIT_EXCEEDED": "${c-rejected}Memory limit exceeded", + }[verdictString], map[string]string{ + "SAMPLES": "sample?", + "PRETESTS": "pretest", + "TESTS": "test", + "CHALLENGES": "hack", + "TESTS1": "TESTS1?", + "TESTS10": "TESTS10?", + }[testset], sub.judged) + } + + if verdictString != "TESTING" { + sub.end = true + } + } + sub.points = 0 + if submission.D[5] != nil { + sub.points = uint64(submission.D[5].(float64)) + } + sub.time = uint64(submission.D[9].(float64)) + sub.memory = uint64(submission.D[10].(float64)) + } + } + + display(submissions, problemID, first, &maxWidth, line) + if ended() { + return + } } return } // WatchSubmission n is the number of submissions -func (c *Client) WatchSubmission(contestID, problemID string, n int, line bool) (submissions []Submission, err error) { +func (c *Client) WatchSubmission_old(contestID, problemID string, n int, line bool) (submissions []Submission, err error) { URL := ToGym(fmt.Sprintf(c.Host+"/contest/%v/my", contestID), contestID) maxWidth := 0 first := true ```

I have just started learning Go yesterday, so there may be bad coding practices.

As a debug feature, running cf watch 0 will watch /problemset/status.

Remark: it's unfortunate that Codeforces has a lot of useful but undocumented API, so each project have to figure out those manually.


The above version only handle the most common cases. This version will handle all cases using the content of the file preparedVerdictFormats (however it makes the code larger)

Code ```diff diff --git a/client/submit.go b/client/submit.go index 11a73cf..f2343f0 100644 --- a/client/submit.go +++ b/client/submit.go @@ -83,6 +83,7 @@ func (c *Client) SubmitContest(contestID, problemID, langID, source string) (err } color.Green("Submitted") + // TODO can body be used here? submissions, err := c.WatchSubmission(contestID, "", 1, true) if err != nil { return diff --git a/client/watch.go b/client/watch.go index 5233e9b..2f25574 100644 --- a/client/watch.go +++ b/client/watch.go @@ -11,11 +11,15 @@ import ( "strconv" "strings" "time" + "net/url" + "encoding/json" + "github.com/gorilla/websocket" "github.com/PuerkitoBio/goquery" "github.com/fatih/color" ansi "github.com/k0kubun/go-ansi" "github.com/olekukonko/tablewriter" + "github.com/xalanq/cf-tool/util" ) // Submission submit state @@ -181,6 +185,26 @@ func parseWhen(raw, cfOffset string) string { return tm.In(time.Local).Format("2006-01-02 15:04") } +var numReg = regexp.MustCompile(`\d+`) +var fmtReg = regexp.MustCompile(`]+?)["']?>`) +var colReg = regexp.MustCompile(`]+?)["']?>`) +var tagReg = regexp.MustCompile(`<[\s\S]*?>`) + +func parseStatusFromHtml(html string) string { + status := fmtReg.ReplaceAllString(html, "") + status = colReg.ReplaceAllString(status, `${c-$1}`) + status = tagReg.ReplaceAllString(status, "") + status = strings.TrimSpace(status) + if status == "" { + status = "Unknown" + } + return status +} + +func isWaitingVerdictString(verdictString string) bool { + return verdictString == "" || verdictString == "null" || verdictString == "TESTING" || verdictString == "SUBMITTED"; +} + func parseSubmission(body []byte, cfOffset string) (ret Submission, err error) { data := fmt.Sprintf("", string(body)) doc, err := goquery.NewDocumentFromReader(strings.NewReader(data)) @@ -203,24 +227,15 @@ func parseSubmission(body []byte, cfOffset string) (ret Submission, err error) { if verdict, exist := sub.Attr("submissionverdict"); exist && !isWait(verdict) { end = true } - status, _ := sub.Html() - numReg := regexp.MustCompile(`\d+`) - fmtReg := regexp.MustCompile(`]+?)["']?>`) - colReg := regexp.MustCompile(`]+?)["']?>`) - tagReg := regexp.MustCompile(`<[\s\S]*?>`) - status = fmtReg.ReplaceAllString(status, "") - status = colReg.ReplaceAllString(status, `${c-$1}`) - status = tagReg.ReplaceAllString(status, "") - status = strings.TrimSpace(status) + html, _ := sub.Html() + status := parseStatusFromHtml(html) + when := get(".format-time") if when != "" { when = parseWhen(when, cfOffset) } else { when = strings.TrimSpace(doc.Find("td").First().Next().Text()) } - if status == "" { - status = "Unknown" - } var num uint64 if s := numReg.FindString(status); s != "" { n, _ := strconv.Atoi(s) @@ -241,6 +256,34 @@ func parseSubmission(body []byte, cfOffset string) (ret Submission, err error) { }, nil } +func (c *Client) getSubmissionsFromBody(body []byte, n int) (submissions []Submission, err error) { + if err = checkLogin(c.Username, body); err != nil { + return + } + + cfOffset, err := findCfOffset(body) + if err != nil { + return + } + + submissionsBody, err := findSubmission(body, n) + if err != nil { + return + } + + for _, submissionBody := range submissionsBody { + if submission, err := parseSubmission(submissionBody, cfOffset); err == nil { + submissions = append(submissions, submission) + } + } + + if len(submissions) < 1 { + return nil, errors.New("Cannot find any submission") + } + + return +} + func (c *Client) getSubmissions(myURL string, n int) (submissions []Submission, err error) { resp, err := c.client.Get(myURL) if err != nil { @@ -252,35 +295,170 @@ func (c *Client) getSubmissions(myURL string, n int) (submissions []Submission, return } - if err = checkLogin(c.Username, body); err != nil { - return + return c.getSubmissionsFromBody(body, n) +} + +func findMeta(body []byte, name string) (string, error) { + // name must not contain any regex meta-character + reg := regexp.MustCompile(``) + tmp := reg.FindSubmatch(body) + if len(tmp) < 2 { + return "", errors.New("Cannot find meta property") } + return string(tmp[1]), nil +} - cfOffset, err := findCfOffset(body) +// WatchSubmission n is the number of submissions +func (c *Client) WatchSubmission(contestID, problemID string, n int, line bool) (submissions []Submission, err error) { + // new version + URL := ToGym(fmt.Sprintf(c.Host+"/contest/%v/my", contestID), contestID) + if contestID == "0" { + URL = c.Host+"/problemset/status" // DEBUG + } + + maxWidth := 0 + first := true + + resp, err := c.client.Get(URL) + if err != nil { + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) if err != nil { return } - submissionsBody, err := findSubmission(body, n) + submissions, err = c.getSubmissionsFromBody(body, n) if err != nil { return } + display(submissions, problemID, first, &maxWidth, line) + first = false - for _, submissionBody := range submissionsBody { - if submission, err := parseSubmission(submissionBody, cfOffset); err == nil { - submissions = append(submissions, submission) + ended := func() bool { + endCount := 0 + for _, submission := range submissions { + if submission.end { + endCount++ + } } + return endCount == len(submissions) + } + if ended() { + return } - if len(submissions) < 1 { - return nil, errors.New("Cannot find any submission") + wssrawurl := "wss://pubsub.codeforces.com/ws/" + + /* + for _, x := range []string{"gc","uc","usmc","cc","pc","tc"} { // is it necessary to include all of those channels? + data, _ := findMeta(body, x) // data: pushstream/websocket channel + fmt.Printf("%v = %v\n", x, data) + if err == nil { + wssrawurl += data + '/' + } + } + */ + + for _, x := range []string{"pc","cc","gc"} { // is it necessary to include all of those channels? + data, err := findMeta(body, x) // data: pushstream/websocket channel + if err == nil { + wssrawurl += `s_` + data + `/` + } + } + + wssurl, _ := url.Parse(wssrawurl) + + conn, _, err := websocket.DefaultDialer.Dial(wssurl.String(), nil) + if err != nil { + return + } + defer conn.Close() + + for { + var bytes []byte + _, bytes, err = conn.ReadMessage() + + if err != nil { + return + } + + + var data struct { + Id int + Channel string + Text string + } + json.Unmarshal(bytes, &data) + + //fmt.Println(data.Text) + + var submission struct { + T string + D []interface{} + /* + var a = submission.d[0]; + var id = submission.d[1]; + var contestId = submission.d[2]; + var problemId = submission.d[3]; + var testset = submission.d[4]; + var points = submission.d[5]; + var verdictString = submission.d[6]; + var passedTestCount = submission.d[7]; + var judgedTestCount = submission.d[8]; + var timeConsumed = submission.d[9]; + var memoryConsumed = submission.d[10]; + var participantId = submission.d[11]; + var verdict = preparedVerdictFormats[submission.d[12]]; + var enCreationTime = submission.d[13]; + var ruCreationTime = submission.d[14]; + var relativeTime = submission.d[15]; + var lang = submission.d[16]; + var diagnostics = submission.d[17]; + */ + } + + json.Unmarshal([]byte(data.Text), &submission) + if submission.T != "s" { + continue + } + + // var a = submission.D[0].(float64); + var id = uint64(submission.D[1].(float64)); + + for i := range submissions { + sub := &submissions[i] + judgedTestCount := uint64(submission.D[8].(float64)) + if sub.id == id && judgedTestCount >= sub.judged { + // NOTE: in Codeforces JS code the "a" property are compared, however Submission struct doesn't have a field for that + sub.passed = uint64(submission.D[7].(float64)) + sub.judged = judgedTestCount + verdictString := submission.D[6].(string); + if !isWaitingVerdictString(verdictString) { + sub.end = true + } + sub.status = util.PreparedVerdictFormats[submission.D[12].(string)]; + sub.points = 0 + if submission.D[5] != nil { + sub.points = uint64(submission.D[5].(float64)) + } + sub.time = uint64(submission.D[9].(float64)) + sub.memory = uint64(submission.D[10].(float64)) + } + } + + display(submissions, problemID, first, &maxWidth, line) + if ended() { + return + } } return } // WatchSubmission n is the number of submissions -func (c *Client) WatchSubmission(contestID, problemID string, n int, line bool) (submissions []Submission, err error) { +func (c *Client) WatchSubmission_old(contestID, problemID string, n int, line bool) (submissions []Submission, err error) { URL := ToGym(fmt.Sprintf(c.Host+"/contest/%v/my", contestID), contestID) maxWidth := 0 first := true @@ -314,3 +492,4 @@ var colorMap = map[string]color.Attribute{ "${c-accepted}": color.FgGreen, "${c-rejected}": color.FgBlue, } + diff --git a/util/util.go b/util/util.go index 801906a..ed6d0f2 100644 --- a/util/util.go +++ b/util/util.go @@ -5,6 +5,7 @@ import ( "fmt" "math/rand" "os" + "regexp" "strconv" "strings" @@ -66,3 +67,707 @@ func YesOrNo(note string) bool { color.Red("Invalid input. Please input again: ") } } + +var fmtReg = regexp.MustCompile(`]+?)["']?>.*?`) +var colReg = regexp.MustCompile(`]+?)["']?>`) +var tagReg = regexp.MustCompile(`<[\s\S]*?>`) + +func prepareVerdictFormats() (x map[string]string) { + // From https://sta.codeforces.com/s/52452/js/preparedVerdictFormats-en.js + x = map[string]string{} + for key, val := range map[string]string { + "30000": "Denial of judgement", + "30001": "Denial of judgement", + "30010": "Denial of judgement", + "30011": "Denial of judgement", + "30020": "Denial of judgement", + "30021": "Denial of judgement", + "30110": "Denial of judgement", + "30111": "Denial of judgement", + "30120": "Denial of judgement", + "30121": "Denial of judgement", + "30220": "Denial of judgement", + "30221": "Denial of judgement", + "31000": "Pretests and hacks passed", + "31001": "Perfect result: 1 points", + "31010": "Pretests and hacks passed", + "31011": "Perfect result: 1 points", + "31020": "Pretests and hacks passed", + "31021": "Perfect result: 1 points", + "31110": "Pretests and hacks passed", + "31111": "Perfect result: 1 points", + "31120": "Pretests and hacks passed", + "31121": "Perfect result: 1 points", + "31220": "Pretests and hacks passed", + "31221": "Perfect result: 1 points", + "32000": "Partial (hacks)", + "32001": "Partial result: 1 points", + "32010": "Partial: 0 hacks ouf of 1", + "32011": "Partial result: 1 points", + "32020": "Partial: 0 hacks ouf of 2", + "32021": "Partial result: 1 points", + "32110": "Partial: 1 hacks ouf of 1", + "32111": "Partial result: 1 points", + "32120": "Partial: 1 hacks ouf of 2", + "32121": "Partial result: 1 points", + "32220": "Partial: 2 hacks ouf of 2", + "32221": "Partial result: 1 points", + "33000": "Compilation error", + "33001": "Compilation error", + "33010": "Compilation error", + "33011": "Compilation error", + "33020": "Compilation error", + "33021": "Compilation error", + "33110": "Compilation error", + "33111": "Compilation error", + "33120": "Compilation error", + "33121": "Compilation error", + "33220": "Compilation error", + "33221": "Compilation error", + "34000": "Runtime error on hack", + "34001": "Runtime error on hack", + "34010": "Runtime error on hack 1", + "34011": "Runtime error on hack 1", + "34020": "Runtime error on hack 2", + "34021": "Runtime error on hack 2", + "34110": "Runtime error on hack 1", + "34111": "Runtime error on hack 1", + "34120": "Runtime error on hack 2", + "34121": "Runtime error on hack 2", + "34220": "Runtime error on hack 2", + "34221": "Runtime error on hack 2", + "35000": "Wrong answer on hack", + "35001": "Wrong answer on hack", + "35010": "Wrong answer on hack 1", + "35011": "Wrong answer on hack 1", + "35020": "Wrong answer on hack 2", + "35021": "Wrong answer on hack 2", + "35110": "Wrong answer on hack 1", + "35111": "Wrong answer on hack 1", + "35120": "Wrong answer on hack 2", + "35121": "Wrong answer on hack 2", + "35220": "Wrong answer on hack 2", + "35221": "Wrong answer on hack 2", + "36000": "Presentation error on hack", + "36001": "Presentation error on hack", + "36010": "Presentation error on hack 1", + "36011": "Presentation error on hack 1", + "36020": "Presentation error on hack 2", + "36021": "Presentation error on hack 2", + "36110": "Presentation error on hack 1", + "36111": "Presentation error on hack 1", + "36120": "Presentation error on hack 2", + "36121": "Presentation error on hack 2", + "36220": "Presentation error on hack 2", + "36221": "Presentation error on hack 2", + "37000": "Time limit exceeded on hack", + "37001": "Time limit exceeded on hack", + "37010": "Time limit exceeded on hack 1", + "37011": "Time limit exceeded on hack 1", + "37020": "Time limit exceeded on hack 2", + "37021": "Time limit exceeded on hack 2", + "37110": "Time limit exceeded on hack 1", + "37111": "Time limit exceeded on hack 1", + "37120": "Time limit exceeded on hack 2", + "37121": "Time limit exceeded on hack 2", + "37220": "Time limit exceeded on hack 2", + "37221": "Time limit exceeded on hack 2", + "38000": "Memory limit exceeded on hack", + "38001": "Memory limit exceeded on hack", + "38010": "Memory limit exceeded on hack 1", + "38011": "Memory limit exceeded on hack 1", + "38020": "Memory limit exceeded on hack 2", + "38021": "Memory limit exceeded on hack 2", + "38110": "Memory limit exceeded on hack 1", + "38111": "Memory limit exceeded on hack 1", + "38120": "Memory limit exceeded on hack 2", + "38121": "Memory limit exceeded on hack 2", + "38220": "Memory limit exceeded on hack 2", + "38221": "Memory limit exceeded on hack 2", + "39000": "Idleness limit exceeded on hack", + "39001": "Idleness limit exceeded on hack", + "39010": "Idleness limit exceeded on hack 1", + "39011": "Idleness limit exceeded on hack 1", + "39020": "Idleness limit exceeded on hack 2", + "39021": "Idleness limit exceeded on hack 2", + "39110": "Idleness limit exceeded on hack 1", + "39111": "Idleness limit exceeded on hack 1", + "39120": "Idleness limit exceeded on hack 2", + "39121": "Idleness limit exceeded on hack 2", + "39220": "Idleness limit exceeded on hack 2", + "39221": "Idleness limit exceeded on hack 2", + "310000": "Security violated on hack", + "310001": "Security violated on hack", + "310010": "Security violated on hack 1", + "310011": "Security violated on hack 1", + "310020": "Security violated on hack 2", + "310021": "Security violated on hack 2", + "310110": "Security violated on hack 1", + "310111": "Security violated on hack 1", + "310120": "Security violated on hack 2", + "310121": "Security violated on hack 2", + "310220": "Security violated on hack 2", + "310221": "Security violated on hack 2", + "311000": "Judgement crashed on hack", + "311001": "Judgement crashed on hack", + "311010": "Judgement crashed on hack", + "311011": "Judgement crashed on hack", + "311020": "Judgement crashed on hack", + "311021": "Judgement crashed on hack", + "311110": "Judgement crashed on hack", + "311111": "Judgement crashed on hack", + "311120": "Judgement crashed on hack", + "311121": "Judgement crashed on hack", + "311220": "Judgement crashed on hack", + "311221": "Judgement crashed on hack", + "312000": "Input preparation failed on hack", + "312001": "Input preparation failed on hack", + "312010": "Input preparation failed on hack 1", + "312011": "Input preparation failed on hack 1", + "312020": "Input preparation failed on hack 2", + "312021": "Input preparation failed on hack 2", + "312110": "Input preparation failed on hack 1", + "312111": "Input preparation failed on hack 1", + "312120": "Input preparation failed on hack 2", + "312121": "Input preparation failed on hack 2", + "312220": "Input preparation failed on hack 2", + "312221": "Input preparation failed on hack 2", + "313000": "Hacked", + "313001": "Hacked", + "313010": "Hacked", + "313011": "Hacked", + "313020": "Hacked", + "313021": "Hacked", + "313110": "Hacked", + "313111": "Hacked", + "313120": "Hacked", + "313121": "Hacked", + "313220": "Hacked", + "313221": "Hacked", + "314000": "Skipped", + "314001": "Skipped", + "314010": "Skipped", + "314011": "Skipped", + "314020": "Skipped", + "314021": "Skipped", + "314110": "Skipped", + "314111": "Skipped", + "314120": "Skipped", + "314121": "Skipped", + "314220": "Skipped", + "314221": "Skipped", + "315000": "Running on hack", + "315001": "Running on hack", + "315010": "Running on hack 1", + "315011": "Running on hack 1", + "315020": "Running on hack 2", + "315021": "Running on hack 2", + "315110": "Running on hack 1", + "315111": "Running on hack 1", + "315120": "Running on hack 2", + "315121": "Running on hack 2", + "315220": "Running on hack 2", + "315221": "Running on hack 2", + "316000": "Rejected on hack", + "316001": "Rejected on hack", + "316010": "Rejected on hack 1", + "316011": "Rejected on hack 1", + "316020": "Rejected on hack 2", + "316021": "Rejected on hack 2", + "316110": "Rejected on hack 1", + "316111": "Rejected on hack 1", + "316120": "Rejected on hack 2", + "316121": "Rejected on hack 2", + "316220": "Rejected on hack 2", + "316221": "Rejected on hack 2", + "317000": "StatusForChallenge::submitted", + "317001": "StatusForChallenge::submitted", + "317010": "StatusForChallenge::submitted 1 tests / =1", + "317011": "StatusForChallenge::submitted 1 tests / =1", + "317020": "StatusForChallenge::submitted 2 tests / 2-4", + "317021": "StatusForChallenge::submitted 2 tests / 2-4", + "317110": "StatusForChallenge::submitted 1 tests / =1", + "317111": "StatusForChallenge::submitted 1 tests / =1", + "317120": "StatusForChallenge::submitted 2 tests / 2-4", + "317121": "StatusForChallenge::submitted 2 tests / 2-4", + "317220": "StatusForChallenge::submitted 2 tests / 2-4", + "317221": "StatusForChallenge::submitted 2 tests / 2-4", + "3-000": "In queue", + "3-001": "In queue", + "3-010": "In queue", + "3-011": "In queue", + "3-020": "In queue", + "3-021": "In queue", + "3-110": "In queue", + "3-111": "In queue", + "3-120": "In queue", + "3-121": "In queue", + "3-220": "In queue", + "3-221": "In queue", + "10000": "Judgement Failed", + "10001": "Judgement Failed", + "10010": "Judgement Failed", + "10011": "Judgement Failed", + "10020": "Judgement Failed", + "10021": "Judgement Failed", + "10110": "Judgement Failed", + "10111": "Judgement Failed", + "10120": "Judgement Failed", + "10121": "Judgement Failed", + "10220": "Judgement Failed", + "10221": "Judgement Failed", + "11000": "Pretests passed", + "11001": "Perfect result: 1 points", + "11010": "Pretests passed", + "11011": "Perfect result: 1 points", + "11020": "Pretests passed", + "11021": "Perfect result: 1 points", + "11110": "Pretests passed", + "11111": "Perfect result: 1 points", + "11120": "Pretests passed", + "11121": "Perfect result: 1 points", + "11220": "Pretests passed", + "11221": "Perfect result: 1 points", + "12000": "Partial (pretests)", + "12001": "Partial result: 1 points", + "12010": "Partial: 0 pretests out of 1", + "12011": "Partial result: 1 points", + "12020": "Partial: 0 pretests out of 2", + "12021": "Partial result: 1 points", + "12110": "Partial: 1 pretests out of 1", + "12111": "Partial result: 1 points", + "12120": "Partial: 1 pretests out of 2", + "12121": "Partial result: 1 points", + "12220": "Partial: 2 pretests out of 2", + "12221": "Partial result: 1 points", + "13000": "Compilation error", + "13001": "Compilation error", + "13010": "Compilation error", + "13011": "Compilation error", + "13020": "Compilation error", + "13021": "Compilation error", + "13110": "Compilation error", + "13111": "Compilation error", + "13120": "Compilation error", + "13121": "Compilation error", + "13220": "Compilation error", + "13221": "Compilation error", + "14000": "Runtime error on pretest", + "14001": "Runtime error on pretest", + "14010": "Runtime error on pretest 1", + "14011": "Runtime error on pretest 1", + "14020": "Runtime error on pretest 2", + "14021": "Runtime error on pretest 2", + "14110": "Runtime error on pretest 1", + "14111": "Runtime error on pretest 1", + "14120": "Runtime error on pretest 2", + "14121": "Runtime error on pretest 2", + "14220": "Runtime error on pretest 2", + "14221": "Runtime error on pretest 2", + "15000": "Wrong answer on pretest", + "15001": "Wrong answer on pretest", + "15010": "Wrong answer on pretest 1", + "15011": "Wrong answer on pretest 1", + "15020": "Wrong answer on pretest 2", + "15021": "Wrong answer on pretest 2", + "15110": "Wrong answer on pretest 1", + "15111": "Wrong answer on pretest 1", + "15120": "Wrong answer on pretest 2", + "15121": "Wrong answer on pretest 2", + "15220": "Wrong answer on pretest 2", + "15221": "Wrong answer on pretest 2", + "16000": "Presentation error on pretest", + "16001": "Presentation error on pretest", + "16010": "Presentation error on pretest 1", + "16011": "Presentation error on pretest 1", + "16020": "Presentation error on pretest 2", + "16021": "Presentation error on pretest 2", + "16110": "Presentation error on pretest 1", + "16111": "Presentation error on pretest 1", + "16120": "Presentation error on pretest 2", + "16121": "Presentation error on pretest 2", + "16220": "Presentation error on pretest 2", + "16221": "Presentation error on pretest 2", + "17000": "Time limit exceeded on pretest", + "17001": "Time limit exceeded on pretest", + "17010": "Time limit exceeded on pretest 1", + "17011": "Time limit exceeded on pretest 1", + "17020": "Time limit exceeded on pretest 2", + "17021": "Time limit exceeded on pretest 2", + "17110": "Time limit exceeded on pretest 1", + "17111": "Time limit exceeded on pretest 1", + "17120": "Time limit exceeded on pretest 2", + "17121": "Time limit exceeded on pretest 2", + "17220": "Time limit exceeded on pretest 2", + "17221": "Time limit exceeded on pretest 2", + "18000": "Memory limit exceeded on pretest", + "18001": "Memory limit exceeded on pretest", + "18010": "Memory limit exceeded on pretest 1", + "18011": "Memory limit exceeded on pretest 1", + "18020": "Memory limit exceeded on pretest 2", + "18021": "Memory limit exceeded on pretest 2", + "18110": "Memory limit exceeded on pretest 1", + "18111": "Memory limit exceeded on pretest 1", + "18120": "Memory limit exceeded on pretest 2", + "18121": "Memory limit exceeded on pretest 2", + "18220": "Memory limit exceeded on pretest 2", + "18221": "Memory limit exceeded on pretest 2", + "19000": "Idleness limit exceeded on pretest", + "19001": "Idleness limit exceeded on pretest", + "19010": "Idleness limit exceeded on pretest 1", + "19011": "Idleness limit exceeded on pretest 1", + "19020": "Idleness limit exceeded on pretest 2", + "19021": "Idleness limit exceeded on pretest 2", + "19110": "Idleness limit exceeded on pretest 1", + "19111": "Idleness limit exceeded on pretest 1", + "19120": "Idleness limit exceeded on pretest 2", + "19121": "Idleness limit exceeded on pretest 2", + "19220": "Idleness limit exceeded on pretest 2", + "19221": "Idleness limit exceeded on pretest 2", + "110000": "Security violated on pretest", + "110001": "Security violated on pretest", + "110010": "Security violated on pretest 1", + "110011": "Security violated on pretest 1", + "110020": "Security violated on pretest 2", + "110021": "Security violated on pretest 2", + "110110": "Security violated on pretest 1", + "110111": "Security violated on pretest 1", + "110120": "Security violated on pretest 2", + "110121": "Security violated on pretest 2", + "110220": "Security violated on pretest 2", + "110221": "Security violated on pretest 2", + "111000": "Denial of judgement", + "111001": "Denial of judgement", + "111010": "Denial of judgement", + "111011": "Denial of judgement", + "111020": "Denial of judgement", + "111021": "Denial of judgement", + "111110": "Denial of judgement", + "111111": "Denial of judgement", + "111120": "Denial of judgement", + "111121": "Denial of judgement", + "111220": "Denial of judgement", + "111221": "Denial of judgement", + "112000": "Input preparation failed on pretest", + "112001": "Input preparation failed on pretest", + "112010": "Input preparation failed on pretest 1", + "112011": "Input preparation failed on pretest 1", + "112020": "Input preparation failed on pretest 2", + "112021": "Input preparation failed on pretest 2", + "112110": "Input preparation failed on pretest 1", + "112111": "Input preparation failed on pretest 1", + "112120": "Input preparation failed on pretest 2", + "112121": "Input preparation failed on pretest 2", + "112220": "Input preparation failed on pretest 2", + "112221": "Input preparation failed on pretest 2", + "113000": "Hacked", + "113001": "Hacked", + "113010": "Hacked", + "113011": "Hacked", + "113020": "Hacked", + "113021": "Hacked", + "113110": "Hacked", + "113111": "Hacked", + "113120": "Hacked", + "113121": "Hacked", + "113220": "Hacked", + "113221": "Hacked", + "114000": "Skipped", + "114001": "Skipped", + "114010": "Skipped", + "114011": "Skipped", + "114020": "Skipped", + "114021": "Skipped", + "114110": "Skipped", + "114111": "Skipped", + "114120": "Skipped", + "114121": "Skipped", + "114220": "Skipped", + "114221": "Skipped", + "115000": "Running on pretest", + "115001": "Running on pretest", + "115010": "Running on pretest 1", + "115011": "Running on pretest 1", + "115020": "Running on pretest 2", + "115021": "Running on pretest 2", + "115110": "Running on pretest 1", + "115111": "Running on pretest 1", + "115120": "Running on pretest 2", + "115121": "Running on pretest 2", + "115220": "Running on pretest 2", + "115221": "Running on pretest 2", + "116000": "Rejected on pretest", + "116001": "Rejected on pretest", + "116010": "Rejected on pretest 1", + "116011": "Rejected on pretest 1", + "116020": "Rejected on pretest 2", + "116021": "Rejected on pretest 2", + "116110": "Rejected on pretest 1", + "116111": "Rejected on pretest 1", + "116120": "Rejected on pretest 2", + "116121": "Rejected on pretest 2", + "116220": "Rejected on pretest 2", + "116221": "Rejected on pretest 2", + "117000": "StatusForPretest::submitted", + "117001": "StatusForPretest::submitted", + "117010": "StatusForPretest::submitted 1 tests / =1", + "117011": "StatusForPretest::submitted 1 tests / =1", + "117020": "StatusForPretest::submitted 2 tests / 2-4", + "117021": "StatusForPretest::submitted 2 tests / 2-4", + "117110": "StatusForPretest::submitted 1 tests / =1", + "117111": "StatusForPretest::submitted 1 tests / =1", + "117120": "StatusForPretest::submitted 2 tests / 2-4", + "117121": "StatusForPretest::submitted 2 tests / 2-4", + "117220": "StatusForPretest::submitted 2 tests / 2-4", + "117221": "StatusForPretest::submitted 2 tests / 2-4", + "1-000": "In queue", + "1-001": "In queue", + "1-010": "In queue", + "1-011": "In queue", + "1-020": "In queue", + "1-021": "In queue", + "1-110": "In queue", + "1-111": "In queue", + "1-120": "In queue", + "1-121": "In queue", + "1-220": "In queue", + "1-221": "In queue", + "20000": "Judgement failed", + "20001": "Judgement failed", + "20010": "Judgement failed", + "20011": "Judgement failed", + "20020": "Judgement failed", + "20021": "Judgement failed", + "20110": "Judgement failed", + "20111": "Judgement failed", + "20120": "Judgement failed", + "20121": "Judgement failed", + "20220": "Judgement failed", + "20221": "Judgement failed", + "21000": "Accepted", + "21001": "Perfect result: 1 points", + "21010": "Accepted", + "21011": "Perfect result: 1 points", + "21020": "Accepted", + "21021": "Perfect result: 1 points", + "21110": "Accepted", + "21111": "Perfect result: 1 points", + "21120": "Accepted", + "21121": "Perfect result: 1 points", + "21220": "Accepted", + "21221": "Perfect result: 1 points", + "22000": "Partial", + "22001": "Partial result: 1 points", + "22010": "Partial: 0 tests out of 1", + "22011": "Partial result: 1 points", + "22020": "Partial: 0 tests out of 2", + "22021": "Partial result: 1 points", + "22110": "Partial: 1 tests out of 1", + "22111": "Partial result: 1 points", + "22120": "Partial: 1 tests out of 2", + "22121": "Partial result: 1 points", + "22220": "Partial: 2 tests out of 2", + "22221": "Partial result: 1 points", + "23000": "Compilation error", + "23001": "Compilation error", + "23010": "Compilation error", + "23011": "Compilation error", + "23020": "Compilation error", + "23021": "Compilation error", + "23110": "Compilation error", + "23111": "Compilation error", + "23120": "Compilation error", + "23121": "Compilation error", + "23220": "Compilation error", + "23221": "Compilation error", + "24000": "Runtime error", + "24001": "Runtime error", + "24010": "Runtime error on test 1", + "24011": "Runtime error on test 1", + "24020": "Runtime error on test 2", + "24021": "Runtime error on test 2", + "24110": "Runtime error on test 1", + "24111": "Runtime error on test 1", + "24120": "Runtime error on test 2", + "24121": "Runtime error on test 2", + "24220": "Runtime error on test 2", + "24221": "Runtime error on test 2", + "25000": "Wrong answer", + "25001": "Wrong answer", + "25010": "Wrong answer on test 1", + "25011": "Wrong answer on test 1", + "25020": "Wrong answer on test 2", + "25021": "Wrong answer on test 2", + "25110": "Wrong answer on test 1", + "25111": "Wrong answer on test 1", + "25120": "Wrong answer on test 2", + "25121": "Wrong answer on test 2", + "25220": "Wrong answer on test 2", + "25221": "Wrong answer on test 2", + "26000": "Presentation error", + "26001": "Presentation error", + "26010": "Presentation error on test 1", + "26011": "Presentation error on test 1", + "26020": "Presentation error on test 2", + "26021": "Presentation error on test 2", + "26110": "Presentation error on test 1", + "26111": "Presentation error on test 1", + "26120": "Presentation error on test 2", + "26121": "Presentation error on test 2", + "26220": "Presentation error on test 2", + "26221": "Presentation error on test 2", + "27000": "Time limit exceeded", + "27001": "Time limit exceeded", + "27010": "Time limit exceeded on test 1", + "27011": "Time limit exceeded on test 1", + "27020": "Time limit exceeded on test 2", + "27021": "Time limit exceeded on test 2", + "27110": "Time limit exceeded on test 1", + "27111": "Time limit exceeded on test 1", + "27120": "Time limit exceeded on test 2", + "27121": "Time limit exceeded on test 2", + "27220": "Time limit exceeded on test 2", + "27221": "Time limit exceeded on test 2", + "28000": "Memory limit exceeded", + "28001": "Memory limit exceeded", + "28010": "Memory limit exceeded on test 1", + "28011": "Memory limit exceeded on test 1", + "28020": "Memory limit exceeded on test 2", + "28021": "Memory limit exceeded on test 2", + "28110": "Memory limit exceeded on test 1", + "28111": "Memory limit exceeded on test 1", + "28120": "Memory limit exceeded on test 2", + "28121": "Memory limit exceeded on test 2", + "28220": "Memory limit exceeded on test 2", + "28221": "Memory limit exceeded on test 2", + "29000": "Idleness limit exceeded", + "29001": "Idleness limit exceeded", + "29010": "Idleness limit exceeded on test 1", + "29011": "Idleness limit exceeded on test 1", + "29020": "Idleness limit exceeded on test 2", + "29021": "Idleness limit exceeded on test 2", + "29110": "Idleness limit exceeded on test 1", + "29111": "Idleness limit exceeded on test 1", + "29120": "Idleness limit exceeded on test 2", + "29121": "Idleness limit exceeded on test 2", + "29220": "Idleness limit exceeded on test 2", + "29221": "Idleness limit exceeded on test 2", + "210000": "Security violated", + "210001": "Security violated", + "210010": "Security violated on test 1", + "210011": "Security violated on test 1", + "210020": "Security violated on test 2", + "210021": "Security violated on test 2", + "210110": "Security violated on test 1", + "210111": "Security violated on test 1", + "210120": "Security violated on test 2", + "210121": "Security violated on test 2", + "210220": "Security violated on test 2", + "210221": "Security violated on test 2", + "211000": "Denial of judgement", + "211001": "Denial of judgement", + "211010": "Denial of judgement", + "211011": "Denial of judgement", + "211020": "Denial of judgement", + "211021": "Denial of judgement", + "211110": "Denial of judgement", + "211111": "Denial of judgement", + "211120": "Denial of judgement", + "211121": "Denial of judgement", + "211220": "Denial of judgement", + "211221": "Denial of judgement", + "212000": "Input preparation failed", + "212001": "Input preparation failed", + "212010": "Input preparation failed on test 1", + "212011": "Input preparation failed on test 1", + "212020": "Input preparation failed on test 2", + "212021": "Input preparation failed on test 2", + "212110": "Input preparation failed on test 1", + "212111": "Input preparation failed on test 1", + "212120": "Input preparation failed on test 2", + "212121": "Input preparation failed on test 2", + "212220": "Input preparation failed on test 2", + "212221": "Input preparation failed on test 2", + "213000": "Hacked", + "213001": "Hacked", + "213010": "Hacked", + "213011": "Hacked", + "213020": "Hacked", + "213021": "Hacked", + "213110": "Hacked", + "213111": "Hacked", + "213120": "Hacked", + "213121": "Hacked", + "213220": "Hacked", + "213221": "Hacked", + "214000": "Skipped", + "214001": "Skipped", + "214010": "Skipped", + "214011": "Skipped", + "214020": "Skipped", + "214021": "Skipped", + "214110": "Skipped", + "214111": "Skipped", + "214120": "Skipped", + "214121": "Skipped", + "214220": "Skipped", + "214221": "Skipped", + "215000": "Running", + "215001": "Running", + "215010": "Running on test 1", + "215011": "Running on test 1", + "215020": "Running on test 2", + "215021": "Running on test 2", + "215110": "Running on test 1", + "215111": "Running on test 1", + "215120": "Running on test 2", + "215121": "Running on test 2", + "215220": "Running on test 2", + "215221": "Running on test 2", + "216000": "Rejected", + "216001": "Rejected", + "216010": "Rejected on test 1", + "216011": "Rejected on test 1", + "216020": "Rejected on test 2", + "216021": "Rejected on test 2", + "216110": "Rejected on test 1", + "216111": "Rejected on test 1", + "216120": "Rejected on test 2", + "216121": "Rejected on test 2", + "216220": "Rejected on test 2", + "216221": "Rejected on test 2", + "217000": "Pending judgement", + "217001": "Pending judgement", + "217010": "Pending judgement of 1 test", + "217011": "Pending judgement of 1 test", + "217020": "Pending judgement of 2 tests", + "217021": "Pending judgement of 2 tests", + "217110": "Pending judgement of 1 test", + "217111": "Pending judgement of 1 test", + "217120": "Pending judgement of 2 tests", + "217121": "Pending judgement of 2 tests", + "217220": "Pending judgement of 2 tests", + "217221": "Pending judgement of 2 tests", + "2-000": "In queue", + "2-001": "In queue", + "2-010": "In queue", + "2-011": "In queue", + "2-020": "In queue", + "2-021": "In queue", + "2-110": "In queue", + "2-111": "In queue", + "2-120": "In queue", + "2-121": "In queue", + "2-220": "In queue", + "2-221": "In queue", + } { + val = fmtReg.ReplaceAllString(val, `${f-$1}`) + val = colReg.ReplaceAllString(val, `${c-$1}`) + val = tagReg.ReplaceAllString(val, "") + val = strings.TrimSpace(val) + x[key] = val + } + return +} + +var PreparedVerdictFormats = prepareVerdictFormats() ```
Fomalhauthmj commented 4 years ago

sorry i haven't learned Go before, maybe you can start a PR to contribute for this project. thank you for your contributions!

xalanq commented 4 years ago
xalanq commented 4 years ago

Now the latest version supports network proxy. Maybe it would be faster.