Exemple #1
0
func runBuildFile(s *WorkerState) {
	var stdout, stderr bytes.Buffer

	s.CompileStartTime = time.Now()
	_, err := runOutput(CompileTimeout,
		nil, /* env */
		&stdout,
		&stderr,
		filepath.Dir(s.BuildFileName),
		[]string{s.BuildFileName},
	)
	s.CompileEndTime = time.Now()

	stats.LogTime("Worker", "CompileTime", s.CompileStartTime, s.CompileEndTime)

	s.CompileStdout = string(stdout.Bytes())
	s.CompileStderr = string(stderr.Bytes())

	if err != nil {
		switch err.(type) {
		case TimeoutError:
			s.TimeoutError = true
			s.TimeoutValue = err.(TimeoutError).Timeout
			stats.Incr("Worker", "RunTimeout")
			panic("Failed to compile program")
			return
		}
	}
	if err != nil ||
		!FileExists(filepath.Join(s.TemporaryDirectory, s.ExecutableFileName)) {
		s.CompilationFailed = true
		stats.Incr("Worker", "CompilationFailed")
		panic("Failed to compile program")
	}
}
Exemple #2
0
func (c SecuredApplication) RevertMachineProblem(mpNumString string) revel.Result {

	var mp models.MachineProblem

	mpNum, err := strconv.Atoi(mpNumString)
	if err != nil {
		c.Flash.Error("Invalid machine problem")
		return c.Render(routes.PublicApplication.Index())
	}

	user := c.connected()
	stats.Incr("App", "ProgramRevert")

	if mp, err = models.FindOrCreateMachineProblemByUser(user, mpNum); err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"data":   "Could not create mp.",
		})
	}

	if _, err := revertMachineProblemProgram(user, mp); err == nil {
		return c.RenderJson(map[string]interface{}{
			"status": "success",
		})
	} else {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
		})
	}
}
Exemple #3
0
func (c CourseraApplication) LTIAuthenticate() revel.Result {
	var values string
	var form string
	var userid string

	user := c.connected()
	if user.Id == 0 {
		c.Flash.Error("Must log in before connecting user to coursera")
		return c.Redirect(routes.PublicApplication.Login())
	}

	c.Params.Bind(&values, "Values")
	c.Params.Bind(&form, "Form")
	c.Params.Bind(&userid, "user_id")

	if userid == "" {
		c.Flash.Error("Cannot get user identity from coursera!")
		stats.Incr("User", "CourseraAuthenticationFailed")
		return c.Redirect(routes.PublicApplication.Index())
	}
	revel.TRACE.Println("identity = ", userid)
	stats.Log("User", "Coursera", "Connected to coursera with identity: "+userid)
	models.SetUserCourseraCredentials(user, form, values, userid)

	c.Flash.Success("Connected to coursera!")
	return c.Redirect(routes.PublicApplication.Index())

}
Exemple #4
0
func (c SecuredApplication) SaveProgram(mpNumString string) revel.Result {
	var program string
	var mp models.MachineProblem

	mpNum, err := strconv.Atoi(mpNumString)
	if err != nil {
		c.Flash.Error("Invalid machine problem")
		return c.Render(routes.PublicApplication.Index())
	}

	user := c.connected()

	c.Params.Bind(&program, "program")

	stats.Incr("App", "ProgramSave")

	if mp, err = models.FindOrCreateMachineProblemByUser(user, mpNum); err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"data":   "Could not create mp.",
		})
	}

	if prog, err := models.CreateProgram(mp, program); err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"data":   "Could not save program.",
		})
	} else {
		return c.RenderJson(map[string]interface{}{
			"status": "success",
			"id":     prog.Id,
		})
	}
}
Exemple #5
0
func (c SecuredApplication) Logout() revel.Result {
	for k := range c.Session {
		delete(c.Session, k)
	}
	stats.Incr("App", "Logout")
	return c.Redirect(routes.PublicApplication.Index())
}
Exemple #6
0
func RegisterWorker(w *WorkerInfo) {
	if strings.Contains(w.Address, "%") {
		return
	}
	if _, p := Workers[w.Address]; p == false {
		Workers[w.Address] = w
		revel.TRACE.Println("Added worker...")
		stats.Incr("Master", "Workers")
	}
}
Exemple #7
0
func (c PublicApplication) CheckLogin() revel.Result {
	var userName string
	var password string

	c.Params.Bind(&userName, "userName")
	c.Params.Bind(&password, "password")

	if models.ValidUserNamePassword(userName, password) {
		c.Session["user"] = userName
		c.Flash.Success("Welcome, " + userName)
		stats.Incr("App", "Login")
		return c.Redirect(routes.PublicApplication.Index())
	} else {
		c.Flash.Error("Failed to login")
		stats.Incr("App", "LoginFailed")

		return c.Redirect(routes.PublicApplication.Login())

	}
}
Exemple #8
0
func (c SecuredApplication) SubmitProgram(mpNumString string) (res revel.Result) {
	var program string
	var datasetId int

	mpNum, err := strconv.Atoi(mpNumString)
	if err != nil {
		c.Flash.Error("Invalid machine problem")
		return c.Render(routes.PublicApplication.Index())
	}

	user := c.connected()

	c.Params.Bind(&program, "program")
	c.Params.Bind(&datasetId, "datasetId")

	mp, err := models.FindOrCreateMachineProblemByUser(user, mpNum)
	if err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"title":  "Error finding MP record",
			"data":   "System was not able to save program.",
		})
	}

	if lastAttempt, err := models.FindLastAttemptByMachineProblem(mp); err == nil && time.Since(lastAttempt.Created).Seconds() < 5 {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"title":  "Attempt limiter",
			"data":   "Too many attempts. Please wait 10 seconds between attempts.",
		})
	}

	if _, err := models.CreateProgram(mp, program); err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"title":  "Error Saving Program",
			"data":   "System was not able to save program.",
		})
	}

	runId := generateRunId(user)

	conf, _ := ReadMachineProblemConfig(mpNum)

	stats.Incr("App", "ProgramSubmission")

	server.SubmitProgram(mp, program, datasetId, conf.Language, runId, false)
	return c.RenderJson(map[string]interface{}{
		"status":  "success",
		"runId":   runId,
		"attempt": "Attempt submitted",
	})
}
Exemple #9
0
func (c SecuredApplication) ComputeGrade(attemptIdString string) revel.Result {

	attemptId, err := strconv.Atoi(attemptIdString)
	if err != nil {
		c.Flash.Error("Invalid attempt Id")
		return c.Render(routes.PublicApplication.Index())
	}

	attempt, err := models.FindAttempt(int64(attemptId))
	if err != nil || attempt.Id == 0 {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"title":  "Failed to grade machine problem",
			"data":   "Cannot find attempt " + attemptIdString + ".",
		})
	}

	mp, err := models.FindMachineProblem(attempt.MachineProblemInstanceId)
	if err != nil || mp.Id == 0 {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"title":  "Failed to grade",
			"data":   "Cannot find machine problem instance.",
		})
	}

	user := c.connected()

	if mp.UserInstanceId != user.Id {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"title":  "Failed to grade",
			"data":   "Invalid user.",
		})
	}

	runId := generateRunId(user)

	conf, _ := ReadMachineProblemConfig(mp.Number)

	stats.Incr("App", "GradeSubmission")

	prog, _ := models.FindProgram(attempt.ProgramInstanceId)
	server.SubmitProgram(mp, prog.Text, -1, conf.Language, runId, true)

	return c.RenderJson(map[string]interface{}{
		"status":  "success",
		"mpId":    strconv.Itoa(int(mp.Id)),
		"runId":   runId,
		"attempt": "Grade submitted",
	})
}
Exemple #10
0
func CompileAndRun(req *WorkerRequest) (res []WorkerState) {

	stats.Incr("Worker", "Compilations")

	conf, _ := ReadMachineProblemConfig(req.MachineProblemNumber)

	stats.Log("Worker", "CompileMP", "MP"+
		strconv.Itoa(req.MachineProblemNumber))
	stats.Log("Worker", "DatasetRun", "MP"+
		strconv.Itoa(req.MachineProblemNumber)+"::"+
		strconv.Itoa(req.DatasetId))

	if req.DatasetId == -1 && len(conf.Datasets) != 0 {
		res = make([]WorkerState, len(conf.Datasets))
		s := compile(req, 0)
		s.OnAllDatasets = true

		for i := range conf.Datasets {
			res[i] = *s
			res[i].DatasetId = i
			run(&res[i])
		}

		/*
			if directoryExists(s.TemporaryDirectory) {
				go func() {
					os.RemoveAll(s.TemporaryDirectory)
				}()
			}
		*/
	} else {
		res = make([]WorkerState, 1)
		s := compile(req, req.DatasetId)
		if req.DatasetId == -1 {
			s.OnAllDatasets = true
		} else {
			s.OnAllDatasets = false
		}
		run(s)
		res[0] = *s

		/*
			if directoryExists(s.TemporaryDirectory) {
				go func() {
					os.RemoveAll(s.TemporaryDirectory)
				}()
			}
		*/
	}
	return
}
Exemple #11
0
func (c SecuredApplication) SaveQuestion(mpNumString string, questionNumString string) revel.Result {
	var answer string

	mpNum, err := strconv.Atoi(mpNumString)
	questionNum, err := strconv.Atoi(questionNumString)

	c.Params.Bind(&answer, "answer")

	if answer == "" {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"data":   "Blank answer was not saved.",
		})
	}

	user := c.connected()

	mp, err := models.FindOrCreateMachineProblemByUser(user, mpNum)
	if err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"data":   "Cannot find machine problem.",
		})
	}

	conf, _ := ReadMachineProblemConfig(mp.Number)
	if MachineProblemCodingDeadlineExpiredQ(conf) {
		return c.RenderJson(map[string]interface{}{
			"status": "error-deadline",
			"data":   "Coding deadline has passed.",
		})
	}

	questions, err := models.FindOrCreateQuestionsByMachineProblem(mp)
	if err != nil {
		return c.RenderJson(map[string]interface{}{
			"status": "error",
			"data":   "Error: create questions.",
		})
	}

	err = models.SaveQuestion(mp, questions, int64(questionNum), answer)

	stats.Incr("App", "QuestionSave")

	return c.RenderJson(map[string]interface{}{
		"status": "success",
		"data":   answer,
	})
}
Exemple #12
0
func (c SecuredApplication) MachineProblem(mpNumString string) revel.Result {

	mpNum, err := strconv.Atoi(mpNumString)
	if err != nil {
		c.Flash.Error("Invalid machine problem")
		return c.Render(routes.PublicApplication.Index())
	}

	user := c.connected()

	conf, _ := ReadMachineProblemConfig(mpNum)

	if MachineProblemCodingDeadlineExpiredQ(conf) {
		c.RenderArgs["coding_expired"] = true
	}
	if MachineProblemPeerReviewDeadlineExpiredQ(conf) {
		c.RenderArgs["peer_review_expired"] = true
	}

	var mp models.MachineProblem
	if mp, err = models.FindOrCreateMachineProblemByUser(user, mpNum); err != nil {
		c.Flash.Error("Cannot create machine problem")
		return c.Render(routes.PublicApplication.Index())
	}

	c.RenderArgs["title"] = conf.Name
	c.RenderArgs["mp_num"] = mpNumString
	c.RenderArgs["mp_description"] = conf.Description

	c.RenderArgs["mp_config"] = conf

	if prog, err := machineProblemProgram(user, mp); err == nil {
		c.RenderArgs["mp_program"] = prog.Text
	}

	if questions, err := machineProblemQuestions(user, mp); err == nil {
		c.RenderArgs["mp_questions"] = questions
	}

	if history, err := recentPrograms(user, mp, 100); err == nil {
		c.RenderArgs["mp_program_history"] = history
	}

	c.RenderArgs["mp_attempts"] = getAttemptsSummary(user, mp)

	stats.Incr("App", "MachineProblemViews")

	return c.Render()
}
Exemple #13
0
func (c SecuredApplication) MachineProblemDatasetDownload(
	mpNumString string, name string) revel.Result {

	if !validMpNumber(mpNumString) {
		return c.Redirect("/404")
	}

	if name != "dataset.zip" && name != "dataset.tar.gz" {
		return c.Redirect("/404")
	}

	path := filepath.Join(MPFileDirectory, mpNumString, name)

	if f, err := os.Open(path); err == nil {
		stats.Incr("App", "DatasetDownload")
		return c.RenderFile(f, "attachement")
	}
	return c.Redirect("/404")
}
Exemple #14
0
func (c PublicApplication) CreateUser() revel.Result {
	var user models.User

	c.Params.Bind(&user, "user")

	if !validEmail(user.Email) {
		c.Flash.Error("Invalid email ... please use the university provided email account")
		return c.Redirect(routes.PublicApplication.CreateUser())
	}
	if models.UserNameExists(user.UserName) {
		c.Flash.Error("Username Already taken")
		return c.Redirect(routes.PublicApplication.CreateUser())
	}

	user.Validate(c.Validation)

	if c.Validation.HasErrors() {
		c.Flash.Error("Cannot signup!")
		c.Validation.Keep()
		c.FlashParams()
		return c.Redirect(routes.PublicApplication.CreateUser())
	}

	user.Hashed = false

	if err := models.CreateUser(user); err != nil {
		stats.TRACE.Println("Failed to create user ", err)
		return c.Redirect(routes.PublicApplication.CreateUser())
	}

	c.Session["user"] = user.UserName

	c.Flash.Success("Welcome, " + user.UserName)

	stats.Incr("App", "Users")

	return c.Redirect(routes.PublicApplication.Index())
}
Exemple #15
0
func SubmitJob(ws WorkerRequest) (res *WorkerState, err error) {

	worker, err := chooseWorker()
	if err != nil {
		return
	}
	js, err := json.Marshal(ws)
	if err != nil {
		return
	}

	b := bytes.NewBufferString(string(js))

	stats.Incr("Master", "SubmittingJob")

	resp, err := http.Post(worker.Address+"/compile", "text/json", b)
	if err != nil {
		return
	}

	defer resp.Body.Close()

	return
}
Exemple #16
0
// TODO: This should not live here
func CreateAttemptWithStates(states []WorkerState) (attempts []models.Attempt, grade models.Grade, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(fmt.Sprint(r))
		}
	}()

	if len(states) == 0 {
		err = errors.New("Invalid attempt")
		return
	}

	firstState := states[0]

	mp, err := models.FindMachineProblem(firstState.MachineProblemId)
	if err != nil {
		return
	}

	prog, err := models.CreateProgram(mp, firstState.Program)
	if err != nil {
		return
	}

	toGrade := false

	for _, ws := range states {

		jsInternalCData, _ := json.Marshal(ws.InternalCData)

		attempt := models.Attempt{
			MachineProblemInstanceId: mp.Id,
			ProgramInstanceId:        prog.Id,
			RunId:                    ws.RunId,
			DatasetId:                ws.DatasetId,
			CompilationFailed:        ws.CompilationFailed,
			CompileStderr:            strings.TrimSpace(ws.CompileStderr),
			CompileStdout:            strings.TrimSpace(ws.CompileStdout),
			RunFailed:                ws.RunFailed,
			RunStdout:                strings.TrimSpace(ws.RunStdout),
			RunStderr:                strings.TrimSpace(ws.RunStderr),
			TimeoutError:             ws.TimeoutError,
			TimeoutValue:             ws.TimeoutValue,
			Sandboxed:                ws.Sandboxed,
			SandboxKeyword:           ws.SandboxKeyword,
			CompileElapsedTime:       ws.CompileEndTime.Sub(ws.CompileStartTime).Nanoseconds(),
			RunElapsedTime:           ws.RunEndTime.Sub(ws.RunStartTime).Nanoseconds(),
			CompileStartTime:         ws.CompileStartTime,
			CompileEndTime:           ws.CompileEndTime,
			RunStartTime:             ws.RunStartTime,
			RunEndTime:               ws.RunEndTime,
			RequestStartTime:         ws.RequestStartTime,
			RequestEndTime:           ws.RequestEndTime,
			SolutionCorrect:          ws.SolutionCorrect,
			SolutionMessage:          ws.SolutionMessage,
			UserOutput:               ws.UserOutput,
			Language:                 ws.Language,
			OnAllDatasets:            ws.OnAllDatasets,
			InternalCData:            string(jsInternalCData),
			Created:                  time.Now(),
			Updated:                  time.Now(),
		}

		if ws.ForGrading {
			attempt.GradedQ = true
			toGrade = true
		}

		err = models.DB.Save(&attempt).Error
		if err != nil {
			revel.TRACE.Println("Failed saving attempt..  ", err)
			stats.Incr("Master", "FailedAttemptStore")
		} else {
			attempts = append(attempts, attempt)
		}
	}

	if toGrade {
		stats.Incr("Master", "UpdatingGrade")
		//revel.TRACE.Println("Updating grade...")
		grade, err = models.UpdateGradeWithAttempts(attempts)
		if err != nil {
			revel.TRACE.Println("Error updating grade  ", err)
		}
	}

	return
}
Exemple #17
0
func doPostCourseraGrade(user models.User, mp models.MachineProblem,
	grade models.Grade, toPost string, forceQ bool) error {
	type CourseraGrade struct {
		UserId              string `json:"user_id"`
		AssignmentId        string `json:"assignment_part_sid"`
		Score               int64  `json:"score"`
		Feedback            string `json:"feedback"`
		APIKey              string `json:"api_key"`
		CreateNewSubmission int    `json:"create_new_submission"`
	}

	toPost = strings.ToLower(toPost)
	toPostCode := false
	toPostPeer := false
	if toPost == "all" || toPost == "code" {
		toPostCode = true
	}

	if toPost == "all" || toPost == "peer" {
		toPostPeer = true
	}

	conf, _ := ReadMachineProblemConfig(mp.Number)

	idty := models.GetUserIdentity(user)
	// Post grade to coursera
	postGrade := func(kind string, key string, score int64) error {
		reason := ""
		if kind == "code" {
			reason = grade.Reasons
		}

		if key == "NONE" {
			return errors.New("You are not graded on this MP")
		}

		t := time.Now().Unix()
		if kind == "code" && time.Since(conf.CodingDeadline).Hours() > conf.GracePeriod {
			t = conf.CodingDeadline.UTC().Unix()
		} else if kind == "peer" && time.Since(conf.PeerReviewDeadline).Hours() > conf.GracePeriod {
			t = conf.PeerReviewDeadline.UTC().Unix()
		}
		vals := url.Values{
			"api_key":             {CourseraGradeAPIKey},
			"user_id":             {idty},
			"score":               {strconv.Itoa(int(score))},
			"assignment_part_sid": {key},
			"feedback":            {reason},
			"submission_time":     {fmt.Sprint(t)},
		}
		resp, err := http.PostForm(CourseraGradeURL,
			vals)
		revel.TRACE.Println("Posting grade for ", idty, "  ", CourseraGradeURL, " with key ", key, vals)
		if err != nil {
			return err
		}
		models.UpdateCourseraGrade(grade, kind, score)
		defer resp.Body.Close()
		return err
	}

	if toPostPeer && grade.PeerReviewScore != 0 && (forceQ == true || grade.PeerReviewScore >= grade.CourseraPeerReviewGrade) {
		if err := postGrade("peer", conf.CourseraPeerReviewPostKey, grade.PeerReviewScore); err != nil {
			revel.ERROR.Println(err)
			return errors.New("Was not able to post coursera grade. Make sure you are connected to coursera first and/or this MP is graded.")
		}
	}

	if toPostCode && grade.CodeScore != 0 && (forceQ == true || grade.CodeScore >= grade.CourseraCodingGrade) {
		if err := postGrade("code", conf.CourseraCodePostKey, grade.CodeScore); err != nil {
			return errors.New("Was not able to post coursera grade. Make sure you are connected to coursera first and/or this MP is graded.")
		}
	}
	stats.Incr("User", "CourseraPostGrade")

	return nil
}
Exemple #18
0
func runProgram(s *WorkerState) {
	var stdout, stderr bytes.Buffer

	stats.Incr("Worker", "Run")

	conf := s.MachineProblemConfig

	outputFileExtension := func() string {
		if conf.OutputType == "image" {
			return "ppm"
		} else {
			return "raw"
		}
	}

	getInputs := func() []string {
		if s.DatasetId < 0 {
			return []string{"none"}
		} else {
			datasetConfig := conf.Datasets[s.DatasetId]
			inputs := make([]string, len(datasetConfig.Input))
			for i, input := range datasetConfig.Input {
				inputs[i] = filepath.Join(s.MachineProblemDirectory, "data", input)
			}
			return inputs
		}
	}

	getOutput := func() string {
		if s.DatasetId < 0 {
			return "none"
		} else {
			datasetConfig := conf.Datasets[s.DatasetId]
			output := datasetConfig.Output
			return filepath.Join(s.MachineProblemDirectory, "data", output)
		}
	}

	s.UserOutput = filepath.Join(s.TemporaryDirectory, "output."+outputFileExtension())

	runCommand := []string{
		filepath.Join(s.TemporaryDirectory, s.ExecutableFileName),
		"-i ", strings.Join(getInputs(), ","),
		//"-o ", s.UserOutput,
		"-e ", getOutput(),
		"-t ", conf.OutputType,
	}

	s.RunStartTime = time.Now()
	_, err := runOutput(RuntimeTimeout,
		nil, /* env */
		&stdout,
		&stderr,
		filepath.Dir(s.BuildFileName),
		runCommand,
	)
	s.RunEndTime = time.Now()

	stats.LogTime("Worker", "RunTime", s.RunStartTime, s.RunEndTime)

	s.RunStdout = string(stdout.Bytes())
	s.RunStderr = string(stderr.Bytes())

	removeInternalData := func(s string) string {
		ss := strings.Split(s, seperator)
		return ss[0]
	}

	switch err.(type) {
	case TimeoutError:
		revel.TRACE.Println("Terminated....")
		s.TimeoutError = true
		s.TimeoutValue = err.(TimeoutError).Timeout
		stats.Incr("Worker", "RunTimeout")
		panic("Failed to run program")
	}

	if strings.Contains(s.RunStderr, "<<SANDBOXED>>") {
		s.Sandboxed = true
		s.SandboxKeyword = "Program sandboxed because of use of " +
			removeInternalData(strings.TrimPrefix(s.RunStdout, "<<SANDBOXED>>::")) +
			" keyword."
		stats.Log("Worker", "RunSandboxed", s.SandboxKeyword)
		panic("Failed to run program")
	} else if strings.Contains(s.RunStderr, "<<MEMORY>>") {
		s.RunFailed = true
		s.RunStdout = ""
		s.RunStderr = "Program teminated because it is allocating too much memory."
		stats.Incr("Worker", "MemoryLimit")
		panic("Failed to run program")
	} else if err != nil {
		s.RunFailed = true
		s.RunStdout = removeInternalData(s.RunStdout)
		stats.Incr("Worker", "RunFailed")
		panic("Failed to run program")
	}

	ss := strings.Split(s.RunStdout, seperator)
	s.RunStdout = ss[0]

	var wbData InternalCData

	normalizeString := func(s string) string {
		res := s
		if !utf8.ValidString(s) {
			v := make([]rune, 0, len(s))
			for i, r := range s {
				if r == utf8.RuneError {
					if _, size := utf8.DecodeRuneInString(s[i:]); size == 1 {
						continue
					}
				}
				v = append(v, r)
			}
			res = string(v)
		}
		return res
	}

	err = json.Unmarshal([]byte(normalizeString(ss[1])), &wbData)
	if err != nil {
		stats.Incr("Worker", "InternalDataReadError")
		s.RunFailed = true
		s.RunStdout = s.RunStdout
		s.RunStderr = "Failed to read program output. Make sure you do not have special characters in your code."
		stats.Log("Worker", "Error", "Failed to read internal data  "+fmt.Sprint(err))
		return
	}

	if s.DatasetId < 0 {
		wbData.SolutionExists = false
		wbData.Solution.CorrectQ = true
		wbData.Solution.Message = "No solution expected."
	}

	s.SolutionCorrect = wbData.Solution.CorrectQ
	s.SolutionMessage = wbData.Solution.Message
	s.InternalCData = wbData

	if !s.SolutionCorrect {
		stats.Log("Worker", "IncorrectSolution", 1)
	} else {
		stats.Log("Worker", "CorrectSolution", 1)
	}
}