text:
package com.thinkbiganalytics.metadata.jpa.jobrepo.job;

import com.google.common.collect.ImmutableList;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.ConstructorExpression;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.thinkbiganalytics.DateTimeUtil;
import com.thinkbiganalytics.jobrepo.common.constants.CheckDataStepConstants;
import com.thinkbiganalytics.jobrepo.common.constants.FeedConstants;
import com.thinkbiganalytics.metadata.api.SearchCriteria;
import com.thinkbiganalytics.metadata.api.event.MetadataEventService;
import com.thinkbiganalytics.metadata.api.event.feed.FeedOperationStatusEvent;
import com.thinkbiganalytics.metadata.api.event.feed.OperationStatus;
import com.thinkbiganalytics.metadata.api.feed.OpsManagerFeed;
import com.thinkbiganalytics.metadata.api.jobrepo.ExecutionConstants;
import com.thinkbiganalytics.metadata.api.jobrepo.job.BatchJobExecution;
import com.thinkbiganalytics.metadata.api.jobrepo.job.BatchJobExecutionProvider;
import com.thinkbiganalytics.metadata.api.jobrepo.job.BatchJobInstance;
import com.thinkbiganalytics.metadata.api.jobrepo.job.BatchRelatedFlowFile;
import com.thinkbiganalytics.metadata.api.jobrepo.job.JobStatusCount;
import com.thinkbiganalytics.metadata.api.jobrepo.step.BatchStepExecutionProvider;
import com.thinkbiganalytics.metadata.api.op.FeedOperation;
import com.thinkbiganalytics.metadata.config.RoleSetExposingSecurityExpressionRoot;
import com.thinkbiganalytics.metadata.jpa.feed.FeedAclIndexQueryAugmentor;
import com.thinkbiganalytics.metadata.jpa.feed.JpaOpsManagerFeed;
import com.thinkbiganalytics.metadata.jpa.feed.OpsManagerFeedRepository;
import com.thinkbiganalytics.metadata.jpa.feed.QJpaOpsManagerFeed;
import com.thinkbiganalytics.metadata.jpa.feed.QOpsManagerFeedId;
import com.thinkbiganalytics.metadata.jpa.jobrepo.nifi.JpaNifiEventJobExecution;
import com.thinkbiganalytics.metadata.jpa.jobrepo.nifi.NifiRelatedRootFlowFilesRepository;
import com.thinkbiganalytics.metadata.jpa.support.CommonFilterTranslations;
import com.thinkbiganalytics.metadata.jpa.support.GenericQueryDslFilter;
import com.thinkbiganalytics.metadata.jpa.support.QueryDslFetchJoin;
import com.thinkbiganalytics.metadata.jpa.support.QueryDslPagingSupport;
import com.thinkbiganalytics.nifi.provenance.model.ProvenanceEventRecordDTO;
import com.thinkbiganalytics.security.AccessController;
import com.thinkbiganalytics.support.FeedNameUtil;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.ReadablePeriod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.inject.Inject;
import javax.persistence.OptimisticLockException;

/**
 * Provider for the {@link JpaBatchJobExecution}
 */
@Service
public class JpaBatchJobExecutionProvider extends QueryDslPagingSupport<JpaBatchJobExecution> implements BatchJobExecutionProvider {

    private static final Logger log = LoggerFactory.getLogger(JpaBatchJobExecutionProvider.class);

    private static String PARAM_TB_JOB_TYPE = "tb.jobType";

    @Autowired
    private JPAQueryFactory factory;

    private BatchJobExecutionRepository jobExecutionRepository;

    private BatchJobInstanceRepository jobInstanceRepository;

    private BatchJobParametersRepository jobParametersRepository;

    private OpsManagerFeedRepository opsManagerFeedRepository;

    private NifiRelatedRootFlowFilesRepository relatedRootFlowFilesRepository;

    @Inject
    private BatchStepExecutionProvider batchStepExecutionProvider;

    private BatchRelatedFlowFileRepository batchRelatedFlowFileRepository;

    @Inject
    private AccessController controller;

    @Inject
    private MetadataEventService eventService;

    @Autowired
    public JpaBatchJobExecutionProvider(BatchJobExecutionRepository jobExecutionRepository, BatchJobInstanceRepository jobInstanceRepository,
                                        NifiRelatedRootFlowFilesRepository relatedRootFlowFilesRepository,
                                        BatchJobParametersRepository jobParametersRepository,
                                        OpsManagerFeedRepository opsManagerFeedRepository,
                                        BatchRelatedFlowFileRepository batchRelatedFlowFileRepository
    ) {
        super(JpaBatchJobExecution.class);
        this.jobExecutionRepository = jobExecutionRepository;
        this.jobInstanceRepository = jobInstanceRepository;
        this.relatedRootFlowFilesRepository = relatedRootFlowFilesRepository;
        this.jobParametersRepository = jobParametersRepository;
        this.opsManagerFeedRepository = opsManagerFeedRepository;
        this.batchRelatedFlowFileRepository = batchRelatedFlowFileRepository;

    }

    @Override
    public BatchJobInstance createJobInstance(ProvenanceEventRecordDTO event) {

        JpaBatchJobInstance jobInstance = new JpaBatchJobInstance();
        jobInstance.setJobKey(jobKeyGenerator(event));
        jobInstance.setJobName(event.getFeedName());
        //wire this instance to the Feed
        OpsManagerFeed feed = opsManagerFeedRepository.findByName(event.getFeedName());
        jobInstance.setFeed(feed);
        BatchJobInstance batchJobInstance = this.jobInstanceRepository.save(jobInstance);
        return batchJobInstance;
    }

    /**
     * Generate a Unique key for the Job Instance table This code is similar to what was used by Spring Batch
     */
    private String jobKeyGenerator(ProvenanceEventRecordDTO event) {

        StringBuffer stringBuffer = new StringBuffer(event.getEventTime() + "").append(event.getFlowFileUuid());
        MessageDigest digest1;
        try {
            digest1 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException var10) {
            throw new IllegalStateException("MD5 algorithm not available.  Fatal (should be in the JDK).");
        }

        try {
            byte[] e1 = digest1.digest(stringBuffer.toString().getBytes("UTF-8"));
            return String.format("%032x", new Object[]{new BigInteger(1, e1)});
        } catch (UnsupportedEncodingException var9) {
            throw new IllegalStateException("UTF-8 encoding not available.  Fatal (should be in the JDK).");
        }

    }

    /**
     * Crate a new job exection from a provenance event
     *
     * @param event the provenance event indicating it is the start of a job
     * @return the job execution
     */
    private JpaBatchJobExecution createNewJobExecution(ProvenanceEventRecordDTO event) {
        BatchJobInstance jobInstance = createJobInstance(event);
        JpaBatchJobExecution jobExecution = createJobExecution(jobInstance, event);

        return jobExecution;
    }

    /**
     * Create a new Job Execution record from a given Provenance Event
     *
     * @param jobInstance the job instance to relate this job execution to
     * @param event       the event that started this job execution
     * @return the job execution
     */
    private JpaBatchJobExecution createJobExecution(BatchJobInstance jobInstance, ProvenanceEventRecordDTO event) {

        JpaBatchJobExecution jobExecution = new JpaBatchJobExecution();
        jobExecution.setJobInstance(jobInstance);
        //add in the parameters from the attributes
        jobExecution.setCreateTime(DateTimeUtil.getNowUTCTime());
        jobExecution.setStartTime(DateTimeUtil.convertToUTC(event.getEventTime()));
        jobExecution.setStatus(BatchJobExecution.JobStatus.STARTED);
        jobExecution.setExitCode(ExecutionConstants.ExitCode.EXECUTING);
        jobExecution.setLastUpdated(DateTimeUtil.getNowUTCTime());

        //create the job params
        Map<String, Object> jobParameters = new HashMap<>();
        if (event.isStartOfJob() && event.getAttributeMap() != null) {
            jobParameters = new HashMap<>(event.getAttributeMap());
        } else {
            jobParameters = new HashMap<>();
        }

        //save the params
        JpaNifiEventJobExecution eventJobExecution = new JpaNifiEventJobExecution(jobExecution, event.getEventId(), event.getJobFlowFileId());
        jobExecution.setNifiEventJobExecution(eventJobExecution);
        jobExecution = this.jobExecutionRepository.save(jobExecution);
        //bootstrap the feed parameters
        jobParameters.put(FeedConstants.PARAM__FEED_NAME, event.getFeedName());
        jobParameters.put(FeedConstants.PARAM__JOB_TYPE, FeedConstants.PARAM_VALUE__JOB_TYPE_FEED);
        Set<JpaBatchJobExecutionParameter> jpaJobParameters = addJobParameters(jobExecution, jobParameters);
        this.jobParametersRepository.save(jpaJobParameters);
        return jobExecution;
    }

