text:
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.flowable.rest.service.api;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.flowable.batch.api.Batch;
import org.flowable.batch.api.BatchPart;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.rest.resolver.ContentTypeResolver;
import org.flowable.common.rest.util.RestUrlBuilder;
import org.flowable.common.rest.variable.BooleanRestVariableConverter;
import org.flowable.common.rest.variable.DateRestVariableConverter;
import org.flowable.common.rest.variable.DoubleRestVariableConverter;
import org.flowable.common.rest.variable.InstantRestVariableConverter;
import org.flowable.common.rest.variable.IntegerRestVariableConverter;
import org.flowable.common.rest.variable.JsonObjectRestVariableConverter;
import org.flowable.common.rest.variable.LocalDateRestVariableConverter;
import org.flowable.common.rest.variable.LocalDateTimeRestVariableConverter;
import org.flowable.common.rest.variable.LongRestVariableConverter;
import org.flowable.common.rest.variable.RestVariableConverter;
import org.flowable.common.rest.variable.ShortRestVariableConverter;
import org.flowable.common.rest.variable.StringRestVariableConverter;
import org.flowable.dmn.api.DmnDecision;
import org.flowable.engine.form.FormData;
import org.flowable.engine.form.FormProperty;
import org.flowable.engine.form.StartFormData;
import org.flowable.engine.form.TaskFormData;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricDetail;
import org.flowable.engine.history.HistoricFormProperty;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricVariableUpdate;
import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Attachment;
import org.flowable.engine.task.Comment;
import org.flowable.engine.task.Event;
import org.flowable.eventsubscription.api.EventSubscription;
import org.flowable.form.api.FormDefinition;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.job.api.HistoryJob;
import org.flowable.job.api.Job;
import org.flowable.rest.service.api.engine.AttachmentResponse;
import org.flowable.rest.service.api.engine.CommentResponse;
import org.flowable.rest.service.api.engine.EventResponse;
import org.flowable.rest.service.api.engine.RestIdentityLink;
import org.flowable.rest.service.api.engine.variable.QueryVariable;
import org.flowable.rest.service.api.engine.variable.RestVariable;
import org.flowable.rest.service.api.engine.variable.RestVariable.RestVariableScope;
import org.flowable.rest.service.api.form.FormDataResponse;
import org.flowable.rest.service.api.form.RestEnumFormProperty;
import org.flowable.rest.service.api.form.RestFormProperty;
import org.flowable.rest.service.api.history.HistoricActivityInstanceResponse;
import org.flowable.rest.service.api.history.HistoricDetailResponse;
import org.flowable.rest.service.api.history.HistoricIdentityLinkResponse;
import org.flowable.rest.service.api.history.HistoricProcessInstanceResponse;
import org.flowable.rest.service.api.history.HistoricTaskInstanceResponse;
import org.flowable.rest.service.api.history.HistoricTaskLogEntryResponse;
import org.flowable.rest.service.api.history.HistoricVariableInstanceResponse;
import org.flowable.rest.service.api.identity.GroupResponse;
import org.flowable.rest.service.api.identity.MembershipResponse;
import org.flowable.rest.service.api.identity.UserInfoResponse;
import org.flowable.rest.service.api.identity.UserResponse;
import org.flowable.rest.service.api.management.BatchPartResponse;
import org.flowable.rest.service.api.management.BatchResponse;
import org.flowable.rest.service.api.management.HistoryJobResponse;
import org.flowable.rest.service.api.management.JobResponse;
import org.flowable.rest.service.api.management.TableResponse;
import org.flowable.rest.service.api.repository.DecisionResponse;
import org.flowable.rest.service.api.repository.DeploymentResourceResponse;
import org.flowable.rest.service.api.repository.DeploymentResponse;
import org.flowable.rest.service.api.repository.FormDefinitionResponse;
import org.flowable.rest.service.api.repository.ModelResponse;
import org.flowable.rest.service.api.repository.ProcessDefinitionResponse;
import org.flowable.rest.service.api.runtime.VariableInstanceResponse;
import org.flowable.rest.service.api.runtime.process.ActivityInstanceResponse;
import org.flowable.rest.service.api.runtime.process.EventSubscriptionResponse;
import org.flowable.rest.service.api.runtime.process.ExecutionResponse;
import org.flowable.rest.service.api.runtime.process.ProcessInstanceResponse;
import org.flowable.rest.service.api.runtime.task.TaskResponse;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskLogEntry;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.flowable.variable.api.persistence.entity.VariableInstance;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Default implementation of a {@link RestResponseFactory}.
 *
 * Added a new "createProcessInstanceResponse" method (with a different signature) to conditionally return the process variables that exist within the process instance when the first wait state is
 * encountered (or when the process instance completes). Also added the population of a "completed" flag - within both the original "createProcessInstanceResponse" method and the new one with the
 * different signature - to let the caller know whether the process instance has completed or not.
 *
 * @author Frederik Heremans
 * @author Ryan Johnston (@rjfsu)
 */
public class RestResponseFactory {

    public static final int VARIABLE_TASK = 1;
    public static final int VARIABLE_EXECUTION = 2;
    public static final int VARIABLE_PROCESS = 3;
    public static final int VARIABLE_VARINSTANCE = 4;
    public static final int VARIABLE_HISTORY_TASK = 5;
    public static final int VARIABLE_HISTORY_PROCESS = 6;
    public static final int VARIABLE_HISTORY_VARINSTANCE = 7;
    public static final int VARIABLE_HISTORY_DETAIL = 8;

    public static final String BYTE_ARRAY_VARIABLE_TYPE = "binary";
    public static final String SERIALIZABLE_VARIABLE_TYPE = "serializable";

    protected ObjectMapper objectMapper;
    protected List<RestVariableConverter> variableConverters = new ArrayList<>();

    public RestResponseFactory(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        initializeVariableConverters();
    }

