text:
package sg.ncl.adapter.deterlab;

import lombok.extern.slf4j.Slf4j;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import sg.ncl.adapter.deterlab.data.jpa.DeterLabProjectRepository;
import sg.ncl.adapter.deterlab.data.jpa.DeterLabUserRepository;
import sg.ncl.adapter.deterlab.dtos.entities.DeterLabProjectEntity;
import sg.ncl.adapter.deterlab.dtos.entities.DeterLabUserEntity;
import sg.ncl.adapter.deterlab.exceptions.*;

import javax.inject.Inject;
import java.util.HashSet;
import java.util.Set;

/**
 * This is to invoke python scripts on the BOSS
 * Created by Te Ye on 15-Jun-16.
 * Contributors: Vu , Teye
 */
@Component
@Slf4j
public class AdapterDeterLab {

    private DeterLabProjectRepository deterLabProjectRepository;
    private DeterLabUserRepository deterLabUserRepository;
    private ConnectionProperties properties;
    private RestTemplate restTemplate;

    private static final String PID = "pid";
    private static final String UID = "uid";
    private static final String NUM_NODES = "numNodes";
    private static final String STATUS = "status";
    private static final String MACHINE_TYPE = "machineType";
    private static final String ERROR = "error";

    @Inject
    public AdapterDeterLab(DeterLabUserRepository repository, DeterLabProjectRepository deterLabProjectRepository, ConnectionProperties connectionProperties, RestTemplate restTemplate) {
        this.deterLabUserRepository = repository;
        this.deterLabProjectRepository = deterLabProjectRepository;
        this.properties = connectionProperties;
        this.restTemplate = restTemplate;
    }

