text:
package org.openqa.selenium.devtools.v88;

import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.idealized.Domains;
import org.openqa.selenium.devtools.idealized.Events;
import org.openqa.selenium.devtools.idealized.Javascript;
import org.openqa.selenium.devtools.idealized.Network;
import org.openqa.selenium.devtools.idealized.log.Log;
import org.openqa.selenium.devtools.idealized.target.Target;
import org.openqa.selenium.internal.Require;

public class V88Domains implements Domains {

  private final V88Javascript js;
  private final V88Events events;
  private final V88Log log;
  private final V88Network network;
  private final V88Target target;

  public V88Domains(DevTools devtools) {
    Require.nonNull("DevTools", devtools);
    events = new V88Events(devtools);
    js = new V88Javascript(devtools);
    log = new V88Log();
    network = new V88Network(devtools);
    target = new V88Target();
  }

  @Override
  public Events<?, ?> events() {
    return events;
  }

  @Override
  public Javascript<?, ?> javascript() {
    return js;
  }

  @Override
  public Network<?, ?> network() {
    return network;
  }

  @Override
  public Target target() {
    return target;
  }

  @Override
  public Log log() {
    return log;
  }
}


text:
rsync -ruv -e "ssh -i ./agile_data_science.pem" \
    --exclude=cassandra \
    --exclude=data \
    --exclude=janusgraph \
    --exclude=hadoop \
    --exclude=spark \
    --exclude=kafka \
    --exclude=lib \
    --exclude=elasticsearch-hadoop \
    --exclude=elasticsearch \
    --exclude=mongo-hadoop \
    --exclude=mongodb \
    --exclude=tmp \
    --exclude=zeppelin \
    ubuntu@`cat .ec2_hostname`:Agile_Data_Code_2/* .

redpajama_set_name: RedPajamaGithub


text:
package ch.christianguedemann.demoplugin.angular;

import org.eclipse.core.runtime.Plugin;
import org.osgi.framework.BundleActivator;

public class AJSActivator extends Plugin implements BundleActivator {

	private static AJSActivator INSTANCE;
	public AJSActivator() {
		INSTANCE = this;
	}
	public static AJSActivator getInstance() {
		return INSTANCE;
	}

}


text:
package com.opengamma.engine.calcnode;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;

import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.NamedThreadPoolFactory;
import com.opengamma.util.async.AsynchronousExecution;
import com.opengamma.util.async.AsynchronousResult;
import com.opengamma.util.async.ResultListener;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;

/**
 * Base class for objects that manage a set of AbstractCalculationNodes with the intention of invoking job executions on them.
 */
public abstract class SimpleCalculationNodeInvocationContainer implements Lifecycle {

  /**
   * After how many failed jobs should a cleanup be attempted.
   */
  private static final int FAILURE_CLEANUP_PERIOD = 100; // clean up after every 100 failed jobs

  /**
   * Retention period for failed jobs needs to be long enough for any tail jobs to have arrived.
   */
  private static final long FAILURE_RETENTION = 5L * 60L * 100000000L; // 5m

  private static final Logger LOGGER = LoggerFactory.getLogger(SimpleCalculationNodeInvocationContainer.class);

  // private static final int KILL_THRESHOLD_SECS = 120;

  /**
   *
   */
  protected interface ExecutionReceiver {

    void executionFailed(SimpleCalculationNode node, Exception exception);

    void executionComplete(CalculationJobResult result);

  }

  private static class JobEntry {

    private final CalculationJob _job;
    private final JobExecution _execution;
    private ExecutionReceiver _receiver;
    private AtomicInteger _blockCount;

    JobEntry(final CalculationJob job, final JobExecution execution, final ExecutionReceiver receiver) {
      _job = job;
      _execution = execution;
      _receiver = receiver;
    }

    public CalculationJob getJob() {
      return _job;
    }

    public JobExecution getExecution() {
      return _execution;
    }

    public ExecutionReceiver getReceiver() {
      return _receiver;
    }

    /**
     * This is only called from a single thread - doing the addJob operation - once it has been called once, another thread
     * will manipulate the block count (e.g. if a job is finishing) and possibly spawn the job. Note that we initialize the
     * count to two so that the job does not get spawned prematurely until the addJob thread has processed the required job
     * list and performs a decrement to clear the additional value.
     */
    public void incrementBlockCount() {
      if (_blockCount == null) {
        _blockCount = new AtomicInteger(2);
      } else {
        _blockCount.incrementAndGet();
      }
    }

    /**
     * Decrements the block count.
     *
     * @return true when the count reaches zero
     */
    public boolean releaseBlockCount() {
      return _blockCount.decrementAndGet() == 0;
    }

    public void invalidate() {
      _receiver = null;
    }

    @Override
    public int hashCode() {
      return getJob().hashCode();
    }

    @Override
    public boolean equals(final Object o) {
      if (o == this) {
        return true;
      }
      if (!(o instanceof JobEntry)) {
        return false;
      }
      return getJob().equals(((JobEntry) o).getJob());
    }

  }

  private static class PartialJobEntry {

    private final JobEntry _entry;
    private final SimpleCalculationNodeState _nodeState;
    private final AsynchronousResult<SimpleCalculationNode.Deferred<CalculationJobResult>> _handle;

    PartialJobEntry(final JobEntry entry, final SimpleCalculationNodeState nodeState,
        final AsynchronousResult<SimpleCalculationNode.Deferred<CalculationJobResult>> handle) {
      _entry = entry;
      _nodeState = nodeState;
      _handle = handle;
    }

    public JobEntry getEntry() {
      return _entry;
    }

    public SimpleCalculationNodeState getNodeState() {
      return _nodeState;
    }

    public AsynchronousResult<SimpleCalculationNode.Deferred<CalculationJobResult>> getHandle() {
      return _handle;
    }

  }

  private static class JobExecution {

    private enum Status {
      RUNNING, COMPLETED, FAILED;
    }