    public List<TaskResponse> createTaskResponseList(List<Task> tasks) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<TaskResponse> responseList = new ArrayList<>(tasks.size());
        for (Task instance : tasks) {
            responseList.add(createTaskResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public TaskResponse createTaskResponse(Task task) {
        return createTaskResponse(task, createUrlBuilder());
    }

    public TaskResponse createTaskResponse(Task task, RestUrlBuilder urlBuilder) {
        TaskResponse response = new TaskResponse(task);
        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_TASK, task.getId()));

        // Add references to other resources, if needed
        if (response.getParentTaskId() != null) {
            response.setParentTaskUrl(urlBuilder.buildUrl(RestUrls.URL_TASK, response.getParentTaskId()));
        }
        if (response.getProcessDefinitionId() != null) {
            response.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, response.getProcessDefinitionId()));
        }
        if (response.getExecutionId() != null) {
            response.setExecutionUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION, response.getExecutionId()));
        }
        if (response.getProcessInstanceId() != null) {
            response.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, response.getProcessInstanceId()));
        }

        if (task.getProcessVariables() != null) {
            Map<String, Object> variableMap = task.getProcessVariables();
            for (String name : variableMap.keySet()) {
                response.addVariable(createRestVariable(name, variableMap.get(name), RestVariableScope.GLOBAL, task.getId(), VARIABLE_TASK, false, urlBuilder));
            }
        }
        if (task.getTaskLocalVariables() != null) {
            Map<String, Object> variableMap = task.getTaskLocalVariables();
            for (String name : variableMap.keySet()) {
                response.addVariable(createRestVariable(name, variableMap.get(name), RestVariableScope.LOCAL, task.getId(), VARIABLE_TASK, false, urlBuilder));
            }
        }

        return response;
    }

    public List<DeploymentResponse> createDeploymentResponseList(List<Deployment> deployments) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<DeploymentResponse> responseList = new ArrayList<>(deployments.size());
        for (Deployment instance : deployments) {
            responseList.add(createDeploymentResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public DeploymentResponse createDeploymentResponse(Deployment deployment) {
        return createDeploymentResponse(deployment, createUrlBuilder());
    }

    public DeploymentResponse createDeploymentResponse(Deployment deployment, RestUrlBuilder urlBuilder) {
        return new DeploymentResponse(deployment, urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT, deployment.getId()));
    }

    public List<DeploymentResourceResponse> createDeploymentResourceResponseList(String deploymentId, List<String> resourceList, ContentTypeResolver contentTypeResolver) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        // Add additional metadata to the artifact-strings before returning
        List<DeploymentResourceResponse> responseList = new ArrayList<>(resourceList.size());
        for (String resourceId : resourceList) {
            responseList.add(createDeploymentResourceResponse(deploymentId, resourceId, contentTypeResolver.resolveContentType(resourceId), urlBuilder));
        }
        return responseList;
    }

    public DeploymentResourceResponse createDeploymentResourceResponse(String deploymentId, String resourceId, String contentType) {
        return createDeploymentResourceResponse(deploymentId, resourceId, contentType, createUrlBuilder());
    }

    public DeploymentResourceResponse createDeploymentResourceResponse(String deploymentId, String resourceId, String contentType, RestUrlBuilder urlBuilder) {
        // Create URL's
        String resourceUrl = urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT_RESOURCE, deploymentId, resourceId);
        String resourceContentUrl = urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT_RESOURCE_CONTENT, deploymentId, resourceId);

        // Determine type
        String type = "resource";
        for (String suffix : ResourceNameUtil.BPMN_RESOURCE_SUFFIXES) {
            if (resourceId.endsWith(suffix)) {
                type = "processDefinition";
                break;
            }
        }
        return new DeploymentResourceResponse(resourceId, resourceUrl, resourceContentUrl, contentType, type);
    }

    public List<ProcessDefinitionResponse> createProcessDefinitionResponseList(List<ProcessDefinition> processDefinitions) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<ProcessDefinitionResponse> responseList = new ArrayList<>(processDefinitions.size());
        for (ProcessDefinition instance : processDefinitions) {
            responseList.add(createProcessDefinitionResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public ProcessDefinitionResponse createProcessDefinitionResponse(ProcessDefinition processDefinition) {
        return createProcessDefinitionResponse(processDefinition, createUrlBuilder());
    }

    public ProcessDefinitionResponse createProcessDefinitionResponse(ProcessDefinition processDefinition, RestUrlBuilder urlBuilder) {
        ProcessDefinitionResponse response = new ProcessDefinitionResponse();
        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, processDefinition.getId()));
        response.setId(processDefinition.getId());
        response.setKey(processDefinition.getKey());
        response.setVersion(processDefinition.getVersion());
        response.setCategory(processDefinition.getCategory());
        response.setName(processDefinition.getName());
        response.setDescription(processDefinition.getDescription());
        response.setSuspended(processDefinition.isSuspended());
        response.setStartFormDefined(processDefinition.hasStartFormKey());
        response.setGraphicalNotationDefined(processDefinition.hasGraphicalNotation());
        response.setTenantId(processDefinition.getTenantId());

        // Links to other resources
        response.setDeploymentId(processDefinition.getDeploymentId());
        response.setDeploymentUrl(urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT, processDefinition.getDeploymentId()));
        response.setResource(urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT_RESOURCE, processDefinition.getDeploymentId(), processDefinition.getResourceName()));
        if (processDefinition.getDiagramResourceName() != null) {
            response.setDiagramResource(urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT_RESOURCE, processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName()));
        }
        return response;
    }

    public String getFormModelString(FormModelResponse formModelResponse) {
        try {
            return objectMapper.writeValueAsString(formModelResponse);
        } catch (Exception e) {
            throw new FlowableException("Error writing form model response", e);
        }
    }

    public List<RestVariable> createRestVariables(Map<String, Object> variables, String id, int variableType, RestVariableScope scope) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<RestVariable> result = new ArrayList<>(variables.size());

        for (Entry<String, Object> pair : variables.entrySet()) {
            result.add(createRestVariable(pair.getKey(), pair.getValue(), scope, id, variableType, false, urlBuilder));
        }

        return result;
    }

    public RestVariable createRestVariable(String name, Object value, RestVariableScope scope, String id, int variableType, boolean includeBinaryValue) {
        return createRestVariable(name, value, scope, id, variableType, includeBinaryValue, createUrlBuilder());
    }

    public RestVariable createRestVariable(String name, Object value, RestVariableScope scope, String id, int variableType, boolean includeBinaryValue, RestUrlBuilder urlBuilder) {

        RestVariableConverter converter = null;
        RestVariable restVar = new RestVariable();
        restVar.setVariableScope(scope);
        restVar.setName(name);

        if (value != null) {
            // Try converting the value
            for (RestVariableConverter c : variableConverters) {
                if (c.getVariableType().isAssignableFrom(value.getClass())) {
                    converter = c;
                    break;
                }
            }

            if (converter != null) {
                converter.convertVariableValue(value, restVar);
                restVar.setType(converter.getRestTypeName());
            } else {
                // Revert to default conversion, which is the
                // serializable/byte-array form
                if (value instanceof Byte[] || value instanceof byte[]) {
                    restVar.setType(BYTE_ARRAY_VARIABLE_TYPE);
                } else {
                    restVar.setType(SERIALIZABLE_VARIABLE_TYPE);
                }

                if (includeBinaryValue) {
                    restVar.setValue(value);
                }

                if (variableType == VARIABLE_TASK) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_VARIABLE_DATA, id, name));
                } else if (variableType == VARIABLE_EXECUTION) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION_VARIABLE_DATA, id, name));
                } else if (variableType == VARIABLE_PROCESS) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE_VARIABLE_DATA, id, name));
                } else if (variableType == VARIABLE_VARINSTANCE) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_VARIABLE_INSTANCE_DATA, id));
                } else if (variableType == VARIABLE_HISTORY_TASK) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_TASK_INSTANCE_VARIABLE_DATA, id, name));
                } else if (variableType == VARIABLE_HISTORY_PROCESS) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE_VARIABLE_DATA, id, name));
                } else if (variableType == VARIABLE_HISTORY_VARINSTANCE) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_VARIABLE_INSTANCE_DATA, id));
                } else if (variableType == VARIABLE_HISTORY_DETAIL) {
                    restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_DETAIL_VARIABLE_DATA, id));
                }
            }
        }
        return restVar;
    }

    public RestVariable createBinaryRestVariable(String name, RestVariableScope scope, String type, String taskId, String executionId, String processInstanceId) {

        RestUrlBuilder urlBuilder = createUrlBuilder();
        RestVariable restVar = new RestVariable();
        restVar.setVariableScope(scope);
        restVar.setName(name);
        restVar.setType(type);

        if (taskId != null) {
            restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_VARIABLE_DATA, taskId, name));
        }
        if (executionId != null) {
            restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION_VARIABLE_DATA, executionId, name));
        }
        if (processInstanceId != null) {
            restVar.setValueUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE_VARIABLE_DATA, processInstanceId, name));
        }

        return restVar;
    }

    public Object getVariableValue(RestVariable restVariable) {
        Object value = null;

        if (restVariable.getType() != null) {
            // Try locating a converter if the type has been specified
            RestVariableConverter converter = null;
            for (RestVariableConverter conv : variableConverters) {
                if (conv.getRestTypeName().equals(restVariable.getType())) {
                    converter = conv;
                    break;
                }
            }
            if (converter == null) {
                throw new FlowableIllegalArgumentException("Variable '" + restVariable.getName() + "' has unsupported type: '" + restVariable.getType() + "'.");
            }
            value = converter.getVariableValue(restVariable);

        } else {
            // Revert to type determined by REST-to-Java mapping when no
            // explicit type has been provided
            value = restVariable.getValue();
        }
        return value;
    }

    public Object getVariableValue(QueryVariable restVariable) {
        Object value = null;

        if (restVariable.getType() != null) {
            // Try locating a converter if the type has been specified
            RestVariableConverter converter = null;
            for (RestVariableConverter conv : variableConverters) {
                if (conv.getRestTypeName().equals(restVariable.getType())) {
                    converter = conv;
                    break;
                }
            }
            if (converter == null) {
                throw new FlowableIllegalArgumentException("Variable '" + restVariable.getName() + "' has unsupported type: '" + restVariable.getType() + "'.");
            }

            RestVariable temp = new RestVariable();
            temp.setValue(restVariable.getValue());
            temp.setType(restVariable.getType());
            temp.setName(restVariable.getName());
            value = converter.getVariableValue(temp);

        } else {
            // Revert to type determined by REST-to-Java mapping when no
            // explicit type has been provided
            value = restVariable.getValue();
        }
        return value;
    }

    public List<RestIdentityLink> createRestIdentityLinks(List<IdentityLink> links) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<RestIdentityLink> responseList = new ArrayList<>(links.size());
        for (IdentityLink instance : links) {
            responseList.add(createRestIdentityLink(instance, urlBuilder));
        }
        return responseList;
    }

    public RestIdentityLink createRestIdentityLink(IdentityLink link) {
        return createRestIdentityLink(link, createUrlBuilder());
    }

    public RestIdentityLink createRestIdentityLink(IdentityLink link, RestUrlBuilder urlBuilder) {
        return createRestIdentityLink(link.getType(), link.getUserId(), link.getGroupId(), link.getTaskId(), link.getProcessDefinitionId(), link.getProcessInstanceId(), urlBuilder);
    }

    public RestIdentityLink createRestIdentityLink(String type, String userId, String groupId, String taskId, String processDefinitionId, String processInstanceId) {
        return createRestIdentityLink(type, userId, groupId, taskId, processDefinitionId, processInstanceId, createUrlBuilder());
    }

    public RestIdentityLink createRestIdentityLink(String type, String userId, String groupId, String taskId, String processDefinitionId, String processInstanceId, RestUrlBuilder urlBuilder) {
        RestIdentityLink result = new RestIdentityLink();
        result.setUser(userId);
        result.setGroup(groupId);
        result.setType(type);

        String family = null;
        if (userId != null) {
            family = RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS;
        } else {
            family = RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS;
        }
        if (processDefinitionId != null) {
            result.setUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION_IDENTITYLINK, processDefinitionId, family, (userId != null ? userId : groupId)));
        } else if (taskId != null) {
            result.setUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_IDENTITYLINK, taskId, family, (userId != null ? userId : groupId), type));
        } else {
            result.setUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, processInstanceId, (userId != null ? userId : groupId), type));
        }
        return result;
    }

    public List<CommentResponse> createRestCommentList(List<Comment> comments) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<CommentResponse> responseList = new ArrayList<>(comments.size());
        for (Comment instance : comments) {
            responseList.add(createRestComment(instance, urlBuilder));
        }
        return responseList;
    }

    public CommentResponse createRestComment(Comment comment) {
        return createRestComment(comment, createUrlBuilder());
    }

    public CommentResponse createRestComment(Comment comment, RestUrlBuilder urlBuilder) {
        CommentResponse result = new CommentResponse();
        result.setAuthor(comment.getUserId());
        result.setMessage(comment.getFullMessage());
        result.setId(comment.getId());
        result.setTime(comment.getTime());
        result.setTaskId(comment.getTaskId());
        result.setProcessInstanceId(comment.getProcessInstanceId());

        if (comment.getTaskId() != null) {
            result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_COMMENT, comment.getTaskId(), comment.getId()));
        }

        if (comment.getProcessInstanceId() != null) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE_COMMENT, comment.getProcessInstanceId(), comment.getId()));
        }

        return result;
    }

    public List<EventResponse> createEventResponseList(List<Event> events) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<EventResponse> responseList = new ArrayList<>(events.size());
        for (Event instance : events) {
            responseList.add(createEventResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public EventResponse createEventResponse(Event event) {
        return createEventResponse(event, createUrlBuilder());
    }

    public EventResponse createEventResponse(Event event, RestUrlBuilder urlBuilder) {
        EventResponse result = new EventResponse();
        result.setAction(event.getAction());
        result.setId(event.getId());
        result.setMessage(event.getMessageParts());
        result.setTime(event.getTime());
        result.setUserId(event.getUserId());

        result.setUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_EVENT, event.getTaskId(), event.getId()));
        result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_TASK, event.getTaskId()));

        if (event.getProcessInstanceId() != null) {
            result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, event.getProcessInstanceId()));
        }
        return result;
    }

    public AttachmentResponse createAttachmentResponse(Attachment attachment) {
        return createAttachmentResponse(attachment, createUrlBuilder());
    }

    public AttachmentResponse createAttachmentResponse(Attachment attachment, RestUrlBuilder urlBuilder) {
        AttachmentResponse result = new AttachmentResponse();
        result.setId(attachment.getId());
        result.setName(attachment.getName());
        result.setDescription(attachment.getDescription());
        result.setTime(attachment.getTime());
        result.setType(attachment.getType());
        result.setUserId(attachment.getUserId());

        if (attachment.getUrl() == null && attachment.getTaskId() != null) {
            // Attachment content can be streamed
            result.setContentUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_ATTACHMENT_DATA, attachment.getTaskId(), attachment.getId()));
        } else {
            result.setExternalUrl(attachment.getUrl());
        }

        if (attachment.getTaskId() != null) {
            result.setUrl(urlBuilder.buildUrl(RestUrls.URL_TASK_ATTACHMENT, attachment.getTaskId(), attachment.getId()));
            result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_TASK, attachment.getTaskId()));
        }
        if (attachment.getProcessInstanceId() != null) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, attachment.getProcessInstanceId()));
        }
        return result;
    }

    public List<ProcessInstanceResponse> createProcessInstanceResponseList(List<ProcessInstance> processInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<ProcessInstanceResponse> responseList = new ArrayList<>(processInstances.size());
        for (ProcessInstance instance : processInstances) {
            responseList.add(createProcessInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public ProcessInstanceResponse createProcessInstanceResponse(ProcessInstance processInstance) {
        return createProcessInstanceResponse(processInstance, createUrlBuilder());
    }

    public ProcessInstanceResponse createProcessInstanceResponse(ProcessInstance processInstance, RestUrlBuilder urlBuilder) {
        ProcessInstanceResponse result = internalCreateProcessInstanceResponse(processInstance, urlBuilder);
        if (processInstance.getProcessVariables() != null) {
            Map<String, Object> variableMap = processInstance.getProcessVariables();
            for (String name : variableMap.keySet()) {
                result.addVariable(createRestVariable(name, variableMap.get(name), RestVariableScope.LOCAL, processInstance.getId(), VARIABLE_PROCESS, false, urlBuilder));
            }
        }

        return result;
    }

    public ProcessInstanceResponse createProcessInstanceResponse(ProcessInstance processInstance, boolean returnVariables,
            Map<String, Object> runtimeVariableMap, List<HistoricVariableInstance> historicVariableList) {

        RestUrlBuilder urlBuilder = createUrlBuilder();
        ProcessInstanceResponse result = internalCreateProcessInstanceResponse(processInstance, urlBuilder);

        if (returnVariables) {

            if (processInstance.isEnded()) {
                if (historicVariableList != null) {
                    for (HistoricVariableInstance historicVariable : historicVariableList) {
                        result.addVariable(createRestVariable(historicVariable.getVariableName(), historicVariable.getValue(), RestVariableScope.LOCAL, processInstance.getId(), VARIABLE_PROCESS, false,
                                urlBuilder));
                    }
                }

            } else {
                if (runtimeVariableMap != null) {
                    for (String name : runtimeVariableMap.keySet()) {
                        result.addVariable(createRestVariable(name, runtimeVariableMap.get(name), RestVariableScope.LOCAL, processInstance.getId(), VARIABLE_PROCESS, false, urlBuilder));
                    }
                }
            }
        }
        return result;
    }

    protected ProcessInstanceResponse internalCreateProcessInstanceResponse(ProcessInstance processInstance, RestUrlBuilder urlBuilder) {
        ProcessInstanceResponse result = new ProcessInstanceResponse();
        result.setActivityId(processInstance.getActivityId());
        result.setStartUserId(processInstance.getStartUserId());
        result.setStartTime(processInstance.getStartTime());
        result.setBusinessKey(processInstance.getBusinessKey());
        result.setBusinessStatus(processInstance.getBusinessStatus());
        result.setId(processInstance.getId());
        result.setName(processInstance.getName());
        result.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        result.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, processInstance.getProcessDefinitionId()));
        result.setEnded(processInstance.isEnded());
        result.setSuspended(processInstance.isSuspended());
        result.setUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, processInstance.getId()));
        result.setCallbackId(processInstance.getCallbackId());
        result.setCallbackType(processInstance.getCallbackType());
        result.setReferenceId(processInstance.getReferenceId());
        result.setReferenceType(processInstance.getReferenceType());
        result.setPropagatedStageInstanceId(processInstance.getPropagatedStageInstanceId());
        result.setTenantId(processInstance.getTenantId());

        if (processInstance.isEnded()) {
            result.setCompleted(true);
        } else {
            result.setCompleted(false);
        }
        return result;
    }

    public List<ExecutionResponse> createExecutionResponseList(List<Execution> executions) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<ExecutionResponse> responseList = new ArrayList<>(executions.size());
        for (Execution instance : executions) {
            responseList.add(createExecutionResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public ExecutionResponse createExecutionResponse(Execution execution) {
        return createExecutionResponse(execution, createUrlBuilder());
    }

    public ExecutionResponse createExecutionResponse(Execution execution, RestUrlBuilder urlBuilder) {
        ExecutionResponse result = new ExecutionResponse();
        result.setActivityId(execution.getActivityId());
        result.setId(execution.getId());
        result.setUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION, execution.getId()));
        result.setSuspended(execution.isSuspended());
        result.setTenantId(execution.getTenantId());

        result.setParentId(execution.getParentId());
        if (execution.getParentId() != null) {
            result.setParentUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION, execution.getParentId()));
        }

        result.setSuperExecutionId(execution.getSuperExecutionId());
        if (execution.getSuperExecutionId() != null) {
            result.setSuperExecutionUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION, execution.getSuperExecutionId()));
        }

        result.setProcessInstanceId(execution.getProcessInstanceId());
        if (execution.getProcessInstanceId() != null) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, execution.getProcessInstanceId()));
        }
        return result;
    }

    public List<ActivityInstanceResponse> createActivityInstanceResponseList(List<ActivityInstance> activityInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<ActivityInstanceResponse> responseList = new ArrayList<>(activityInstances.size());
        for (ActivityInstance instance : activityInstances) {
            responseList.add(createActivityInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public ActivityInstanceResponse createActivityInstanceResponse(ActivityInstance activityInstance) {
        return createActivityInstanceResponse(activityInstance, createUrlBuilder());
    }

    public ActivityInstanceResponse createActivityInstanceResponse(ActivityInstance activityInstance, RestUrlBuilder urlBuilder) {
        ActivityInstanceResponse result = new ActivityInstanceResponse();
        result.setActivityId(activityInstance.getActivityId());
        result.setActivityName(activityInstance.getActivityName());
        result.setActivityType(activityInstance.getActivityType());
        result.setAssignee(activityInstance.getAssignee());
        result.setCalledProcessInstanceId(activityInstance.getCalledProcessInstanceId());
        result.setDurationInMillis(activityInstance.getDurationInMillis());
        result.setEndTime(activityInstance.getEndTime());
        result.setExecutionId(activityInstance.getExecutionId());
        result.setId(activityInstance.getId());
        result.setProcessDefinitionId(activityInstance.getProcessDefinitionId());
        result.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, activityInstance.getProcessDefinitionId()));
        result.setProcessInstanceId(activityInstance.getProcessInstanceId());
        result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, activityInstance.getProcessInstanceId()));
        result.setStartTime(activityInstance.getStartTime());
        result.setTaskId(activityInstance.getTaskId());
        result.setTenantId(activityInstance.getTenantId());
        return result;
    }

    public List<VariableInstanceResponse> createVariableInstanceResponseList(List<VariableInstance> variableInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<VariableInstanceResponse> responseList = new ArrayList<>(variableInstances.size());
        for (VariableInstance instance : variableInstances) {
            responseList.add(createVariableInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public VariableInstanceResponse createVariableInstanceResponse(VariableInstance variableInstance) {
        return createVariableInstanceResponse(variableInstance, createUrlBuilder());
    }

    public VariableInstanceResponse createVariableInstanceResponse(VariableInstance variableInstance, RestUrlBuilder urlBuilder) {
        VariableInstanceResponse result = new VariableInstanceResponse();
        result.setId(variableInstance.getId());
        result.setProcessInstanceId(variableInstance.getProcessInstanceId());
        if (variableInstance.getProcessInstanceId() != null) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, variableInstance.getProcessInstanceId()));
        }
        result.setTaskId(variableInstance.getTaskId());
        result.setExecutionId(variableInstance.getExecutionId());

        RestVariableScope scope;
        if (variableInstance.getExecutionId() != null && !variableInstance.getExecutionId().equals(variableInstance.getProcessInstanceId())
                || variableInstance.getTaskId() != null) {
            scope = RestVariableScope.LOCAL;
        } else {
            scope = RestVariableScope.GLOBAL;
        }

        result.setVariable(
                createRestVariable(variableInstance.getName(), variableInstance.getValue(), scope, variableInstance.getId(), VARIABLE_VARINSTANCE, false,
                        urlBuilder));
        return result;
    }

    public FormDataResponse createFormDataResponse(FormData formData) {
        FormDataResponse result = new FormDataResponse();
        result.setDeploymentId(formData.getDeploymentId());
        result.setFormKey(formData.getFormKey());
        if (formData.getFormProperties() != null) {
            for (FormProperty formProp : formData.getFormProperties()) {
                RestFormProperty restFormProp = new RestFormProperty();
                restFormProp.setId(formProp.getId());
                restFormProp.setName(formProp.getName());
                if (formProp.getType() != null) {
                    restFormProp.setType(formProp.getType().getName());
                }
                restFormProp.setValue(formProp.getValue());
                restFormProp.setReadable(formProp.isReadable());
                restFormProp.setRequired(formProp.isRequired());
                restFormProp.setWritable(formProp.isWritable());
                if ("enum".equals(restFormProp.getType())) {
                    Object values = formProp.getType().getInformation("values");
                    if (values != null) {
                        @SuppressWarnings("unchecked")
                        Map<String, String> enumValues = (Map<String, String>) values;
                        for (String enumId : enumValues.keySet()) {
                            RestEnumFormProperty enumProperty = new RestEnumFormProperty();
                            enumProperty.setId(enumId);
                            enumProperty.setName(enumValues.get(enumId));
                            restFormProp.addEnumValue(enumProperty);
                        }
                    }
                } else if ("date".equals(restFormProp.getType())) {
                    restFormProp.setDatePattern((String) formProp.getType().getInformation("datePattern"));
                }
                result.addFormProperty(restFormProp);
            }
        }
        RestUrlBuilder urlBuilder = createUrlBuilder();
        if (formData instanceof StartFormData) {
            StartFormData startFormData = (StartFormData) formData;
            if (startFormData.getProcessDefinition() != null) {
                result.setProcessDefinitionId(startFormData.getProcessDefinition().getId());
                result.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, startFormData.getProcessDefinition().getId()));
            }
        } else if (formData instanceof TaskFormData) {
            TaskFormData taskFormData = (TaskFormData) formData;
            if (taskFormData.getTask() != null) {
                result.setTaskId(taskFormData.getTask().getId());
                result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_TASK, taskFormData.getTask().getId()));
            }
        }
        return result;
    }

    public List<HistoricProcessInstanceResponse> createHistoricProcessInstanceResponseList(List<HistoricProcessInstance> processInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricProcessInstanceResponse> responseList = new ArrayList<>(processInstances.size());
        for (HistoricProcessInstance instance : processInstances) {
            responseList.add(createHistoricProcessInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricProcessInstanceResponse createHistoricProcessInstanceResponse(HistoricProcessInstance processInstance) {
        return createHistoricProcessInstanceResponse(processInstance, createUrlBuilder());
    }

    public HistoricProcessInstanceResponse createHistoricProcessInstanceResponse(HistoricProcessInstance processInstance, RestUrlBuilder urlBuilder) {
        HistoricProcessInstanceResponse result = new HistoricProcessInstanceResponse();
        result.setBusinessKey(processInstance.getBusinessKey());
        result.setBusinessStatus(processInstance.getBusinessStatus());
        result.setDeleteReason(processInstance.getDeleteReason());
        result.setDurationInMillis(processInstance.getDurationInMillis());
        result.setEndActivityId(processInstance.getEndActivityId());
        result.setEndTime(processInstance.getEndTime());
        result.setId(processInstance.getId());
        result.setName(processInstance.getName());
        result.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        result.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, processInstance.getProcessDefinitionId()));
        result.setStartActivityId(processInstance.getStartActivityId());
        result.setStartTime(processInstance.getStartTime());
        result.setStartUserId(processInstance.getStartUserId());
        result.setSuperProcessInstanceId(processInstance.getSuperProcessInstanceId());
        result.setUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE, processInstance.getId()));
        if (processInstance.getProcessVariables() != null) {
            Map<String, Object> variableMap = processInstance.getProcessVariables();
            for (String name : variableMap.keySet()) {
                result.addVariable(createRestVariable(name, variableMap.get(name), RestVariableScope.LOCAL, processInstance.getId(), VARIABLE_HISTORY_PROCESS, false, urlBuilder));
            }
        }
        result.setCallbackId(processInstance.getCallbackId());
        result.setCallbackType(processInstance.getCallbackType());
        result.setReferenceId(processInstance.getReferenceId());
        result.setReferenceType(processInstance.getReferenceType());
        result.setPropagatedStageInstanceId(processInstance.getPropagatedStageInstanceId());
        result.setTenantId(processInstance.getTenantId());
        return result;
    }

    public List<HistoricTaskInstanceResponse> createHistoricTaskInstanceResponseList(List<HistoricTaskInstance> taskInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricTaskInstanceResponse> responseList = new ArrayList<>(taskInstances.size());
        for (HistoricTaskInstance instance : taskInstances) {
            responseList.add(createHistoricTaskInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricTaskInstanceResponse createHistoricTaskInstanceResponse(HistoricTaskInstance taskInstance) {
        return createHistoricTaskInstanceResponse(taskInstance, createUrlBuilder());
    }

    public HistoricTaskInstanceResponse createHistoricTaskInstanceResponse(HistoricTaskInstance taskInstance, RestUrlBuilder urlBuilder) {
        HistoricTaskInstanceResponse result = new HistoricTaskInstanceResponse();
        result.setAssignee(taskInstance.getAssignee());
        result.setClaimTime(taskInstance.getClaimTime());
        result.setDeleteReason(taskInstance.getDeleteReason());
        result.setDescription(taskInstance.getDescription());
        result.setDueDate(taskInstance.getDueDate());
        result.setDurationInMillis(taskInstance.getDurationInMillis());
        result.setEndTime(taskInstance.getEndTime());
        result.setExecutionId(taskInstance.getExecutionId());
        result.setFormKey(taskInstance.getFormKey());
        result.setId(taskInstance.getId());
        result.setName(taskInstance.getName());
        result.setOwner(taskInstance.getOwner());
        result.setParentTaskId(taskInstance.getParentTaskId());
        result.setPriority(taskInstance.getPriority());
        result.setProcessDefinitionId(taskInstance.getProcessDefinitionId());
        result.setScopeDefinitionId(taskInstance.getScopeDefinitionId());
        result.setScopeId(taskInstance.getScopeId());
        result.setScopeType(taskInstance.getScopeType());
        result.setPropagatedStageInstanceId(taskInstance.getPropagatedStageInstanceId());
        result.setTenantId(taskInstance.getTenantId());
        result.setCategory(taskInstance.getCategory());
        if (taskInstance.getProcessDefinitionId() != null) {
            result.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, taskInstance.getProcessDefinitionId()));
        }
        result.setProcessInstanceId(taskInstance.getProcessInstanceId());
        if (taskInstance.getProcessInstanceId() != null) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE, taskInstance.getProcessInstanceId()));
        }
        result.setStartTime(taskInstance.getStartTime());
        result.setTaskDefinitionKey(taskInstance.getTaskDefinitionKey());
        result.setWorkTimeInMillis(taskInstance.getWorkTimeInMillis());
        result.setUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_TASK_INSTANCE, taskInstance.getId()));
        if (taskInstance.getProcessVariables() != null) {
            Map<String, Object> variableMap = taskInstance.getProcessVariables();
            for (String name : variableMap.keySet()) {
                result.addVariable(createRestVariable(name, variableMap.get(name), RestVariableScope.GLOBAL, taskInstance.getId(), VARIABLE_HISTORY_TASK, false, urlBuilder));
            }
        }
        if (taskInstance.getTaskLocalVariables() != null) {
            Map<String, Object> variableMap = taskInstance.getTaskLocalVariables();
            for (String name : variableMap.keySet()) {
                result.addVariable(createRestVariable(name, variableMap.get(name), RestVariableScope.LOCAL, taskInstance.getId(), VARIABLE_HISTORY_TASK, false, urlBuilder));
            }
        }
        return result;
    }

    public List<HistoricTaskLogEntryResponse> createHistoricTaskLogEntryResponseList(List<HistoricTaskLogEntry> logEntries) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricTaskLogEntryResponse> responseList = new ArrayList<>(logEntries.size());
        for (HistoricTaskLogEntry instance : logEntries) {
            responseList.add(createHistoricTaskLogEntryResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricTaskLogEntryResponse createHistoricTaskLogEntryResponse(HistoricTaskLogEntry logEntry, RestUrlBuilder urlBuilder) {
        HistoricTaskLogEntryResponse response = new HistoricTaskLogEntryResponse();
        response.setLogNumber(logEntry.getLogNumber());
        response.setType(logEntry.getType());
        response.setTaskId(logEntry.getTaskId());
        response.setTimeStamp(logEntry.getTimeStamp());
        response.setUserId(logEntry.getUserId());
        response.setData(logEntry.getData());
        response.setExecutionId(logEntry.getExecutionId());
        response.setProcessInstanceId(logEntry.getProcessInstanceId());
        response.setProcessDefinitionId(logEntry.getProcessDefinitionId());
        response.setScopeId(logEntry.getScopeId());
        response.setScopeDefinitionId(logEntry.getScopeDefinitionId());
        response.setSubScopeId(logEntry.getSubScopeId());
        response.setScopeType(logEntry.getScopeType());
        response.setTenantId(logEntry.getTenantId());
        return response;
    }

    public List<HistoricActivityInstanceResponse> createHistoricActivityInstanceResponseList(List<HistoricActivityInstance> activityInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricActivityInstanceResponse> responseList = new ArrayList<>(activityInstances.size());
        for (HistoricActivityInstance instance : activityInstances) {
            responseList.add(createHistoricActivityInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricActivityInstanceResponse createHistoricActivityInstanceResponse(HistoricActivityInstance activityInstance) {
        return createHistoricActivityInstanceResponse(activityInstance, createUrlBuilder());
    }

    public HistoricActivityInstanceResponse createHistoricActivityInstanceResponse(HistoricActivityInstance activityInstance, RestUrlBuilder urlBuilder) {
        HistoricActivityInstanceResponse result = new HistoricActivityInstanceResponse();
        result.setActivityId(activityInstance.getActivityId());
        result.setActivityName(activityInstance.getActivityName());
        result.setActivityType(activityInstance.getActivityType());
        result.setAssignee(activityInstance.getAssignee());
        result.setCalledProcessInstanceId(activityInstance.getCalledProcessInstanceId());
        result.setDurationInMillis(activityInstance.getDurationInMillis());
        result.setEndTime(activityInstance.getEndTime());
        result.setExecutionId(activityInstance.getExecutionId());
        result.setId(activityInstance.getId());
        result.setProcessDefinitionId(activityInstance.getProcessDefinitionId());
        result.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, activityInstance.getProcessDefinitionId()));
        result.setProcessInstanceId(activityInstance.getProcessInstanceId());
        result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE, activityInstance.getProcessInstanceId()));
        result.setStartTime(activityInstance.getStartTime());
        result.setTaskId(activityInstance.getTaskId());
        result.setTenantId(activityInstance.getTenantId());
        return result;
    }

    public List<HistoricVariableInstanceResponse> createHistoricVariableInstanceResponseList(List<HistoricVariableInstance> variableInstances) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricVariableInstanceResponse> responseList = new ArrayList<>(variableInstances.size());
        for (HistoricVariableInstance instance : variableInstances) {
            responseList.add(createHistoricVariableInstanceResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricVariableInstanceResponse createHistoricVariableInstanceResponse(HistoricVariableInstance variableInstance) {
        return createHistoricVariableInstanceResponse(variableInstance, createUrlBuilder());
    }

    public HistoricVariableInstanceResponse createHistoricVariableInstanceResponse(HistoricVariableInstance variableInstance, RestUrlBuilder urlBuilder) {
        HistoricVariableInstanceResponse result = new HistoricVariableInstanceResponse();
        result.setId(variableInstance.getId());
        result.setProcessInstanceId(variableInstance.getProcessInstanceId());
        if (variableInstance.getProcessInstanceId() != null) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE, variableInstance.getProcessInstanceId()));
        }

        RestVariableScope scope;
        if (variableInstance.getExecutionId() != null && !variableInstance.getExecutionId().equals(variableInstance.getProcessInstanceId())
                || variableInstance.getTaskId() != null) {
            scope = RestVariableScope.LOCAL;
        } else {
            scope = RestVariableScope.GLOBAL;
        }
        result.setTaskId(variableInstance.getTaskId());
        result.setExecutionId(variableInstance.getExecutionId());
        result.setVariable(createRestVariable(variableInstance.getVariableName(), variableInstance.getValue(), scope, variableInstance.getId(),
                VARIABLE_HISTORY_VARINSTANCE, false, urlBuilder));
        return result;
    }

    public List<HistoricDetailResponse> createHistoricDetailResponse(List<HistoricDetail> detailList) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricDetailResponse> responseList = new ArrayList<>(detailList.size());
        for (HistoricDetail instance : detailList) {
            responseList.add(createHistoricDetailResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricDetailResponse createHistoricDetailResponse(HistoricDetail detail) {
        return createHistoricDetailResponse(detail, createUrlBuilder());
    }

    public HistoricDetailResponse createHistoricDetailResponse(HistoricDetail detail, RestUrlBuilder urlBuilder) {
        HistoricDetailResponse result = new HistoricDetailResponse();
        result.setId(detail.getId());
        result.setProcessInstanceId(detail.getProcessInstanceId());
        if (StringUtils.isNotEmpty(detail.getProcessInstanceId())) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE, detail.getProcessInstanceId()));
        }
        result.setExecutionId(detail.getExecutionId());
        result.setActivityInstanceId(detail.getActivityInstanceId());
        result.setTaskId(detail.getTaskId());
        if (StringUtils.isNotEmpty(detail.getTaskId())) {
            result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_TASK_INSTANCE, detail.getTaskId()));
        }
        result.setTime(detail.getTime());
        if (detail instanceof HistoricFormProperty) {
            HistoricFormProperty formProperty = (HistoricFormProperty) detail;
            result.setDetailType(HistoricDetailResponse.FORM_PROPERTY);
            result.setPropertyId(formProperty.getPropertyId());
            result.setPropertyValue(formProperty.getPropertyValue());
        } else if (detail instanceof HistoricVariableUpdate) {
            HistoricVariableUpdate variableUpdate = (HistoricVariableUpdate) detail;
            result.setDetailType(HistoricDetailResponse.VARIABLE_UPDATE);
            result.setRevision(variableUpdate.getRevision());
            result.setVariable(createRestVariable(variableUpdate.getVariableName(), variableUpdate.getValue(), null, detail.getId(), VARIABLE_HISTORY_DETAIL, false, urlBuilder));
        }
        return result;
    }

    public List<HistoricIdentityLinkResponse> createHistoricIdentityLinkResponseList(List<HistoricIdentityLink> identityLinks) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoricIdentityLinkResponse> responseList = new ArrayList<>(identityLinks.size());
        for (HistoricIdentityLink instance : identityLinks) {
            responseList.add(createHistoricIdentityLinkResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public HistoricIdentityLinkResponse createHistoricIdentityLinkResponse(HistoricIdentityLink identityLink) {
        return createHistoricIdentityLinkResponse(identityLink, createUrlBuilder());
    }

    public HistoricIdentityLinkResponse createHistoricIdentityLinkResponse(HistoricIdentityLink identityLink, RestUrlBuilder urlBuilder) {
        HistoricIdentityLinkResponse result = new HistoricIdentityLinkResponse();
        result.setType(identityLink.getType());
        result.setUserId(identityLink.getUserId());
        result.setGroupId(identityLink.getGroupId());
        result.setTaskId(identityLink.getTaskId());
        if (StringUtils.isNotEmpty(identityLink.getTaskId())) {
            result.setTaskUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_TASK_INSTANCE, identityLink.getTaskId()));
        }
        result.setProcessInstanceId(identityLink.getProcessInstanceId());
        if (StringUtils.isNotEmpty(identityLink.getProcessInstanceId())) {
            result.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORIC_PROCESS_INSTANCE, identityLink.getProcessInstanceId()));
        }
        return result;
    }

    public List<TableResponse> createTableResponseList(Map<String, Long> tableCounts) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<TableResponse> tables = new ArrayList<>(tableCounts.size());
        for (Entry<String, Long> entry : tableCounts.entrySet()) {
            tables.add(createTableResponse(entry.getKey(), entry.getValue(), urlBuilder));
        }
        return tables;
    }

    public TableResponse createTableResponse(String name, Long count) {
        return createTableResponse(name, count, createUrlBuilder());
    }

    public TableResponse createTableResponse(String name, Long count, RestUrlBuilder urlBuilder) {
        TableResponse result = new TableResponse();
        result.setName(name);
        result.setCount(count);
        result.setUrl(urlBuilder.buildUrl(RestUrls.URL_TABLE, name));
        return result;
    }

    public List<JobResponse> createJobResponseList(List<Job> jobs) {
        return createJobResponseList(jobs, RestUrls.URL_JOB);
    }

    public List<JobResponse> createTimerJobResponseList(List<Job> jobs) {
        return createJobResponseList(jobs, RestUrls.URL_TIMER_JOB);
    }

    public List<JobResponse> createSuspendedJobResponseList(List<Job> jobs) {
        return createJobResponseList(jobs, RestUrls.URL_SUSPENDED_JOB);
    }

    public List<JobResponse> createDeadLetterJobResponseList(List<Job> jobs) {
        return createJobResponseList(jobs, RestUrls.URL_DEADLETTER_JOB);
    }

    protected List<JobResponse> createJobResponseList(List<Job> jobs, String[] urlJobSegments) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<JobResponse> responseList = new ArrayList<>(jobs.size());
        for (Job instance : jobs) {
            responseList.add(createJobResponse(instance, urlBuilder, urlJobSegments));
        }
        return responseList;
    }

    public JobResponse createJobResponse(Job job) {
        return createJobResponse(job, createUrlBuilder());
    }

    public JobResponse createTimerJobResponse(Job job) {
        return createJobResponse(job, createUrlBuilder(), RestUrls.URL_TIMER_JOB);
    }

    public JobResponse createSuspendedJobResponse(Job job) {
        return createJobResponse(job, createUrlBuilder(), RestUrls.URL_SUSPENDED_JOB);
    }

    public JobResponse createDeadLetterJobResponse(Job job) {
        return createJobResponse(job, createUrlBuilder(), RestUrls.URL_DEADLETTER_JOB);
    }

    public JobResponse createJobResponse(Job job, RestUrlBuilder urlBuilder) {
        return createJobResponse(job, urlBuilder, RestUrls.URL_JOB);
    }

    protected JobResponse createJobResponse(Job job, RestUrlBuilder urlBuilder, String[] urlJobSegments) {
        JobResponse response = new JobResponse();
        response.setId(job.getId());
        response.setCorrelationId(job.getCorrelationId());
        response.setDueDate(job.getDuedate());
        response.setExceptionMessage(job.getExceptionMessage());
        response.setExecutionId(job.getExecutionId());
        response.setProcessDefinitionId(job.getProcessDefinitionId());
        response.setProcessInstanceId(job.getProcessInstanceId());
        response.setElementId(job.getElementId());
        response.setElementName(job.getElementName());
        response.setRetries(job.getRetries());
        response.setCreateTime(job.getCreateTime());
        response.setTenantId(job.getTenantId());

        response.setUrl(urlBuilder.buildUrl(urlJobSegments, job.getId()));

        if (job.getProcessDefinitionId() != null) {
            response.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, job.getProcessDefinitionId()));
        }

        if (job.getProcessInstanceId() != null) {
            response.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, job.getProcessInstanceId()));
        }

        if (job.getExecutionId() != null) {
            response.setExecutionUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION, job.getExecutionId()));
        }

        return response;
    }

    public List<HistoryJobResponse> createHistoryJobResponseList(List<HistoryJob> jobs) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<HistoryJobResponse> responseList = new ArrayList<>(jobs.size());
        for (HistoryJob job : jobs) {
            responseList.add(createHistoryJobResponse(job, urlBuilder));
        }
        return responseList;
    }

    public HistoryJobResponse createHistoryJobResponse(HistoryJob job) {
        return createHistoryJobResponse(job, createUrlBuilder());
    }

    public HistoryJobResponse createHistoryJobResponse(HistoryJob job, RestUrlBuilder urlBuilder) {
        HistoryJobResponse response = new HistoryJobResponse();
        response.setId(job.getId());
        response.setExceptionMessage(job.getExceptionMessage());
        response.setRetries(job.getRetries());
        response.setCreateTime(job.getCreateTime());
        response.setScopeType(job.getScopeType());
        response.setJobHandlerType(job.getJobHandlerType());
        response.setJobHandlerConfiguration(job.getJobHandlerConfiguration());
        response.setCustomValues(job.getCustomValues());
        response.setTenantId(job.getTenantId());

        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_HISTORY_JOB, job.getId()));

        return response;
    }

    public List<BatchResponse> createBatchResponse(List<Batch> batches) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<BatchResponse> responseList = new ArrayList<>(batches.size());
        for (Batch instance : batches) {
            responseList.add(createBatchResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public BatchResponse createBatchResponse(Batch batch) {
        return createBatchResponse(batch, createUrlBuilder());
    }

    public BatchResponse createBatchResponse(Batch batch, RestUrlBuilder urlBuilder) {
        BatchResponse response = new BatchResponse();
        response.setId(batch.getId());
        response.setBatchType(batch.getBatchType());
        response.setSearchKey(batch.getBatchSearchKey());
        response.setSearchKey2(batch.getBatchSearchKey2());
        response.setCreateTime(batch.getCreateTime());
        response.setCompleteTime(batch.getCompleteTime());
        response.setStatus(batch.getStatus());
        response.setTenantId(batch.getTenantId());

        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_BATCH, batch.getId()));

        return response;
    }

    public List<BatchPartResponse> createBatchPartResponse(List<BatchPart> batchParts) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<BatchPartResponse> responseList = new ArrayList<>(batchParts.size());
        for (BatchPart instance : batchParts) {
            responseList.add(createBatchPartResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public BatchPartResponse createBatchPartResponse(BatchPart batchPart) {
        return createBatchPartResponse(batchPart, createUrlBuilder());
    }

    public BatchPartResponse createBatchPartResponse(BatchPart batchPart, RestUrlBuilder urlBuilder) {
        BatchPartResponse response = new BatchPartResponse();
        response.setId(batchPart.getId());
        response.setBatchId(batchPart.getBatchId());
        response.setBatchType(batchPart.getBatchType());
        response.setSearchKey(batchPart.getBatchSearchKey());
        response.setSearchKey2(batchPart.getBatchSearchKey2());
        response.setScopeId(batchPart.getScopeId());
        response.setSubScopeId(batchPart.getSubScopeId());
        response.setScopeType(batchPart.getScopeType());
        response.setCreateTime(batchPart.getCreateTime());
        response.setCompleteTime(batchPart.getCompleteTime());
        response.setStatus(batchPart.getStatus());
        response.setTenantId(batchPart.getTenantId());

        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_BATCH_PART, batchPart.getId()));
        response.setBatchUrl(urlBuilder.buildUrl(RestUrls.URL_BATCH, batchPart.getBatchId()));

        return response;
    }

    public List<EventSubscriptionResponse> createEventSubscriptionResponseList(List<EventSubscription> eventSubscriptions) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<EventSubscriptionResponse> responseList = new ArrayList<>(eventSubscriptions.size());
        for (EventSubscription instance : eventSubscriptions) {
            responseList.add(createEventSubscriptionResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public EventSubscriptionResponse createEventSubscriptionResponse(EventSubscription eventSubscription) {
        return createEventSubscriptionResponse(eventSubscription, createUrlBuilder());
    }

    public EventSubscriptionResponse createEventSubscriptionResponse(EventSubscription eventSubscription, RestUrlBuilder urlBuilder) {
        EventSubscriptionResponse response = new EventSubscriptionResponse();
        response.setId(eventSubscription.getId());
        response.setCreated(eventSubscription.getCreated());
        response.setEventType(eventSubscription.getEventType());
        response.setEventName(eventSubscription.getEventName());
        response.setActivityId(eventSubscription.getActivityId());
        response.setExecutionId(eventSubscription.getExecutionId());
        response.setProcessDefinitionId(eventSubscription.getProcessDefinitionId());
        response.setProcessInstanceId(eventSubscription.getProcessInstanceId());
        response.setScopeId(eventSubscription.getScopeId());
        response.setScopeType(eventSubscription.getScopeType());
        response.setSubScopeId(eventSubscription.getSubScopeId());
        response.setScopeDefinitionId(eventSubscription.getScopeDefinitionId());
        response.setConfiguration(eventSubscription.getConfiguration());
        response.setTenantId(eventSubscription.getTenantId());

        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_EVENT_SUBSCRIPTION, eventSubscription.getId()));

        if (eventSubscription.getProcessDefinitionId() != null) {
            response.setProcessDefinitionUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION, eventSubscription.getProcessDefinitionId()));
        }

        if (eventSubscription.getProcessInstanceId() != null) {
            response.setProcessInstanceUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_INSTANCE, eventSubscription.getProcessInstanceId()));
        }

        if (eventSubscription.getExecutionId() != null) {
            response.setExecutionUrl(urlBuilder.buildUrl(RestUrls.URL_EXECUTION, eventSubscription.getExecutionId()));
        }

        return response;
    }

    public List<UserResponse> createUserResponseList(List<User> users) {
        return createUserResponseList(users, false);
    }

    public List<UserResponse> createUserResponseList(List<User> users, boolean includePassword) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<UserResponse> responseList = new ArrayList<>(users.size());
        for (User instance : users) {
            responseList.add(createUserResponse(instance, includePassword, urlBuilder));
        }
        return responseList;
    }

    public UserResponse createUserResponse(User user, boolean includePassword) {
        return createUserResponse(user, includePassword, createUrlBuilder());
    }

    public UserResponse createUserResponse(User user, boolean incudePassword, RestUrlBuilder urlBuilder) {
        UserResponse response = new UserResponse();
        response.setFirstName(user.getFirstName());
        response.setLastName(user.getLastName());
        response.setDisplayName(user.getDisplayName());
        response.setId(user.getId());
        response.setEmail(user.getEmail());
        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_USER, user.getId()));
        response.setTenantId(user.getTenantId());

        if (incudePassword) {
            response.setPassword(user.getPassword());
        }

        if (user.isPictureSet()) {
            response.setPictureUrl(urlBuilder.buildUrl(RestUrls.URL_USER_PICTURE, user.getId()));
        }
        return response;
    }

    public List<UserInfoResponse> createUserInfoKeysResponse(List<String> keys, String userId) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<UserInfoResponse> responseList = new ArrayList<>(keys.size());
        for (String instance : keys) {
            responseList.add(createUserInfoResponse(instance, null, userId, urlBuilder));
        }
        return responseList;
    }

    public UserInfoResponse createUserInfoResponse(String key, String value, String userId) {
        return createUserInfoResponse(key, value, userId, createUrlBuilder());
    }

    public UserInfoResponse createUserInfoResponse(String key, String value, String userId, RestUrlBuilder urlBuilder) {
        UserInfoResponse response = new UserInfoResponse();
        response.setKey(key);
        response.setValue(value);
        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_USER_INFO, userId, key));
        return response;
    }

    public List<GroupResponse> createGroupResponseList(List<Group> groups) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<GroupResponse> responseList = new ArrayList<>(groups.size());
        for (Group instance : groups) {
            responseList.add(createGroupResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public GroupResponse createGroupResponse(Group group) {
        return createGroupResponse(group, createUrlBuilder());
    }

    public GroupResponse createGroupResponse(Group group, RestUrlBuilder urlBuilder) {
        GroupResponse response = new GroupResponse();
        response.setId(group.getId());
        response.setName(group.getName());
        response.setType(group.getType());
        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_GROUP, group.getId()));

        return response;
    }

    public MembershipResponse createMembershipResponse(String userId, String groupId) {
        return createMembershipResponse(userId, groupId, createUrlBuilder());
    }

    public MembershipResponse createMembershipResponse(String userId, String groupId, RestUrlBuilder urlBuilder) {
        MembershipResponse response = new MembershipResponse();
        response.setGroupId(groupId);
        response.setUserId(userId);
        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_GROUP_MEMBERSHIP, groupId, userId));
        return response;
    }

    public List<ModelResponse> createModelResponseList(List<Model> models) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<ModelResponse> responseList = new ArrayList<>(models.size());
        for (Model instance : models) {
            responseList.add(createModelResponse(instance, urlBuilder));
        }
        return responseList;
    }

    public ModelResponse createModelResponse(Model model) {
        return createModelResponse(model, createUrlBuilder());
    }

    public ModelResponse createModelResponse(Model model, RestUrlBuilder urlBuilder) {
        ModelResponse response = new ModelResponse();

        response.setCategory(model.getCategory());
        response.setCreateTime(model.getCreateTime());
        response.setId(model.getId());
        response.setKey(model.getKey());
        response.setLastUpdateTime(model.getLastUpdateTime());
        response.setMetaInfo(model.getMetaInfo());
        response.setName(model.getName());
        response.setDeploymentId(model.getDeploymentId());
        response.setVersion(model.getVersion());
        response.setTenantId(model.getTenantId());

        response.setUrl(urlBuilder.buildUrl(RestUrls.URL_MODEL, model.getId()));
        if (model.getDeploymentId() != null) {
            response.setDeploymentUrl(urlBuilder.buildUrl(RestUrls.URL_DEPLOYMENT, model.getDeploymentId()));
        }

        if (model.hasEditorSource()) {
            response.setSourceUrl(urlBuilder.buildUrl(RestUrls.URL_MODEL_SOURCE, model.getId()));
        }

        if (model.hasEditorSourceExtra()) {
            response.setSourceExtraUrl(urlBuilder.buildUrl(RestUrls.URL_MODEL_SOURCE_EXTRA, model.getId()));
        }

        return response;
    }

    public List<DecisionResponse> createDecisionResponseList(List<DmnDecision> decisions, String processDefinitionId) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<DecisionResponse> responseList = new ArrayList<>(decisions.size());
        for (DmnDecision decision : decisions) {
            responseList.add(createDecisionResponse(decision, processDefinitionId, urlBuilder));
        }
        return responseList;
    }

    public DecisionResponse createDecisionResponse(DmnDecision decision, String processDefinitionId) {
        return createDecisionResponse(decision, processDefinitionId, createUrlBuilder());
    }

    public DecisionResponse createDecisionResponse(DmnDecision decision, String processDefinitionId, RestUrlBuilder urlBuilder) {
        DecisionResponse decisionResponse = new DecisionResponse(decision);
        decisionResponse.setUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION_DECISION_COLLECTION, processDefinitionId));

        return decisionResponse;
    }

    public List<FormDefinitionResponse> createFormDefinitionResponseList(List<FormDefinition> formDefinitions, String processDefinitionId) {
        RestUrlBuilder urlBuilder = createUrlBuilder();
        List<FormDefinitionResponse> responseList = new ArrayList<>(formDefinitions.size());
        for (FormDefinition formDefinition : formDefinitions) {
            responseList.add(createFormDefinitionResponse(formDefinition, processDefinitionId, urlBuilder));
        }
        return responseList;
    }

    public FormDefinitionResponse createFormDefintionResponse(FormDefinition formDefinition, String processDefinitionId) {
        return createFormDefinitionResponse(formDefinition, processDefinitionId, createUrlBuilder());
    }

    public FormDefinitionResponse createFormDefinitionResponse(FormDefinition formDefinition, String processDefinitionId, RestUrlBuilder urlBuilder) {
        FormDefinitionResponse formDefinitionResponse = new FormDefinitionResponse(formDefinition);
        formDefinitionResponse.setUrl(urlBuilder.buildUrl(RestUrls.URL_PROCESS_DEFINITION_FORM_DEFINITIONS_COLLECTION, processDefinitionId));

        return formDefinitionResponse;
    }

    /**
     * @return list of {@link RestVariableConverter} which are used by this factory. Additional converters can be added and existing ones replaced ore removed.
     */
    public List<RestVariableConverter> getVariableConverters() {
        return variableConverters;
    }

    /**
     * Called once when the converters need to be initialized. Override of custom conversion needs to be done between java and rest.
     */
    protected void initializeVariableConverters() {
        variableConverters.add(new StringRestVariableConverter());
        variableConverters.add(new IntegerRestVariableConverter());
        variableConverters.add(new LongRestVariableConverter());
        variableConverters.add(new ShortRestVariableConverter());
        variableConverters.add(new DoubleRestVariableConverter());
        variableConverters.add(new BooleanRestVariableConverter());
        variableConverters.add(new DateRestVariableConverter());
        variableConverters.add(new InstantRestVariableConverter());
        variableConverters.add(new LocalDateRestVariableConverter());
        variableConverters.add(new LocalDateTimeRestVariableConverter());
        variableConverters.add(new JsonObjectRestVariableConverter(objectMapper));
    }

    protected String formatUrl(String serverRootUrl, String[] fragments, Object... arguments) {
        StringBuilder urlBuilder = new StringBuilder(serverRootUrl);
        for (String urlFragment : fragments) {
            urlBuilder.append("/");
            urlBuilder.append(MessageFormat.format(urlFragment, arguments));
        }
        return urlBuilder.toString();
    }

    protected RestUrlBuilder createUrlBuilder() {
        return RestUrlBuilder.fromCurrentRequest();
    }

}