    /**
     * Creates a join project request to Deterlab
     * Also creates a new user
     *
     * @param jsonString
     * @return The Deter userid (randomly generated)
     */
    public String joinProjectNewUsers(String jsonString) {
        log.debug("Joining project as new user: {}", jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;
        try {
            response = restTemplate.exchange(properties.getJoinProjectNewUsers(), HttpMethod.POST, request, String.class);
        } catch (ResourceAccessException rae) {
            log.warn("New user join project error: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("New user join project error: Adapter DeterLab internal server error {}", hsee);
            throw hsee;
        }
        // Will get the following JSON:
        // msg: join project request new users fail
        // msg: no user created, uid: xxx
        // msg: user is created, uid: xxx
        // msg: user not found, uid: xxx
        String responseBody = response.getBody().toString();
        try {
            String deterMessage = new JSONObject(responseBody).getString("msg");
            if("user is created".equalsIgnoreCase(deterMessage)) {
                log.info("Join project as new user to DeterLab OK");
                return responseBody;
            }
            log.warn("Join project new user error: {}", deterMessage);
            throw new DeterLabOperationFailedException(deterMessage);
        } catch (JSONException e) {
            log.warn("Error parsing response code new user join project: {}", responseBody);
            throw e;
        }
    }

    /**
     * Creates a apply project request to Deterlab
     * Also creates a new user
     *
     * @param jsonString
     * @return The Deter userid (randomly generated)
     */
    public String applyProjectNewUsers(String jsonString) {
        log.debug("Applying new project as new user: {}", jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;
        try {
            response = restTemplate.exchange(properties.getApplyProjectNewUsers(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error new user apply project: {}", e);
            throw new AdapterConnectionException();
        }
        // Will get the following JSON:
        // msg: join project request new users fail
        // msg: no user created, uid: xxx
        // msg: user is created, uid: xxx
        // msg: user not found, uid: xxx
        String responseBody = response.getBody().toString();
        try {

            String deterMessage = new JSONObject(responseBody).getString("msg");
            if("user is created".equalsIgnoreCase(deterMessage)) {
                log.info("Apply project as new user to DeterLab OK");
                return responseBody;
            }
            log.warn("Apply project new user error: {}", deterMessage);
            throw new DeterLabOperationFailedException(deterMessage);
        } catch (JSONException e) {
            log.warn("Error parsing response code new user apply project: {}", responseBody);
            throw e;
        }
    }

    /**
     * Creates a apply project request to Deterlab
     * Does not create a new user
     *
     * @param jsonString Contains uid, project name, pid, project goals, project web, project organisation, project visibility
     */
    public String applyProject(String jsonString) {
        log.info("Applying project as existing user: {}", jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getApplyProject(), HttpMethod.POST, request, String.class);

            final String responseBody = response.getBody().toString();

            log.debug("Apply project as existing user : Deter response -- {}", responseBody);

            String deterMessage = new JSONObject(responseBody).getString("msg");

            if ("apply project existing users ok".equalsIgnoreCase(deterMessage)) {
                log.info("Apply project as existing user : OK");
                return responseBody;
            }
            log.warn("Apply project as existing user : error: {}", deterMessage);
            throw new DeterLabOperationFailedException(deterMessage);

        } catch (ResourceAccessException rae) {
            log.warn("Apply project as existing user : Adapter connection error {}", rae);
            throw new AdapterConnectionException();

        } catch (HttpServerErrorException hsee) {
            log.warn("Apply project as existing user : Adapter internal server error {}", hsee);
            throw new AdapterInternalErrorException();

        } catch (JSONException e) {
            log.warn("Apply project as existing user : error parsing response body");
            throw e;
        }
    }

    /**
     * Creates a join project request to Deterlab
     * Does not create a new user
     *
     * @param jsonString Contains uid, pid
     */
    public String joinProject(String jsonString) {
        log.info("Joining project as existing user : {}", jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getJoinProject(), HttpMethod.POST, request, String.class);

            String responseBody = response.getBody().toString();

            log.debug("Join project as existing user : adapter response body -- {}", responseBody);

            String deterMessage = new JSONObject(responseBody).getString("msg");

            if ("Join project existing user ok".equalsIgnoreCase(deterMessage)) {
                log.info("Join project as existing user : OK");
                return responseBody;
            }
            log.warn("Join project as existing user : error on DeterLab -- {}", deterMessage);
            throw new DeterLabOperationFailedException(deterMessage);

        } catch (ResourceAccessException rae) {
            log.warn("Join project as existing user : adapter connection error {}", rae);
            throw new AdapterConnectionException();

        } catch (HttpServerErrorException hsee) {
            log.warn("Join project as existing user : adapter internal server error {}", hsee);
            throw new AdapterInternalErrorException();

        } catch (JSONException e) {
            log.warn("Join project as existing user : error parsing response body");
            throw e;
        }
    }

    /**
     * Creates a edit user profile request to Deterlab
     *
     * @param jsonString Contains uid, password, confirm password
     */
    public void updateCredentials(String jsonString) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getUpdateCredentials(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error update credentials: {}", e);
            throw new AdapterConnectionException();
        }

        try {
            String jsonResult = new JSONObject(response.getBody().toString()).getString("msg");
            if (!"password change success".equals(jsonResult)) {
                log.warn("Change password failed: {}", response.getBody().toString());
                throw new CredentialsUpdateException();
            }
            log.info("Change password OK");
        } catch (JSONException e) {
            log.warn("Error parsing response code update credentials: {}", response.getBody().toString());
            throw e;
        }
    }

    /**
     *
     * @param jsonString {"uid" : "uid",
     *                   "password": "password"
     *                   }
     */
    public void resetPassword(String jsonString) {
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab reset password");
            return;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        JSONObject newObject = new JSONObject(jsonString);
//      Add secret
        newObject.put("secret",properties.getAPISecret());
        HttpEntity<String> request = new HttpEntity<>(newObject.toString(), headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getResetPasswordURI(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("Cannot connect to adapter | server internal error: {}", e);
            //throw new AdapterConnectionException();
            return;
        }

        String msg = new JSONObject(response.getBody().toString()).getString("msg");
        if ("password was reset".equals(msg)) {
            log.info("Password was reset");
            return;
        }

        log.warn("Reset password failed: {}", msg);
        //throw new CredentialsUpdateException();
        return;
    }

    /**
     * Creates the cookie file on the boss machine due to the timeout issue
     *
     * @param nclUserId The ncl user id is required to retrieve the deter user id
     * @param password  Raw password
     */
    public void login(String nclUserId, String password) {
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab login");
            return;
        }

        JSONObject adapterObject = new JSONObject();
        if(!getDeterUserIdByNclUserId(nclUserId).equals("")){
            adapterObject.put(UID, getDeterUserIdByNclUserId(nclUserId));
            adapterObject.put("password", password);
        }
        else{
            return;
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(adapterObject.toString(), headers);
        ResponseEntity response;

        log.info("DeterLab Login URL:" + properties.login());
        try {
            response = restTemplate.exchange(properties.login(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("Adapter connection error login on deterlab: {}", e.getMessage());
            return;
        }

        try {
            String jsonResult = new JSONObject(response.getBody().toString()).getString("msg");
            if (!"user is logged in".equals(jsonResult)) {
                log.warn("login failed: {}", response.getBody().toString());
                return;
            }
            log.info("login success");
        } catch (JSONException e) {
            log.warn("Error parsing response code login on deterlab: {}", response.getBody().toString());
            return;
        }
    }

    @Transactional
    public void saveDeterUserIdMapping(String deterUserId, String nclUserId) {
        DeterLabUserEntity deterLabUserEntity = new DeterLabUserEntity();
        deterLabUserEntity.setNclUserId(nclUserId);
        deterLabUserEntity.setDeterUserId(deterUserId);
        deterLabUserRepository.save(deterLabUserEntity);
    }

    public String getNclUserIdByDeterUserId(String deterUserId) {
        DeterLabUserEntity deterLabUserEntity = deterLabUserRepository.findByDeterUserId(deterUserId);
        if (deterLabUserEntity == null) {
           // throw new UserNotFoundException(deterUserId);
            return "";
        }
        return deterLabUserEntity.getNclUserId();
    }

    public String getDeterUserIdByNclUserId(String nclUserId) {
        DeterLabUserEntity deterLabUserEntity = deterLabUserRepository.findByNclUserId(nclUserId);
        if (deterLabUserEntity == null) {
            return "";
        }
        return deterLabUserEntity.getDeterUserId();
    }

    // deterProjectId is ncl teamName
    @Transactional
    public DeterLabProjectEntity saveDeterProjectId(String deterProjectId, String nclTeamId) {
        DeterLabProjectEntity deterLabProjectEntity = new DeterLabProjectEntity();
        deterLabProjectEntity.setNclTeamId(nclTeamId);
        deterLabProjectEntity.setDeterProjectId(deterProjectId);
        return deterLabProjectRepository.save(deterLabProjectEntity);
    }

    public String getNclTeamIdByDeterProjectId(String deterProjectId) {
        DeterLabProjectEntity deterLabProjectEntity = deterLabProjectRepository.findByDeterProjectId(deterProjectId);
        if (deterLabProjectEntity == null) {
            //throw new TeamNotFoundException(deterProjectId);
            return  "";
        }
        return deterLabProjectEntity.getNclTeamId();
    }

    public String getDeterProjectIdByNclTeamId(String nclTeamId) {
        DeterLabProjectEntity deterLabProjectEntity = deterLabProjectRepository.findByNclTeamId(nclTeamId);
        if (deterLabProjectEntity == null) {
            //throw new TeamNotFoundException(nclTeamId);
            return "";
        }
        return deterLabProjectEntity.getDeterProjectId();
    }

    /**
     * Creates a create experiment request to Deterlab
     *
     * @param jsonString Contains id, userId, teamId, teamName, name (experiment name), description, nsFile, nsFileContent, idleSwap, maxDuration, deterLogin (deter userId), userServerUri
     */
    public void createExperiment(String jsonString) {
         log.info("Creating experiment to {} at {}: {}", properties.getIp(), properties.getPort(), jsonString);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        log.info("create deterLab exp URL :" + properties.getCreateExperiment());
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getCreateExperiment(), HttpMethod.POST, request, String.class);
         } catch (Exception e) {
            throw new AdapterConnectionException();
        }

        String jsonResult = new JSONObject(response.getBody().toString()).getString("msg");

        if ("experiment create fail ns file error".equals(jsonResult)) {
            throw new NSFileParseException(jsonResult);
        } else if ("experiment create fail exp name already in use".equals(jsonResult)) {
            throw new ExperimentNameAlreadyExistsException(jsonResult);
        } else if (!"experiment create success".equals(jsonResult)) {
            throw new AdapterConnectionException();
        }
    }

    /**
     * Creates a start experiment request to Deterlab
     *
     * @param teamName equivalent of pid
     * @param experimentName equivalent of eid
     * @param nclUserId the ncl user id who starts the experiment
     * @return a experiment report if the experiment is started successfully and active, otherwise a "experiment start fail" is return
     * @implNote must return the entire response body as realization service needs to store the experiment report to transmit back to UI
     */
    public String startExperiment(String teamName, String experimentName, String nclUserId) {

        String jsonString = craftJSONStringStartStopExperiment("in", teamName, experimentName, nclUserId);

        log.info("Start experiment - {} at {}: {}", properties.getIp(), properties.getPort(), jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.startExperiment(), HttpMethod.POST, request, String.class);
        } catch (Exception e) {
            log.warn("Adapter error start experiment: {}", e);
            throw new AdapterConnectionException(e.getMessage());
        }

        log.info("Start experiment request submitted to deterlab");
        log.info("Start experiment response from deterlab: {}", response.getBody());
        String jsonResult = new JSONObject(response.getBody().toString()).getString("msg");

        if ("experiment start fail".equals(jsonResult)) {
            log.warn("Fail to start experiment at deterlab {}", jsonString);
            throw new ExperimentStartException();
        } else if (!"experiment start success".equals(jsonResult)) {
            log.warn("Start experiment connection error {}", jsonString);
            throw new AdapterConnectionException();
        }

        log.info("Start experiment request success at deterlab {}", response.getBody().toString());
        return response.getBody().toString();
    }

    /**
     * Creates a stop experiment request to Deterlab
     *
     * @param teamName equivalent of pid
     * @param experimentName equivalent of eid
     * @param nclUserId the ncl user id that stops the experiment
     * @return the experiment status
     * @implNote we don't throw any exception if the result returned from deterlab is not "swapped" since there may be other types of experiment status unknown to us
     */
    public String stopExperiment(String teamName, String experimentName, String nclUserId) {

        String jsonString = craftJSONStringStartStopExperiment("out", teamName, experimentName, nclUserId);

        log.info("Stop experiment - {} at {}: {}", properties.getIp(), properties.getPort(), jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.stopExperiment(), HttpMethod.POST, request, String.class);
        } catch (Exception e) {
            log.warn("Adapter error start experiment: {}", e);
            throw new AdapterConnectionException(e.getMessage());
        }

        log.info("Stop experiment request submitted to deterlab");
        String expStatus = new JSONObject(response.getBody().toString()).getString(STATUS);

        if (!"swapped".equals(expStatus)) {
            log.warn("Fail to stop experiment at deterlab {}", jsonString);
        }
        log.info("Stop experiment request success at deterlab {}", response.getBody().toString());
        return expStatus;
    }

    /**
     * Creates a delete experiment request to Deterlab
     *
     * @param teamName equivalent of pid
     * @param experimentName equivalent of eid
     * @param nclUserId the ncl user id who deletes the experiment
     * @return the experiment status
     */
    public String deleteExperiment(String teamName, String experimentName, String nclUserId) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("teamName", teamName);
        jsonObject.put("experimentName", experimentName);
        jsonObject.put("deterLogin", getDeterUserIdByNclUserId(nclUserId));

        String jsonString = jsonObject.toString();

        log.info("Delete experiment - {} at {} : {}", properties.getIp(), properties.getPort(), jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.deleteExperiment(), HttpMethod.POST, request, String.class);
        } catch (Exception e) {
            log.warn("Adapter error delete experiment: {}", e);
            throw new AdapterConnectionException(e.getMessage());
        }