    private final long _jobId;
    private final long _timestamp;
    private Status _status;
    private Set<JobEntry> _blocked;
    private Pair<Thread, CalculationJob> _executor;

    JobExecution(final long jobId) {
      _jobId = jobId;
      _timestamp = System.nanoTime();
      _status = Status.RUNNING;
    }

    public long getJobId() {
      return _jobId;
    }

    public long getAge() {
      return System.nanoTime() - _timestamp;
    }

    public Status getStatus() {
      return _status;
    }

    public void setStatus(final Status status) {
      _status = status;
    }

    public synchronized Pair<Thread, CalculationJob> getAndSetExecutor(final Pair<Thread, CalculationJob> executor) {
      final Pair<Thread, CalculationJob> previous = _executor;
      _executor = executor;
      return previous;
    }

    public synchronized boolean threadBusy(final CalculationJob job) {
      assert _executor == null;
      if (_status == Status.FAILED) {
        return false;
      }
      _executor = Pairs.of(Thread.currentThread(), job);
      return true;
    }

    // Caller must own the monitor
    public Set<JobEntry> getBlocked() {
      final Set<JobEntry> blocked = _blocked;
      _blocked = null;
      return blocked;
    }

    // Caller must own the monitor
    public void blockJob(final JobEntry job) {
      if (_blocked == null) {
        _blocked = new HashSet<>();
      }
      _blocked.add(job);
    }

  }

  /**
   * The nodes that are available for execution.
   */
  private final Queue<SimpleCalculationNode> _nodes = new ConcurrentLinkedQueue<>();

  /**
   * The total number of nodes that are in the container.
   */
  private final AtomicInteger _nodeCount = new AtomicInteger();

  /**
   * The set of jobs that are either running, in the runnable queue or blocked by other jobs.
   */
  private final ConcurrentMap<Long, JobExecution> _executions = new ConcurrentHashMap<>();

  /**
   * The set of failed jobs. Anything not in this set or {@link #_executions} has completed successfully.
   */
  private final ConcurrentMap<Long, JobExecution> _failures = new ConcurrentSkipListMap<>();
  private final AtomicInteger _failureCount = new AtomicInteger();

  /**
   * The queue of runnable jobs. Each are jobs that have been received and are ready to run but have not been started,
   * probably because they are waiting for a node to become available. When nodes are available they will take partial
   * jobs from the {@link #_partialJobs} queue in preference to this queue.
   */
  private final Queue<JobEntry> _runnableJobs = new ConcurrentLinkedQueue<>();
  /**
   * The queue of partially executed jobs. Each represents a piece of work that was started, became blocked on something
   * external, but is now ready to run again. Note that the resume may not take place on the original node and/or
   * original thread. This is to avoid a potential bottleneck. Nothing should be retaining thread/node specific state
   * (other than the saved node state) so this should not be a problem.
   */
  private final Queue<PartialJobEntry> _partialJobs = new ConcurrentLinkedQueue<>();

  private ExecutorService _executorService = createExecutorService();

  private static ExecutorService createExecutorService() {
    return NamedThreadPoolFactory.newCachedThreadPool("CalcNode", true);
  }

  protected Queue<SimpleCalculationNode> getNodes() {
    return _nodes;
  }

  public void addNode(final SimpleCalculationNode node) {
    ArgumentChecker.notNull(node, "node");
    _nodeCount.incrementAndGet();
    getNodes().add(node);
    onNodeChange();
  }

  public void addNodes(final Collection<SimpleCalculationNode> nodes) {
    ArgumentChecker.notNull(nodes, "nodes");
    _nodeCount.addAndGet(nodes.size());
    getNodes().addAll(nodes);
    onNodeChange();
  }

  public void setNode(final SimpleCalculationNode node) {
    ArgumentChecker.notNull(node, "node");
    getNodes().clear();
    _nodeCount.set(1);
    getNodes().add(node);
    onNodeChange();
  }

  public void setNodes(final Collection<SimpleCalculationNode> nodes) {
    ArgumentChecker.notNull(nodes, "nodes");
    getNodes().clear();
    _nodeCount.set(nodes.size());
    getNodes().addAll(nodes);
    onNodeChange();
  }

  /**
   * Removes a node if one is available.
   *
   * @return the node removed from the live set, or null if there are none to remove
   */
  public SimpleCalculationNode removeNode() {
    final SimpleCalculationNode node = getNodes().poll();
    if (node != null) {
      _nodeCount.decrementAndGet();
    }
    return node;
  }

  /**
   * Returns the total number of nodes in this invocation set. This includes those in the available set and those that are currently busy executing jobs.
   *
   * @return the total number of nodes
   */
  public int getTotalNodeCount() {
    return _nodeCount.get();
  }

  /**
   * Returns the number of available nodes in the set. Note that the structure that holds the nodes may have quite a costly size operation.
   *
   * @return the number of available nodes in the set
   */
  public int getAvailableNodeCount() {
    return getNodes().size();
  }

  /**
   * Returns the total number of jobs enqueued at this node. This includes both runnable, partial and blocked jobs.
   * Note that the structure that holds the jobs may have quite a costly size operation.
   *
   * @return the number of jobs
   */
  public int getTotalJobCount() {
    return _executions.size();
  }

  /**
   * Returns the number of jobs enqueued at this node that are available to start. This includes both runnable, partial
   * and blocked jobs. Note that the structure that holds the jobs may have quite a costly size operation.
   *
   * @return the number of jobs
   */
  public int getRunnableJobCount() {
    return _runnableJobs.size();
  }

  /**
   * Returns the number of jobs enqueued at this node that have been partially completed and are ready for continuation.
   * Note that the structure that holds the jobs may have quite a costly size operation.
   *
   * @return the number of jobs
   */
  public int getPartialJobCount() {
    return _partialJobs.size();
  }

  protected abstract void onNodeChange();

  protected void onJobExecutionComplete() {
  }

  protected ExecutorService getExecutorService() {
    return _executorService;
  }

  private JobExecution createExecution(final Long jobId) {
    final JobExecution jobexec = new JobExecution(jobId);
    _executions.put(jobId, jobexec);
    return jobexec;
  }