text:
The Servant (engl. der Diener) ist die Bezeichnung

 eines Films von Joseph Losey aus dem Jahre 1963, siehe Der Diener (1963).

 einer Band, die sich nach dem Film benannt hat, siehe The Servant (Band).

redpajama_set_name: RedPajamaWikipedia


I would like to introduce you to an easy yet effective meditation technique, quite provocatively named, "The Quickie". No, no, it's not what you think! I first learned about the exercise from one of my favourite teachers, Dr Aviva Romm, and have found it to be a powerful, on-the-go technique that is easy to learn and practice. I've then taken it to the next level by adding acupressure to it, to supercharge this technique for maximum impact.
So, are you ready to learn more?


text:
Lusahowit – wieś w Armenii, w prowincji Tawusz. W 2011 roku liczyła 364 mieszkańców.

Miejscowości w prowincji Tawusz


Knowing that coconut oil can help treat acne, some acne sufferers simply smear coconut oil on their pimply face and then expect their skin to clear in a couple of days. But what they normally get is an acne breakout... more severe than before they use coconut oil. Why?
This is because coconut oil is a powerful anti-toxin – it will draw toxins up to the surface of your skin as it gets deeper into the skin (our skin cells do store certain amount of toxins). And when your skin has more dead cells clogging the pores, those toxins can't find a way out and so pimples in the form of whiteheads start to pop up. What's even worse is that your existing pimples will grow even larger due to the expulsion of toxins.
Hence, you need a breakout-free method of using coconut oil for treating acne. Otherwise you'll end up like many others who freak out and then run back to using commercial products that will keep burying more toxic chemicals underneath your skin.
Non-organic coconut oil may contain unknown (and harmful) chemicals and other contaminants that will make your skin even worse by depositing them into your skin.
There are essentially two types of coconut oil – one meant for skin care (external) use only while the other you can use on your skin as well as eat it. So, get the type which is edible too. The best would be unrefined virgin coconut oil.
Eating coconut oil can help to detoxify your body so your body won't have too much toxins to get stored in your skin. And when your skin has got less toxic deposits, you won't easily suffer an acne breakout when you use coconut oil on your skin for acne.
Always keep in mind that you should not slather coconut oil on your skin. Our skin gets saturated easily. So, just put a dab of coconut oil and then rub it on the acne zone until the oil gets absorbed. That's the first layer. And re-apply subsequent thin layers as often as you deem necessary. Make sure you cleanse your face and skin thoroughly before application to enhance the absorption.
If you use on your skin and consume coconut oil for acne, you should not suffer any breakout easily. Even if you do, the breakout should not appear too severe. Don't quit just yet. Stick through the "healing crisis" and allow coconut oil ample time to help clear your acne and heal your skin. It could take up to several weeks if your skin has got lots of toxins to clear. But the reward is incredibly immeasurable if you're able to brave through it.