        log.info("Delete experiment request submitted to deterlab");
        String expStatus = new JSONObject(response.getBody().toString()).getString(STATUS);

        if (!"no experiment found".equals(expStatus)) {
            log.warn("Fail to delete experiment at deterlab {}", jsonString);
            throw new ExperimentDeleteException();
        }

        log.info("Delete experiment request success at deterlab {}", response.getBody().toString());
        return expStatus;
    }

    public String modifyNSFile(String jsonString) {
        log.info("Modify experiment ns file - {} at {} : {}", properties.getIp(), properties.getPort(), jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.modifyNSFile(), HttpMethod.POST, request, String.class);
        } catch (Exception e) {
            log.warn("Adapter error modify experiment ns file: {}", e);
            throw new AdapterConnectionException(e.getMessage());
        }

        log.info("Modify experiment ns file request submitted to deterlab");
        String status = new JSONObject(response.getBody().toString()).getString("msg");
        String modifyOutput = new JSONObject(response.getBody().toString()).getString("modify_experiment");

        if ("modify experiment fail ns file parse error".equals(status)) {
            throw new NSFileParseException(modifyOutput);
        } else if (!"modify experiment success".equals(status)) {
            throw new ExperimentModifyException(modifyOutput);
        }

        log.info("Modify experiment ns file request success at deterlab");
        log.debug("Deter response: {}", response.getBody().toString());
        return status;
    }

    // modify the experiment settings, such as max duration, etc
    public String modifyExperimentSettings(String jsonString) {
        log.info("Modify experiment settings - {} at {} : {}", properties.getIp(), properties.getPort(), jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.modifyExperimentSettings(), HttpMethod.POST, request, String.class);
        } catch (Exception e) {
            log.warn("Adapter error modify experiment settings: {}", e);
            throw new AdapterConnectionException(e.getMessage());
        }

        log.info("Modify experiment settings request submitted to deterlab");
        String status = new JSONObject(response.getBody().toString()).getString("msg");

        if ("modify experiment settings: max_duration fail".equals(status)) {
            throw new ExperimentModifyException("Please select an appropriate shutdown time.");
        }

        log.info("Modify experiment settings request success at deterlab");
        log.debug("Deter response: {}", response.getBody().toString());
        return status;
    }

    /**
     * Retrieves the experiment status from Deterlab
     *
     * @param teamName equivalent of pid
     * @param experimentName equivalent of eid
     * @return the status of the experiment, a "error" if the request fails
     * @implNote cannot throw exception for this method
     */
    public String getExperimentStatus(String teamName, String experimentName) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(PID, teamName);
        jsonObject.put("eid", experimentName);
        String jsonString = jsonObject.toString();

        log.info("Get experiment status - {} at {} : {}", properties.getIp(), properties.getPort(), jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getExpStatus(), HttpMethod.POST, request, String.class);
        } catch (Exception e) {
            log.warn("Adapter connection error get experiment status: {}", e);
            return "{\"status\": \"error\"}";
        }

        log.info("Get experiment status request submitted to deterlab");

        return response.getBody().toString();
    }

    public String processJoinRequest(String jsonString) {
        JSONObject request = new JSONObject(jsonString);
        if (request.length() < 5) {
            log.warn("NOT enough inputs: {}", jsonString);
            throw new IllegalArgumentException();
        }
        String pid = request.getString(PID);
        String approverUid = request.getString("approverUid");
        String uid = request.getString(UID);
        String gid = request.getString("gid");
        String action = request.getString("action");
        log.info("Processing join request: team {}, requester {}, approver {}, group {}, action {}",
                pid, uid, approverUid, gid, action);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> httpRequest = new HttpEntity<>(jsonString, headers);
        String reqUrl = "approve".equals(action) ? properties.getApproveJoinRequest() : properties.getRejectJoinRequest();

        ResponseEntity httpResponse;
        try {
            httpResponse = restTemplate.exchange(reqUrl, HttpMethod.POST, httpRequest, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error process join request: {}", e);
            throw new AdapterConnectionException();
        }
        String responseBody = httpResponse.getBody().toString();
        try {
            // cases where we want to process join request:
            // case1: normal join request entry exists on deterlab
            // case2: approve a join request not updated on our DB but already approved on deterlab DB
            // case3: reject a join request not updated on our DB but does not exists on deterlab DB
            String adapterResponse = new JSONObject(responseBody).getString("msg");
            log.info("process join request adapter response: {}", adapterResponse);
            if ("process join request OK".equals(adapterResponse) || isJoinRequestValid(action, adapterResponse)) {
                log.info("{} join request to team {} OK", action, pid);
                return responseBody;
            } else {
                log.warn("{} join request to team {} FAIL", action, pid);
                throw new DeterLabOperationFailedException(responseBody);
            }
        } catch (JSONException e) {
            log.warn("Error parsing response code process join request: {}", responseBody);
            throw e;
        }
    }

    private boolean isJoinRequestValid(String action, String adapterResponse) {
        return ("approve".equals(action) && "user is already an approved member in the project".equals(adapterResponse)) ||
                ("deny".equals(action) && "no join request found".equals(adapterResponse));
    }

    public String approveProject(String jsonString) {
        // for ncl admins to approve teams
        String pid = new JSONObject(jsonString).getString(PID);
        log.info("Approving team {}: {}", pid, jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getApproveProject(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error approve project: {}", e);
            throw new AdapterConnectionException();
        }
        try {
            String jsonResult = new JSONObject(response.getBody().toString()).getString("msg");
            if ("approve project OK".equals(jsonResult)) {
                log.info("Approve team {} OK", pid);
                return response.getBody().toString();
            } else {
                log.warn("Approve team {} FAIL", pid);
                throw new DeterLabOperationFailedException(jsonResult);
            }
        } catch (JSONException e) {
            log.warn("Error parsing response code approve project: {}", response.getBody().toString());
            throw e;
        }
    }

    public String rejectProject(String jsonString) {
        // for ncl admins to reject teams
        String pid = new JSONObject(jsonString).getString(PID);
        log.info("Rejecting team {}: {}", pid, jsonString);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getRejectProject(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error reject project: {}", e);
            throw new AdapterConnectionException();
        }
        try {
            String jsonResult = new JSONObject(response.getBody().toString()).getString("msg");
            if ("reject project OK".equals(jsonResult)) {
                log.info("Reject team {} OK", pid);
                return response.getBody().toString();
            } else {
                log.warn("Reject team {} FAIL", pid);
                throw new DeterLabOperationFailedException(jsonResult);
            }
        } catch (JSONException e) {
            log.warn("Error parsing response code reject project: {}", response.getBody().toString());
            throw e;
        }
    }

    /**
     * information for displaying experiment profile
     * @param jsonString the team name and experiment name
     * @return  a json string in the format:
     *   {
     *       'ns_file' :
     *       {
     *           'msg' : 'success/fail',
     *           'ns_file' : 'ns_file_contents'
     *       },
     *       'realization_details' :
     *       {
     *           'msg' : 'success/fail',
     *           'realization_details' : 'realization_details_contents'
     *       },
     *       'activity_log'	:
     *       {
     *           'msg' : 'success/fail',
     *           'activity_log' : 'activity_log_contents'
     *       }
     *   }
     *   otherwise, returns a '{}'
     */
    public String getExperimentDetails(String jsonString) {
        log.info("Getting experiment details for experiment profile...");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;
        log.info("Detail URL " +  properties.getExpDetails());

        try {
            response = restTemplate.exchange(properties.getExpDetails(), HttpMethod.POST, request, String.class);
            String responseBody = response.getBody().toString();
            if (responseBody.contains("ns_file")) {
                log.info("Get experiment details for experiment profile OK");
                return responseBody;
            } else {
                log.warn("Get experiment details for experiment profile FAIL");
            }
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get experiment details for experiment profile: {}", e);
        }
        return "{}";
    }

    /**
     * get list of experiments from a project
     * @param teamId the NCL team ID to get experiments list
     * @return  a json string in the format:
     *  {
     *      "eid1": {"state": "active", "min_nodes": "2", "nodes": "2", "idle_hours": "0", "details": "..."},
     *      "eid2": {"state": "swapped", "min_nodes": "1", "nodes": "0", "idle_hours": "0", "details": ""},
     *      "eid3": {"state": "active", "min_nodes": "2", "nodes": "2", "idle_hours": "0", "details": "..."}
     *   }
     *   otherwise, returns {}
     */
    public String getExperimentsByTeam(String teamId) {
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab Team check");
            return "{}";
        }

        final String pid = getDeterProjectIdByNclTeamId(teamId);
        log.info("Getting list of experiments for project: {}",teamId + ":" + pid);

        JSONObject json = new JSONObject();
        json.put(PID, pid);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;
        log.info("DeterLap Experiment URL " + properties.getExperimentsByTeam());
        try {
            response = restTemplate.exchange(properties.getExperimentsByTeam(), HttpMethod.POST, request, String.class);

        } catch (RestClientException e) {
            log.warn("Adapter connection error: {}", e.getMessage());
            return "{}";
        }
        //log.info("List of experiments for project {}:\n{}", pid, response.getBody().toString());
        return response.getBody().toString();
    }

    /**
     * get status of an experiment from a project
     * @param teamId the NCL team ID to get experiments list
     * @param expName the experiment name eid
     * @return  a json string in the format:
     *  {
     *      "eid1": {"state": "active", "min_nodes": "2", "nodes": "2", "idle_hours": "0", "details": "..."}
     *   }
     *   otherwise, returns {}
     */
    public String getExperiment(String teamId, String expName) {
        final String pid = getDeterProjectIdByNclTeamId(teamId);
        log.info("Getting experiment status for {}/{}" +  pid +":"+ expName);

        JSONObject json = new JSONObject();
        json.put(PID, pid);
        json.put("eid", expName);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        log.info("DeterLab experiment Status URL" +  properties.getExperiment());
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getExperiment(), HttpMethod.POST, request, String.class);
         } catch (RestClientException e) {
            log.warn("Adapter connection error: {}", e);
            return "{}";
        }

        log.debug("Status for {}/{}:\n{}", pid, expName, response.getBody().toString());
        return response.getBody().toString();
    }

    public String getFreeNodes() {
        log.info("Getting free nodes...");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getFreeNodes(), HttpMethod.GET, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get free nodes: {}", e);
            return "0";
        }
        return response.getBody().toString();
    }

    public String getNodesStatus() {
        log.info("Getting nodes status...");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getNodesStatus(), HttpMethod.GET, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get nodes status: {}", e);
            return "{}";
        }
        return response.getBody().toString();
    }

    /**
     * @return number of logged in users at the current time
     */
    public String getLoggedInUsersCount() {
        log.info("Getting number of logged in users...");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getLoggedInUsersCount(), HttpMethod.GET, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get number of logged in users: {}", e);
            return "0";
        }
        return response.getBody().toString();
    }

    /**
     * @return number of running experiments
     */
    public String getRunningExperimentsCount() {
        log.info("Getting number of running experiments...");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getRunningExperimentsCount(), HttpMethod.GET, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get number of running experiments: {}", e);
            return "0";
        }
        return response.getBody().toString();
    }

    public String getTotalNodes() {
        log.info("Getting total nodes...");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getTotalNodes(), HttpMethod.GET, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get total nodes: {}", e);
            return "0";
        }
        return response.getBody().toString();
    }

    public String getTopologyThumbnail(String jsonString) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getTopoThumbnail(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get thumbnail: {}", e);
            throw new AdapterConnectionException();
        }
        return response.getBody().toString();
    }

    // no longer in use; it has been replaced by getTeamExptStats()
    public String getUsageStatistics(String teamId, String startDate, String endDate) {
        // start : mm/dd/yy
        // end : mm/dd/yy
        JSONObject tmp = new JSONObject();
        tmp.put(PID, deterLabProjectRepository.findByNclTeamId(teamId).getDeterProjectId());
        tmp.put("start", startDate);
        tmp.put("end", endDate);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(tmp.toString(), headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getUsageStatistics(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get usage statistics: {}", e);
            return "?";
        }
        return response.getBody().toString();
    }

    public String getGlobalImages() {
        log.info("Getting list of global images from the system");

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getGlobalImages(), HttpMethod.GET, request, String.class);
        } catch (RestClientException e) {
            log.warn("DeterLab connection error get global images: {}", e);
            return "{}";
        }
        log.info("Get list of global images OK");
        return response.getBody().toString();
    }

    public String getSavedImages(String teamId) {
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab get saved image");
            return "{}";
        }
        final String pid = getDeterProjectIdByNclTeamId(teamId);
        log.info("Getting list of saved images for project: {}", pid);

        if (pid.equals("")) { //check deterlab is enabled or not
            log.info("Bypass DeterLab get saved image");
            return "{}";
        }
        JSONObject json = new JSONObject();
        json.put(PID, pid);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getSavedImages(), HttpMethod.POST, request, String.class);
        } catch (RestClientException e) {
            log.warn("Adapter connection error get list of saved images by team: {}", e);
            return "{}";
        }

        log.info("Get list of saved images OK, Deter response: {}", response.getBody().toString());

        return response.getBody().toString();
    }

    public String saveImage(String nclTeamId, String nclUserId, String nodeId, String imageName) {
        final String pid = getDeterProjectIdByNclTeamId(nclTeamId);
        final String uid = getDeterUserIdByNclUserId(nclUserId);
        log.info("Saving image: pid {}, uid {}, node ID {}, image name {}", pid, uid, nodeId, imageName);

        JSONObject json = new JSONObject();
        json.put(PID, pid);
        json.put(UID, uid);
        json.put("nodeId", nodeId);
        json.put("imageName", imageName);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.saveImage(), HttpMethod.POST, request, String.class);
            String responseBody = response.getBody().toString();
            String deterMessage = new JSONObject(responseBody).getString("msg");

            if ("save image OK".equals(deterMessage)) {
                log.info("Save image OK");
                return responseBody;
            } else {
                log.warn("Save image FAIL: {}", deterMessage);
                throw new DeterLabOperationFailedException(deterMessage);
            }

        } catch (ResourceAccessException rae) {
            log.warn("Save image error: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("Save image error: Adapter DeterLab internal server error {}", hsee);
            throw new AdapterInternalErrorException();
        }
    }

    public String deleteImage(String teamId, String userId, String imageName, boolean imageCreator) {
        // uid, pid in deter is the same as sio project and user name
        final String uid = getDeterUserIdByNclUserId(userId);
        final String pid = getDeterProjectIdByNclTeamId(teamId);

        log.info("Deleting image '{}' from uid '{}' of pid '{}'", imageName, uid, pid);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(PID, pid);
        jsonObject.put(UID, uid);
        jsonObject.put("imageName", imageName);

        if (imageCreator) {
            jsonObject.put("isImageCreator", "yes");
        } else {
            jsonObject.put("isImageCreator", "no");
        }

        HttpHeaders httpHeaders= new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), httpHeaders);

        try {
            ResponseEntity responseEntity = restTemplate.exchange(properties.deleteImage(), HttpMethod.DELETE, request, String.class);
            String responseBody = responseEntity.getBody().toString();
            String deterMessage = new JSONObject(responseBody).getString("msg");

            Set<String> curlSuccess = new HashSet<>();
            curlSuccess.add("delete image OK from both web and project directory");
            curlSuccess.add("delete image OK from web but there is unknown error when deleting physical image");
            curlSuccess.add("image still in use");

            String exceptionMessage = "Deleting image '" + imageName + "' of team '" +  pid + "' : " + deterMessage;
            String errorMessage = "Error in deleting image '{}' from uid '{}' of pid '{}' : {} ";

            if (curlSuccess.contains(deterMessage)) {
                log.info("Deleting image '{}' from uid '{}' of pid '{}' : {} ", imageName, uid, pid, deterMessage);
                return responseBody;

            } else if ("not the creator".equals(deterMessage) ||
                    "no permission to delete the imageid when executing Curl command".equals(deterMessage)) {
                log.warn(errorMessage , uid, pid, imageName, deterMessage);
                throw new InsufficientPermissionException(exceptionMessage);

            } else if ("required image id is not found when querying database".equals(deterMessage) ||
                    "no creator found when querying database".equals(deterMessage) ||
                    "imageid could not be found when executing Curl command".equals(deterMessage)) {
                log.warn(errorMessage , uid, pid, imageName, deterMessage);
                throw new ImageNotFoundException(exceptionMessage);

            } else {
                log.warn("Error in deleting image '{}' from uid '{}' of pid '{}' : {} ", imageName, uid, pid, deterMessage);
                throw new DeterLabOperationFailedException(exceptionMessage);
            }

        }catch (ResourceAccessException resourceAccessException) {
            log.warn("Deleting image {} from uid {} of pid {} error: {}", imageName, uid, pid, resourceAccessException);
            throw new AdapterConnectionException(resourceAccessException.getMessage());

        } catch (HttpServerErrorException httpServerErrorException) {
            log.warn("Deleting image {} from uid {} of pid {} error: Adapter DeterLab internal server error {}", imageName, uid, pid, httpServerErrorException);
            throw new AdapterInternalErrorException();
        }
    }

    public String removeUserFromTeam(String nclTeamId, String nclUserId, String nclTeamOwnerId) {
        final String pid = getDeterProjectIdByNclTeamId(nclTeamId);
        final String uid = getDeterUserIdByNclUserId(nclUserId);
        final String ownerUid = getDeterUserIdByNclUserId(nclTeamOwnerId);

        log.info("Removing user {} from team {} requested by owner {}", uid, pid, ownerUid);

        JSONObject json = new JSONObject();
        json.put(PID, pid);
        json.put("uidToBeRemoved", uid);
        json.put("ownerUid", ownerUid);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.removeUserFromTeam(), HttpMethod.POST, request, String.class);
            String responseBody = response.getBody().toString();
            String deterMessage = new JSONObject(responseBody).getString("msg");

            if ("remove user from team ok".equals(deterMessage)) {
                log.info("Remove user from team OK");
                return responseBody;
            } else {
                log.warn("Remove user from team FAIL");
                throw new DeterLabOperationFailedException(deterMessage);
            }

        } catch (ResourceAccessException rae) {
            log.warn("Remove user from team: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("Remove user from team: Adapter DeterLab internal server error {}", hsee);
            throw new AdapterInternalErrorException();
        }
    }

    /**
     * Crafts the JSON string for start/stop experiment
     * @param operation in or out, implies start or stop experiment respectively
     * @param teamName the equivalent of pid
     * @param experimentName the equivalent of eid
     * @param nclUserId the ncl user id that initiate the start/stop experiment
     * @return a JSON string representation of the items to be sent to adapter
     */
    private String craftJSONStringStartStopExperiment(String operation, String teamName, String experimentName, String nclUserId) {
        StringBuilder httpCommand = new StringBuilder();
        httpCommand.append("?inout=" + operation);
        httpCommand.append("&");
        httpCommand.append("pid=" + teamName);
        httpCommand.append("&");
        httpCommand.append("eid=" + experimentName);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("httpCommand", httpCommand.toString());
        jsonObject.put("deterLogin", getDeterUserIdByNclUserId(nclUserId));
        jsonObject.put(PID, teamName);
        jsonObject.put("eid", experimentName);

        return jsonObject.toString();
    }

    public String getPublicKeys(String nclUserId) {
        final String uid = getDeterUserIdByNclUserId(nclUserId);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put(UID, uid);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), httpHeaders);

        try {
            ResponseEntity responseEntity = restTemplate.exchange(properties.getPublicKeys(), HttpMethod.POST, request, String.class);
            return responseEntity.getBody().toString();
        } catch (ResourceAccessException rae) {
            log.warn("Get ssh public keys: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("Get ssh public keys: Adapter DeterLab internal server error {}", hsee);
            throw new AdapterInternalErrorException();
        }
    }

    public String addPublicKey(String nclUserId, String pubkey, String passwd) {
        //1. get uid from deterlab_user
        //2.prepare json format
        //3. deterlab api
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab add Public Key");
            return "{}";
        }

        final String uid = getDeterUserIdByNclUserId(nclUserId);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put(UID, uid);
        jsonObject.put("pubkey", pubkey);
        jsonObject.put("passwd", passwd);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), httpHeaders);

        log.info("DeterLab Public Key URL : {} ",properties.addPublicKey());
        log.info("DeterLab Public Key request : {} ",jsonObject.toString());

        try {
            ResponseEntity responseEntity = restTemplate.exchange(properties.addPublicKey(), HttpMethod.POST, request, String.class);
            log.info("DeterLab Public Key response : {} ",responseEntity.getBody().toString());
            return responseEntity.getBody().toString();
        } catch (ResourceAccessException rae) {
            //log.warn("Add ssh public key: {}", rae);
            //throw new AdapterConnectionException(rae.getMessage());
            return "DeterLab Adapter Connection Fail.";
        } catch (HttpServerErrorException hsee) {
            //log.warn("Add ssh public key: Adapter DeterLab internal server error {}", hsee);
            //throw new AdapterInternalErrorException();
            return "Add ssh public key: Adapter DeterLab internal server error {}";
        }
    }

    public String deletePublicKey(String nclUserId, String publicKeyId) {
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab login");
            return "Bypass DeterLab delete Public Key!";
        }

        final String uid = getDeterUserIdByNclUserId(nclUserId);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put(UID, uid);
        jsonObject.put("kid", publicKeyId);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), httpHeaders);

        try {
            ResponseEntity responseEntity = restTemplate.exchange(properties.deletePublicKey(), HttpMethod.DELETE, request, String.class);
            return responseEntity.getBody().toString();
        } catch (ResourceAccessException rae) {
            log.info("Failed to delete ssh public key in DeterLab");
            return "Failed to delete ssh public key in DeterLab";
        } catch (HttpServerErrorException hsee) {
            log.info("Delete ssh public key: Adapter DeterLab internal server error ");
            return "Delete ssh public key: Adapter DeterLab internal server error ";
        }
    }

    /**
     * Retrieve the list of nodes reserved for a team
     * @param teamId e.g. F12345-G12345-H12345
     * @return  a json string in the format:
     *   {
     *       "status" : "ok/fail",
     *       "reserved": ["pc1", "pc4", "pc2"],
     *       "in_use": [["pc4", "ncltest01", "vnctest"], ["pc2", "testbed-ncl", "thales-poc"]]
     *   }
     */
    public String getReservationStatus(String teamId) {
        final String pid = getDeterProjectIdByNclTeamId(teamId);

        JSONObject json = new JSONObject();
        json.put(PID, pid);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.getReservationStatus(), HttpMethod.POST, request, String.class);
            String responseBody = response.getBody().toString();
            String status = new JSONObject(responseBody).getString(STATUS);

            if ("OK".equals(status)) {
                log.info("Get reservation for team {} OK", teamId);
                return responseBody;
            } else {
                log.warn("Get reservation for team {} FAIL: {}", teamId, status);
                throw new DeterLabOperationFailedException(status);
            }

        } catch (ResourceAccessException rae) {
            log.warn("Get reservation: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("Get reservation error: Adapter DeterLab internal server error {}", hsee);
            throw new AdapterInternalErrorException();
        }
    }

    /**
     * Release all the nodes or a specific number of nodes
     * @param teamId e.g. F12345-G12345-H12345
     * @param numNodes no. of nodes to release; -1 means release all the nodes
     * @return  a json string in the format:
     *   {
     *       'status' : 'ok/fail'
     *       'released' : [node_id_list]
     *   }
     */
    public String releaseNodes(String teamId, Integer numNodes) {
        final String pid = getDeterProjectIdByNclTeamId(teamId);

        JSONObject json = new JSONObject();
        json.put(PID, pid);
        json.put(NUM_NODES, numNodes);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.releaseNodes(), HttpMethod.POST, request, String.class);
            // return regardless of success / fail
            return response.getBody().toString();

        } catch (ResourceAccessException rae) {
            log.warn("release reservation: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("release reservation error: Adapter DeterLab internal server error {}", hsee);
            throw new AdapterInternalErrorException();
        }
    }

    /**
     * Reserve a specific number of nodes or a particular node type
     * @param teamId e.g. F12345-G12345-H12345
     * @param numNodes no. of nodes to reserve; required
     * @param machineType optional; will attempt to reserve X number of nodes with this machine type if specified
     * @return  a json string in the format:
     *   {
     *       'status' : 'ok/fail'
     *       'message' : 'error message'
     *       'reserved' : [node_id_list]
     *   }
     */
    public String reserveNodes(String teamId, Integer numNodes, String machineType) {
        final String pid = getDeterProjectIdByNclTeamId(teamId);

        JSONObject json = new JSONObject();
        json.put(PID, pid);
        json.put(NUM_NODES, numNodes);
        json.put(MACHINE_TYPE, (machineType != null) ? machineType : "");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(json.toString(), headers);

        ResponseEntity response;

        try {
            response = restTemplate.exchange(properties.reserveNodes(), HttpMethod.POST, request, String.class);
            // return regardless of success / fail
            return response.getBody().toString();

        } catch (ResourceAccessException rae) {
            log.warn("node reservation: {}", rae);
            throw new AdapterConnectionException(rae.getMessage());
        } catch (HttpServerErrorException hsee) {
            log.warn("node reservation error: Adapter DeterLab internal server error {}", hsee);
            throw new AdapterInternalErrorException();
        }
    }

    // return all experiment swap-in and swap-out records for a project
    public String getTeamExptStats(String teamId) {
        if (!properties.isEnabled()) { //check deterlab is enabled or not
            log.info("Bypass DeterLab TeamExpStats");
            return "{}";
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("pid", getDeterProjectIdByNclTeamId(teamId));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), headers);

        ResponseEntity response;
        log.info("DeterLab TeamExpStats URL : {} , method : {} , request : {}", properties.getTeamExptStats(),HttpMethod.POST,request);

        try {
            response = restTemplate.exchange(properties.getTeamExptStats(), HttpMethod.POST, request, String.class);
            log.info("DeterLab TeamExpStats response : {}", response);
        } catch (Exception e) {
            log.warn("DeterLab connection error get usage statistics: {}", e.getMessage());
            return "{}";
        }

        return response.getBody().toString();

    }

    /**
     *Sending request to deterlab to add student members by email
     *
     * @param nclTeamId
     * @param nclUserId
     * @param emails
     * @return dictionary with keys are emails and values are newly created deterlab UID
     */

    public String addStudentsByEmail(String nclTeamId, String nclUserId, String emails) {

        final String deterPid = getDeterProjectIdByNclTeamId(nclTeamId) ;
        final String deterUid = getDeterUserIdByNclUserId(nclUserId);

        log.info("Adding students to team {}", deterPid);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put(PID, deterPid);
        jsonObject.put(UID, deterUid);
        jsonObject.put("emails", emails);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), headers);
        String logMessage = "Error in adding students to team {}: {}";
        try {
            ResponseEntity responseEntity = restTemplate.exchange(properties.addStudentsByEmail(), HttpMethod.POST, request, String.class);
            String responseBody = responseEntity.getBody().toString();
            JSONObject responseJsonObject = new JSONObject(responseBody);

            if (responseJsonObject.has(ERROR)) {
                String deterError = responseJsonObject.getString(ERROR);
                log.warn(logMessage, deterPid, deterError);
                throw new DeterLabOperationFailedException(deterError);
            }

            log.info("Adding students to team {} succeeded", deterPid);
            return responseBody;

        } catch (ResourceAccessException resourceAccessException) {
            log.warn(logMessage, deterPid, resourceAccessException);
            throw new AdapterConnectionException(resourceAccessException.getMessage());
        } catch (HttpServerErrorException httpServerErrorException) {
            log.warn(logMessage, deterPid , httpServerErrorException);
            throw new AdapterInternalErrorException();
        }

    }

    /**
     * Send request to DeterLab reset password, phone, first and last name when student click on the "Reset password" link in email
     *
     * @param nclUid
     * @param firstName
     * @param phone
     * @param password
     * @return void
     */

    public void changePasswordStudent(String nclUid, String firstName, String lastName, String phone, String password) {

        log.info("Resetting password for student {}", nclUid);

        final String deterUid = getDeterUserIdByNclUserId(nclUid);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("uid", deterUid);
        jsonObject.put("password", password);
        jsonObject.put("firstName", firstName);
        jsonObject.put("lastName", lastName);
        jsonObject.put("phone", phone);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), headers);
        ResponseEntity responseEntity;
        String responseBody;
        String errorMessage = "Error in resetting password for student {}: {}";

        try {
            responseEntity = restTemplate.exchange(properties.changePasswordStudent(), HttpMethod.POST, request, String.class);
            responseBody = responseEntity.getBody().toString();

            JSONObject responseJsonObject = new JSONObject(responseBody);

            if (responseJsonObject.has(ERROR)) {
                String deterError = responseJsonObject.getString(ERROR);
                log.warn(errorMessage, nclUid, deterError);
                throw new DeterLabOperationFailedException(deterError);
            }

            log.info("Password for student {} was reset", nclUid);

        }  catch (ResourceAccessException resourceAccessException) {
            log.warn(errorMessage, nclUid, resourceAccessException);
            throw new AdapterConnectionException(resourceAccessException.getMessage());
        } catch (HttpServerErrorException httpServerErrorException) {
            log.warn(errorMessage, nclUid, httpServerErrorException);
            throw new AdapterInternalErrorException();
        }
    }

}