  private JobExecution getExecution(final Long jobId) {
    return _executions.get(jobId);
  }

  private JobExecution getFailure(final Long jobId) {
    return _failures.get(jobId);
  }

  /**
   * Adds a job to the runnable queue, spawning a worker thread if a node is supplied or one is available.
   */
  private void spawnOrQueueJob(final JobEntry jobexec, SimpleCalculationNode node) {
    if (node == null) {
      node = getNodes().poll();
      if (node == null) {
        synchronized (this) {
          node = getNodes().poll();
          if (node == null) {
            LOGGER.debug("Adding job {} to runnable queue", jobexec.getJob().getSpecification().getJobId());
            _runnableJobs.add(jobexec);
            return;
          }
        }
      }
    }
    LOGGER.debug("Spawning execution of job {}", jobexec.getJob().getSpecification().getJobId());
    final SimpleCalculationNode parallelNode = node;
    getExecutorService().execute(new Runnable() {
      @Override
      public void run() {
        executeJobs(parallelNode, jobexec, null);
      }
    });
  }

  private void spawnOrQueueJob(final PartialJobEntry jobexec) {
    SimpleCalculationNode node = getNodes().poll();
    if (node == null) {
      synchronized (this) {
        node = getNodes().poll();
        if (node == null) {
          LOGGER.debug("Adding job {} to partially run queue", jobexec.getEntry().getJob().getSpecification().getJobId());
          _partialJobs.add(jobexec);
          return;
        }
      }
    }
    LOGGER.debug("Spawning re-execution of job {}", jobexec.getEntry().getJob().getSpecification().getJobId());
    final SimpleCalculationNode parallelNode = node;
    getExecutorService().execute(new Runnable() {
      @Override
      public void run() {
        executeJobs(parallelNode, null, jobexec);
      }
    });
  }

  private void failExecution(final JobExecution execution) {
    final Set<JobEntry> blocked;
    synchronized (execution) {
      execution.setStatus(JobExecution.Status.FAILED);
      blocked = execution.getBlocked();
      // Add to failure set first, so the job is never missing from both
      _failures.put(execution.getJobId(), execution);
      _failureCount.incrementAndGet();
    }
    if (blocked != null) {
      for (final JobEntry tail : blocked) {
        tail.invalidate();
        failExecution(tail.getExecution());
      }
    }
  }

  private void succeedExecution(final JobExecution execution) {
    final Set<JobEntry> blocked;
    synchronized (execution) {
      execution.setStatus(JobExecution.Status.COMPLETED);
      blocked = execution.getBlocked();
    }
    if (blocked != null) {
      LOGGER.info("Job {} completed - releasing blocked jobs", execution.getJobId());
      for (final JobEntry tail : blocked) {
        if (tail.getReceiver() != null) {
          if (tail.releaseBlockCount()) {
            spawnOrQueueJob(tail, null);
          }
        }
      }
    } else {
      LOGGER.info("Job {} completed - no tail jobs", execution.getJobId());
    }
  }

  /**
   * Adds jobs to the runnable queue, spawning a worker thread if a node is supplied or one is available. Jobs must
   * be added in dependency order - i.e. a job must be submitted before any that require it. This is to simplify
   * retention of job status as we only need to track jobs that are still running or have failed which saves a lot
   * of housekeeping overhead.
   *
   * @param job job to run, not null
   * @param receiver execution status receiver, not null
   * @param node optional node to start a worker thread with
   */
  protected void addJob(final CalculationJob job, final ExecutionReceiver receiver, final SimpleCalculationNode node) {
    final JobExecution jobExecution = createExecution(job.getSpecification().getJobId());
    final long[] requiredJobIds = job.getRequiredJobIds();
    final JobEntry jobEntry = new JobEntry(job, jobExecution, receiver);
    if (requiredJobIds != null) {
      // Shouldn't be passing a node in with a job that might not be runnable
      assert node == null;
      boolean failed = false;
      boolean blocked = false;
      for (final Long requiredId : requiredJobIds) {
        JobExecution required = getExecution(requiredId);
        LOGGER.debug("Job {} requires {}", jobExecution.getJobId(), requiredId);
        if (required != null) {
          synchronized (required) {
            switch (required.getStatus()) {
              case COMPLETED:
                // No action needed - we can continue
                LOGGER.debug("Required job {} completed (from execution cache)", requiredId);
                break;
              case FAILED:
                // We can't run
                failed = true;
                LOGGER.debug("Required job {} failed (from execution cache)", requiredId);
                break;
              case RUNNING:
                // We're blocked
                blocked = true;
                // Will increment or initialize to 2
                jobEntry.incrementBlockCount();
                required.blockJob(jobEntry);
                LOGGER.debug("Required job {} blocking {}", requiredId, jobExecution.getJobId());
                break;
              default:
            }
          }
        } else {
          required = getFailure(requiredId);
          if (required != null) {
            failed = true;
            LOGGER.debug("Required job {} failed (from failure cache)", requiredId);
          } else {
            LOGGER.debug("Required job {} completion inferred", requiredId);
          }
        }
      }
      if (failed) {
        LOGGER.debug("Failing execution of {}", jobExecution.getJobId());
        failExecution(jobExecution);
        return;
      }
      if (blocked) {
        // Decrement the additional count from the initialization
        if (!jobEntry.releaseBlockCount()) {
          LOGGER.debug("Blocked execution of {}", jobExecution.getJobId());
          return;
        }
      }
    }
    spawnOrQueueJob(jobEntry, node);
  }

