func handleLink(w http.ResponseWriter, r *http.Request) {
	defer logPanic()

	jid, err := parseJobIdOrBadRequest(w, r.URL.Path)
	if err != nil {
		return
	}

	status, err := db.JobGetStatus(jid)
	if err != nil {
		glog.Errorf("Error getting job status for job %d: %s", jid, err)
		http.Error(w, "Invalid job ID", http.StatusBadRequest)
		return
	}
	switch r.Method {
	case "GET":
		var respath string
		switch status {
		case db.JobSuccess:
			respath = filepath.Join(getJobDir(jid), "result")
		case db.JobFail:
			respath = filepath.Join(getJobDir(jid), "error")
		default:
			http.NotFound(w, r)
			return
		}
		http.ServeFile(w, r, respath)
		return
	}
}
func handleResult(w http.ResponseWriter, r *http.Request) {
	defer logPanic()

	jid, err := parseJobIdOrBadRequest(w, r.URL.Path)
	if err != nil {
		return
	}

	status, err := db.JobGetStatus(jid)
	if err != nil {
		glog.Errorf("Error getting job status for job %d: %s", jid, err)
		http.Error(w, "Invalid job ID", http.StatusBadRequest)
		return
	}
	switch r.Method {
	case "GET":
		var respath string
		response := ResultRensponse{}
		if ret, exists := jobStatus2StringMap[status]; exists {
			response.Status = ret
		} else {
			error500(w)
			return
		}
		switch status {
		case db.JobSuccess:
			respath = filepath.Join(getJobDir(jid), "result")
			response.Link = fmt.Sprint(link, jid)
		case db.JobFail:
			respath = filepath.Join(getJobDir(jid), "error")
			response.Link = fmt.Sprint(link, jid)
		}
		if respath != "" {
			//read first few lines
			f, errf := os.Open(respath)
			if errf == nil {
				r4 := bufio.NewReader(f)
				b4, errf := r4.Peek(80)
				if errf == nil {
					response.Summary = string(b4)
				}
			}
		}
		json_response, err := json.Marshal(response)
		if err != nil {
			glog.Errorln("json response", err)
			error500(w)
			return
		}
		glog.Infoln("result json response", string(json_response))
		w.Write(json_response)
		w.Header().Set("Content-Type", "application/json")
	case "PUT":
		statusType := "result"
		if r.URL.Query().Get("status") == "error" {
			statusType = "error"
		}
		resultFile, err := openJobFile(jid, statusType)
		if err != nil {
			glog.Errorf("Error opening result file for job %d: %s", jid, err)
			error500(w)
			return
		}
		defer resultFile.Close()
		if _, err = io.Copy(resultFile, r.Body); err != nil {
			glog.Errorf("Error opening result file for job %d: %s", jid, err)
			error500(w)
			return
		}
		if statusType == "error" {
			if err = db.JobSetError(jid, "Error"); err != nil {
				glog.Errorf("Error marking failed job %d: %s", jid, err)
			}
		} else {
			if err = db.JobSetSuccess(jid); err != nil {
				glog.Errorf("Error marking successful job %d: %s", jid, err)
			}
		}
		if err == nil {
			glog.Infof("Job #%d finished with %s", jid, statusType)
		}
	}
}