text:
namespace Ralph.Test.Project.Properties
{
    public class Menus
    {

    }
}

redpajama_set_name: RedPajamaGithub


text:
var linter = require('../src/linter'),
    colors = require('colors');

describe('linter', function() {
  it('returns false if the code does not pass jslint', function() {
    var code = "hi = 10;";

    expect(linter(code)).toBe(false);
  });

  it('displays the line with error in red', function() {
    spyOn(console, 'log').andCallThrough();
    var code = "hi = 10;";

    var isValid = linter(code);

    expect(isValid).toBe(false);
    expect(console.log).toHaveBeenCalledWith(code.yellow + '\t' + ("// ERROR: 'hi' is not defined.").red);
  });

  it('displays only the invalid line in red for multiple code lines', function() {
    spyOn(console, 'log').andCallThrough();
    var lines = [
        'var a = 10;',
        'b = 20;',
        'a += 1;'
      ],
      code = lines.join('\n');

    var isValid = linter(code);

    expect(isValid).toBe(false);
    expect(console.log).toHaveBeenCalledWith(lines[0]);
    expect(console.log).toHaveBeenCalledWith(lines[1].yellow + '\t' + ("// ERROR: 'b' is not defined.").red);
    expect(console.log).toHaveBeenCalledWith(lines[2]);
  });

  it('displays only the invalid lines in red if there are multiple errors', function() {
    spyOn(console, 'log').andCallThrough();
    var lines = [
        'var a = 10;',
        'b = 20;',
        'a *= 2;',
        'a += 1',
        'a = 0;'
      ],
      code = lines.join('\n');

    var isValid = linter(code);

    expect(isValid).toBe(false);
    expect(console.log).toHaveBeenCalledWith(lines[0]);
    expect(console.log).toHaveBeenCalledWith(lines[1].yellow + '\t' + ("// ERROR: 'b' is not defined.").red);
    expect(console.log).toHaveBeenCalledWith(lines[2]);
    expect(console.log).toHaveBeenCalledWith(lines[3].yellow + '\t' + ("// ERROR: Missing semicolon.").red);
    expect(console.log).toHaveBeenCalledWith(lines[4]);
  });
});