    /**
     * add parameters to a job execution
     *
     * @param jobExecution  the job execution
     * @param jobParameters the parameters to add to the {@code jobExecution}
     * @return the newly created job parameters
     */
    private Set<JpaBatchJobExecutionParameter> addJobParameters(JpaBatchJobExecution jobExecution, Map<String, Object> jobParameters) {
        Set<JpaBatchJobExecutionParameter> jobExecutionParametersList = new HashSet<>();
        for (Map.Entry<String, Object> entry : jobParameters.entrySet()) {
            JpaBatchJobExecutionParameter jobExecutionParameters = jobExecution.addParameter(entry.getKey(), entry.getValue());
            jobExecutionParametersList.add(jobExecutionParameters);
        }
        return jobExecutionParametersList;
    }

    /**
     * Check to see if the NifiEvent has the attributes indicating it is a Check Data Job
     */
    private boolean isCheckDataJob(ProvenanceEventRecordDTO event) {
        if (event.getAttributeMap() != null) {
            String jobType = event.getAttributeMap().get(NIFI_JOB_TYPE_PROPERTY);
            if (StringUtils.isBlank(jobType)) {
                jobType = event.getAttributeMap().get(NIFI_KYLO_JOB_TYPE_PROPERTY);
            }
            return StringUtils.isNotBlank(jobType) && FeedConstants.PARAM_VALUE__JOB_TYPE_CHECK.equalsIgnoreCase(jobType);
        }
        return false;
    }

    /**
     * Sets the Job Execution params to either Check Data or Feed Jobs
     */
    private boolean updateJobType(BatchJobExecution jobExecution, ProvenanceEventRecordDTO event) {

        if (event.getUpdatedAttributes() != null && (event.getUpdatedAttributes().containsKey(NIFI_JOB_TYPE_PROPERTY) || event.getUpdatedAttributes().containsKey(NIFI_KYLO_JOB_TYPE_PROPERTY))) {
            String jobType = event.getUpdatedAttributes().get(NIFI_JOB_TYPE_PROPERTY);
            if (StringUtils.isBlank(jobType)) {
                jobType = event.getUpdatedAttributes().get(NIFI_KYLO_JOB_TYPE_PROPERTY);
            }
            String nifiCategory = event.getAttributeMap().get(NIFI_CATEGORY_PROPERTY);
            String nifiFeedName = event.getAttributeMap().get(NIFI_FEED_PROPERTY);
            String feedName = FeedNameUtil.fullName(nifiCategory, nifiFeedName);
            if (FeedConstants.PARAM_VALUE__JOB_TYPE_CHECK.equalsIgnoreCase(jobType)) {
                Set<JpaBatchJobExecutionParameter> updatedParams = ((JpaBatchJobExecution) jobExecution).setAsCheckDataJob(feedName);
                jobParametersRepository.save(updatedParams);

                //update feed type
                JpaOpsManagerFeed checkDataFeed = (JpaOpsManagerFeed) opsManagerFeedRepository.findByName(event.getFeedName());
                checkDataFeed.setFeedType(OpsManagerFeed.FeedType.CHECK);
                //relate to this feed
                JpaOpsManagerFeed feedToCheck = (JpaOpsManagerFeed) opsManagerFeedRepository.findByName(feedName);
                feedToCheck.getCheckDataFeeds().add(checkDataFeed);

                return true;
            }
        }
        return false;
    }

    /**
     * When the job is complete determine its status, write out execution context, and determine if all related jobs are complete
     */
    private void finishJob(ProvenanceEventRecordDTO event, JpaBatchJobExecution jobExecution) {

        if (jobExecution.getJobExecutionId() == null) {
            log.error("Warning execution id is null for ending event {} ", event);
        }
        if (event.isStream()) {
            jobExecution.finishStreamingJob();
        } else {
            if (event.isFailure()) {  //event.hasFailureEvents
                jobExecution.failJob();
            } else {
                jobExecution.completeJob();
            }
        }

        //ensure check data jobs are property failed if they dont pass
        if (isCheckDataJob(event)) {
            String valid = event.getAttributeMap().get(CheckDataStepConstants.VALIDATION_KEY);
            String msg = event.getAttributeMap().get(CheckDataStepConstants.VALIDATION_MESSAGE_KEY);
            if (StringUtils.isNotBlank(valid)) {
                if (!BooleanUtils.toBoolean(valid)) {
                    jobExecution.failJob();
                }
            }
            if (StringUtils.isNotBlank(msg)) {
                jobExecution.setExitMessage(msg);
            }
        }

        jobExecution.setEndTime(DateTimeUtil.convertToUTC(event.getEventTime()));
        log.info("Finishing Job: {} with a status of: {} for event: {} ", jobExecution.getJobExecutionId(), jobExecution.getStatus(), event.getEventId());
        //add in execution contexts
        Map<String, String> allAttrs = event.getAttributeMap();
        if (allAttrs != null && !allAttrs.isEmpty()) {
            for (Map.Entry<String, String> entry : allAttrs.entrySet()) {
                JpaBatchJobExecutionContextValue executionContext = new JpaBatchJobExecutionContextValue(jobExecution, entry.getKey());
                executionContext.setStringVal(entry.getValue());
                jobExecution.addJobExecutionContext(executionContext);

                if (entry.getKey().equals(BatchJobExecutionProvider.NIFI_JOB_EXIT_DESCRIPTION_PROPERTY)) {
                    String msg = jobExecution.getExitMessage() != null ? jobExecution.getExitMessage() + "\n" : "";
                    msg += entry.getValue();
                    jobExecution.setExitMessage(msg);
                }
            }
        }

    }

    public JpaBatchJobExecution findJobExecution(ProvenanceEventRecordDTO event) {
        return jobExecutionRepository.findByFlowFile(event.getJobFlowFileId());
    }

    /**
     * Get or Create the JobExecution for a given ProvenanceEvent
     */
    @Override
    public synchronized JpaBatchJobExecution getOrCreateJobExecution(ProvenanceEventRecordDTO event, OpsManagerFeed feed) {
        if (event.isStream()) {
            //Streams only care about start/stop events to track.. otherwise we can disregard the events)
            if (event.isStartOfJob() || event.isFinalJobEvent()) {
                return getOrCreateStreamJobExecution(event);
            } else {
                return null;
            }
        } else {
            if (feed == null) {
                feed = opsManagerFeedRepository.findByName(event.getFeedName());
            }
            if (isProcessBatchEvent(event, feed)) {
                return getOrCreateBatchJobExecution(event);
            } else {
                return null;
            }
        }

    }

    private BatchRelatedFlowFile getOtherBatchJobFlowFile(ProvenanceEventRecordDTO event) {

        BatchRelatedFlowFile relatedFlowFile = batchRelatedFlowFileRepository.findOne(event.getJobFlowFileId());
        return relatedFlowFile;
    }

    private Long timeBetweenStartingJobs(OpsManagerFeed feed) {
        Long time = null;
        if (feed != null) {
            time = feed.getTimeBetweenBatchJobs();
        }
        if (time == null) {
            time = 1000L;
        }
        return time;
    }

    private BatchRelatedFlowFile relateFlowFiles(String eventFlowFileId, String batchJobExecutionFlowFile, Long batchJobExecutionId) {
        JpaBatchRelatedFlowFile relatedFlowFile = new JpaBatchRelatedFlowFile(eventFlowFileId, batchJobExecutionFlowFile, batchJobExecutionId);
        return batchRelatedFlowFileRepository.save(relatedFlowFile);
    }

    private boolean isProcessBatchEvent(ProvenanceEventRecordDTO event, OpsManagerFeed feed) {

        //if we have a job already for this event then let it pass
        JpaBatchJobExecution jobExecution = jobExecutionRepository.findByFlowFile(event.getJobFlowFileId());
        if (jobExecution != null) {
            return true;
        } else {
            jobExecution = (JpaBatchJobExecution) findLatestJobForFeed(event.getFeedName());

            if (jobExecution != null) {
                String jobFlowFile = jobExecution.getNifiEventJobExecution().getFlowFileId();
                if (jobFlowFile.equals(event.getJobFlowFileId())) {
                    return true;
                } else {
                    boolean isSkipped = getOtherBatchJobFlowFile(event) != null;
                    Long diff = event.getEventTime() - jobExecution.getStartTime().getMillis();
                    Long threshold = timeBetweenStartingJobs(feed);
                    if (!isSkipped && threshold != -1 && jobExecution != null && diff >= 0 && diff < threshold) {

                        //relate this to that and return
                        BatchRelatedFlowFile related = getOtherBatchJobFlowFile(event);
                        if (related == null) {
                            relateFlowFiles(event.getJobFlowFileId(), jobFlowFile, jobExecution.getJobExecutionId());
                            event.setJobFlowFileId(jobFlowFile);
                            log.debug("Relating {} to {}, {} ", event.getJobFlowFileId(), jobFlowFile, jobExecution.getJobExecutionId());
                        }
                        return false;
                    } else {
                        return !isSkipped;
                    }
                }

            }
        }
        return true;

    }