  private void threadFree(final JobExecution exec) {
    // The executor should only go null transiently while the cancel action happens and should then
    // be restored. If, for probably erroneous reasons, the job has been launched twice we can see
    // a continuous null here from the second running thread so have a spin count here to give up
    // after 1s regardless (which may cause further errors, but is better than deadlock).
    int spin = 0;
    do {
      final Pair<Thread, CalculationJob> previous = exec.getAndSetExecutor(null);
      if (previous != null) {
        assert previous.getFirst() == Thread.currentThread();
        return;
      }
      // Executor reference is null while the job is being canceled. An interrupt may be done as part of
      // this so we need to make sure we swallow it rather than leave ourselves in an interrupted state.
      if (Thread.interrupted()) {
        LOGGER.debug("Interrupt status cleared");
        return;
      }
      switch (spin) {
        case 0:
          LOGGER.debug("Waiting for interrupt");
          break;
        case 1:
          LOGGER.info("Waiting for interrupt");
          break;
        case 2:
          LOGGER.warn("Waiting for interrupt");
          break;
        default:
          LOGGER.error("Waiting for interrupt");
          break;
      }
      try {
        Thread.sleep(10);
      } catch (final InterruptedException e) {
        LOGGER.debug("Interrupt received");
        return;
      }
    } while (++spin < 1000);
  }

  /**
   * Executes jobs from the runnable and partially-run queues until both are empty.
   *
   * @param node Node to run on, not null
   * @param job The first job to run, not null if resumeJob is null
   * @param resumeJob the first job to run, not null if newJob is null
   */
  private void executeJobs(final SimpleCalculationNode node, JobEntry job, PartialJobEntry resumeJob) {
    do {
      if (resumeJob == null) {
        LOGGER.info("Executing job {} on {}", job.getExecution().getJobId(), node.getNodeId());
      } else {
        job = resumeJob.getEntry();
        LOGGER.info("Resuming job {} on {}", job.getExecution().getJobId(), node.getNodeId());
      }
      CalculationJobResult result = null;
      if (job.getExecution().threadBusy(job.getJob())) {
        try {
          if (resumeJob == null) {
            result = node.executeJob(job.getJob());
          } else {
            node.restoreState(resumeJob.getNodeState());
            result = resumeJob.getHandle().getResult().call(node);
          }
          threadFree(job.getExecution());
        } catch (final AsynchronousExecution e) {
          if (SimpleCalculationNode.Deferred.class.isAssignableFrom(e.getResultType())) {
            // The job is running asynchronously (e.g. blocked on an external process). Registering a listener with the exception
            // will give us a callable handle back to the job when it is ready to return to this thread. In the meantime we use
            // this thread to perform other work.
            threadFree(job.getExecution());
            LOGGER.debug("Job {} running asynchronously", job.getExecution().getJobId());
            final SimpleCalculationNodeState state = node.saveState();
            final JobEntry originalJob = job;
            e.setResultListener(new ResultListener<SimpleCalculationNode.Deferred<CalculationJobResult>>() {
              @Override
              public void operationComplete(final AsynchronousResult<SimpleCalculationNode.Deferred<CalculationJobResult>> result) {
                spawnOrQueueJob(new PartialJobEntry(originalJob, state, result));
              }
            });
          } else {
            // Job has completed but its cache writes are being flushed asynchronously. We'll mark it as succeeded to release any
            // tail jobs but not report back to the receiver until the flush is complete.
            threadFree(job.getExecution());
            succeedExecution(job.getExecution());
            final JobEntry originalJob = job;
            e.setResultListener(new ResultListener<CalculationJobResult>() {
              @Override
              public void operationComplete(final AsynchronousResult<CalculationJobResult> aresult) {
                final CalculationJobResult result;
                try {
                  result = aresult.getResult();
                } catch (final RuntimeException e) {
                  // Don't fail the execution locally as we already declared it as completed; just report back to the receiver
                  LOGGER.warn("Jop {} failed: {}", originalJob.getExecution().getJobId(), e.getMessage());
                  originalJob.getReceiver().executionFailed(node, e);
                  _executions.remove(originalJob.getExecution().getJobId());
                  return;
                }
                originalJob.getReceiver().executionComplete(result);
                _executions.remove(originalJob.getExecution().getJobId());
              }
            });
          }
        } catch (final CancellationException e) {
          LOGGER.debug("Job {} cancelled", job.getExecution().getJobId());
        } catch (final Exception e) {
          // Any tail jobs will be abandoned
          threadFree(job.getExecution());
          LOGGER.warn("Job {} failed: {}", job.getExecution().getJobId(), e.getMessage());
          failExecution(job.getExecution());
          job.getReceiver().executionFailed(node, e);
          _executions.remove(job.getExecution().getJobId());
        }
      } else {
        LOGGER.debug("Job {} cancelled", job.getExecution().getJobId());
      }
      if (result != null) {
        succeedExecution(job.getExecution());
        job.getReceiver().executionComplete(result);
        _executions.remove(job.getExecution().getJobId());
      }
      resumeJob = _partialJobs.poll();
      if (resumeJob == null) {
        job = _runnableJobs.poll();
        if (job == null) {
          synchronized (this) {
            resumeJob = _partialJobs.poll();
            if (resumeJob == null) {
              job = _runnableJobs.poll();
              if (job == null) {
                getNodes().add(node);
                break;
              }
            }
          }
        }
      }
    } while (true);
    LOGGER.debug("Finished job execution on {}", node.getNodeId());
    onJobExecutionComplete();
    // Housekeeping
    if (_failureCount.get() > FAILURE_CLEANUP_PERIOD) {
      _failureCount.set(0);
      int count = 0;
      final Iterator<Map.Entry<Long, JobExecution>> entryIterator = _failures.entrySet().iterator();
      while (entryIterator.hasNext()) {
        final Map.Entry<Long, JobExecution> entry = entryIterator.next();
        if (entry.getValue().getAge() > FAILURE_RETENTION) {
          LOGGER.debug("Removed job {} from failure set", entry.getKey());
          entryIterator.remove();
          count++;
        } else {
          break;
        }
      }
      LOGGER.info("Removed {} dead entries from failure map, {} remaining", count, _failures.size());
    }
    LOGGER.debug("Failure map size = {}, execution map size = {}", _failures.size(), _executions.size());
  }