text:
<resources>
    <string name="app_name">MultiTypeListViewAdapter</string>
</resources>


text:
import {
  GraphQLNonNull,
  GraphQLID
} from 'graphql';

import blogPostType from '../../types/blog-post';
import getProjection from '../../get-projection';
import BlogPostModel from '../../../models/blog-post';

export default {
  type: blogPostType,
  args: {
    _id: {
      name: '_id',
      type: new GraphQLNonNull(GraphQLID)
    }
  },
  async resolve (root, params, options) {
    const projection = getProjection(options.fieldASTs[0]);
    const removedBlogPost = await BlogPostModel
      .findByIdAndRemove(params._id, {
        select: projection
      })
      .exec();

    if (!removedBlogPost) {
      throw new Error('Error removing blog post');
    }

    return removedBlogPost;
  }
};


text:
using Radical.Reflection;
using System;

namespace Radical.Validation
{
    /// <summary>
    /// Extends the generic Ensure class to add behaviors when the inspected object
    /// is an <c>Enum</c>.
    /// </summary>
    public static class EnumEnsureExtensions
    {
        /// <summary>
        /// Determines whether the specified enumeration value is defined.
        /// </summary>
        /// <typeparam name="T">THe type of the enumeration to inspect.</typeparam>
        /// <param name="validator">The current validator.</param>
        /// <returns>
        /// The Ensure instance for fluent interface usage.
        /// </returns>
        /// <exception cref="NotSupportedException">A <c>NotSupportedException</c> is raised if the supplied type T is not an enum type.</exception>
        /// <exception cref="EnumValueOutOfRangeException">An <c>EnumValueOutOfRangeException</c>
        /// is raised if the supplied enum value is not defined.</exception>
        public static IEnsure<T> IsDefined<T>(this IEnsure<T> validator)
        {
            if (!typeof(T).Is<Enum>())
            {
                throw new NotSupportedException("Only enum types are supported by this ensure extension");
            }

            var enumType = validator.Value.GetType();
            if (!Enum.IsDefined(enumType, validator.Value))
            {
                validator.Throw(new EnumValueOutOfRangeException(Resources.Exceptions.EnumValidatorNotDefinedException));
            }

            return validator;
        }
    }
}