    private JpaBatchJobExecution getOrCreateBatchJobExecution(ProvenanceEventRecordDTO event) {
        JpaBatchJobExecution jobExecution = null;
        boolean isNew = false;
        try {
            jobExecution = jobExecutionRepository.findByFlowFile(event.getJobFlowFileId());
            if (jobExecution == null) {
                jobExecution = createNewJobExecution(event);
                isNew = true;
            }
        } catch (OptimisticLockException e) {
            //read
            jobExecution = jobExecutionRepository.findByFlowFile(event.getJobFlowFileId());
        }

        //if the attrs coming in change the type to a CHECK job then update the entity
        boolean updatedJobType = updateJobType(jobExecution, event);
        boolean save = isNew || updatedJobType;
        if (event.isFinalJobEvent()) {
            finishJob(event, jobExecution);
            save = true;
        }

        //if the event is the start of the Job, but the job execution was created from another downstream event, ensure the start time and event are related correctly
        if (event.isStartOfJob() && !isNew) {
            jobExecution.getNifiEventJobExecution().setEventId(event.getEventId());
            jobExecution.setStartTime(DateTimeUtil.convertToUTC(event.getEventTime()));
            //create the job params
            Map<String, Object> jobParameters = new HashMap<>();
            if (event.isStartOfJob() && event.getAttributeMap() != null) {
                jobParameters = new HashMap<>(event.getAttributeMap());
            } else {
                jobParameters = new HashMap<>();
            }

            this.jobParametersRepository.save(addJobParameters(jobExecution, jobParameters));
            save = true;
        }
        if (save) {
            jobExecution = jobExecutionRepository.save(jobExecution);
            if (isNew) {
                log.info("Created new Job Execution with id of {} and starting event {} ", jobExecution.getJobExecutionId(), event);
            }

        }
        return jobExecution;
    }

    private JpaBatchJobExecution getOrCreateStreamJobExecution(ProvenanceEventRecordDTO event) {
        JpaBatchJobExecution jobExecution = null;
        boolean isNew = false;
        try {
            BatchJobExecution latestJobExecution = findLatestJobForFeed(event.getFeedName());
            if (latestJobExecution == null || (latestJobExecution != null && !latestJobExecution.isStream())) {
                //If the latest Job is not set to be a Stream and its still running we need to fail it and create the new streaming job.
                if (latestJobExecution != null && !latestJobExecution.isFinished()) {
                    ProvenanceEventRecordDTO tempFailedEvent = new ProvenanceEventRecordDTO();
                    tempFailedEvent.setFeedName(event.getFeedName());
                    tempFailedEvent.setAttributeMap(new HashMap<>());
                    tempFailedEvent.setIsFailure(true);
                    tempFailedEvent.setDetails("Failed Running Batch event as this Feed has now become a Stream");
                    finishJob(tempFailedEvent, (JpaBatchJobExecution) latestJobExecution);
                    latestJobExecution.setExitMessage("Failed Running Batch event as this Feed has now become a Stream");
                    jobExecutionRepository.save((JpaBatchJobExecution) latestJobExecution);
                }

                jobExecution = createNewJobExecution(event);
                jobExecution.setStream(true);
                log.info("Created new Streaming Job Execution with id of {} and starting event {} ", jobExecution.getJobExecutionId(), event);
            } else {
                jobExecution = (JpaBatchJobExecution) latestJobExecution;
            }
        } catch (OptimisticLockException e) {
            //read
            jobExecution = (JpaBatchJobExecution) findLatestJobForFeed(event.getFeedName());
        }

        boolean save = isNew;

        if (!jobExecution.isStream()) {
            jobExecution.setStream(true);
            save = true;
        }

        if (save) {
            jobExecutionRepository.save(jobExecution);
        }
        return jobExecution;
    }

    @Override
    public BatchJobExecution save(BatchJobExecution jobExecution, ProvenanceEventRecordDTO event) {
        if (jobExecution == null) {
            return null;
        }
        batchStepExecutionProvider.createStepExecution(jobExecution, event);
        return jobExecution;
    }

    /**
     * Save the job execution in the database
     *
     * @return the saved job execution
     */
    @Override
    public BatchJobExecution save(ProvenanceEventRecordDTO event) {
        OpsManagerFeed feed = opsManagerFeedRepository.findByName(event.getFeedName());
        JpaBatchJobExecution jobExecution = getOrCreateJobExecution(event, feed);
        if (jobExecution != null) {
            return save(jobExecution, event);
        }
        return null;
    }

    /**
     * Save a job execution to the database
     *
     * @return the saved job execution
     */
    @Override
    public BatchJobExecution save(BatchJobExecution jobExecution) {
        return jobExecutionRepository.save((JpaBatchJobExecution) jobExecution);
    }

    @Override
    public BatchJobExecution findByJobExecutionId(Long jobExecutionId) {
        return jobExecutionRepository.findOne(jobExecutionId);
    }

    @Override
    public List<? extends BatchJobExecution>  findRunningJobsForFeed(String feedName) {
     List<? extends BatchJobExecution> jobs = jobExecutionRepository.findJobsForFeedMatchingStatus(feedName,BatchJobExecution.JobStatus.STARTED, BatchJobExecution.JobStatus.STARTING);
     return jobs != null ? jobs : Collections.emptyList();
    }

    /**
     * Find all the job executions for a feed that have been completed since a given date
     *
     * @param feedName  the feed to check
     * @param sinceDate the min end date for the jobs on the {@code feedName}
     * @return the job executions for a feed that have been completed since a given date
     */
    @Override
    public Set<? extends BatchJobExecution> findJobsForFeedCompletedSince(String feedName, DateTime sinceDate) {
        return jobExecutionRepository.findJobsForFeedCompletedSince(feedName, sinceDate);
    }

    @Override
    public BatchJobExecution findLatestCompletedJobForFeed(String feedName) {
        List<JpaBatchJobExecution> jobExecutions = jobExecutionRepository.findLatestCompletedJobForFeed(feedName);
        if (jobExecutions != null && !jobExecutions.isEmpty()) {
            return jobExecutions.get(0);
        } else {
            return null;
        }
    }

    @Override
    public BatchJobExecution findLatestJobForFeed(String feedName) {
        List<JpaBatchJobExecution> jobExecutions = jobExecutionRepository.findLatestJobForFeed(feedName);
        if (jobExecutions != null && !jobExecutions.isEmpty()) {
            return jobExecutions.get(0);
        } else {
            return null;
        }
    }

    @Override
    public Boolean isFeedRunning(String feedName) {
        return jobExecutionRepository.isFeedRunning(feedName);
    }

    /**
     * Find all BatchJobExecution objects with the provided filter. the filter needs to match
     *
     * @return a paged result set of all the job executions matching the incoming filter
     */
    @Override
    public Page<? extends BatchJobExecution> findAll(String filter, Pageable pageable) {
        QJpaBatchJobExecution jobExecution = QJpaBatchJobExecution.jpaBatchJobExecution;
        //if the filter contains a filter on the feed then delegate to the findAllForFeed method to include any check data jobs
        List<SearchCriteria> searchCriterias = GenericQueryDslFilter.parseFilterString(filter);
        SearchCriteria feedFilter = searchCriterias.stream().map(searchCriteria -> searchCriteria.withKey(CommonFilterTranslations.resolvedFilter(jobExecution, searchCriteria.getKey()))).filter(
            sc -> sc.getKey().equalsIgnoreCase(CommonFilterTranslations.jobExecutionFeedNameFilterKey)).findFirst().orElse(null);
        if (feedFilter != null && feedFilter.getPreviousSearchCriteria() != null && !feedFilter.isValueCollection()) {
            //remove the feed filter from the list and filter by this feed
            searchCriterias.remove(feedFilter.getPreviousSearchCriteria());
            String feedValue = feedFilter.getValue().toString();
            //remove any quotes around the feedValue
            feedValue = feedValue.replaceAll("^\"|\"$", "");
            return findAllForFeed(feedValue, searchCriterias, pageable);
        } else {
            pageable = CommonFilterTranslations.resolveSortFilters(jobExecution, pageable);
            QJpaBatchJobInstance jobInstancePath = new QJpaBatchJobInstance("jobInstance");
            QJpaOpsManagerFeed feedPath = new QJpaOpsManagerFeed("feed");

            return findAllWithFetch(jobExecution,
                                    GenericQueryDslFilter.buildFilter(jobExecution, filter).and(augment(feedPath.id)),
                                    pageable,
                                    QueryDslFetchJoin.innerJoin(jobExecution.nifiEventJobExecution),
                                    QueryDslFetchJoin.innerJoin(jobExecution.jobInstance, jobInstancePath),
                                    QueryDslFetchJoin.innerJoin(jobInstancePath.feed, feedPath)
            );
        }

    }