  public void cancel(final CalculationJobSpecification jobSpec) {
    final JobExecution jobExec = getExecution(jobSpec.getJobId());
    if (jobExec == null) {
      LOGGER.warn("Request to cancel job {} but already failed or completed", jobSpec.getJobId());
      return;
    }
    LOGGER.info("Cancelling job {}", jobSpec.getJobId());
    failExecution(jobExec);
    Pair<Thread, CalculationJob> executor = jobExec.getAndSetExecutor(null);
    if (executor != null) {
      LOGGER.debug("Marking job {} cancelled", executor.getSecond().getSpecification().getJobId());
      executor.getSecond().cancel();
      LOGGER.info("Interrupting thread {}", executor.getFirst().getName());
      executor.getFirst().interrupt();
      // Need to wait for the execution thread to acknowledge the interrupt, or it may be canceled by us swapping the executor
      // reference back in and the interrupt will affect a subsequent wait causing erroneous behavior
      while (executor.getFirst().isInterrupted() && executor.getFirst().isAlive()) {
        LOGGER.debug("Waiting for thread {} to accept the interrupt", executor.getFirst().getName());
        try {
          Thread.sleep(20);
        } catch (final InterruptedException ex) {
          LOGGER.debug("cancel interrupted", ex);
        }
      }
      LOGGER.debug("Thread {} interrupted", executor.getFirst().getName());
      executor = jobExec.getAndSetExecutor(executor);
      assert executor == null;
    }
  }

  public boolean isAlive(final CalculationJobSpecification jobSpec) {
    final JobExecution jobExec = getExecution(jobSpec.getJobId());
    if (jobExec == null) {
      // Completed or failed, not alive at any rate!
      return false;
    }
    return true;
  }

  // Lifecycle

  @Override
  public void start() {
    synchronized (this) {
      if (_executorService == null) {
        _executorService = createExecutorService();
      }
    }
  }

  @Override
  public void stop() {
    final ExecutorService executorService;
    synchronized (this) {
      executorService = _executorService;
      _executorService = null;
    }
    if (executorService != null) {
      executorService.shutdown();
    }
  }

  @Override
  public boolean isRunning() {
    return _executorService != null;
  }

}


text:
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="CompilerConfiguration">
    <bytecodeTargetLevel>
      <module name="1.12-Minecordbot_main" target="1.8" />
      <module name="Minecordbot_main" target="1.8" />
      <module name="Minecordbot_test" target="1.8" />
    </bytecodeTargetLevel>
  </component>
</project>


text:
package cn.rlstech.callnumber.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.GridView;

public class StopMoveGridView extends GridView {
    public StopMoveGridView(Context context) {
        super(context);
    }

    public StopMoveGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public StopMoveGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_MOVE){
            return true;
        }
        return super.dispatchTouchEvent(ev);
    }
}


text:
@interface DHModifyPasswordViewController : UIViewController

@end


text:
SYNONYM

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Bot. Mag. 52: t. 2524. 1825

#### Original name
null

### Remarks
null