text:
NetApp Strengthens Board of Directors with New Appointments
Sunnyvale, Calif. - November 15, 2017 -
NetApp, Inc. (NASDAQ: NTAP) today announced that Deborah Kerr, former EVP and chief product and technology officer at Sabre, and Scott Schenkel, CFO at eBay, have joined its board of directors.
Deborah Kerr brings keen insights into the ways customers are buying, deploying, managing, and using IT. In her various roles, including as the chief product and technology officer at Sabre and Fair Isaac, as well as in leadership roles at Hewlett Packard and Peregrine Systems, Ms. Kerr has developed a deep understanding of customer priorities, digital transformation, and the future of IT.
Scott Schenkel, CFO of eBay, brings current C-level experience to NetApp's board, with his understanding of the technology landscape and market forces, capital structure, and modern financial reporting. With more than 10 years in e-commerce at eBay and nearly 17 years with General Electric, Mr. Schenkel brings extensive global business and financial leadership experience from large, complex, IT-driven organizations in multiple industries.
"The addition of Deborah and Scott further strengthens our board," said NetApp Chairman of the Board Mike Nevens. "They will be a valuable resource for our executive team at a time when NetApp has an unprecedented opportunity to grow our business and deliver value to shareholders."
"I am delighted to welcome Deborah and Scott to our board," added George Kurian, chief executive officer at NetApp. "Their understanding of our evolving markets and customers' data-driven digital transformations, combined with their deep business experience, will be of tremendous benefit as we continue our transformation and deliver sustained and profitable growth."
For more information about NetApp's board of directors, go to investors.netapp.com/directors.cfm.
NetApp is the data authority for hybrid cloud. We provide a full range of hybrid cloud data services that simplify management of applications and data across cloud and on-premises environments to accelerate digital transformation. Together with our partners, we empower global organizations to unleash the full potential of their data to expand customer touchpoints, foster greater innovation, and optimize their operations. For more information, visit www.netapp.com. #DataDriven
Madge Miller
NetApp Inc.
ng-uspr@netapp.com
Kris Newton
kris.newton@netapp.com
NETAPP, the NETAPP logo, and the marks listed at www.netapp.com/TM are trademarks of NetApp, Inc. Other company and product names may be trademarks of their respective owners.
NetApp Reports Second Quarter Fiscal Year 2018 Results
NetApp Press Releases