    private Predicate augment(QOpsManagerFeedId id) {
        return FeedAclIndexQueryAugmentor.generateExistsExpression(id, controller.isEntityAccessControlled());
    }

    private RoleSetExposingSecurityExpressionRoot getUserContext() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return new RoleSetExposingSecurityExpressionRoot(authentication);
    }

    private Page<? extends BatchJobExecution> findAllForFeed(String feedName, List<SearchCriteria> filters, Pageable pageable) {
        QJpaBatchJobExecution jobExecution = QJpaBatchJobExecution.jpaBatchJobExecution;
        QJpaOpsManagerFeed feed = QJpaOpsManagerFeed.jpaOpsManagerFeed;
        QJpaOpsManagerFeed checkDataFeed = new QJpaOpsManagerFeed("checkDataFeed");
        QJpaBatchJobInstance jobInstance = QJpaBatchJobInstance.jpaBatchJobInstance;
        JPQLQuery checkFeedQuery = JPAExpressions.select(checkDataFeed.id).from(feed).join(feed.checkDataFeeds, checkDataFeed).where(feed.name.eq(feedName));

        JPAQuery
            query = factory.select(jobExecution)
            .from(jobExecution)
            .join(jobExecution.jobInstance, jobInstance)
            .join(jobInstance.feed, feed)
            .where((feed.name.eq(feedName).or(feed.id.in(checkFeedQuery)))
                       .and(GenericQueryDslFilter.buildFilter(jobExecution, filters)
                                .and(augment(feed.id))))
            .fetchAll();

        pageable = CommonFilterTranslations.resolveSortFilters(jobExecution, pageable);
        return findAll(query, pageable);
    }

    /**
     * Get count of Jobs grouped by Status
     */
    @Override
    public List<JobStatusCount> getJobStatusCount(String filter) {

        QJpaBatchJobExecution jobExecution = QJpaBatchJobExecution.jpaBatchJobExecution;

        QJpaBatchJobInstance jobInstance = QJpaBatchJobInstance.jpaBatchJobInstance;

        QJpaOpsManagerFeed feed = QJpaOpsManagerFeed.jpaOpsManagerFeed;

        List<BatchJobExecution.JobStatus> runningStatus = ImmutableList.of(BatchJobExecution.JobStatus.STARTED, BatchJobExecution.JobStatus.STARTING);

        com.querydsl.core.types.dsl.StringExpression jobState = new CaseBuilder().when(jobExecution.status.eq(BatchJobExecution.JobStatus.FAILED)).then("FAILED")
            .when(jobExecution.status.in(runningStatus)).then("RUNNING")
            .otherwise(jobExecution.status.stringValue());

        BooleanBuilder whereBuilder = new BooleanBuilder();
        if (StringUtils.isNotBlank(filter)) {
            whereBuilder.and(GenericQueryDslFilter.buildFilter(jobExecution, filter));
        }

        ConstructorExpression<JpaBatchJobExecutionStatusCounts> expr =
            Projections.constructor(JpaBatchJobExecutionStatusCounts.class,
                                    jobState.as("status"),
                                    jobExecution.jobExecutionId.count().as("count"));

        JPAQuery<?> query = factory.select(expr)
            .from(jobExecution)
            .innerJoin(jobInstance).on(jobExecution.jobInstance.jobInstanceId.eq(jobInstance.jobInstanceId))
            .innerJoin(feed).on(jobInstance.feed.id.eq(feed.id))
            .where(whereBuilder
                       .and(FeedAclIndexQueryAugmentor.generateExistsExpression(feed.id, controller.isEntityAccessControlled())))
            .groupBy(jobExecution.status);

        return (List<JobStatusCount>) query.fetch();
    }

    @Override
    public List<JobStatusCount> getJobStatusCountByDate() {

        QJpaBatchJobExecution jobExecution = QJpaBatchJobExecution.jpaBatchJobExecution;

        QJpaBatchJobInstance jobInstance = QJpaBatchJobInstance.jpaBatchJobInstance;

        QJpaOpsManagerFeed feed = QJpaOpsManagerFeed.jpaOpsManagerFeed;

        List<BatchJobExecution.JobStatus> runningStatus = ImmutableList.of(BatchJobExecution.JobStatus.STARTED, BatchJobExecution.JobStatus.STARTING);

        com.querydsl.core.types.dsl.StringExpression jobState = new CaseBuilder().when(jobExecution.status.eq(BatchJobExecution.JobStatus.FAILED)).then("FAILED")
            .when(jobExecution.status.in(runningStatus)).then("RUNNING")
            .otherwise(jobExecution.status.stringValue());

        JPAQuery
            query = factory.select(
            Projections.constructor(JpaBatchJobExecutionStatusCounts.class,
                                    jobState.as("status"),
                                    jobExecution.startYear,
                                    jobExecution.startMonth,
                                    jobExecution.startDay,
                                    jobExecution.count().as("count")))
            .from(jobExecution)
            .innerJoin(jobInstance).on(jobExecution.jobInstance.jobInstanceId.eq(jobInstance.jobInstanceId))
            .innerJoin(feed).on(jobInstance.feed.id.eq(feed.id))
            .where(FeedAclIndexQueryAugmentor.generateExistsExpression(feed.id, controller.isEntityAccessControlled()))
            .groupBy(jobExecution.status, jobExecution.startYear, jobExecution.startMonth, jobExecution.startDay);

        return (List<JobStatusCount>) query.fetch();

    }

    /**
     * gets job executions grouped by status and Day looking back from Now - the supplied {@code period}
     *
     * @param period period to look back from the current time to get job execution status
     */
    @Override
    public List<JobStatusCount> getJobStatusCountByDateFromNow(ReadablePeriod period, String filter) {

        QJpaBatchJobExecution jobExecution = QJpaBatchJobExecution.jpaBatchJobExecution;

        QJpaBatchJobInstance jobInstance = QJpaBatchJobInstance.jpaBatchJobInstance;

        QJpaOpsManagerFeed feed = QJpaOpsManagerFeed.jpaOpsManagerFeed;

        List<BatchJobExecution.JobStatus> runningStatus = ImmutableList.of(BatchJobExecution.JobStatus.STARTED, BatchJobExecution.JobStatus.STARTING);

        com.querydsl.core.types.dsl.StringExpression jobState = new CaseBuilder().when(jobExecution.status.eq(BatchJobExecution.JobStatus.FAILED)).then("FAILED")
            .when(jobExecution.status.in(runningStatus)).then("RUNNING")
            .otherwise(jobExecution.status.stringValue());

        BooleanBuilder whereBuilder = new BooleanBuilder();
        whereBuilder.and(jobExecution.startTime.goe(DateTimeUtil.getNowUTCTime().minus(period)));
        if (StringUtils.isNotBlank(filter)) {
            whereBuilder.and(GenericQueryDslFilter.buildFilter(jobExecution, filter));
        }

        JPAQuery
            query = factory.select(
            Projections.constructor(JpaBatchJobExecutionStatusCounts.class,
                                    jobState.as("status"),
                                    jobExecution.startYear,
                                    jobExecution.startMonth,
                                    jobExecution.startDay,
                                    jobExecution.count().as("count")))
            .from(jobExecution)
            .innerJoin(jobInstance).on(jobExecution.jobInstance.jobInstanceId.eq(jobInstance.jobInstanceId))
            .innerJoin(feed).on(jobInstance.feed.id.eq(feed.id))
            .where(whereBuilder
                       .and(FeedAclIndexQueryAugmentor.generateExistsExpression(feed.id, controller.isEntityAccessControlled())))
            .groupBy(jobExecution.status, jobExecution.startYear, jobExecution.startMonth, jobExecution.startDay);

        return (List<JobStatusCount>) query.fetch();

    }

    public List<String> findRelatedFlowFiles(String flowFileId) {
        return relatedRootFlowFilesRepository.findRelatedFlowFiles(flowFileId);
    }

    public void notifyFailure(BatchJobExecution jobExecution, String feedName, String status) {
        if (feedName == null) {
            feedName = jobExecution.getJobInstance().getFeed().getName();
        }
        if (StringUtils.isBlank(status)) {
            status = "Failed Job";
        }
        FeedOperation.State state = FeedOperation.State.FAILURE;
        this.eventService.notify(new FeedOperationStatusEvent(new OperationStatus(feedName, new OpId(jobExecution.getJobExecutionId()), state, status)));
    }

    public void notifySuccess(BatchJobExecution jobExecution, String feedName, String status) {
        if (feedName == null) {
            feedName = jobExecution.getJobInstance().getFeed().getName();
        }
        if (StringUtils.isBlank(status)) {
            status = "Job Succeeded for feed: " + feedName;
        }
        FeedOperation.State state = FeedOperation.State.SUCCESS;
        this.eventService.notify(new FeedOperationStatusEvent(new OperationStatus(feedName, new OpId(jobExecution.getJobExecutionId()), state, status)));
    }

    /*
    public Page<? extends BatchJobExecution> findAllByExample(String filter, Pageable pageable){

        //construct new instance of JpaBatchExecution for searching
        JpaBatchJobExecution example = new JpaBatchJobExecution();
        example.setStatus(BatchJobExecution.JobStatus.valueOf("status"));
        ExampleMatcher matcher = ExampleMatcher.matching()
            .withIgnoreCase().withIgnoreCase(true);

      return   jobExecutionRepository.findAll(Example.of(example,matcher),pageable);

    }
    */

    protected static class OpId implements FeedOperation.ID {

        private final String idValue;

        public OpId(Serializable value) {
            this.idValue = value.toString();
        }

        @Override
        public boolean equals(Object obj) {
            if (getClass().isAssignableFrom(obj.getClass())) {
                OpId that = (OpId) obj;
                return Objects.equals(this.idValue, that.idValue);
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            return Objects.hash(getClass(), this.idValue);
        }

        @Override
        public String toString() {
            return this.idValue;
        }
    }

}