text:
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');

process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  const agent = new WebhookClient({ request, response });
  console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
  console.log('Dialogflow Request body: ' + JSON.stringify(request.body));

  function validateEmployeeID (agent) {
    // get the employee ID parameter from the request header received from Dialogflow
    let employeeID = agent.parameters.employeeID;
    let pattern = /[^a-zA-Z0-9]/;
    if (employeeID.length !== 6) {
      agent.add(`The length of the Employee ID should be six characters. Please enter the correct ID.`);
    } else if (employeeID.match(pattern) !== null) {
      agent.add(`Employee ID should have only letters or numbers. Please enter the correct ID.`);
    } else {
      agent.add(agent.request_.body.queryResult.fulfillmentText);
    }
  }

  function welcome (agent) {
    agent.add(`Welcome to my agent!`);
    agent.add(agent.request_.body.queryResult.fulfillmentText);
  }

  function fallback (agent) {
    agent.add(`I didn't understand`);
    agent.add(`I'm sorry, can you try again?`);
  }

  // Run the proper function handler based on the matched Dialogflow intent name
  let intentMap = new Map();
  intentMap.set('Get Employee ID', validateEmployeeID);
  intentMap.set('Default Welcome Intent', welcome);
  intentMap.set('Default Fallback Intent', fallback);
  agent.handleRequest(intentMap);
});