text:
(function () {
  "use strict";
  var debug = VPAnimEngine.debug;

  // constants
  var kColorSettings = ['fillStyle', 'strokeStyle', 'color', 'colorFrom', 'colorTo'];

  // Private transition processing functions
  function deleteTransKey(transition, fieldName) {
    delete transition.changing[fieldName];
    for (var cb in transition.callbacks) {
      var callbackDef = transition.callbacks[cb];
      var keyIndex = callbackDef.keys.indexOf(fieldName);
      if (keyIndex !== -1) {
        callbackDef.keys.splice(keyIndex,1);
      }
    }
  }

  function doTransitionCallbacks(transition, removeOnly) {
    // must be applied, setting "this"
    for (var cb in transition.callbacks) {
      var callbackDef = transition.callbacks[cb];
      if (callbackDef.keys.length === 0) {
        var actions = callbackDef.actions;
        if (removeOnly) {
          // I don't think this can work, and is effectively a no-op
          // not sure what the implications of that might be
          actions.length = 0;
        } else {
          delete transition.callbacks[cb];
          if (actions.length !== 0) {
            this.processStages(actions);
          }
        }
      }
    }
  }

  function processTransition(transition) {
    for (var changing in transition.changing) {
      var transParams = transition.changing[changing];
      var progress = Math.max((this.getTime(transition.timeType) - (transParams.started + transParams.delay)), 0) / transParams.duration;

      if (progress > 1) {
        progress = 1;
      } else if (transParams.bezier) {
        var bez = transParams.bezier;
        progress = this.cubicBezierAtTime(progress, bez[0], bez[1], bez[2], bez[3], transParams.duration);
      }

      if (transParams.gradient) {
        if (progress === 1) {
          transition.settings[changing] = transParams.to;
        } else {
          var pixData = transParams.gradient;
          var offset = Math.round(progress * 99) * 4;

          var red = pixData[offset];
          var green = pixData[offset+1];
          var blue = pixData[offset+2];
          var alpha = pixData[offset+3] / 255;

          transition.settings[changing] = "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
        }
      } else if (transParams.delta) {
        transition.settings[changing] = transParams.from + (transParams.delta * progress);
      }

      if (progress === 1) {
        this.removeTransition(transition.path, changing);
      }
    }
  }

  function processAllTransitions() {
    for (var trans in this.transitions) {
      processTransition.apply(this, [this.transitions[trans]]);
    }
  }

  function removeTransition(path, fieldName, ignoreWarn, ignoreCallbacks, noDelete) {
    if (!Array.isArray(path)) {
      path = [path];
    }
    var settingsName = path.join('-') || '-global';
    var transition = this.transitions[settingsName];

    if (transition) {
      if (fieldName) {
        deleteTransKey(transition, fieldName);
      } else {
        for (var key in transition.changing) {
          deleteTransKey(transition, key);
        }
      }
      if (!noDelete) {
        var active = 0;
        for (var key in transition.changing) {
          active++;
        }
        if (active === 0) {
          delete this.transitions[transition.name]
        }
      }
      doTransitionCallbacks.apply(this, [transition, ignoreCallbacks]);
    } else if (!ignoreWarn) {
      debug("Warning: Transition %o already removed", settingsName);
    }
  }

  function clearTransitions() {
    delete this.transitions;
    this.transitions = {};
  }

  VPAnimEngine.addInitialiser('transitions', function transitionsInitialiser() {
    clearTransitions.apply(this);
  });

  VPAnimEngine.addResetter('transitions', function transitionsResetter(skipClear) {
    if (!skipClear) {
      clearTransitions.apply(this);
    }
  });

  VPAnimEngine.addAdjustCallback(removeTransition);
  VPAnimEngine.addPipeProcessCallback(processAllTransitions);

  VPAnimEngine.addActions([
    {
      // Bezier timing info/method public to allow for it to be used
      name: 'timingBeziers',
      version: 1,
      value: {
               "ease": [ 0.25, 0.1, 0.25, 1.0 ],
             "linear": [ 0.0, 0.0, 1.0, 1.0 ],
            "ease-in": [ 0.42, 0.0, 1.0, 1.0 ],
           "ease-out": [ 0.0, 0.0, 0.58, 1.0 ],
        "ease-in-out": [ 0.42, 0.0, 0.58, 1.0 ]
      }
    },

    {
      name: 'addTransition',
      version: 1,
      action: function addTransition(path, newSettings, transPath) {
        if (!Array.isArray(path)) {
          path = [path];
        }

        var settingsName = path.join('-') || '-global';

        var transition;
        if (VPUtils.isString(transPath) || Array.isArray(transPath)) {
          transition = this.getSettings(transPath, true);
        } else {
          transition = transPath;
        }

        if (!VPUtils.isObject(transition)) {
          debug("Cannot add transition for %o because transition %o not found/defined", path, transPath);
          return;
        }

        var oldSettings;
        if (!this.transitions[settingsName]) {
          oldSettings = this.getSettings(path, true);
          if (!VPUtils.isObject(oldSettings)) {
            debug("Cannot add transition %o for settings named %o since there are no settings with that name (%o)", transition, settingsName, oldSettings);
            return;
          }
          this.transitions[settingsName] = {
            name: settingsName,
            path: JSON.parse(JSON.stringify(path)),
            changing: {},
            callbacks: {},
            settings: oldSettings
          };
        }

        var trans = this.transitions[settingsName];

        if (VPUtils.isString(newSettings) || Array.isArray(newSettings)) {
          newSettings = this.getSettings(newSettings);
        }

        for (var fieldName in newSettings) {
          if (trans.changing[fieldName]) {
            // this call skips callbacks for previous transition that is getting removed,
            // and ensures the existing transition doesn't get deleted
            this.removeTransition(path, fieldName, true, true, true);
          }
        }

        oldSettings = oldSettings || trans.settings;

        var delay = transition.delay || 0;

        var started;
        if (transition.now) {
          started = this.getTime(transition.timeType);
        } else {
          started = transition.fromTime || this.currentTime;
          if (started === undefined) {
            started = this.getTime(transition.timeType);
          }
        }
        var until = started + transition.duration + delay;
        debug("addTransition started %o, until %o, duration %o, delay %o, path %o", started, until, transition.duration, delay, settingsName);

        if (transition.callbacks) {
          if (!trans.callbacks[until]) {
            trans.callbacks[until] = { keys: [], actions: [] };
          }

          // only add the callback actions if they're not already on the action list
          if (trans.callbacks[until].actions.indexOf(transition.callbacks) === -1) {
            trans.callbacks[until].actions.push(transition.callbacks);
          }
        }

        for (var fieldName in newSettings) {
          var transParams = {
            started: started,
            until: until,
            delay: delay,
            from: oldSettings[fieldName],
            to: newSettings[fieldName],
            duration: transition.duration
          };

          if (transition.bezier) {
            if (Array.isArray(transition.bezier) && (transition.bezier.length === 4)) {
              transParams.bezier = transition.bezier;
            } else if (VPUtils.isString(transition.bezier) && this.timingBeziers[transition.bezier]) {
              transParams.bezier = this.timingBeziers[transition.bezier];
            } else {
              debug("Transition (%o) bezier function %o not understood", transition, transition.bezier);
            }
          }

          if (kColorSettings.indexOf(fieldName) != -1) {
            var gradCanvas = document.createElement("canvas");
            gradCanvas.width = 1;
            gradCanvas.height = 100;
            var ctx = gradCanvas.getContext('2d');
            var gradient = ctx.createLinearGradient(0, 0, 0, 100);
            if (!transParams.from || !transParams.to) {
              debug("Transition (%o) ignoring because to/from colour is undefined", transition);
              continue;
            }
            gradient.addColorStop(0, transParams.from);
            gradient.addColorStop(1, transParams.to);
            ctx.fillStyle = gradient;
            ctx.fillRect(0,0,1,100);
            transParams.gradient = ctx.getImageData(0, 0, 1, 100).data;
          } else if (!isNaN(new Number(transParams.from)) && !isNaN(new Number(transParams.to))) {
            transParams.delta = transParams.to - transParams.from;
          } else {
            debug("Transition (%o) of non numeric or colour value not supported %o: %o", transition, fieldName, transParams.from);
            continue;
          }

          trans.changing[fieldName] = transParams;

          if (transition.callbacks) {
            trans.callbacks[until].keys.push(fieldName);
          }
        }
      }
    },

    {
      name: 'hasTransition',
      version: 1,
      action: function hasTransition(path, newSettings, lookupPath) {
        if (lookupPath) {
          path = this.getSettings(path);
        }
        if (!Array.isArray(path)) {
          path = [path];
        }

        var settingsName = path.join('-') || '-global';
        var trans = this.transitions[settingsName];
        if (!trans) {
          debug("no transition matching path %s found", settingsName);
          return false;
        }

        if (VPUtils.isUndefined(newSettings)) {
          debug("Object at path %s has transition, and no newSettings object given to compare against, so returning true", settingsName);
          return true;
        }
        if (VPUtils.isString(newSettings) || Array.isArray(newSettings)) {
          newSettings = this.getSettings(newSettings);
        }

        for (var fieldName in newSettings) {
          if (trans.changing[fieldName]) {
            debug("transition found matching path %s and fieldName %s found", settingsName, fieldName);
            return true;
          }
        }

        debug("transition was found for path %s, but not for the field", settingsName);
        return false;
      }
    },

    {
      name: 'removeTransition',
      version: 1,
      action: removeTransition
    },

    {
      name: 'processAllTransitions',
      version: 1,
      action: processAllTransitions
    },

    {
      name: 'cubicBezierAtTime',
      version: 1,
      // Cubic bezier code based on WebKit code, care of: http://www.netzgesta.de/dev/cubic-bezier-timing-function.html
      action: function cubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) {
        var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
        // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
        function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
        function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
        function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
        // The epsilon value to pass given that the animation is going to run over |dur| seconds. The longer the
        // animation, the more precision is needed in the timing function result to avoid ugly discontinuities.
        function solveEpsilon(duration) {return 1.0/(200.0*duration);};
        function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
        // Given an x value, find a parametric value it came from.
        function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
          function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
          // First try a few iterations of Newton's method -- normally very fast.
          for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
          // Fall back to the bisection method for reliability.
          t0=0.0; t1=1.0; t2=x; if(t2<t0) {return t0;} if(t2>t1) {return t1;}
          while(t0<t1) {x2=sampleCurveX(t2); if(fabs(x2-x)<epsilon) {return t2;} if(x>x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
          return t2; // Failure.
        };
        // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
        cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
        // Convert from input time to parametric value in curve, then from that to output time.
        return solve(t, solveEpsilon(duration));
      }
    }

  ]);

})();