redpajama_set_name: RedPajamaCommonCrawl


Published 04/21/2019 11:05:49 pm at 04/21/2019 11:05:49 pm in Bamboo Trees Images.
bamboo trees images worm view of bamboo trees bamboo plant images hd with names.
bamboo images silhouettes,bambou images of flowers,lucky bamboo plant images,golden bamboo plant images,black bamboo plant images,bamboo plant images hd,bambou images,bamboo images for house number plate,buddha bamboo plant images,bamboo images with white background,willowy green bamboo plant images.


A Pawpaw looks like a mango, tastes like banana custard, grows across the broad range of 26 U.S. states, shows up in fossil records from 56 million years ago! Gardener and writer Andrew Moore's new book dishes the amazing story of this versatile fruit and the handsome tree that produces it.
What happened in recent history to drop the Pawpaw off our cultural menu, when it had been so well loved (and spooned up) by Native Americans, enslaved Africans - even 20th century opponents of Prohibition? And what potentials is the Pawpaw offering today for local food economies, cocktail wizards and even cancer researchers?
Hear this great story - and consider a couple of Pawpaw trees to plant some tasty biodiversity where you live. Forgotten fruit? Earthworms is thinking that's history!
Clif Bar wrappers, shampoo tubes, chip bags - even cigarette butts? TerraCycle accepts and recycles them all! At the Missouri Botanical Garden in St. Louis, the in-house Green Team makes this sustainability service available to employees and volunteers.
Hear how from Joyce Gorrell, Sustainability Events Coordinator for the Garden's EarthWays Center. But be forewarned: you may catch the TerraCycling bug for your school, business, church or institution. If you do, tell 'em Earthworms sent you!
And - hear the intrepid story of Terracycle direct from its founder, Tom Szaky in Earthworms exclusive conversation with this Recycling Rock Star!
As a Princeton student in 2001, Tom Szaky packaged and sold the liquified worm poop he produced to super-feed special plants. From those beginnings (including selling to the "world's largest retailer" in reused plastic bottles purchased from school kids) Tom founded Terracycle, a powerhouse non-profit where "up-cycling" resourcefulness is Eliminating the Idea of Waste®.
Innovator, entrepreneur, media figure Tom Szaky is an Environmental Rock Star! He spoke in September 2015 to the Missouri Recycling Association Conference - and to Earthworms host Jean Ponzi in this extended one-on-one conversation. Don't miss it!
Tom talks about the "why" and impressive impacts of Terracycle's unique material collection and repurposing systems. Jean also talks with Joyce Gorrell, her colleague at the Missouri Botanical Garden, who serves on the Garden's Green Team and manages an extensive internal Terracycle practice for Garden employees.
TerraCycle works with more than 100 major brands in the U.S. and 22 countries overseas to collect used packaging and products that would otherwise be destined for landfills. It repurposes that waste into new, innovative materials and products that are available online and through major retailers. Thousands of school, business and community organizations TerraCycle, around the world.
Wes Jackson - Growing Our Food Crops as Prairies?
What if the grains we eat could be grown in a biodiverse ecosystem - like a prairie - instead of fossil fuel and chemical-intensive row-cropping? The Land Institute, a research non-profit in Salina, Kansas, has been working wth plants to achive this goal for nearly 40 years.
As TLI's founder and president Wes Jackson explains, humankind's decision (10,000 years ago!) to eat annual, instead of perennial, plants has spawned an agriculture that rips up the Earth and overwhelms natural communities. But his team's work is showing the way to reverse these consequences, by crossing our grain mainstays with their wild perennial relatives.
It's a ground-restoring body of work!
Wes and Joan Jackson welcome Jean Ponzi for a tour and interview.
This conversation, recorded on Earthworms' Summer Vacation, is a very special one-on-one with one of the environmental greats of our time, biologist Wes Jackson.