text:
package ca.chrisbarrett.bubblecount.util;

import java.util.Random;

/**
 * A placeholder for shared Values information, such as Preference, Extra tags
 *
 * @author Chris Barrett
 * @see
 * @since Jul 10, 2016
 */
public final class Values {

    public static final Random RANDOM = new Random();

    private Values (){}

    /**
     * Contains tags used during Extras
     */
    public static abstract class  Extra {
        public static final String GAME_ID_SELECTOR = "GAME_ID_SELECTOR";
        public static final String PLAYER_ID_SELECTOR = "PLAYER_ID_SELECTOR";

    }

    /**
     * Contains tags used during startActivityForResult ResultRequest values
     */
    public static abstract class ResultRequest {
        public static final int ACTIVITY_GAME = 2000;       // Used for starting GameActivity
        public static final int ACTIVITY_SETTINGS = 1000;   // Used for starting SettingsActivity
    }
}


text:
<!DOCTYPE html>

	<title>Leaflet debug page</title>

	<link rel="stylesheet" href="../../dist/leaflet.css" />

	<meta name="viewport" content="width=device-width, initial-scale=1.0">

	<link rel="stylesheet" href="../css/screen.css" />

	<input type="range" min="0" max="360" step="1" name="rho" id='rho_input' style='width:800px'/>

		<button onclick="map.setBearing(0);" > 0</button>
		<button onclick="map.setBearing(15);">15</button>
		<button onclick="map.setBearing(30);">30</button>
		<button onclick="map.setBearing(45);">45</button>
		<button onclick="map.setBearing(60);">60</button>
		<button onclick="map.setBearing(75);">75</button>
		<button onclick="map.setBearing(90);">90</button>