redpajama_set_name: RedPajamaGithub


text:
Coelosphaera dividuum är en svampdjursart som först beskrevs av Topsent 1927.  Coelosphaera dividuum ingår i släktet Coelosphaera och familjen Coelosphaeridae. Inga underarter finns listade i Catalogue of Life.

Källor

Horn- och kiselsvampar
dividuum

redpajama_set_name: RedPajamaWikipedia


Temperate grasslands occupy ~8% of the earth's terrestrial surface and are now considered the most altered and beleaguered ecosystem on the planet, with only 5.5% protected. Temperate grasslands used to be home to some of the greatest assemblages of wildlife on earth.
In 2005, the J.M. Kaplan Fund invited expressions of interest designed to enhance international communication and cooperation for the protection and conservation of the world's temperate grasslands. The Grasslands Protected Area Task Force of the World Commission on Protected Areas (WCPA) submitted a proposal and was awarded a grant - as a result the Temperate Grasslands Conservation Initiative (TGCI) was born.
The TGCI scheduled a workshop on June 28-29, 2008 in Hohhot, China, in conjunction with the joint International Grasslands Congress and the International Rangelands Congress, and invited 35 grassland specialists to attend, to develop an action plan with the following purpose and outcomes. Purpose: To reverse the trend of biodiversity loss and degradation of the temperate grassland biome by promoting both the designation and sustainable management of representative protected areas, and the widespread use of sustainable management practices beyond protected area boundaries, with the goal of at least doubling the current level of protection by 2014.
Producing a communications document that describes the global role, values and purpose of the temperate grasslands initiative.
Facilitating the establishment of regional action plans for East Asia and South America.
Developing a mechanism for improving international communications and cooperation related to temperate grasslands.
Promoting the benefits of transboundary protected area networks.
To provide information on the status of temperate grasslands, 15 participants completed a regional template document that was brought together into a Compendium. This compendium provides a 'world perspective' and will be helpful in both a global strategy and regional approaches in East Asia and South America. It was determined that the greatest potential for grasslands conservation on a landscape scale is in eastern Mongolia, the Kazakh steppe, the Patagonian steppe and the mixed and short grass prairie of North America.
There was much discussion at the workshop about the threats to the temperate grasslands biome with the focus on the low level of actual legal protection that protected areas offer and the many existing management challenges, such as: widespread livestock grazing, the introduction of exotic species, fire management and the loss of grasslands through urban and forest encroachment. Of these management challenges the most pervasive seems to be livestock grazing - with an overarching, yet not well understood, concern for global climate change. The importance of how 'grazing' is characterized was stressed, since when properly managed on a sustainable basis, grazing can be an effective practice for maintaining the biodiversity of most indigenous grasslands. However, the message is clear that temperate grasslands must be better managed if the trend toward habitat loss, fragmentation, loss of diversity and integrity, degradation and desertification is to be reversed.
There was a strong suggestion to build socio-economic instruments into our analysis as a stronger socioeconomic perspective strengthens the connection between temperate grasslands, human health, the economy and water security.


Why Not Be Your Personal Pet Insurance coverage Firm?
High quality pet insurance coverage insurance policies vary from $35-75 per thirty days relying on protection and deductibles. Why not put that very same quantity in a financial savings account in your pet(s)? In a single 12 months the account could be price $420-900. In accordance with the American Veterinary Medical Affiliation pet possession statistics, the common family spends solely $378 yearly for canines and $191 yearly for cats in veterinary care. Your account would simply cowl these bills.Over the lifetime of your canine, the account would develop to make sure care within the pet's later years. In case you thought-about yearly exams and vaccines as "a deductible" and paid them out of pocket as an alternative of the account, particularly through the early, wholesome years of your pet, the account would even be bigger within the later years.One other strategy to defend your pet financial savings account within the early years is to contemplate the addition of a "catastrophic" pet insurance coverage coverage. These are cheaper than main insurance policies and defend towards a critical damage or illness. Ultimately the coverage will be dropped because the saving account grows.Evaluation of pet insurance coverage insurance policies in Shopper Reviews agrees that self-insured pet plans are superior. The chances are in your favor that your pet financial savings account can have cash left after your pet is deceased. You keep the cash that may have been spent as month-to-month premiums and income for the insurance coverage firms. Feeding a top quality weight loss plan and maximizing your pet's well being will even decrease veterinary payments and enhance the worth of your pet financial savings account.
Is Pet Insurance coverage Actually Price It?