text:
UNPACK — Unpack an array of rank one into an array

Description

Store the elements of <var>VECTOR</var> in an array of higher rank.

Syntax

RESULT = UNPACK(VECTOR, MASK, FIELD)

Arguments

<var>VECTOR</var> 	Shall be an array of any type and rank one. It
shall have at least as many elements as <var>MASK</var> has TRUE values.

<var>MASK</var>   	Shall be an array of type LOGICAL.

<var>FIELD</var>  	Shall be of the same type as <var>VECTOR</var> and have
the same shape as <var>MASK</var>.

Return value

The resulting array corresponds to <var>FIELD</var> with TRUE elements
of <var>MASK</var> replaced by values from <var>VECTOR</var> in array element order.

Example

PROGRAM test_unpack

  integer :: vector(2)  = (/1,1/)

  logical :: mask(4)  = (/ .TRUE., .FALSE., .FALSE., .TRUE. /)

  integer :: field(2,2) = 0, unity(2,2)

  ! result: unity matrix

  unity = unpack(vector, reshape(mask, (/2,2/)), field)

END PROGRAM

Standard

Fortran 95 and later

Class

Transformational function

See also

PACK, SPREAD


text:
namespace device {
class UsbDevice;
}

namespace mojo {

template <>
struct TypeConverter<device::UsbDeviceFilter, device::usb::DeviceFilterPtr> {
  static device::UsbDeviceFilter Convert(
      const device::usb::DeviceFilterPtr& mojo_filter);
};

template <>
struct TypeConverter<device::usb::TransferDirection,
                     device::UsbEndpointDirection> {
  static device::usb::TransferDirection Convert(
      const device::UsbEndpointDirection& direction);
};

template <>
struct TypeConverter<device::usb::TransferStatus, device::UsbTransferStatus> {
  static device::usb::TransferStatus Convert(
      const device::UsbTransferStatus& status);
};

template <>
struct TypeConverter<device::UsbDeviceHandle::TransferRequestType,
                     device::usb::ControlTransferType> {
  static device::UsbDeviceHandle::TransferRequestType Convert(
      const device::usb::ControlTransferType& type);
};

template <>
struct TypeConverter<device::UsbDeviceHandle::TransferRecipient,
                     device::usb::ControlTransferRecipient> {
  static device::UsbDeviceHandle::TransferRecipient Convert(
      const device::usb::ControlTransferRecipient& recipient);
};

template <>
struct TypeConverter<device::usb::EndpointType, device::UsbTransferType> {
  static device::usb::EndpointType Convert(const device::UsbTransferType& type);
};

template <>
struct TypeConverter<device::usb::EndpointInfoPtr,
                     device::UsbEndpointDescriptor> {
  static device::usb::EndpointInfoPtr Convert(
      const device::UsbEndpointDescriptor& endpoint);
};

template <>
struct TypeConverter<device::usb::AlternateInterfaceInfoPtr,
                     device::UsbInterfaceDescriptor> {
  static device::usb::AlternateInterfaceInfoPtr Convert(
      const device::UsbInterfaceDescriptor& interface);
};

// Note that this is an explicit vector-to-array conversion, as
// UsbInterfaceDescriptor collections are flattened to contain all alternate
// settings, whereas InterfaceInfos contain their own sets of alternates with
// a different structure type.
template <>
struct TypeConverter<mojo::Array<device::usb::InterfaceInfoPtr>,
                     std::vector<device::UsbInterfaceDescriptor>> {
  static mojo::Array<device::usb::InterfaceInfoPtr> Convert(
      const std::vector<device::UsbInterfaceDescriptor>& interfaces);
};

template <>
struct TypeConverter<device::usb::ConfigurationInfoPtr,
                     device::UsbConfigDescriptor> {
  static device::usb::ConfigurationInfoPtr Convert(
      const device::UsbConfigDescriptor& config);
};

template <>
struct TypeConverter<device::usb::WebUsbFunctionSubsetPtr,
                     device::WebUsbFunctionSubset> {
  static device::usb::WebUsbFunctionSubsetPtr Convert(
      const device::WebUsbFunctionSubset& function);
};

template <>
struct TypeConverter<device::usb::WebUsbConfigurationSubsetPtr,
                     device::WebUsbConfigurationSubset> {
  static device::usb::WebUsbConfigurationSubsetPtr Convert(
      const device::WebUsbConfigurationSubset& config);
};

template <>
struct TypeConverter<device::usb::WebUsbDescriptorSetPtr,
                     device::WebUsbDescriptorSet> {
  static device::usb::WebUsbDescriptorSetPtr Convert(
      const device::WebUsbDescriptorSet& set);
};

template <>
struct TypeConverter<device::usb::DeviceInfoPtr, device::UsbDevice> {
  static device::usb::DeviceInfoPtr Convert(const device::UsbDevice& device);
};

}  // namespace mojo