text:
<?php

namespace CodeIgniter\Helpers;

use CodeIgniter\Cookie\Exceptions\CookieException;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\Response;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockResponse;
use Config\App;
use Config\Services;

/**
 * @internal
 */
final class CookieHelperTest extends CIUnitTestCase
{
    private $name;
    private string $value;
    private int $expire;
    private Response $response;

    protected function setUp(): void
    {
        parent::setUp();

        $this->name   = 'greetings';
        $this->value  = 'hello world';
        $this->expire = 9999;

        Services::injectMock('response', new MockResponse(new App()));
        $this->response = Services::response();
        $this->request  = new IncomingRequest(new App(), new URI(), null, new UserAgent());
        Services::injectMock('request', $this->request);

        helper('cookie');
    }

    public function testSetCookie()
    {
        set_cookie($this->name, $this->value, $this->expire);

        $this->assertTrue($this->response->hasCookie($this->name));

        delete_cookie($this->name);
    }

    public function testHasCookie()
    {
        $cookieAttr = [
            'name'   => $this->name,
            'value'  => $this->value,
            'expire' => $this->expire,
        ];
        set_cookie($cookieAttr);

        $this->assertTrue(has_cookie($this->name, $this->value));

        delete_cookie($this->name);
    }

    public function testSetCookieByArrayParameters()
    {
        $cookieAttr = [
            'name'   => $this->name,
            'value'  => $this->value,
            'expire' => $this->expire,
        ];
        set_cookie($cookieAttr);

        $this->assertTrue($this->response->hasCookie($this->name, $this->value));

        delete_cookie($this->name);
    }

    public function testSetCookieSecured()
    {
        $pre       = 'Hello, I try to';
        $pst       = 'your site';
        $unsec     = "{$pre} <script>alert('Hack');</script> {$pst}";
        $sec       = "{$pre} [removed]alert('Hack');[removed] {$pst}";
        $unsecured = 'unsecured';
        $secured   = 'secured';

        set_cookie($unsecured, $unsec, $this->expire);
        set_cookie($secured, $sec, $this->expire);

        $this->assertTrue($this->response->hasCookie($unsecured, $unsec));
        $this->assertTrue($this->response->hasCookie($secured, $sec));

        delete_cookie($unsecured);
        delete_cookie($secured);
    }

    public function testDeleteCookie()
    {
        $this->response->setCookie($this->name, $this->value, $this->expire);

        delete_cookie($this->name);

        $cookie = $this->response->getCookie($this->name);

        // The cookie is set to be cleared when the request is sent....
        $this->assertSame('', $cookie->getValue());
        $this->assertSame(0, $cookie->getExpiresTimestamp());
    }

    public function testGetCookie()
    {
        $_COOKIE['TEST'] = 5;

        $this->assertSame('5', get_cookie('TEST'));
    }

    public function testDeleteCookieAfterLastSet()
    {
        delete_cookie($this->name);

        $cookie = $this->response->getCookie($this->name);
        // The cookie is set to be cleared when the request is sent....
        $this->assertSame('', $cookie->getValue());
    }

    public function testSameSiteDefault()
    {
        $cookieAttr = [
            'name'   => $this->name,
            'value'  => $this->value,
            'expire' => $this->expire,
        ];

        set_cookie($cookieAttr);

        $this->assertTrue($this->response->hasCookie($this->name));
        $theCookie = $this->response->getCookie($this->name);
        $this->assertSame('Lax', $theCookie->getSameSite());

        delete_cookie($this->name);
    }

    public function testSameSiteInvalid()
    {
        $cookieAttr = [
            'name'     => $this->name,
            'value'    => $this->value,
            'expire'   => $this->expire,
            'samesite' => 'Invalid',
        ];

        $this->expectException(CookieException::class);
        $this->expectExceptionMessage(lang('Cookie.invalidSameSite', ['Invalid']));

        set_cookie($cookieAttr);
    }

    public function testSameSiteParamArray()
    {
        $cookieAttr = [
            'name'     => $this->name,
            'value'    => $this->value,
            'expire'   => $this->expire,
            'samesite' => 'Strict',
        ];

        set_cookie($cookieAttr);

        $this->assertTrue($this->response->hasCookie($this->name));
        $theCookie = $this->response->getCookie($this->name);
        $this->assertSame('Strict', $theCookie->getSameSite());

        delete_cookie($this->name);
    }

    public function testSameSiteParam()
    {
        set_cookie($this->name, $this->value, $this->expire, '', '', '', '', '', 'Strict');

        $this->assertTrue($this->response->hasCookie($this->name));
        $theCookie = $this->response->getCookie($this->name);
        $this->assertSame('Strict', $theCookie->getSameSite());

        delete_cookie($this->name);
    }
}