text:
Kathryn Bridget Moynahan (born April 28, 1971 height 5' 9½" (1,77 m)), best known as Bridget Moynahan, is an American model and actress. After graduating from Longmeadow High School in 1989, Moynahan pursued a career in modeling. She was signed by a modeling agency, which led her to appear in department store catalogs and the covers of widely known magazines. After doing television commercials, sh... Read more
The database contains 79 images with Bridget Moynahan, divided over 13 titles.
2017 John Wick: Chapter Two 1/80
2014 John Wick 1/51
2010 Ramona and Beezus 2/9
2010 "Blue Bloods" 7/41
2007 Prey 4/7
2006 Gray Matters 4/13
2006 "Six Degrees" 5/23
2005 Lord Of War 6/94
2004 I, Robot 15/62
2003 The Recruit 5/20
2002 The Sum Of All Fears 1/20
2001 Serendipity 1/28
2000 Coyote Ugly 27/74
5760 * 3840 John Wick: Chapter Two 2017
4424 * 2740 John Wick 2014
2835 * 1890 Coyote Ugly 2000
3900 * 2598 I, Robot 2004
2000 * 3008 Lord Of War 2005
1536 * 1020 Ramona and Beezus 2010
1600 * 897 I, Robot 2004
2464 * 1632 Prey 2007


Several of the island's young entrepreneurs were able to showcase their innovative products at the Junior Achievement Asia Pacific Company of the Year Competition in the Philippines. The top two companies from this year's JA program, Astrea from Simon Sanchez High School and Napu, competed for the title of "Company of the Year" at the international competition consisting of teen entrepreneurs from Singapore, China, Japan, Thailand, Guam, South Korea, Hong Kong, and Malaysia.
The competition spanned over the course of several days. The first day consisted of a series icebreakers in which all the competitors were encouraged to meet other competitors through games and activities. Companies conducted stage presentations and panel interviews in front of judges on the second day.
For Roxanne Mikel, the CEO of Napu and a St. John's junior, said the second day was the tensest. "The second day was pretty nerve-wracking since everyone knew this was a big portion of evaluation for being Company of the Year. But through it all, different companies were encouraging one another...and there was nothing to worry about," Mikel explained. On the third day, each company had the opportunity to set up a booth and showcase their products.
"This was extremely fun because lots of the people from the other companies bought my company's product, the sea glass jewelry, and really loved it. Likewise, I bought some products from the other companies as a souvenir and momentum to remember them by," Mikel recalled.
Devin Patawaran, the vice president of marketing of Astrea, was shocked by the relaxed atmosphere of the competition.
"The only thing that I was surprised by was that the competition didn't feel like a competition because we made good friendships with the people there...It felt more like a bonding experience with all of them," described the Simon Sanchez junior.
Both Patawaran and Mikel find that attending the competition has inspired them to progress in the business world.
"I've wanted to pursue a career in business before JA because I am in the GCC Course of Marketing, but JA has pushed me more to pursue owning my own busin9beess," Patawaran explained.
Julie Cheng, the vice president of finance for Napu, finds that experience has allowed her to look at the world a different way.
"The trip broadened my horizon of what other countries are like based on other people's personal experience. At some point, the world became more real. The trip also taught me about what it is like to become a young entrepreneur. You want to create a market and ultimately, make the world a better place," the St. John's junior stated.
The Junior Achievement of Guam is a nonprofit organization dedicated to cultivating young entrepreneurs and spreading economic awareness among teens. Having served over 5000 students, the organization has been active in teen entrepreneurship outreach since 1976 according to the JA website.


text:
Raúl Márquez Hernández is a Puerto Rican lawyer who served as the Secretary of State of Puerto Rico since August 31, 2020 till January 2, 2021. He was the campaign director of Wanda Vázquez Garced during the 2020 Puerto Rico gubernatorial election. Márquez Hernández was as a contractor and advisor for the legislators Ricardo Llerandi, Gabriel Rodríguez Aguiló, and mayor Carlos Molina and worked closely with Gabriel Rodríguez Aguiló.

Márquez Hernández completed a B.A. at University of Puerto Rico, Río Piedras and a J.D. at Pontifical Catholic University of Puerto Rico School of Law. He earned a LL.M. at Interamerican University of Puerto Rico in litigation and alternate dispute resolution on 2016.

References

20th-century births
21st-century Puerto Rican lawyers
Interamerican University of Puerto Rico alumni
Living people
New Progressive Party (Puerto Rico) politicians
Pontifical Catholic University of Puerto Rico alumni
Secretaries of State of Puerto Rico
University of Puerto Rico, Río Piedras Campus alumni
Year of birth missing (living people)


Our foot's in the door.
A PoetryNotes™ Analysis of Mushrooms by Sylvia Plath, is Available!
URL: http://plagiarist.com/poetry/1416/ | Viewed on 23 April 2019.
©1998-2019 Plagiarist.com. All rights reserved. | 150,279,322 served.


Huxley Global Limited is a UK registered company headquartered at London and a leading exporter of agri-commodities and metals. Huxleys leadership team have several decades of operating experience across the United Kingdom and Africa with well-established networks and partnerships. Every day we use our expertise and experience backed with strong infrastructure network to distribute agro-commodities and metals around the world, efficiently and responsibly.
Should follow rules as laid down by company.
N25,000 monthly + applicable overtime + sunday working allowance + shared accomodation with other drivers.


text:
National Alliance for Hispanic Health Announces Support for CDC's Televised Línea de Ayuda Smoki
WASHINGTON, May 3, 2017 /PRNewswire-USNewswire/ -- "With tobacco companies estimated to spend $9.1 billion this year to addict new customers, the CDC's Línea de Ayuda and Tips Campaign are critical tools to make sure all our communities know the real costs of tobacco use, nicotine addiction, and how to get help to quit," said Dr. Jane L. Delgado, President and CEO of the National Alliance for Hispanic Health (the Alliance), the nation's leading Hispanic health advocacy group.
This month CDC is airing Línea de Ayuda (Helpline), a telethon-style event on 15 Telemundo television network affiliate stations around the country. Línea de Ayuda will air in prime time and feature four 90-second spots where Dr. Ralph Caraballo, CDC Chief Epidemiologist, will be interviewed about smoking-related illnesses, health benefits from quitting, and accessing free help to quit. Each segment directs callers to the Spanish-language Quitline, 1-855-DÉJELO-YA (1-800-QUIT-NOW), for support.
Línea de Ayuda will air in Philadelphia, Dallas, Tampa and Atlanta (May 4); Orlando, El Paso, Las Vegas and Phoenix (May 11); Puerto Rico, McAllen, TX and Denver (May 18); and, New York, Chicago, Houston and Albuquerque (May 25). The 2017 Spanish and English language Tips Campaign ads are also airing nationwide on television and radio through July to bring attention to the risks of smoking. The ads feature former smokers who describe the health consequences they have suffered, motivate others to quit, and promote free cessation support available through Quitlines.
The Alliance is promoting the Línea de Ayuda television events and the broader Tips Campaign through its Nuestras Voces (Our Voices) Network, spearheaded by 11 regional partners around the country, which works to reduce tobacco use and cancer incidence in Hispanic communities. Activities to support these efforts include individual cessation support, bilingual social media, and local media outreach.
"The individual stories told in the Línea de Ayuda and Tips campaigns represent similar experiences of the over 16 million Americans suffering from illnesses caused by smoking and give encouragement to smokers to quit and others not to start. We are proud to support these efforts, including through the Alliance's Su Familia Helpline at 1-866-783-2645 where callers can get information in Spanish and English on quitting smoking, talking to a loved one about smoking, or connecting to health services in their communities," emphasized Dr. Delgado.
About the Nuestras Voces Network. Nuestras Voces is a national network of over 200 members working for a tobacco-free world and to eliminate disparities in cancer prevention and treatment services. You can be part of this effort being led by the National Alliance for Hispanic Health! Join us at www.nuestrasvoces.org/join.
About the National Alliance for Hispanic Health. The Alliance is the nation's foremost science-based source of information and trusted advocate for the health of Hispanics in the United States with a mission to achieve the best health outcomes for all. For more information visit us www.healthyamericas.org.
SOURCE National Alliance for Hispanic Health


text:
Prototype Online: Jacob Rosenberg explores the skate world through his films
Founding Fragments
Filmmaker Jacob Rosenberg knows more than a little about the skate world. A former skater himself, Rosenberg grew up with skateboarder Danny Way, whose 2005 jump over the Great Wall of China is the stuff of legend. Rosenberg talks about his personal connection to skating and its significance in American culture. He also reflects on his work as a maker of documentary films, especially his inspirational portrait of Danny Way in Waiting for Lightning.
pod_rosenberg.mp3