#endif  // DEVICE_DEVICES_APP_USB_TYPE_CONVERTERS_H_


text:
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

import os
import string
import sys
import TestSCons

_python_ = TestSCons._python_

test = TestSCons.TestSCons()

bin1_build_py = test.workpath('bin1', 'build.py')
bin2_build_py = test.workpath('bin2', 'build.py')

test.write('SConstruct', """
import os
Bld = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
env1 = Environment(BUILDERS = { 'Bld' : Bld })
env2 = Environment(BUILDERS = { 'Bld' : Bld })
env1['ENV']['X'] = 'env1'
env2['ENV']['X'] = 'env2'
env1.Bld(target = 'env1.out', source = 'input')
env2.Bld(target = 'env2.out', source = 'input')
""" % locals())

test.write('build.py',
r"""#!/usr/bin/env python
import os
import sys
contents = open(sys.argv[2], 'rb').read()
open(sys.argv[1], 'wb').write("build.py %s\n%s" % (os.environ['X'], contents))
""")

test.write('input', "input file\n")

test.run(arguments = '.')

test.fail_test(test.read('env1.out') != "build.py env1\ninput file\n")
test.fail_test(test.read('env2.out') != "build.py env2\ninput file\n")

test.write('SConstruct', """
env = Environment()
foo = env.Command('foo', [], r'%(_python_)s build.py $TARGET')
env['ENV']['LIST'] = [foo, 'bar']
env['ENV']['FOO'] = foo
""" % locals())

test.write('build.py',
r"""
import os
print 'LIST:', os.environ['LIST']
print 'FOO:', os.environ['FOO']
""")

test.run()

test.fail_test(string.find(test.stdout(), "LIST: foo%sbar"%os.pathsep) == -1)
test.fail_test(string.find(test.stdout(), "FOO: foo") == -1)

test.pass_test()


text:
// Copyright 2009 the Sputnik authors.  All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/**
 * String.prototype.replace (searchValue, replaceValue)
 *
 * @path ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A1_T13.js
 * @description Call replace (searchValue, replaceValue) function with objects arguments of string.
 * First objects have overrided toString and valueOf functions.
 * Second objects have overrided toString function, that throw exception
 */

var __obj = {toString:function(){return {};}, valueOf:function(){return 1;}};
var __obj2 = {toString:function(){throw "inreplaceValue";}};

//////////////////////////////////////////////////////////////////////////////
//CHECK#1
try {
    var x = "ABB\u0041BABAB\u0031BBAA".replace(__obj, __obj2);
    $FAIL('#1: var x = "ABB\\u0041BABAB\\u0031BBAA".replace(__obj,__obj2) lead to throwing exception');
} catch (e) {
    if (e!=="inreplaceValue") {
        $ERROR('#1.1: Exception === "inreplaceValue". Actual: '+e);
    }
}
//
//////////////////////////////////////////////////////////////////////////////


text:
/**
 *
 */
package com.marcos.moiploja.catalog;

import com.marcos.moiploja.MoiplojaException;
import com.marcos.moiploja.entities.Category;
import com.marcos.moiploja.entities.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author Marcos
 */
@Service
@Transactional
public class CatalogService {
    @Autowired
    CategoryRepository categoryRepository;
    @Autowired
    ProductRepository productRepository;

    public List<Category> getAllCategories() {

        return categoryRepository.findAll();
    }

    public List<Product> getAllProducts() {

        return productRepository.findAll();
    }

    public Category getCategoryByName(String name) {
        return categoryRepository.getByName(name);
    }

    public Category getCategoryById(Integer id) {
        return categoryRepository.findOne(id);
    }

    public Category createCategory(Category category) throws MoiplojaException {
        Category persistedCategory = getCategoryByName(category.getName());
        if (persistedCategory != null) {
            throw new MoiplojaException("Category " + category.getName() + " already exist");
        }
        return categoryRepository.save(category);
    }

    public Category updateCategory(Category category) throws MoiplojaException{
        Category persistedCategory = getCategoryById(category.getId());
        if (persistedCategory == null) {
            throw new MoiplojaException("Category " + category.getId() + " doesn't exist");
        }
        persistedCategory.setDescription(category.getDescription());
        persistedCategory.setDisplayOrder(category.getDisplayOrder());
        persistedCategory.setDisabled(category.isDisabled());
        return categoryRepository.save(persistedCategory);
    }

    public Product getProductById(Integer id) {
        return productRepository.findOne(id);
    }

    public Product getProductBySku(String sku) {
        return productRepository.findBySku(sku);
    }

    public Product createProduct(Product product) throws MoiplojaException{
        Product persistedProduct = getProductBySku(product.getName());
        if (persistedProduct != null) {
            throw new MoiplojaException("Product SKU " + product.getSku() + " already exist");
        }
        return productRepository.save(product);
    }

    public Product updateProduct(Product product) throws MoiplojaException{
        Product persistedProduct = getProductById(product.getId());
        if (persistedProduct == null) {
            throw new MoiplojaException("Product " + product.getId() + " doesn't exist");
        }
        persistedProduct.setDescription(product.getDescription());
        persistedProduct.setDisabled(product.isDisabled());
        persistedProduct.setPrice(product.getPrice());
        persistedProduct.setCategory(getCategoryById(product.getCategory().getId()));
        return productRepository.save(persistedProduct);
    }

    public List<Product> searchProducts(String query) {
        return productRepository.search("%" + query + "%");
    }
}