text:
Justia › US Law › Case Law › Illinois Case Law › Supreme Court of Illinois Decisions › 1993 › Postma v. Jack Brown Buick, Inc.
Postma v. Jack Brown Buick, Inc.
Ronald POSTMA, Appellant, v. JACK BROWN BUICK, INC., et al., Appellees.
November 18, 1993.
Rehearing Denied January 31, 1994.
*200 Richard Karr and Jonathan P. Geen, Hardt & Stern, P.C., Chicago, for appellant.
Louis H. Lindeman, Jr., Detroit, MI, and Richard C. Godfrey and J. Robert Robertson, Kirkland & Ellis, Chicago, for appellee General Motors Corp.
*201 Justice HARRISON delivered the opinion of the court:
Jack Brown owned a Buick dealership which he agreed to sell to Ronald Postma. When Brown sought General Motors' approval for the transfer, as required by the terms of his franchise agreement, the company decided to exercise its contractual right to buy the dealership itself. Postma responded by filing suit for injunctive relief in the circuit court of Cook County. He also moved for issuance of a preliminary injunction. The circuit court denied that motion, and its order was affirmed on interlocutory appeal (134 Ill.2d R. 307(a)) in an unpublished order (No. 1901546 (unpublished order under Supreme Court Rule 23)). We granted Postma leave to appeal (134 Ill.2d R. 315), 149 Ill. 2d 660, 183 Ill. Dec. 871, 612 N.E.2d 523, and now affirm.
The record before us shows that on February 14, 1990, Brown and Postma executed a written contract under which Postma agreed to purchase Brown's Buick dealership in Chicago Heights. By the terms of the contract, Postma was to pay Brown $100,000 plus other consideration and to lease from him the dealership premises and various items of personal property. The contract further provided that consummation of the transaction was contingent on approval of Postma as a dealer by the Buick Motor Division of General Motors. This approval contingency was necessary because article 3 of Brown's "Dealer Sales and Service Agreement" conferred on General Motors "the right to select each successor and replacement dealer and to approve its dealer operator and owners and the location of its dealership facilities."
Shortly after the contract was executed, Brown submitted a proposal to General Motors on Postma's behalf, asking that Postma's dealership application be approved. By letter dated March 2, 1990, General Motors formally rejected that proposal based on various enumerated deficiencies. It also advised Brown that it might exercise its "right of first refusal" under article 3.4 of the "Dealer Sales and Service Agreement." That provision provides:
"If a proposal by Dealer is not accepted by General Motors [as provided by this agreement] General Motors shall have a right of first refusal or option to purchase the dealership assets * * * in addition to whatever other rights the parties may have under this Agreement."
Article 3.4 further provides that where, as here, the dealer, i.e., Brown, has entered into a "bona fide buy/sell agreement" with respect to the dealership,
"General Motors[] right under this Article 3.4 shall be a right of first refusal, enabling General Motors to assume the buyer's rights and obligations under such buy/sell agreement [and] the purchase price and other terms shall be those set forth in such agreement and any related documents."
At the same time General Motors rejected the proposal, it offered to allow Brown to submit a new or revised proposal for further consideration. Supplemental materials were then forwarded to General Motors by Postma, but the company opted not to rescind its rejection of the proposal. Instead, it notified Brown that it would, in fact, exercise its contractual right of first refusal and buy the dealership itself. As required by its "Dealer Sales and Service Agreement" with Brown, it agreed to consummate the sale for the same price and under the same terms as specified in Brown's contract with Postma. Brown agreed that General Motors had the right to take such action and did not contest its decision.
With General Motor's actions, the contingency in Brown's contract with Postma requiring General Motors' approval could no longer be satisfied. Brown therefore regarded the contract to be terminated and so notified Postma. When Postma could not persuade Brown to sue General Motors, he filed suit against both General Motors and Brown in the circuit court of Cook County. Postma's complaint sought only injunctive relief and was in four counts. Count I was directed at Brown alone, while counts II through IV were directed solely at General Motors.
*202 In count I, Postma alleged that Brown had been wrong to regard their contract as terminated. Brown was wrong, in Postma's view, because General Motors' right of first refusal was invalid under both the "Dealer Sales and Service Agreement" and section 4(e)(11) of the Motor Vehicle Franchise Act (815 ILCS 710/4(e)(11) (West 1992)). Postma therefore requested (1) that Brown be enjoined from terminating the contract with Postma "unless and until valid grounds exist for termination," (2) that Brown be ordered to elicit from General Motors that company's "formal position on [Postma's] application to receive Brown's franchise," and (3) that Brown be enjoined from selling the dealership assets "until the above occurs."
Counts II through IV were likewise premised on the notion that General Motors' right of first refusal was invalid. Postma charged that by exercising that invalid right, and thereby causing Brown to declare his agreement with Postma to be at an end, General Motors was guilty of tortious interference with contract (count II), tortious interference with prospective business advantage (count III), and violation of the Motor Vehicle Franchise Act (815 ILCS 710/1 et seq. (West 1992)) (count IV). For his relief, Postma asked that General Motors be ordered to approve his application to be the successor franchisee to Brown and that the company be enjoined from exercising its right of first refusal and from purchasing the dealership for itself.
Six days after filing this complaint, Postma filed his motion for a preliminary injunction. The motion was opposed by both General Motors and Brown, and a hearing on the matter was convened by the circuit court. At the conclusion of that hearing, the circuit court denied Postma's motion, holding, inter alia, that Postma had little likelihood of success on the merits, that he had an adequate remedy at law, and that he lacked standing to sue under the Motor Vehicle Franchise Act. The court further held that Postma would be allowed to amend his complaint to assert a claim for damages.
Postma subsequently took an interlocutory appeal as of right pursuant to Supreme Court Rule 307(a)(1) (134 Ill.2d R. 307(a)(1)). On that appeal, Postma did not pursue his claim against Brown, nor did he challenge the denial of preliminary injunctive relief on his claims against General Motors for tortious interference with contract and tortious interference with prospective business advantage. The sole issue he raised was whether the circuit court erred in concluding that he lacked standing and therefore was not entitled to sue under the Motor Vehicle Franchise Act. As we have previously discussed, the appellate court affirmed. We then granted Postma's petition for leave to appeal, and the matter is now before us for review.
In upholding the circuit court's order denying preliminary injunctive relief, the appellate court not only agreed that Postma lacked standing to pursue a statutory claim, it also concluded that he had failed to show that he lacked an adequate remedy at law. In his petition for leave to appeal, in his brief and at oral argument before this court, Postma has not taken issue with the second of these holdings. Rather, he once again purports to limit his appeal solely to the issue of whether he has standing to pursue a statutory claim against General Motors under the Motor Vehicle Franchise Act. We do not reach this question, however, for even if we were to conclude that he possessed the requisite standing, there would still be no basis for reversing the determination that he was not entitled to a preliminary injunction.
Our analysis begins with the familiar principle that a preliminary injunction is merely provisional in nature and concludes no rights. (Spunar v. Clark Oil & Refining Corp. (1977), 53 Ill.App.3d 477, 481, 11 Ill. Dec. 382, 368 N.E.2d 990.) Its purpose is simply to preserve the status quo pending a decision on the merits of a cause. (Hartlein v. Illinois Power Co. (1992), 151 Ill. 2d 142, 156, 176 Ill. Dec. 22, 601 N.E.2d 720.) The status quo to be preserved by a preliminary injunction is the last, actual, peaceable, uncontested status which preceded the pending controversy. *203 (In re Marriage of Schwartz (1985), 131 Ill.App.3d 351, 354, 86 Ill. Dec. 698, 475 N.E.2d 1077.) Here, that would be the situation which existed immediately prior to General Motors' rejection of Brown's proposal for a transfer to Postma and its decision to exercise its right of first refusal.
A threshold problem with Postma's motion for a preliminary injunction against General Motors is that it did not seek to preserve this state of affairs. Instead, it asked for the same relief on an interim basis as Postma had requested in his underlying complaint for permanent injunctive relief. As our previous discussion has indicated, that basically amounted to compelling General Motors to approve Postma as a dealer so that he and not General Motors could take over the dealership. Because preliminary injunctions are improper where they tend to change the status quo of the parties rather than preserve it (Schwartz, 131 Ill.App.3d at 354, 86 Ill. Dec. 698, 475 N.E.2d 1077), allowing Postma's motion under these circumstances would have been an abuse of discretion.
Even if Postma had properly sought preservation of the status quo, we would be confronted with the additional problem that the status quo has now changed and there is no apparent way of restoring it. After the circuit court refused to preliminarily enjoin General Motors' purchase of Brown's dealership, the sale went forward as planned. Thereafter, a second transfer was made. The record does not disclose the dealership's present status, but counsel for Postma advised this court at oral argument that it is no longer owned by General Motors. Given that neither of the defendants in this case now owns the dealership, that the new owner has not been joined as a party, and that Postma has not appealed the denial of the preliminary injunction as to Brown, it is difficult to see how we could now order that the dealership be placed back under Brown's ownership.
When confronted with this problem, counsel for Postma candidly acknowledged that preliminary injunctive relief may no longer be appropriate and that Postma may be limited to pursuing money damages. He suggested, however, his client's entitlement to preliminary injunctive relief is no longer of primary concern. As argued in the appellate court and in this court, Postma's principle objective in pursuing this appeal has simply been to obtain a ruling that he has standing to bring an action under the Motor Vehicle Franchise Act. According to Postma's counsel, the circuit court's adverse ruling on this issue was tantamount to a final judgment on his statutory claim and could have been appealed under Supreme Court Rule 304(a) (134 Ill.2d R. 304(a)). He chose to pursue this objective by means of a Rule 307(a)(1) (134 Ill.2d R. 307(a)(1)) appeal instead merely because it afforded the most expeditious avenue for obtaining review of the issue.
The flaw in this strategy is that it overlooks the limited scope of review on a Rule 307(a)(1) appeal. In such an appeal, the only question properly before the reviewing court is whether there was a sufficient showing made to the trial court to sustain its order granting or denying the interlocutory relief sought. (Hartlein, 151 Ill. 2d at 157, 176 Ill. Dec. 22, 601 N.E.2d 720.) The rule may not be used as a vehicle to determine the merits of a plaintiff's case. (See Buzz Barton & Associates, Inc. v. Giannone (1985), 108 Ill. 2d 373, 386, 91 Ill. Dec. 636, 483 N.E.2d 1271.) Accordingly, once Postma has ceased to press his claim that he is entitled to preliminary injunctive relief, the justification for his Rule 307(a)(1) appeal evaporates. Moreover, we cannot now allow him to treat this appeal as if it had been brought pursuant to Rule 304(a). This is so because the circuit court did not make an express written finding that there is no just reason for delaying enforcement or appeal, as required by the rule (Marsh v. Evangelical Covenant Church (1990), 138 Ill. 2d 458, 464-69, 150 Ill. Dec. 572, 563 N.E.2d 459), and Postma does not contend that the circuit court erred in not entering such a finding.
Finally, we note that even if Postma were still interested in obtaining preliminary injunctive relief and the status quo *204 could somehow be restored, his appeal would fail. As a general rule, a preliminary injunction will only be granted where a plaintiff shows (1) that he has a clearly ascertainable right that needs protection, (2) that he will suffer irreparable harm without the protection, (3) that he has no adequate remedy at law, and (4) that he is likely to succeed on the merits. (Hartlein, 151 Ill. 2d at 156, 176 Ill. Dec. 22, 601 N.E.2d 720.) With respect to his statutory claim against General Motors, Postma argues that these requirements need not be established. This, however, is incorrect.
Section 13 of the Motor Vehicle Franchise Act provides that any franchisee or motor vehicle dealer who suffers any loss of money or property as a result of acts or practices declared unlawful by the Act "may bring an action for damages and equitable relief, including injunctive relief." (815 ILCS 710/13 (West 1992).) It is true that the courts of this State have held that the normal rules of equity requiring a showing of a lack of an adequate remedy at law and irreparable injury do not apply where a statute expressly authorizes injunctive relief. (See People v. Fiorini (1991), 143 Ill. 2d 318, 346, 158 Ill. Dec. 499, 574 N.E.2d 612.) This principle, however, has been limited to situations (1) where a statute expressly provides for injunctive relief as a tool for public officials to use in enforcing the law, or as a means to afford citizens a private right of action to restrain public officials from acting in a fashion which would violate the statute which prescribes the officials' duties and powers, or (2) where a statute is such that even an isolated violation of its terms is presumed to cause irreparable harm to the country as a whole, as under title VII of the Civil Rights Act of 1964 (42 U.S.C. § 2000e et seq. (1976)). Sadat v. American Motors Corp. (1984), 104 Ill. 2d 105, 113-15, 83 Ill. Dec. 577, 470 N.E.2d 997.
Section 13 of the Motor Vehicle Franchise Act does not fall within these exceptions. The statute, by its terms, creates a purely private right of action to redress purely private injuries. Although injunctions are specifically mentioned, the statute provides for general equitable relief and gives plaintiffs the authority to pursue damage claims as well. Nowhere in the statute does it purport to specify the conditions under which any particular form of relief, legal or equitable, will be appropriate. Under analogous circumstances, we have held that the traditional common law requirements of irreparable injury and inadequacy of legal remedies must be satisfied before injunctive relief will issue. (Sadat, 104 Ill. 2d at 113-15, 83 Ill. Dec. 577, 470 N.E.2d 997.) Postma has cited no authority which suggests that this holding should not be followed here.
For the foregoing reasons, the judgment of the appellate court affirming the denial of Postma's motion for a preliminary injunction is affirmed.

redpajama_set_name: RedPajamaCommonCrawl


As a mathematician, Paul R. Halmos (1916-2006) made fundamental contributions to probability theory, statistics, functional analysis, mathematical logic, and other areas of mathematics. He was also widely recognized as a masterly mathematical expositor. And he served as editor (1981-1985) of the American Mathematical Monthly.
Halmos then expands on what he sees as the key elements of good mathematical writing.
Say something. To have something to say is by far the most important ingredient of good exposition.
Speak to someone. Ask yourself who it is that you want to reach.
Organize. Arrange the material so as to minimize the resistance and maximize the insight of the reader.
Use consistent notation. The letters (or symbols) that you use to denote the concepts that you'll discuss are worthy of thought and careful design.
Write in spirals. Write the first section, write the second section, rewrite the first section, rewrite the second section, write the third section, rewrite the first section, rewrite the second section, rewrite the third section, write the fourth section, and so on.
Watch your language. Good English style implies correct grammar, correct choice of words, correct punctuation, and common sense.
Be honest. Smooth the reader's way, anticipating difficulties and forestalling them. Aim for clarity, not pedantry; understanding, not fuss.
Remove the irrelevant. Irrelevant assumptions, incorrect emphasis, or even the absence of correct emphasis can wreak havoc.
Use words correctly. Think about and use with care the small words of common sense and intuitive logic, and the specifically mathematical words (technical terms) that can have a profound effect on mathematical meaning.
Resist symbols. The best notation is no notation; whenever it is possible to avoid the use of a complicated alphabetic apparatus, avoid it.


Portage Learning provides quality academic preparation to students who can not easily obtain the appropriate instruction from a traditional institution. The aim of our high school, college, and specialty programs is to build sound academic fundamentals that will increase students' confidence in their areas of deficiency, with the outcome of enabling students to advance their educational achievement and respective career goals.
Portage Learning serves a diverse population of students who need particular academic courses and skills in order to continue their progress toward educational or career goals. Most of these students are current or prospective applicants to nursing programs who need prerequisite classes or remediation to meet admission requirements. We recognize that many of these students, though motivated, lack confidence in their ability to handle the required subject matter. Many are non-traditional students who are returning to the work force, currently are working another full-time job, have been removed from the academic arena for an extended time, and/or are uncomfortable taking the necessary courses in a traditional environment. Recognizing the unique pressures and commitments of our students' lifestyles, Portage Learning offers a delivery method that fits those students' schedules and makes more achievable their academic goals.
Portage Learning offers a systematic academic program based on a foundation of excellent, understandable content, which is administered in a self-paced online or correspondence study format. This delivery method allows students the flexibility of beginning courses in a time frame that meets their needs, as well as completing those courses at a pace that meshes with the confines of their diverse schedules -- including the option of accelerated learning, if a student so desires. Portage Learning offers readily-available assistance in the form of personal, individualized, patient tutoring -- in order to help even the least experienced students realize and attain a level of confident success.
Portage Learning commits to respecting students and their goals; our administration and instructors care that our students learn the material well and achieve success. Because our goals are service-oriented in nature, we maintain an "open-door" policy between students and instructors. Students are free to contact their instructors via student dashboard messaging system to request and receive assistance related to their course of study. Instructors are diligent to maintain rapport with students through prompt, pleasant service that helps to build students' confidence and ensure their comfort in asking for further assistance, when necessary.
Relationships between Portage Learning faculty and staff members are critical to our mission, as these individuals are the backbone of the program's success. Staff members strive to maintain healthy and friendly personal relationships that foster enthusiasm for the common goal of educating students in a quality fashion. Portage Learning strives to generate a contented working environment by communicating that each staff member is essential to the successful operation of the program -- through timely staff news, updates, and frequent requests for staff input regarding program mission, goals, and current and future objectives.
Because Portage Learning desires to positively impact the field of nursing through the training of students, we place a high priority on our relationship with participating schools and organizations. In an effort to serve these institutions, Portage Learning surveys the individual and collective needs of their programs and responds to those needs via improvements and additions to our curriculum, as well as the development of instructional tools and services which are made available for the nursing schools' use. This close partnership allows us to assist these schools in recognizing and addressing the distinct needs of their applicants and future students in continuously improving ways.


a new hack came to town!
I've published a new Hack in http://wiki.e-shell.org. This one explains how you can create a little mailing list using only Sendmail aliases and a simple Python script.
It is a quick way to have a mailing list, without having to install and set up MailMan or Majordomo, and it would be easy to add more features to that simple script like, for example, a little archive or some content filtering.


text:
Metroid Prime: Federation Force Review
Few games in Nintendo's history have caused as much of a stir as Metroid Prime: Federation Force. With the Metroid series laying dormant for six years – with it's most recent release being the atrocious Metroid: Other M – fans had been begging for a new iteration in the franchise like never before. So when Federation Force was revealed, with a cartoony look and simplified action-based gameplay that was a stark contrast to the atmosphere and exploration the series is known for, the game was all but dead on arrival. Now that Federation Force is out on 3DS, does it prove it's naysayers wrong in the same vein as The Wind Waker? Or were the cries of Nintendo fans actually justified for once?
It's obvious from the get-go that Metroid Prime: Federation Force is not like other Metroid games. The most obvious differences being the aforementioned art style (possibly implemented to gloss over the 3DS' aging hardware), and the fact that players do not take on the role of series' protagonist Samus Aran. Samus still shows up from time to time, but here, players control members of the titular Federation Force, who embark on various missions aboard mech suits.
Gameplay-wise, Federation Force is more than capable. The game takes on a first-person perspective, with the usual controls of the genre being well translated onto the 3DS. The only issue I ran into with the core gameplay was switching between secondary weapons. Though the mechs have a blaster canon as their primary weapon, secondary weapons and items include health packs, fireballs, lightning bursts, and ice attacks to freeze enemies. The secondary items are switched by pressing the X button, and are fired by pressing the Y button. Because you can only cycle through the secondary weapons by going forward, it often gets confusing, since you instinctively think the two buttons would cycle through the item in different directions. I often ended up shooting the items and wasting precious ammo when I was just trying to switch abilities.
A very welcome addition to the game are the customization options. Players can add mods to their mechs, which grant special bonuses like extra damage, double health, and other such things. You can also paint different designs on your mech, and even alter your character's voice. Best of all, you can swap with mods you're using in between missions, meaning you can play the game in whatever way you want until you find the method you like best. These mods also give the game a tiny taste of the series' explorative elements, as players have to search high and low to find the mods hidden within the missions.
Unfortunately, searching for the mods doesn't add a whole lot of depth to what are otherwise pretty uninspired levels. While the missions at least have some variety with their objectives, the level design itself leaves a lot to be desired. There's just not much to them. There are a few puzzles, enemy encounters and boss fights to be had, but the puzzles feel bland, the enemy encounters can get monotonous, and the boss fights are just too tedious.
Things can pick up a little if you're playing with a few friends. Federation Force allows up to four players to take part in the game's campaign. When all four players are active, Federation Force begins to feel like the game it was meant to be. The largely empty levels begin to come to life with four players working in tandem. Unfortunately, even having all four players on board doesn't help the puzzles or boss fights stand out more.
Metroid Prime: Federation Force also includes a competitive multplayer mode known as Blast Ball, which is more or less Rocket League but with mechs shooting the ball into the other team's goal instead of using cars to do the job. Though Blast Ball can provide some bursts of fun, the concept doesn't always mesh with the game's mechanics, and you quickly feel like you'd rather be playing the actual Rocket League instead.
As a whole, Metroid Prime: Federation Force is not the disaster that Nintendo's fans made it out to be, and it's an insurmountably better game than Other M. But it's also incredibly unspectacular. The gameplay works, and though the art direction may not be what one would expect from a Metroid title, it does help make the visuals pop, especially with the 3DS' 3D effects turned on. Unfortunately, the bland level design and emptiness within them prevent Federation Force from putting up much of an argument against its naysayers.
Still though, it's not Other M. Be thankful for that.
Author themancalledscottPosted on September 26, 2016 July 29, 2018 Categories 3DS, Video GamesTags Metroid, Metroid Prime, Metroid Prime: Federation Force, Nintendo, Nintendo 3DS, Video Games
6 thoughts on "Metroid Prime: Federation Force Review"
Reblogged this on Miketendo64! The News, Reviews & Personal Views Website On All Things Nintendo and commented:
A Wizard Dojo Review.
I can't say I am surprised about how average it is. Great review!
I will play it eventually, when I can find a used copy at a low price.
Justacommenter says:
I think it's fair to assume the backlash for the game wouldn't have been so big had there been a proper Metroid game announced with it, or released after the ever so disappointing Other M.
Still, even without taking in mind the crazy reactions against this game, it never looked like anything more than a super average multiplayer shooter, and while it being coop does make it more appealing than being yet another competitive game, I can't say I'm too interested in something that solely relies on multiplayer to be any sort of decent.
Mr. Panda says:
Awesome review! I thought about getting this at one point, but it just doesn't seem like I'd like it, especially unless I played multiplayer. Though I guess from what you're saying, even multiplayer is lackluster. I'm not the biggest Metroid Prime series fan, but if the game were at least fun, I might have considered it more. It's great that it's not the disaster that everyone (for some reason) wanted it to be. However, as it's just average, I'll probably hold off. Thanks for sharing your thoughts!
veryverygaming says:
Since I really liked Other M, does that mean Federation Force is destined to be my favourite game? 😛 I'm hearing a lot of mixed reports on this one and am really curious about it.
I appreciate your review in that you're accepting the game on its own terms and judging it for what it is, as opposed to what it isn't. I thought the whole controversy around this game pre-release (#notmymetroid) was completely ridiculous from Metroid fans. It was a complete kneejerk reaction which demonstrates Nintendo's impossible position of trying to appease fans who do not want the company to innovate or think outside of the box with their franchises, and non-fans who believe that Nintendo is too conservative with their franchises and are content to rehash content and ideas generation after generation.
Grubdog says:
Yep, the fan reaction was toxic, and if we never get another Metroid game, that will be the reason. They just stamped a big fat "nope" on ever dealing with these people again.
It's a really fun game and I agree with some of your points, but I strongly disagree that the level design is bland. You have some incredible design that interacts with the environments even more than traditional Metroid games. Objects to pull, things to shoot open, enemies to distract, and multiple objectives to think about at once. It also has better Metroid combat and escape sequences than any other game in the series. Seriously, when has anyone ever come close to dying in a Metroid escape sequence? I'm so glad to finally feel that, and a lot more in Federation Force. It feels like Metroid Prime 4 to me and I'm so glad to have it on my 3DS. You can tell some missions were designed for multiplayer, like dragging the cart, but it still feels pretty unusual and engaging in single player. You're just all alone, like Samus.
Previous Previous post: Nintendo 64 Turns 20!
Next Next post: Mario Kart 64 Review


Three of the four Eastern Conference Quarterfinal series look rather blah on paper. I would argue that the marquee matchup is the one that might look (wrongly) lopsided from a seeding perspective: No. 1 Boston hosts No. 8 Chicago in Game 1 on Sunday.
Game 1 of this series tips off at 6:30 p.m. ET on Sunday and is shown on TNT.
The Celtics were the beneficiaries of the Cleveland Cavaliers' season-ending four-game losing streak and all but conceding the last two of those by resting LeBron James and Kyrie Irving. When Boston was crushed 114-91 at home by the Cavs on April 5, it seemed all but a lock that Cleveland would be the East's top seed with a one-game lead and the head-to-head tiebreaker on Boston. However, the Cavs didn't win again and the Celtics won three of four.
It's the first time since 2008 that Boston is the top seed. That team was a lot better than this one, finishing 66-16 and winning the NBA Finals. By some statistical measures, these Celtics are the worst top seed in many years. For example, Boston's point differential of plus-2.7 and net rating (points per 100 possessions) of plus-3.1 are the worst marks for a No. 1 since the 1978-79 Seattle SuperSonics, although that team won the NBA title.
Boston fattened its record inside its Atlantic Division by going 10-2 against the Knicks, 76ers and Nets, three of the NBA's worst teams. The Celtics were 1-3 vs. Cleveland, 1-3 vs. Toronto and 0-2 vs. San Antonio, to name three. Also potentially working against Boston is that it has the least playoff experience (5,461 minutes) of any No. 1 seed since the 2004-05 Phoenix Suns. Chicago's Dwayne Wade (6,380) minutes has more by himself.
The Celtics have a worse defensive efficiency rating (105.5 points per 100 possessions) than Chicago (104.5) and they are a much worse rebounding team. The Bulls ranked third in pulling down 46.3 per game and the Celtics 26th at 44.5. That's why Boston was looking to deal for a big at the trade deadline.
Despite all those red flags, Boston is -500 on the series line and -7.5 on NBA odds for Game 1 vs. Chicago.
The individual story line of this series surrounds Bulls All-Star guard Jimmy Butler. Celtics president of basketball operations Danny Ainge thought he needed a star to get on equal footing with Cleveland in the East. He looked into trading for Butler this past offseason and again at the February trade deadline but wasn't willing to meet Chicago's price.
Will Butler be with the Bulls next season? A lot of that could depend on what happens in this series. If the Bulls go out with a whimper, they are likely to go into full rebuild mode and could be more likely to deal Butler. If the Celtics are upset in this series or the next, then Ainge probably has proof he needs a wingman for All-Star Isaiah Thomas. Ainge can offer the Nets' 2017 first-round pick as part of the package for Butler, who has two years left on his contract after this one.
Butler averaged 20.3 points, 6.8 rebounds and 3.8 assists vs. Boston this year as the Bulls split, winning both at home. He hit two free throws with less than a second left for the winning points in one of those. Thomas averaged 24.8 points and 5.8 assists vs. the Bulls.
There's only so much the 5-foot-9 Thomas can do, however, and the lack of a second scoring option is why many feel the Celtics won't win the East. Last year, the Hawks upset the Celtics in the first round because Thomas struggled from the field in Boston's four losses.
The Bulls have covered their past five road games vs. teams with a winning home record and are 6-1 ATS in their past seven playing on at least three days of rest. The Celtics are just 3-7 ATS in their past 10 overall and 1-6 ATS in their previous seven at home. Chicago is my NBA pick.


This is a placeholder page for Edward Peacock, which means this person is not currently on this site. We do suggest using the tools below to find Edward Peacock.
You are visiting the placeholder page for Edward Peacock. This page is here because someone used our placeholder utility to look for Edward Peacock. We created this page automatically in hopes Edward Peacock would find it. If you are not Edward Peacock, but are an alumni of Evart High School, register on this site for free now.


If you are passionate about the Kawasaki Vaquero, then our Ride It Women`s Dark T-Shirt is essential! This ladies t-shirt is just really cool, and is ideal for any activity.
Our Kawasaki Vaquero Ride It Women`s Dark T-Shirt is the softest, smoothest, best-looking, classic fit ladies tee shirt available anywhere! It features creative artwork of the Kawasaki Vaquero on the finest quality Women`s Dark T-Shirt. Our Kawasaki Vaquero Ride It Women`s Dark T-Shirt is the ultimate COOL gift for the Kawasaki Vaquero enthusiast on birthdays, holidays, anniversaries, retirement, or for no reason at all. A fashion must have for everyone.
It features our original Ride It graphic design for the Kawasaki Vaquero .
If you are passionate about the Kawasaki Vaquero, or know someone who does, then our Ride It Women`s Dark T-Shirt is a must have!


Your home is more than just a house—it's a place where memories are made and moments are cherished. Time spent doing the things you love shouldn't be compromised by everyday chores. At Merry Maids®, you can live in the moment and leave the tedious housework to us. Our Lodi cleaning services use advanced methods and proven processes backed by 40 years of experience to ensure results unlike any other for a home that deserves only the best.
At Merry Maids of Lodi, we have spent countless hours in homes just like yours and understand how tough it can be to find time for a cleaning service. That's why we provide customizable cleaning plans that fit your hectic schedule. From routine housekeeping to one-time detailed cleanings, our bonded and insured team members deliver results you can see and feel. We're so confident you'll be in love with your re-energized space, we provide our worry-free guarantee. Coming home should never be a chore. Merry Maids® is here to make sure it isn't.
Request Your Free Estimate Fill out our estimate form or give us a call at (209) 759-4080 to get started.