text:
"""Google OAuth2 related functions."""

import BaseHTTPServer
import collections
import datetime
import functools
import hashlib
import json
import logging
import optparse
import os
import socket
import sys
import threading
import urllib
import urlparse
import webbrowser

from third_party import httplib2
from third_party.oauth2client import client
from third_party.oauth2client import multistore_file

# depot_tools/.
DEPOT_TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))

# Google OAuth2 clients always have a secret, even if the client is an installed
# application/utility such as this. Of course, in such cases the "secret" is
# actually publicly known; security depends entirely on the secrecy of refresh
# tokens, which effectively become bearer tokens. An attacker can impersonate
# service's identity in OAuth2 flow. But that's generally fine as long as a list
# of allowed redirect_uri's associated with client_id is limited to 'localhost'
# or 'urn:ietf:wg:oauth:2.0:oob'. In that case attacker needs some process
# running on user's machine to successfully complete the flow and grab refresh
# token. When you have a malicious code running on your machine, you're screwed
# anyway.
# This particular set is managed by API Console project "chrome-infra-auth".
OAUTH_CLIENT_ID = (
    '446450136466-2hr92jrq8e6i4tnsa56b52vacp7t3936.apps.googleusercontent.com')
OAUTH_CLIENT_SECRET = 'uBfbay2KCy9t4QveJ-dOqHtp'

# List of space separated OAuth scopes for generated tokens. GAE apps usually
# use userinfo.email scope for authentication.
OAUTH_SCOPES = 'https://www.googleapis.com/auth/userinfo.email'

# Path to a file with cached OAuth2 credentials used by default relative to the
# home dir (see _get_token_cache_path). It should be a safe location accessible
# only to a current user: knowing content of this file is roughly equivalent to
# knowing account password. Single file can hold multiple independent tokens
# identified by token_cache_key (see Authenticator).
OAUTH_TOKENS_CACHE = '.depot_tools_oauth2_tokens'

# Authentication configuration extracted from command line options.
# See doc string for 'make_auth_config' for meaning of fields.
AuthConfig = collections.namedtuple('AuthConfig', [
    'use_oauth2', # deprecated, will be always True
    'save_cookies', # deprecated, will be removed
    'use_local_webserver',
    'webserver_port',
    'refresh_token_json',
])

# OAuth access token with its expiration time (UTC datetime or None if unknown).
AccessToken = collections.namedtuple('AccessToken', [
    'token',
    'expires_at',
])

# Refresh token passed via --auth-refresh-token-json.
RefreshToken = collections.namedtuple('RefreshToken', [
    'client_id',
    'client_secret',
    'refresh_token',
])

class AuthenticationError(Exception):
  """Raised on errors related to authentication."""

class LoginRequiredError(AuthenticationError):
  """Interaction with the user is required to authenticate."""

  def __init__(self, token_cache_key):
    # HACK(vadimsh): It is assumed here that the token cache key is a hostname.
    msg = (
        'You are not logged in. Please login first by running:\n'
        '  depot-tools-auth login %s' % token_cache_key)
    super(LoginRequiredError, self).__init__(msg)

def make_auth_config(
    use_oauth2=None,
    save_cookies=None,
    use_local_webserver=None,
    webserver_port=None,
    refresh_token_json=None):
  """Returns new instance of AuthConfig.

  If some config option is None, it will be set to a reasonable default value.
  This function also acts as an authoritative place for default values of
  corresponding command line options.
  """
  default = lambda val, d: val if val is not None else d
  return AuthConfig(
      default(use_oauth2, True),
      default(save_cookies, True),
      default(use_local_webserver, not _is_headless()),
      default(webserver_port, 8090),
      default(refresh_token_json, ''))

def add_auth_options(parser, default_config=None):
  """Appends OAuth related options to OptionParser."""
  default_config = default_config or make_auth_config()
  parser.auth_group = optparse.OptionGroup(parser, 'Auth options')
  parser.add_option_group(parser.auth_group)

  # OAuth2 vs password switch.
  auth_default = 'use OAuth2' if default_config.use_oauth2 else 'use password'
  parser.auth_group.add_option(
      '--oauth2',
      action='store_true',
      dest='use_oauth2',
      default=default_config.use_oauth2,
      help='Use OAuth 2.0 instead of a password. [default: %s]' % auth_default)
  parser.auth_group.add_option(
      '--no-oauth2',
      action='store_false',
      dest='use_oauth2',
      default=default_config.use_oauth2,
      help='Use password instead of OAuth 2.0. [default: %s]' % auth_default)

  # Password related options, deprecated.
  parser.auth_group.add_option(
      '--no-cookies',
      action='store_false',
      dest='save_cookies',
      default=default_config.save_cookies,
      help='Do not save authentication cookies to local disk.')

  # OAuth2 related options.
  parser.auth_group.add_option(
      '--auth-no-local-webserver',
      action='store_false',
      dest='use_local_webserver',
      default=default_config.use_local_webserver,
      help='Do not run a local web server when performing OAuth2 login flow.')
  parser.auth_group.add_option(
      '--auth-host-port',
      type=int,
      default=default_config.webserver_port,
      help='Port a local web server should listen on. Used only if '
          '--auth-no-local-webserver is not set. [default: %default]')
  parser.auth_group.add_option(
      '--auth-refresh-token-json',
      default=default_config.refresh_token_json,
      help='Path to a JSON file with role account refresh token to use.')

def extract_auth_config_from_options(options):
  """Given OptionParser parsed options, extracts AuthConfig from it.

  OptionParser should be populated with auth options by 'add_auth_options'.
  """
  return make_auth_config(
      use_oauth2=options.use_oauth2,
      save_cookies=False if options.use_oauth2 else options.save_cookies,
      use_local_webserver=options.use_local_webserver,
      webserver_port=options.auth_host_port,
      refresh_token_json=options.auth_refresh_token_json)

def auth_config_to_command_options(auth_config):
  """AuthConfig -> list of strings with command line options.

  Omits options that are set to default values.
  """
  if not auth_config:
    return []
  defaults = make_auth_config()
  opts = []
  if auth_config.use_oauth2 != defaults.use_oauth2:
    opts.append('--oauth2' if auth_config.use_oauth2 else '--no-oauth2')
  if auth_config.save_cookies != auth_config.save_cookies:
    if not auth_config.save_cookies:
      opts.append('--no-cookies')
  if auth_config.use_local_webserver != defaults.use_local_webserver:
    if not auth_config.use_local_webserver:
      opts.append('--auth-no-local-webserver')
  if auth_config.webserver_port != defaults.webserver_port:
    opts.extend(['--auth-host-port', str(auth_config.webserver_port)])
  if auth_config.refresh_token_json != defaults.refresh_token_json:
    opts.extend([
        '--auth-refresh-token-json', str(auth_config.refresh_token_json)])
  return opts

def get_authenticator_for_host(hostname, config):
  """Returns Authenticator instance to access given host.

  Args:
    hostname: a naked hostname or http(s)://<hostname>[/] URL. Used to derive
        a cache key for token cache.
    config: AuthConfig instance.

  Returns:
    Authenticator object.
  """
  hostname = hostname.lower().rstrip('/')
  # Append some scheme, otherwise urlparse puts hostname into parsed.path.
  if '://' not in hostname:
    hostname = 'https://' + hostname
  parsed = urlparse.urlparse(hostname)
  if parsed.path or parsed.params or parsed.query or parsed.fragment:
    raise AuthenticationError(
        'Expecting a hostname or root host URL, got %s instead' % hostname)
  return Authenticator(parsed.netloc, config)

class Authenticator(object):
  """Object that knows how to refresh access tokens when needed.

  Args:
    token_cache_key: string key of a section of the token cache file to use
        to keep the tokens. See hostname_to_token_cache_key.
    config: AuthConfig object that holds authentication configuration.
  """

  def __init__(self, token_cache_key, config):
    assert isinstance(config, AuthConfig)
    assert config.use_oauth2
    self._access_token = None
    self._config = config
    self._lock = threading.Lock()
    self._token_cache_key = token_cache_key
    self._external_token = None
    if config.refresh_token_json:
      self._external_token = _read_refresh_token_json(config.refresh_token_json)
    logging.debug('Using auth config %r', config)

  def login(self):
    """Performs interactive login flow if necessary.

    Raises:
      AuthenticationError on error or if interrupted.
    """
    if self._external_token:
      raise AuthenticationError(
          'Can\'t run login flow when using --auth-refresh-token-json.')
    return self.get_access_token(
        force_refresh=True, allow_user_interaction=True)

  def logout(self):
    """Revokes the refresh token and deletes it from the cache.

    Returns True if had some credentials cached.
    """
    with self._lock:
      self._access_token = None
      storage = self._get_storage()
      credentials = storage.get()
      had_creds = bool(credentials)
      if credentials and credentials.refresh_token and credentials.revoke_uri:
        try:
          credentials.revoke(httplib2.Http())
        except client.TokenRevokeError as e:
          logging.warning('Failed to revoke refresh token: %s', e)
      storage.delete()
    return had_creds

  def has_cached_credentials(self):
    """Returns True if long term credentials (refresh token) are in cache.

    Doesn't make network calls.

    If returns False, get_access_token() later will ask for interactive login by
    raising LoginRequiredError.

    If returns True, most probably get_access_token() won't ask for interactive
    login, though it is not guaranteed, since cached token can be already
    revoked and there's no way to figure this out without actually trying to use
    it.
    """
    with self._lock:
      return bool(self._get_cached_credentials())

  def get_access_token(self, force_refresh=False, allow_user_interaction=False):
    """Returns AccessToken, refreshing it if necessary.

    Args:
      force_refresh: forcefully refresh access token even if it is not expired.
      allow_user_interaction: True to enable blocking for user input if needed.

    Raises:
      AuthenticationError on error or if authentication flow was interrupted.
      LoginRequiredError if user interaction is required, but
          allow_user_interaction is False.
    """
    with self._lock:
      if force_refresh:
        logging.debug('Forcing access token refresh')
        self._access_token = self._create_access_token(allow_user_interaction)
        return self._access_token

      # Load from on-disk cache on a first access.
      if not self._access_token:
        self._access_token = self._load_access_token()

      # Refresh if expired or missing.
      if not self._access_token or _needs_refresh(self._access_token):
        # Maybe some other process already updated it, reload from the cache.
        self._access_token = self._load_access_token()
        # Nope, still expired, need to run the refresh flow.
        if not self._access_token or _needs_refresh(self._access_token):
          self._access_token = self._create_access_token(allow_user_interaction)

      return self._access_token

  def get_token_info(self):
    """Returns a result of /oauth2/v2/tokeninfo call with token info."""
    access_token = self.get_access_token()
    resp, content = httplib2.Http().request(
        uri='https://www.googleapis.com/oauth2/v2/tokeninfo?%s' % (
            urllib.urlencode({'access_token': access_token.token})))
    if resp.status == 200:
      return json.loads(content)
    raise AuthenticationError('Failed to fetch the token info: %r' % content)

  def authorize(self, http):
    """Monkey patches authentication logic of httplib2.Http instance.

    The modified http.request method will add authentication headers to each
    request and will refresh access_tokens when a 401 is received on a
    request.

    Args:
       http: An instance of httplib2.Http.

    Returns:
       A modified instance of http that was passed in.
    """
    # Adapted from oauth2client.OAuth2Credentials.authorize.

    request_orig = http.request

    @functools.wraps(request_orig)
    def new_request(
        uri, method='GET', body=None, headers=None,
        redirections=httplib2.DEFAULT_MAX_REDIRECTS,
        connection_type=None):
      headers = (headers or {}).copy()
      headers['Authorization'] = 'Bearer %s' % self.get_access_token().token
      resp, content = request_orig(
          uri, method, body, headers, redirections, connection_type)
      if resp.status in client.REFRESH_STATUS_CODES:
        logging.info('Refreshing due to a %s', resp.status)
        access_token = self.get_access_token(force_refresh=True)
        headers['Authorization'] = 'Bearer %s' % access_token.token
        return request_orig(
            uri, method, body, headers, redirections, connection_type)
      else:
        return (resp, content)

    http.request = new_request
    return http

  ## Private methods.

  def _get_storage(self):
    """Returns oauth2client.Storage with cached tokens."""
    # Do not mix cache keys for different externally provided tokens.
    if self._external_token:
      token_hash = hashlib.sha1(self._external_token.refresh_token).hexdigest()
      cache_key = '%s:refresh_tok:%s' % (self._token_cache_key, token_hash)
    else:
      cache_key = self._token_cache_key
    path = _get_token_cache_path()
    logging.debug('Using token storage %r (cache key %r)', path, cache_key)
    return multistore_file.get_credential_storage_custom_string_key(
        path, cache_key)

  def _get_cached_credentials(self):
    """Returns oauth2client.Credentials loaded from storage."""
    storage = self._get_storage()
    credentials = storage.get()

    if not credentials:
      logging.debug('No cached token')
    else:
      _log_credentials_info('cached token', credentials)

    # Is using --auth-refresh-token-json?
    if self._external_token:
      # Cached credentials are valid and match external token -> use them. It is
      # important to reuse credentials from the storage because they contain
      # cached access token.
      valid = (
          credentials and not credentials.invalid and
          credentials.refresh_token == self._external_token.refresh_token and
          credentials.client_id == self._external_token.client_id and
          credentials.client_secret == self._external_token.client_secret)
      if valid:
        logging.debug('Cached credentials match external refresh token')
        return credentials
      # Construct new credentials from externally provided refresh token,
      # associate them with cache storage (so that access_token will be placed
      # in the cache later too).
      logging.debug('Putting external refresh token into the cache')
      credentials = client.OAuth2Credentials(
          access_token=None,
          client_id=self._external_token.client_id,
          client_secret=self._external_token.client_secret,
          refresh_token=self._external_token.refresh_token,
          token_expiry=None,
          token_uri='https://accounts.google.com/o/oauth2/token',
          user_agent=None,
          revoke_uri=None)
      credentials.set_store(storage)
      storage.put(credentials)
      return credentials

    # Not using external refresh token -> return whatever is cached.
    return credentials if (credentials and not credentials.invalid) else None

  def _load_access_token(self):
    """Returns cached AccessToken if it is not expired yet."""
    logging.debug('Reloading access token from cache')
    creds = self._get_cached_credentials()
    if not creds or not creds.access_token or creds.access_token_expired:
      logging.debug('Access token is missing or expired')
      return None
    return AccessToken(str(creds.access_token), creds.token_expiry)

  def _create_access_token(self, allow_user_interaction=False):
    """Mints and caches a new access token, launching OAuth2 dance if necessary.

    Uses cached refresh token, if present. In that case user interaction is not
    required and function will finish quietly. Otherwise it will launch 3-legged
    OAuth2 flow, that needs user interaction.

    Args:
      allow_user_interaction: if True, allow interaction with the user (e.g.
          reading standard input, or launching a browser).

    Returns:
      AccessToken.

    Raises:
      AuthenticationError on error or if authentication flow was interrupted.
      LoginRequiredError if user interaction is required, but
          allow_user_interaction is False.
    """
    logging.debug(
        'Making new access token (allow_user_interaction=%r)',
        allow_user_interaction)
    credentials = self._get_cached_credentials()

    # 3-legged flow with (perhaps cached) refresh token.
    refreshed = False
    if credentials and not credentials.invalid:
      try:
        logging.debug('Attempting to refresh access_token')
        credentials.refresh(httplib2.Http())
        _log_credentials_info('refreshed token', credentials)
        refreshed = True
      except client.Error as err:
        logging.warning(
            'OAuth error during access token refresh (%s). '
            'Attempting a full authentication flow.', err)

    # Refresh token is missing or invalid, go through the full flow.
    if not refreshed:
      # Can't refresh externally provided token.
      if self._external_token:
        raise AuthenticationError(
            'Token provided via --auth-refresh-token-json is no longer valid.')
      if not allow_user_interaction:
        logging.debug('Requesting user to login')
        raise LoginRequiredError(self._token_cache_key)
      logging.debug('Launching OAuth browser flow')
      credentials = _run_oauth_dance(self._config)
      _log_credentials_info('new token', credentials)

    logging.info(
        'OAuth access_token refreshed. Expires in %s.',
        credentials.token_expiry - datetime.datetime.utcnow())
    storage = self._get_storage()
    credentials.set_store(storage)
    storage.put(credentials)
    return AccessToken(str(credentials.access_token), credentials.token_expiry)

## Private functions.

def _get_token_cache_path():
  # On non Win just use HOME.
  if sys.platform != 'win32':
    return os.path.join(os.path.expanduser('~'), OAUTH_TOKENS_CACHE)
  # Prefer USERPROFILE over HOME, since HOME is overridden in
  # git-..._bin/cmd/git.cmd to point to depot_tools. depot-tools-auth.py script
  # (and all other scripts) doesn't use this override and thus uses another
  # value for HOME. git.cmd doesn't touch USERPROFILE though, and usually
  # USERPROFILE == HOME on Windows.
  if 'USERPROFILE' in os.environ:
    return os.path.join(os.environ['USERPROFILE'], OAUTH_TOKENS_CACHE)
  return os.path.join(os.path.expanduser('~'), OAUTH_TOKENS_CACHE)

def _is_headless():
  """True if machine doesn't seem to have a display."""
  return sys.platform == 'linux2' and not os.environ.get('DISPLAY')

def _read_refresh_token_json(path):
  """Returns RefreshToken by reading it from the JSON file."""
  try:
    with open(path, 'r') as f:
      data = json.load(f)
      return RefreshToken(
          client_id=str(data.get('client_id', OAUTH_CLIENT_ID)),
          client_secret=str(data.get('client_secret', OAUTH_CLIENT_SECRET)),
          refresh_token=str(data['refresh_token']))
  except (IOError, ValueError) as e:
    raise AuthenticationError(
        'Failed to read refresh token from %s: %s' % (path, e))
  except KeyError as e:
    raise AuthenticationError(
        'Failed to read refresh token from %s: missing key %s' % (path, e))

def _needs_refresh(access_token):
  """True if AccessToken should be refreshed."""
  if access_token.expires_at is not None:
    # Allow 5 min of clock skew between client and backend.
    now = datetime.datetime.utcnow() + datetime.timedelta(seconds=300)
    return now >= access_token.expires_at
  # Token without expiration time never expires.
  return False

def _log_credentials_info(title, credentials):
  """Dumps (non sensitive) part of client.Credentials object to debug log."""
  if credentials:
    logging.debug('%s info: %r', title, {
        'access_token_expired': credentials.access_token_expired,
        'has_access_token': bool(credentials.access_token),
        'invalid': credentials.invalid,
        'utcnow': datetime.datetime.utcnow(),
        'token_expiry': credentials.token_expiry,
    })

def _run_oauth_dance(config):
  """Perform full 3-legged OAuth2 flow with the browser.

  Returns:
    oauth2client.Credentials.

  Raises:
    AuthenticationError on errors.
  """
  flow = client.OAuth2WebServerFlow(
      OAUTH_CLIENT_ID,
      OAUTH_CLIENT_SECRET,
      OAUTH_SCOPES,
      approval_prompt='force')

  use_local_webserver = config.use_local_webserver
  port = config.webserver_port
  if config.use_local_webserver:
    success = False
    try:
      httpd = _ClientRedirectServer(('localhost', port), _ClientRedirectHandler)
    except socket.error:
      pass
    else:
      success = True
    use_local_webserver = success
    if not success:
      print(
        'Failed to start a local webserver listening on port %d.\n'
        'Please check your firewall settings and locally running programs that '
        'may be blocking or using those ports.\n\n'
        'Falling back to --auth-no-local-webserver and continuing with '
        'authentication.\n' % port)

  if use_local_webserver:
    oauth_callback = 'http://localhost:%s/' % port
  else:
    oauth_callback = client.OOB_CALLBACK_URN
  flow.redirect_uri = oauth_callback
  authorize_url = flow.step1_get_authorize_url()

  if use_local_webserver:
    webbrowser.open(authorize_url, new=1, autoraise=True)
    print(
      'Your browser has been opened to visit:\n\n'
      '    %s\n\n'
      'If your browser is on a different machine then exit and re-run this '
      'application with the command-line parameter\n\n'
      '  --auth-no-local-webserver\n' % authorize_url)
  else:
    print(
      'Go to the following link in your browser:\n\n'
      '    %s\n' % authorize_url)

  try:
    code = None
    if use_local_webserver:
      httpd.handle_request()
      if 'error' in httpd.query_params:
        raise AuthenticationError(
            'Authentication request was rejected: %s' %
            httpd.query_params['error'])
      if 'code' not in httpd.query_params:
        raise AuthenticationError(
            'Failed to find "code" in the query parameters of the redirect.\n'
            'Try running with --auth-no-local-webserver.')
      code = httpd.query_params['code']
    else:
      code = raw_input('Enter verification code: ').strip()
  except KeyboardInterrupt:
    raise AuthenticationError('Authentication was canceled.')

  try:
    return flow.step2_exchange(code)
  except client.FlowExchangeError as e:
    raise AuthenticationError('Authentication has failed: %s' % e)

class _ClientRedirectServer(BaseHTTPServer.HTTPServer):
  """A server to handle OAuth 2.0 redirects back to localhost.

  Waits for a single request and parses the query parameters
  into query_params and then stops serving.
  """
  query_params = {}

class _ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
  """A handler for OAuth 2.0 redirects back to localhost.

  Waits for a single request and parses the query parameters
  into the servers query_params and then stops serving.
  """

  def do_GET(self):
    """Handle a GET request.

    Parses the query parameters and prints a message
    if the flow has completed. Note that we can't detect
    if an error occurred.
    """
    self.send_response(200)
    self.send_header('Content-type', 'text/html')
    self.end_headers()
    query = self.path.split('?', 1)[-1]
    query = dict(urlparse.parse_qsl(query))
    self.server.query_params = query
    self.wfile.write('<html><head><title>Authentication Status</title></head>')
    self.wfile.write('<body><p>The authentication flow has completed.</p>')
    self.wfile.write('</body></html>')

  def log_message(self, _format, *args):
    """Do not log messages to stdout while running as command line program."""


text:
<?php
namespace CtiDigital\Configurator\Test\Unit\Component;

use CtiDigital\Configurator\Component\Customers;
use CtiDigital\Configurator\Exception\ComponentException;
use FireGento\FastSimpleImport\Model\ImporterFactory;
use Magento\Customer\Api\GroupRepositoryInterface;
use Magento\Customer\Api\GroupManagementInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SearchCriteria;
use Magento\Framework\Api\SearchResults;
use Magento\Indexer\Model\IndexerFactory;
use CtiDigital\Configurator\Api\LoggerInterface;
use Magento\Customer\Model\Data\Group;

class CustomersTest extends \PHPUnit\Framework\TestCase
{
    /**
     * @var Customers
     */
    private $customers;

    /**
     * @var ImporterFactory|\PHPUnit\Framework\MockObject\MockObject
     */
    private $importerFactory;

    /**
     * @var GroupRepositoryInterface | |PHPUnit_Framework_MockObject_MockObject
     */
    private $groupRepository;

    /**
     * @var GroupManagementInterface | \PHPUnit_Framework_MockObject_MockObject
     */
    private $groupManagement;

    /**
     * @var SearchCriteriaBuilder | \PHPUnit_Framework_MockObject_MockObject
     */
    private $searchBuilder;

    /**
     * @var SearchCriteria | \PHPUnit_Framework_MockObject_MockObject
     */
    private $searchCriteria;

    /**
     * @var SearchResults | \PHPUnit_Framework_MockObject_MockObject
     */
    private $searchResults;

    /**
     * @var IndexerFactory|\PHPUnit\Framework\MockObject\MockObject
     */
    private $indexerFactory;

    /**
     * @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject
     */
    private $log;

    protected function setUp()
    {
        $this->importerFactory = $this->getMockBuilder(ImporterFactory::class)
            ->setMethods(['create'])
            ->disableOriginalConstructor()
            ->getMock();

        $this->searchResults = $this->getMockBuilder(SearchResults::class)
            ->setMethods(['getItems'])
            ->disableOriginalConstructor()
            ->getMock();

        $this->groupRepository = $this->getMockBuilder(GroupRepositoryInterface::class)
            ->setMethods(['save', 'getById', 'delete', 'deleteById', 'getList'])
            ->disableOriginalConstructor()
            ->getMock();

        $this->groupRepository->expects($this->any())
            ->method('getList')
            ->willReturn($this->searchResults);

        $groupDefault = $this->createCustomerGroup(1);

        $this->groupManagement = $this->getMockBuilder(GroupManagementInterface::class)
            ->setMethods(
                ['isReadOnly', 'getNotLoggedInGroup', 'getLoggedInGroups', 'getAllCustomersGroup', 'getDefaultGroup']
            )
            ->disableOriginalConstructor()
            ->getMock();

        $this->groupManagement->expects($this->any())
            ->method('getDefaultGroup')
            ->willReturn($groupDefault);

        $this->searchCriteria = $this->getMockBuilder(SearchCriteria::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->searchBuilder = $this->getMockBuilder(SearchCriteriaBuilder::class)
            ->setMethods(['create'])
            ->disableOriginalConstructor()
            ->getMock();
        $this->searchBuilder->expects($this->any())
            ->method('create')
            ->willReturn($this->searchCriteria);

        $this->indexerFactory = $this->getMockBuilder(IndexerFactory::class)
            ->setMethods(['create'])
            ->disableOriginalConstructor()
            ->getMock();

        $this->log = $this->getMockBuilder(LoggerInterface::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->customers = new Customers(
            $this->importerFactory,
            $this->groupRepository,
            $this->groupManagement,
            $this->searchBuilder,
            $this->indexerFactory,
            $this->log
        );
    }

    public function testDataMissingRows()
    {
        $testData = [];
        $this->expectException(ComponentException::class);
        $this->customers->getColumnHeaders($testData);
    }

    public function testColumnsNotFound()
    {
        $testData = [['_website', '_store', 'firstname', 'notallowed']];
        $this->expectException(ComponentException::class, 'The column "email" is required.');
        $this->customers->getColumnHeaders($testData);
    }

    public function testGetColumns()
    {
        $expected = ['email', '_website', '_store', 'firstname', 'lastname'];
        $testData = [
            ['email', '_website', '_store', 'firstname', 'lastname'],
            ['example@example.com', 'base', 'Default', 'Test', 'Test']
        ];
        $this->customers->getColumnHeaders($testData);
        $this->assertEquals($expected, $this->customers->getHeaders());
    }

    public function testGroupIsValid()
    {
        $group1 = $this->createCustomerGroup(1);
        $group2 = $this->createCustomerGroup(2);
        $groups = [$group1, $group2];
        $this->searchResults->expects($this->any())
            ->method('getItems')
            ->willReturn($groups);
        $this->assertTrue($this->customers->isValidGroup(1));
    }

    public function testGroupNotValid()
    {
        $group1 = $this->createCustomerGroup(1);
        $group2 = $this->createCustomerGroup(2);
        $groups = [$group1, $group2];
        $this->searchResults->expects($this->any())
            ->method('getItems')
            ->willReturn($groups);
        $this->assertFalse($this->customers->isValidGroup(4));
    }

    public function testGetDefault()
    {
        $this->assertEquals(1, $this->customers->getDefaultGroupId());
    }

    private function createCustomerGroup($groupId)
    {
        $group = $this->getMockBuilder(Group::class)
            ->setMethods(['getId'])
            ->disableOriginalConstructor()
            ->getMock();
        $group->expects($this->any())
            ->method('getId')
            ->willReturn($groupId);
        return $group;
    }
}

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

    <persistence-unit name="ApplicationEntityManager" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>cn.org.eshow.model.User</class>
        <class>cn.org.eshow.model.Role</class>
    </persistence-unit>

    <!-- WARNING: This file's file original source is at web/common/src/main/resources/META-INF. The
        META-INF directory is included in the jsf, spring, struts and tapestry projects using svn:externals.
        If you need to modify this file, please do so in web/common/src/main/resources/META-INF, check it
        in, and then "svn up" for the other modules. -->
</persistence>


text:
using System.Collections.Concurrent;
using Microsoft.CodeAnalysis;
using Wyam.Common;
using Wyam.Common.Documents;
using Wyam.Common.Meta;

namespace Wyam.Modules.CodeAnalysis
{
    internal class SymbolDocumentValue : IMetadataValue
    {
        private readonly ISymbol _symbol;
        private readonly AnalyzeSymbolVisitor _visitor;
        private bool _cached;
        private IDocument _value;

        public SymbolDocumentValue(ISymbol symbol, AnalyzeSymbolVisitor visitor)
        {
            _symbol = symbol;
            _visitor = visitor;
        }

        public object Get(string key, IMetadata metadata)
        {
            if (!_cached)
            {
                if (_symbol == null)
                {
                    _value = null;
                }
                else if (!_visitor.TryGetDocument(_symbol, out _value))
                {
                    // Visit the symbol and try again
                    _symbol.Accept(_visitor);
                    if (!_visitor.TryGetDocument(_symbol, out _value))
                    {
                        _value = null;
                    }
                }
                _cached = true;
            }
            return _value;
        }
    }
}


text:
<!DOCTYPE html>

	<meta charset="UTF-8"/>
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
	<meta name="generator" content="Jekyll">

	<title>Sobre o Workshop</title>

	<link rel="stylesheet" href="/Workshop_genetica_esalq/css/main.css">
	<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700,900,400italic%7CSignika:700,300,400,600' rel='stylesheet' type='text/css'>

	<link href="/atom.xml" type="application/atom+xml" rel="alternate" title="ATOM Feed" />

		Home

	      Sobre minicursos

	      Sobre a equipe

	      Sobre o Workshop

	      Apresentações teóricas

	  Project on Github

Materiais didáticos

Minicursos de Introdução ao R

 Aqui você irá encontrar o material utilizado nos minicursos ministrados nos anos de 2015, 2016, 2017, 2018, 2019 e 2020

	elaborados por alunos de pós-graduação dos laboratórios de Genética Estatística e de Bioinformática Aplicada à Bioenergia, ambos da ESALQ-USP.

Utilize o menu localizado no canto direito superior desta página para acesso às apresentações teóricas e outras informações.

É uma iniciativa dos alunos do programa de pós-graduação em Genética e Melhoramento de Plantas, da Comissão Coordenadora do Programa e apoio do Departamento de Genética da ESALQ/USP categories.

Ocorre todos os anos no período das férias de inverno. Acesse mais informações na página do facebook

	    Powered by Jekyll with Emerald theme


text:
import { expect } from 'chai';
import sinon from 'sinon';
import { randomWithRange, simplifyAngle } from './mathHelpers';

describe('mathHelpers', () => {
    describe('randomWithRange', () => {
        it("returns a number that's a random amount between the min and max range", () => {
            sinon.stub(Math, 'random').returns(0.5);
            expect(randomWithRange(2, 4)).to.equal(3);
            Math.random.restore();
        });
    });

    describe('simplifyAngle', () => {
        it('returns the angle if it is between 0 and 360', () => {
            expect(simplifyAngle(180)).to.equal(180);
        });

        it('returns an angle between 0 and 360 if it is less than 0', () => {
            expect(simplifyAngle(-2133)).to.equal(27);
        });

        it('returns an angle between 0 and 360 if it is greater than or equal to 360', () => {
            expect(simplifyAngle(2387)).to.equal(227);
        });

        it('returns 0 if the angle is 360', () => {
            expect(simplifyAngle(360)).to.equal(0);
        });
    });
});


text:
var gulp = require('gulp'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    jshint = require('gulp-jshint'),
    rename = require('gulp-rename'),
    karma = require('gulp-karma'),
    connect = require('gulp-connect'),
    myth = require('gulp-myth'),
    minifyCSS = require('gulp-minify-css'),
    stylish = require('jshint-stylish'),
    babel = require('gulp-babel'),
    debug = false,
    WATCH_MODE = 'watch',
    RUN_MODE = 'run';

var mode = WATCH_MODE;

// Lints JavaScript code style based on jshint rules in .jshintrc
gulp.task('lint', () => {
  gulp.src('src/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter(stylish));
});

//gulp.task('karma', function() {
//  // undefined.js: unfortunately necessary for now
//  gulp.src(['undefined.js'])
//    .pipe(karma({
//      configFile: 'karma.conf.js',
//      action: mode
//    }))
//    .on('error', function() {});
//});

// Creates distribution and minified distribution file from source
gulp.task('js', () => {
  var jsTask = gulp
    .src('src/**/*.js')
    .pipe(babel())
    .pipe(concat('ng-dropdown.js'))
    .pipe(gulp.dest('dist/js'));
  if (!debug) {
    jsTask.pipe(uglify());
  }
  jsTask
    .pipe(rename('ng-dropdown.min.js'))
    .pipe(gulp.dest('dist/js'))
    .pipe(connect.reload());
});

gulp.task('css', function () {
  var cssTask = gulp
    .src('src/css/**/*.css')
    .pipe(concat('ng-dropdown.css'))
    .pipe(myth())
    .pipe(gulp.dest('dist/css'));
  if (!debug) {
    cssTask.pipe(minifyCSS());
  }
  cssTask
    .pipe(rename('ng-dropdown.min.css'))
    .pipe(gulp.dest('dist/css'))
    .pipe(connect.reload());
});

gulp.task('connect', function() {
  gulp.watch(['index.html'], function() {
    gulp.src(['index.html'])
      .pipe(connect.reload());
  });

  connect.server({
    livereload: true
  });
});

//gulp.task('kill-connect', ['protractor'], function() {
//  connect.serverClose();
//});

gulp.task('run-mode', function() {
  mode = RUN_MODE;
});

gulp.task('debug', function() {
  debug = true;
});

// Watches files for changes and re-runs relevant tasks
gulp.task('watch', () => {
  var jsWatcher = gulp.watch('src/**/*.js', gulp.parallel('lint', 'js')),
      cssWatcher = gulp.watch('src/**/*.css', gulp.parallel('css'));

  function changeNotification(event) {
    console.log('File', event.path, 'was', event.type);
  }

  jsWatcher.on('change', changeNotification);
  cssWatcher.on('change', changeNotification);
});

gulp.task('default', gulp.parallel('lint', 'js', 'watch'));

gulp.task('server', gulp.parallel('connect', 'default'));

//gulp.task('test', ['run-mode', 'debug', 'connect', 'all', 'kill-connect']);


text:
package com.u2ware.springfield.sample.part2.step1;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;

import com.u2ware.springfield.sample.ApplicationContextTestRoot;

public class QueryBeanControllerTest extends ApplicationContextTestRoot{

	@Test
	public void testFind1() throws Exception{
		this.mockMvc.perform(
				get("/part2/step1"))
			.andExpect(status().isOk());
	}

	@Test
	public void testFind2() throws Exception{
		this.mockMvc.perform(
				get("/part2/step1")
			.param("id", "1"))
			.andExpect(status().isOk());
	}

	@Test
	public void testFind3() throws Exception{
		this.mockMvc.perform(
				get("/part2/step1")
			.param("id", "1")
			.param("password", "1"))
			.andExpect(status().isOk());
	}

}


text:
namespace ConsumingWebServicesUsingCSharp.Models
{
    using Newtonsoft.Json;

    public class Pdf
    {
        [JsonProperty("isAvailable")]
        public bool IsAvailable { get; set; }
    }
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using OpenMetaverse;

namespace Aurora.Framework
{
    public sealed class InventoryFolderImpl : InventoryFolderBase
    {
        //private static readonly ILog MainConsole.Instance = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public static readonly string PATH_DELIMITER = "/";

        ///
        ///   Items that are contained in this folder
        ///
        public Dictionary<UUID, InventoryItemBase> Items = new Dictionary<UUID, InventoryItemBase>();

        ///
        ///   Child folders that are contained in this folder
        ///
        private Dictionary<UUID, InventoryFolderImpl> m_childFolders = new Dictionary<UUID, InventoryFolderImpl>();

        // Constructors
        public InventoryFolderImpl(InventoryFolderBase folderbase)
        {
            Owner = folderbase.Owner;
            ID = folderbase.ID;
            Name = folderbase.Name;
            ParentID = folderbase.ParentID;
            Type = folderbase.Type;
            Version = folderbase.Version;
        }

        public InventoryFolderImpl()
        {
        }

        /// <value>
        ///   The total number of items in this folder and in the immediate child folders (though not from other
        ///   descendants).
        /// </value>
        public int TotalCount
        {
            get
            {
#if (!ISWIN)
                int result = Items.Count;
                foreach (InventoryFolderImpl value in m_childFolders.Values)
                    result = result + value.TotalCount;
                return result;
#else
                return m_childFolders.Values.Aggregate(Items.Count, (current, folder) => current + folder.TotalCount);
#endif
            }
        }

        ///
        ///   Create a new subfolder.
        ///
        /// <param name = "folderID"></param>
        /// <param name = "folderName"></param>
        /// <param name = "type"></param>
        /// <returns>The newly created subfolder.  Returns null if the folder already exists</returns>
        public InventoryFolderImpl CreateChildFolder(UUID folderID, string folderName, ushort type)
        {
            lock (m_childFolders)
            {
                if (!m_childFolders.ContainsKey(folderID))
                {
                    InventoryFolderImpl subFold = new InventoryFolderImpl
                                                      {
                                                          Name = folderName,
                                                          ID = folderID,
                                                          Type = (short) type,
                                                          ParentID = this.ID,
                                                          Owner = Owner
                                                      };
                    m_childFolders.Add(subFold.ID, subFold);

                    return subFold;
                }
            }

            return null;
        }

        ///
        ///   Add a folder that already exists.
        ///
        /// <param name = "folder"></param>
        public void AddChildFolder(InventoryFolderImpl folder)
        {
            lock (m_childFolders)
            {
                folder.ParentID = ID;
                m_childFolders[folder.ID] = folder;
            }
        }

        ///
        ///   Does this folder contain the given child folder?
        ///
        /// <param name = "folderID"></param>
        /// <returns></returns>
        public bool ContainsChildFolder(UUID folderID)
        {
            return m_childFolders.ContainsKey(folderID);
        }

        ///
        ///   Get a child folder
        ///
        /// <param name = "folderID"></param>
        /// <returns>The folder if it exists, null if it doesn't</returns>
        public InventoryFolderImpl GetChildFolder(UUID folderID)
        {
            InventoryFolderImpl folder = null;

            lock (m_childFolders)
            {
                m_childFolders.TryGetValue(folderID, out folder);
            }

            return folder;
        }

        ///
        ///   Removes the given child subfolder.
        ///
        /// <param name = "folderID"></param>
        /// <returns>
        ///   The folder removed, or null if the folder was not present.
        /// </returns>
        public InventoryFolderImpl RemoveChildFolder(UUID folderID)
        {
            InventoryFolderImpl removedFolder = null;

            lock (m_childFolders)
            {
                if (m_childFolders.ContainsKey(folderID))
                {
                    removedFolder = m_childFolders[folderID];
                    m_childFolders.Remove(folderID);
                }
            }

            return removedFolder;
        }

        ///
        ///   Delete all the folders and items in this folder.
        ///
        public void Purge()
        {
            foreach (InventoryFolderImpl folder in m_childFolders.Values)
            {
                folder.Purge();
            }

            m_childFolders.Clear();
            Items.Clear();
        }

        ///
        ///   Returns the item if it exists in this folder or in any of this folder's descendant folders
        ///
        /// <param name = "itemID"></param>
        /// <returns>null if the item is not found</returns>
        public InventoryItemBase FindItem(UUID itemID)
        {
            lock (Items)
            {
                if (Items.ContainsKey(itemID))
                {
                    return Items[itemID];
                }
            }

            lock (m_childFolders)
            {
#if (!ISWIN)
                foreach (InventoryFolderImpl folder in m_childFolders.Values)
                {
                    InventoryItemBase item = folder.FindItem(itemID);
                    if (item != null)
                    {
                        return item;
                    }
                }
#else
                foreach (InventoryItemBase item in m_childFolders.Values.Select(folder => folder.FindItem(itemID)).Where(item => item != null))
                {
                    return item;
                }
#endif
            }

            return null;
        }

        public InventoryItemBase FindAsset(UUID assetID)
        {
            lock (Items)
            {
#if (!ISWIN)
                foreach (InventoryItemBase item in Items.Values)
                {
                    if (item.AssetID == assetID)
                    {
                        return item;
                    }
                }
#else
                foreach (InventoryItemBase item in Items.Values.Where(item => item.AssetID == assetID))
                {
                    return item;
                }
#endif
            }

            lock (m_childFolders)
            {
#if (!ISWIN)
                foreach (InventoryFolderImpl folder in m_childFolders.Values)
                {
                    InventoryItemBase item = folder.FindAsset(assetID);
                    if (item != null)
                    {
                        return item;
                    }
                }
#else
                foreach (InventoryItemBase item in m_childFolders.Values.Select(folder => folder.FindAsset(assetID)).Where(item => item != null))
                {
                    return item;
                }
#endif
            }

            return null;
        }

        ///
        ///   Deletes an item if it exists in this folder or any children
        ///
        /// <param name = "folderID"></param>
        /// <returns></returns>
        public bool DeleteItem(UUID itemID)
        {
            bool found = false;

            lock (Items)
            {
                if (Items.ContainsKey(itemID))
                {
                    Items.Remove(itemID);
                    return true;
                }
            }

            lock (m_childFolders)
            {
                foreach (InventoryFolderImpl folder in m_childFolders.Values)
                {
                    found = folder.DeleteItem(itemID);

                    if (found)
                    {
                        break;
                    }
                }
            }

            return found;
        }

        ///
        ///   Returns the folder requested if it is this folder or is a descendent of this folder.  The search is depth
        ///   first.
        ///
        /// <returns>The requested folder if it exists, null if it does not.</returns>
        public InventoryFolderImpl FindFolder(UUID folderID)
        {
            if (folderID == ID)
                return this;

            lock (m_childFolders)
            {
#if (!ISWIN)
                foreach (InventoryFolderImpl folder in m_childFolders.Values)
                {
                    InventoryFolderImpl returnFolder = folder.FindFolder(folderID);
                    if (returnFolder != null)
                    {
                        return returnFolder;
                    }
                }
#else
                foreach (InventoryFolderImpl returnFolder in m_childFolders.Values.Select(folder => folder.FindFolder(folderID)).Where(returnFolder => returnFolder != null))
                {
                    return returnFolder;
                }
#endif
            }

            return null;
        }

        ///
        ///   Look through all child subfolders for a folder marked as one for a particular asset type, and return it.
        ///
        /// <param name = "type"></param>
        /// <returns>Returns null if no such folder is found</returns>
        public InventoryFolderImpl FindFolderForType(int type)
        {
            lock (m_childFolders)
            {
#if (!ISWIN)
                foreach (InventoryFolderImpl f in m_childFolders.Values)
                {
                    if (f.Type == type)
                    {
                        return f;
                    }
                }
#else
                foreach (InventoryFolderImpl f in m_childFolders.Values.Where(f => f.Type == type))
                {
                    return f;
                }
#endif
            }

            return null;
        }

        ///
        ///  Find a folder given a PATH_DELIMITER delimited path starting from this folder
        ///
        ///This method does not handle paths that contain multiple delimitors
        ///
        ///FIXME: We do not yet handle situations where folders have the same name.  We could handle this by some
        ///XPath like expression
        ///
        ///FIXME: Delimitors which occur in names themselves are not currently escapable.
        ///<param name = "path">
        ///  The path to the required folder.
        ///  It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
        ///</param>
        ///<returns>null if the folder is not found</returns>
        public InventoryFolderImpl FindFolderByPath(string path)
        {
            if (path == string.Empty)
                return this;

            path = path.Trim();

            if (path == PATH_DELIMITER)
                return this;

            string[] components = path.Split(new[] {PATH_DELIMITER}, 2, StringSplitOptions.None);

            lock (m_childFolders)
            {
#if (!ISWIN)
                foreach (InventoryFolderImpl folder in m_childFolders.Values)
                {
                    if (folder.Name == components[0])
                    {
                        if (components.Length > 1)
                            return folder.FindFolderByPath(components[1]);
                        else
                            return folder;
                    }
                }
#else
                foreach (InventoryFolderImpl folder in m_childFolders.Values.Where(folder => folder.Name == components[0]))
                {
                    if (components.Length > 1)
                        return folder.FindFolderByPath(components[1]);
                    else
                        return folder;
                }
#endif
            }

            // We didn't find a folder with the given name
            return null;
        }

        ///
        ///  Find an item given a PATH_DELIMITOR delimited path starting from this folder.
        ///
        ///  This method does not handle paths that contain multiple delimitors
        ///
        ///  FIXME: We do not yet handle situations where folders or items have the same name.  We could handle this by some
        ///  XPath like expression
        ///
        ///  FIXME: Delimitors which occur in names themselves are not currently escapable.
        ///
        ///<param name = "path">
        ///  The path to the required item.
        ///</param>
        ///<returns>null if the item is not found</returns>
        public InventoryItemBase FindItemByPath(string path)
        {
            string[] components = path.Split(new[] {PATH_DELIMITER}, 2, StringSplitOptions.None);

            if (components.Length == 1)
            {
                lock (Items)
                {
#if (!ISWIN)
                    foreach (InventoryItemBase item in Items.Values)
                    {
                        if (item.Name == components[0])
                        {
                            return item;
                        }
                    }
#else
                    foreach (InventoryItemBase item in Items.Values.Where(item => item.Name == components[0]))
                    {
                        return item;
                    }
#endif
                }
            }
            else
            {
                lock (m_childFolders)
                {
#if (!ISWIN)
                    foreach (InventoryFolderImpl folder in m_childFolders.Values)
                    {
                        if (folder.Name == components[0])
                        {
                            return folder.FindItemByPath(components[1]);
                        }
                    }
#else
                    foreach (InventoryFolderImpl folder in m_childFolders.Values.Where(folder => folder.Name == components[0]))
                    {
                        return folder.FindItemByPath(components[1]);
                    }
#endif
                }
            }

            // We didn't find an item or intermediate folder with the given name
            return null;
        }

        ///
        ///   Return a copy of the list of child items in this folder.  The items themselves are the originals.
        ///
        public List<InventoryItemBase> RequestListOfItems()
        {
            List<InventoryItemBase> itemList = new List<InventoryItemBase>();

            lock (Items)
            {
                itemList.AddRange(Items.Values);
            }

            //MainConsole.Instance.DebugFormat("[INVENTORY FOLDER IMPL]: Found {0} items", itemList.Count);

            return itemList;
        }

        ///
        ///   Return a copy of the list of child folders in this folder.  The folders themselves are the originals.
        ///
        public List<InventoryFolderBase> RequestListOfFolders()
        {
            List<InventoryFolderBase> folderList = new List<InventoryFolderBase>();

            lock (m_childFolders)
            {
                folderList.AddRange(m_childFolders.Values.Cast<InventoryFolderBase>());
            }

            return folderList;
        }

        public List<InventoryFolderImpl> RequestListOfFolderImpls()
        {
            List<InventoryFolderImpl> folderList = new List<InventoryFolderImpl>();

            lock (m_childFolders)
            {
                folderList.AddRange(m_childFolders.Values);
            }

            return folderList;
        }
    }
}


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

package com.google.devtools.build.lib.rules.proto;

import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER;
import static com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.createCommandLineFromToolchains;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;

import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.actions.util.LabelArtifactOwner;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.Deps;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.Exports;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.Services;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.ToolchainInvocation;
import com.google.devtools.build.lib.util.LazyString;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.DigestHashFunction;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
import javax.annotation.Nullable;
import net.starlark.java.syntax.Location;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link ProtoCompileActionBuilder}. */
@RunWith(JUnit4.class)
public class ProtoCompileActionBuilderTest {

  private static final InMemoryFileSystem FILE_SYSTEM =
      new InMemoryFileSystem(DigestHashFunction.SHA256);
  private final ArtifactRoot root =
      ArtifactRoot.asSourceRoot(Root.fromPath(FILE_SYSTEM.getPath("/")));
  private final ArtifactRoot derivedRoot =
      ArtifactRoot.asDerivedRoot(FILE_SYSTEM.getPath("/"), "out");

  private ProtoInfo protoInfo(
      ImmutableList<Artifact> directProtos,
      NestedSet<Artifact> transitiveProtos,
      NestedSet<String> transitiveProtoSourceRoots,
      NestedSet<String> strictImportableProtoSourceRoots,
      NestedSet<Pair<Artifact, String>> strictImportableProtos,
      NestedSet<Pair<Artifact, String>> exportedProtos) {
    return new ProtoInfo(
        directProtos,
        directProtos,
        /* directProtoSourceRoot= */ "",
        transitiveProtos,
        transitiveProtos,
        transitiveProtoSourceRoots,
        /* strictImportableProtosForDependents */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
        strictImportableProtos,
        strictImportableProtos,
        strictImportableProtoSourceRoots,
        exportedProtos,
        /* exportedProtoSourceRoots */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
        artifact("//:direct-descriptor-set", "direct-descriptor-set"),
        /* getTransitiveDescriptorSets */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
        Location.BUILTIN);
  }

  @Test
  public void commandLine_basic() throws Exception {
    FilesToRunProvider plugin =
        new FilesToRunProvider(
            NestedSetBuilder.emptySet(Order.STABLE_ORDER),
            null /* runfilesSupport */,
            artifact("//:dont-care", "protoc-gen-javalite.exe"));

    ProtoLangToolchainProvider toolchainNoPlugin =
        ProtoLangToolchainProvider.create(
            "--java_out=param1,param2:$(OUT)",
            /* pluginExecutable= */ null,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    ProtoLangToolchainProvider toolchainWithPlugin =
        ProtoLangToolchainProvider.create(
            "--$(PLUGIN_OUT)=param3,param4:$(OUT)",
            plugin,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    CustomCommandLine cmdLine =
        createCommandLineFromToolchains(
            ImmutableList.of(
                new ToolchainInvocation(
                    "dontcare_because_no_plugin", toolchainNoPlugin, "foo.srcjar"),
                new ToolchainInvocation("pluginName", toolchainWithPlugin, "bar.srcjar")),
            "bazel-out",
            protoInfo(
                /* directProtos */ ImmutableList.of(artifact("//:dont-care", "source_file.proto")),
                /* transitiveProtos */ NestedSetBuilder.create(
                    STABLE_ORDER,
                    artifact("//:dont-care", "import1.proto"),
                    artifact("//:dont-care", "import2.proto")),

                /* transitiveProtoSourceRoots= */ NestedSetBuilder.create(STABLE_ORDER, "."),
                /* strictImportableProtoSourceRoots= */ NestedSetBuilder.create(
                    Order.STABLE_ORDER, "."),
                /* strictImportableProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* exportedProtos = */ NestedSetBuilder.emptySet(STABLE_ORDER)),
            Label.parseAbsoluteUnchecked("//foo:bar"),
            Deps.NON_STRICT,
            Exports.DO_NOT_USE,
            Services.ALLOW,
            /* protocOpts= */ ImmutableList.of(),
            false);

    assertThat(cmdLine.arguments())
        .containsExactly(
            "--java_out=param1,param2:foo.srcjar",
            "--PLUGIN_pluginName_out=param3,param4:bar.srcjar",
            "--plugin=protoc-gen-PLUGIN_pluginName=protoc-gen-javalite.exe",
            "-Iimport1.proto=import1.proto",
            "-Iimport2.proto=import2.proto",
            "source_file.proto")
        .inOrder();
  }

  @Test
  public void commandline_derivedArtifact() {
    // Verify that the command line contains the correct path to a generated protocol buffers.
    CustomCommandLine cmdLine =
        createCommandLineFromToolchains(
            /* toolchainInvocations= */ ImmutableList.of(),
            "bazel-out",
            protoInfo(
                /* directProtos */ ImmutableList.of(derivedArtifact("source_file.proto")),
                /* transitiveProtos */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* transitiveProtoSourceRoots= */ NestedSetBuilder.create(Order.STABLE_ORDER, "."),
                /* strictImportableProtoSourceRoots= */ NestedSetBuilder.create(
                    Order.STABLE_ORDER, "."),
                /* strictImportableProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* exportedProtos = */ NestedSetBuilder.emptySet(STABLE_ORDER)),
            Label.parseAbsoluteUnchecked("//foo:bar"),
            Deps.NON_STRICT,
            Exports.DO_NOT_USE,
            Services.ALLOW,
            /* protocOpts= */ ImmutableList.of(),
            false);

    assertThat(cmdLine.arguments()).containsExactly("out/source_file.proto");
  }

  @Test
  public void commandLine_strictDeps() throws Exception {
    ProtoLangToolchainProvider toolchain =
        ProtoLangToolchainProvider.create(
            "--java_out=param1,param2:$(OUT)",
            /* pluginExecutable= */ null,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    CustomCommandLine cmdLine =
        createCommandLineFromToolchains(
            ImmutableList.of(new ToolchainInvocation("dontcare", toolchain, "foo.srcjar")),
            "bazel-out",
            protoInfo(
                /* directProtos */ ImmutableList.of(artifact("//:dont-care", "source_file.proto")),
                /* transitiveProtos */ NestedSetBuilder.create(
                    STABLE_ORDER,
                    artifact("//:dont-care", "import1.proto"),
                    artifact("//:dont-care", "import2.proto")),

                /* transitiveProtoSourceRoots= */ NestedSetBuilder.create(STABLE_ORDER, "."),
                /* strictImportableProtoSourceRoots= */ NestedSetBuilder.create(STABLE_ORDER, "."),
                NestedSetBuilder.create(
                    STABLE_ORDER,
                    Pair.of(artifact("//:dont-care", "import1.proto"), "import1.proto")),
                /* exportedProtos = */ NestedSetBuilder.emptySet(STABLE_ORDER)),
            Label.parseAbsoluteUnchecked("//foo:bar"),
            Deps.STRICT,
            Exports.DO_NOT_USE,
            Services.ALLOW,
            /* protocOpts= */ ImmutableList.of(),
            false);

    assertThat(cmdLine.arguments())
        .containsExactly(
            "--java_out=param1,param2:foo.srcjar",
            "-Iimport1.proto=import1.proto",
            "-Iimport2.proto=import2.proto",
            "--direct_dependencies",
            "import1.proto",
            String.format(ProtoCompileActionBuilder.STRICT_DEPS_FLAG_TEMPLATE, "//foo:bar"),
            "source_file.proto")
        .inOrder();
  }

  @Test
  public void commandLine_exports() throws Exception {
    ProtoLangToolchainProvider toolchain =
        ProtoLangToolchainProvider.create(
            "--java_out=param1,param2:$(OUT)",
            /* pluginExecutable= */ null,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    CustomCommandLine cmdLine =
        createCommandLineFromToolchains(
            ImmutableList.of(new ToolchainInvocation("dontcare", toolchain, "foo.srcjar")),
            "bazel-out",
            protoInfo(
                /* directProtos */ ImmutableList.of(artifact("//:dont-care", "source_file.proto")),
                /* transitiveProtos */ NestedSetBuilder.create(
                    STABLE_ORDER,
                    artifact("//:dont-care", "import1.proto"),
                    artifact("//:dont-care", "import2.proto")),

                /* transitiveProtoSourceRoots= */ NestedSetBuilder.create(STABLE_ORDER, "."),
                /* strictImportableProtoSourceRoots= */ NestedSetBuilder.create(STABLE_ORDER, "."),
                /* strictImportableProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* exportedProtos = */ NestedSetBuilder.create(
                    STABLE_ORDER,
                    Pair.of(artifact("//:dont-care", "foo/export1.proto"), "export1.proto"))),
            Label.parseAbsoluteUnchecked("//foo:bar"),
            Deps.NON_STRICT,
            Exports.USE,
            Services.ALLOW,
            /* protocOpts= */ ImmutableList.of(),
            false);

    assertThat(cmdLine.arguments())
        .containsExactly(
            "--java_out=param1,param2:foo.srcjar",
            "-Iimport1.proto=import1.proto",
            "-Iimport2.proto=import2.proto",
            "--allowed_public_imports",
            "export1.proto",
            "source_file.proto")
        .inOrder();
  }

  @Test
  public void otherParameters() throws Exception {
    CustomCommandLine cmdLine =
        createCommandLineFromToolchains(
            ImmutableList.of(),
            "bazel-out",
            protoInfo(
                /* directProtos */ ImmutableList.of(),
                /* transitiveProtos */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* transitiveProtoSourceRoots= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* strictImportableProtoSourceRoots= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* strictImportableProtos */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* exportedProtos = */ NestedSetBuilder.emptySet(STABLE_ORDER)),
            Label.parseAbsoluteUnchecked("//foo:bar"),
            Deps.STRICT,
            Exports.DO_NOT_USE,
            Services.DISALLOW,
            /* protocOpts= */ ImmutableList.of("--foo", "--bar"),
            false);

    assertThat(cmdLine.arguments()).containsAtLeast("--disallow_services", "--foo", "--bar");
  }

  @Test
  public void outReplacementAreLazilyEvaluated() throws Exception {
    final boolean[] hasBeenCalled = new boolean[1];
    hasBeenCalled[0] = false;

    CharSequence outReplacement =
        new LazyString() {
          @Override
          public String toString() {
            hasBeenCalled[0] = true;
            return "mu";
          }
        };

    ProtoLangToolchainProvider toolchain =
        ProtoLangToolchainProvider.create(
            "--java_out=param1,param2:$(OUT)",
            /* pluginExecutable= */ null,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    CustomCommandLine cmdLine =
        createCommandLineFromToolchains(
            ImmutableList.of(new ToolchainInvocation("pluginName", toolchain, outReplacement)),
            "bazel-out",
            protoInfo(
                /* directProtos*/ ImmutableList.of(),
                /* transitiveProtos */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* transitiveProtoSourceRoots= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* strictImportableProtoSourceRoots= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* strictImportableProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                /* exportedProtos = */ NestedSetBuilder.emptySet(STABLE_ORDER)),
            Label.parseAbsoluteUnchecked("//foo:bar"),
            Deps.STRICT,
            Exports.DO_NOT_USE,
            Services.ALLOW,
            /* protocOpts= */ ImmutableList.of(),
            false);

    assertThat(hasBeenCalled[0]).isFalse();
    cmdLine.arguments();
    assertThat(hasBeenCalled[0]).isTrue();
  }

  /**
   * Tests that if the same invocation-name is specified by more than one invocation,
   * ProtoCompileActionBuilder throws an exception.
   */
  @Test
  public void exceptionIfSameName() throws Exception {
    ProtoLangToolchainProvider toolchain1 =
        ProtoLangToolchainProvider.create(
            "dontcare",
            /* pluginExecutable= */ null,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    ProtoLangToolchainProvider toolchain2 =
        ProtoLangToolchainProvider.create(
            "dontcare",
            /* pluginExecutable= */ null,
            /* runtime= */ mock(TransitiveInfoCollection.class),
            /* blacklistedProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER));

    IllegalStateException e =
        assertThrows(
            IllegalStateException.class,
            () ->
                createCommandLineFromToolchains(
                    ImmutableList.of(
                        new ToolchainInvocation("pluginName", toolchain1, "outReplacement"),
                        new ToolchainInvocation("pluginName", toolchain2, "outReplacement")),
                    "bazel-out",
                    protoInfo(
                        /* directProtos */ ImmutableList.of(),
                        /* transitiveProtos */ NestedSetBuilder.emptySet(STABLE_ORDER),
                        /* transitiveProtoSourceRoots= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                        /* strictImportableProtoSourceRoots= */ NestedSetBuilder.emptySet(
                            STABLE_ORDER),
                        /* strictImportableProtos= */ NestedSetBuilder.emptySet(STABLE_ORDER),
                        /* exportedProtos = */ NestedSetBuilder.emptySet(STABLE_ORDER)),
                    Label.parseAbsoluteUnchecked("//foo:bar"),
                    Deps.STRICT,
                    Exports.DO_NOT_USE,
                    Services.ALLOW,
                    /* protocOpts= */ ImmutableList.of(),
                    false));
    assertThat(e)
        .hasMessageThat()
        .isEqualTo(
            "Invocation name pluginName appears more than once. "
                + "This could lead to incorrect proto-compiler behavior");
  }

  @Test
  public void testProtoCommandLineArgv() throws Exception {
    assertThat(
            protoArgv(
                null /* directDependencies */,
                ImmutableList.of(derivedArtifact("foo.proto")),
                ImmutableList.of(".")))
        .containsExactly("-Ifoo.proto=out/foo.proto");

    assertThat(
            protoArgv(
                ImmutableList.of() /* directDependencies */,
                ImmutableList.of(derivedArtifact("foo.proto")),
                ImmutableList.of(".")))
        .containsExactly("-Ifoo.proto=out/foo.proto", "--direct_dependencies=");

    assertThat(
            protoArgv(
                ImmutableList.of(
                    Pair.of(derivedArtifact("foo.proto"), null)) /* directDependencies */,
                ImmutableList.of(derivedArtifact("foo.proto")),
                ImmutableList.of(".")))
        .containsExactly("-Ifoo.proto=out/foo.proto", "--direct_dependencies", "foo.proto");

    assertThat(
            protoArgv(
                ImmutableList.of(
                    Pair.of(derivedArtifact("foo.proto"), null),
                    Pair.of(derivedArtifact("bar.proto"), null)) /* directDependencies */,
                ImmutableList.of(derivedArtifact("foo.proto")),
                ImmutableList.of(".")))
        .containsExactly(
            "-Ifoo.proto=out/foo.proto", "--direct_dependencies", "foo.proto:bar.proto");
  }

  /**
   * Include-maps are the -Ivirtual=physical arguments passed to proto-compiler. When including a
   * file named 'foo/bar.proto' from an external repository 'bla', the include-map should be
   * -Ifoo/bar.proto=external/bla/foo/bar.proto. That is - 'virtual' should be the path relative to
   * the external repo root, and physical should be the physical file location.
   */
  @Test
  public void testIncludeMapsOfExternalFiles() throws Exception {
    assertThat(
            protoArgv(
                null /* protosInDirectoDependencies */,
                ImmutableList.of(artifact("@bla//foo:bar", "external/bla/foo/bar.proto")),
                ImmutableList.of("external/bla")))
        .containsExactly("-Ifoo/bar.proto=external/bla/foo/bar.proto");
  }

  @Test
  public void directDependenciesOnExternalFiles() throws Exception {
    ImmutableList<Artifact> protos =
        ImmutableList.of(artifact("@bla//foo:bar", "external/bla/foo/bar.proto"));
    ImmutableList<Pair<Artifact, String>> protosImports =
        ImmutableList.of(Pair.of(artifact("@bla//foo:bar", "external/bla/foo/bar.proto"), null));
    assertThat(protoArgv(protosImports, protos, ImmutableList.of("external/bla")))
        .containsExactly(
            "-Ifoo/bar.proto=external/bla/foo/bar.proto", "--direct_dependencies", "foo/bar.proto");
  }

  private Artifact artifact(String ownerLabel, String path) {
    return new Artifact.SourceArtifact(
        root,
        root.getExecPath().getRelative(path),
        new LabelArtifactOwner(Label.parseAbsoluteUnchecked(ownerLabel)));
  }

  /** Creates a dummy artifact with the given path, that actually resides in /out/<path>. */
  private Artifact derivedArtifact(String path) {
    Artifact.DerivedArtifact derivedArtifact =
        new Artifact.DerivedArtifact(
            derivedRoot,
            derivedRoot.getExecPath().getRelative(path),
            ActionsTestUtil.NULL_ARTIFACT_OWNER);
    derivedArtifact.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
    return derivedArtifact;
  }

  private static Iterable<String> protoArgv(
      @Nullable Iterable<Pair<Artifact, String>> protosInDirectDependencies,
      Iterable<Artifact> transitiveImports,
      Iterable<String> protoSourceRoots) {
    CustomCommandLine.Builder commandLine = CustomCommandLine.builder();
    NestedSet<Pair<Artifact, String>> protosInDirectDependenciesBuilder =
        protosInDirectDependencies != null
            ? NestedSetBuilder.wrap(STABLE_ORDER, protosInDirectDependencies)
            : null;
    NestedSet<Artifact> transitiveImportsNestedSet =
        NestedSetBuilder.wrap(STABLE_ORDER, transitiveImports);
    ProtoCompileActionBuilder.addIncludeMapArguments(
        "blaze-out",
        commandLine,
        protosInDirectDependenciesBuilder,
        NestedSetBuilder.wrap(Order.STABLE_ORDER, protoSourceRoots),
        transitiveImportsNestedSet,
        false);
    return commandLine.build().arguments();
  }
}


text:
package org.apache.jena.sparql.path.eval ;

import java.util.* ;

import org.apache.jena.atlas.iterator.Iter ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.sparql.path.P_FixedLength ;
import org.apache.jena.sparql.path.P_Mod ;
import org.apache.jena.sparql.path.P_NegPropSet ;
import org.apache.jena.sparql.path.Path ;

/** Path evaluator that produces duplicates.
 * This is NOT SPARQL semantics.
 * This class exists for experimentation.
 * It is written to get the right results - not necessarily with maximum efficiency.
 */

final class PathEngineN extends PathEngine
{
    private boolean forwardMode ;

    public PathEngineN(Graph graph, boolean forward) {
        super(graph, null) ;
        this.forwardMode = forward ;
    }

    protected Set<Node> visitedAcc() {
        return new HashSet<>() ;
    }

    @Override
    protected void flipDirection() {
        forwardMode = !forwardMode ;
    }

    @Override
    protected boolean direction() {
        return forwardMode ;
    }

    @Override
    protected void doNegatedPropertySet(P_NegPropSet pathNotOneOf, Node node, Collection<Node> output) {
        // X !(:a|:b|^:c|^:d) Y = { X !(:a|:b) Y } UNION { Y !(:c|:d) X }
        if ( pathNotOneOf.getFwdNodes().size() > 0 ) {
            Iterator<Node> nodes1 = stepExcludeForwards(node, pathNotOneOf.getFwdNodes()) ;
            fill(nodes1, output) ;
        }
        if ( pathNotOneOf.getBwdNodes().size() > 0 ) {
            Iterator<Node> nodes2 = stepExcludeBackwards(node, pathNotOneOf.getBwdNodes()) ;
            fill(nodes2, output) ;
        }
    }

    @Override
    protected void doAlt(Path pathStepLeft, Path pathStepRight, Node node, Collection<Node> output) {
        // Try both sizes, accumulate into output.
        Iterator<Node> iter = eval(pathStepLeft, node) ;
        fill(iter, output) ;
        iter = eval(pathStepRight, node) ;
        fill(iter, output) ;
    }

    @Override
    protected void doSeq(Path pathStepLeft, Path pathStepRight, Node node, Collection<Node> output) {
        Path part1 = forwardMode ? pathStepLeft : pathStepRight ;
        Path part2 = forwardMode ? pathStepRight : pathStepLeft ;

        // Feed one side into the other
        Iter<Node> iter = eval(part1, node) ;
        iter.forEachRemaining((n)->eval(part2, n, output)) ;
    }

    @Override
    protected void doMultiLengthPath(Path pathStep, Node node, long min1, long max1, Collection<Node> output) {
        // Why not always reduce {N,M} to {N} and {0,M-N}
        // Why not iterate, not recurse, for {N,}
        // -- optimizer wil have expanded this so only in unoptimized mode.

        if ( min1 == P_Mod.UNSET )
            // {,N}
            min1 = 0 ;

        // ----------------
        // This code is for p{n,m} and :p{,n} inc :p{0,n}
        // and for :p{N,}

        // if ( max1 == P_Mod.UNSET ) max1 = 0 ;

        if ( min1 == 0 )
            output.add(node) ;

        if ( max1 == 0 )
            return ;

        // The next step
        long min2 = dec(min1) ;
        long max2 = dec(max1) ;

        // TODO Rewrite
        Path p1 = pathStep ;
        Path p2 = new P_Mod(pathStep, min2, max2) ;

        if ( !forwardMode ) {
            // Reverse order. Do the second bit first.
            Path tmp = p1 ;
            p1 = p2 ;
            p2 = tmp ;
            // This forces execution to be in the order that it's written, when
            // working backwards.
            // {N,*} is {*} then {N} backwards != do {N} then do {*} as
            // cardinality of the
            // two operations is different.
        }
        // ****

        // One step.
        Iterator<Node> iter = eval(p1, node) ;

        // Moved on one step
        for (; iter.hasNext();) {
            Node n2 = iter.next() ;
            Iterator<Node> iter2 = eval(p2, n2) ;
            fill(iter2, output) ;
        }

        // If no matches, will not call eval and we drop out.
    }

    @Override
    protected void doFixedLengthPath(Path pathStep, Node node, long fixedLength, Collection<Node> output) {
        if ( fixedLength == 0 ) {
            output.add(node) ;
            return ;
        }
        // P_Mod(path, count, count)
        // One step.
        Iterator<Node> iter = eval(pathStep, node) ;
        // Build a path for all remaining steps.
        long count2 = dec(fixedLength) ;
        P_FixedLength nextPath = new P_FixedLength(pathStep, count2) ;
        // For each element in the first step, do remaining step
        // Accumulate across everything from first step.
        for (; iter.hasNext();) {
            Node n2 = iter.next() ;
            Iterator<Node> iter2 = eval(nextPath, n2) ;
            fill(iter2, output) ;
        }
    }

    @Override
    protected void doZeroOrOne(Path pathStep, Node node, Collection<Node> output) {
        doZero(pathStep, node, output) ;
        doOne(pathStep, node, output) ;
    }

    private void doOne(Path path, Node node, Collection<Node> output) {
        Iterator<Node> iter = eval(path, node) ;
        fill(iter, output) ;
    }

    @Override
    protected void doZero(Path path, Node node, Collection<Node> output) {
        output.add(node) ;
    }

    @Override
    protected void doZeroOrMore(Path path, Node node, Collection<Node> output) {
        Set<Node> visited = visitedAcc() ;
        ALP(node, path, visited, output) ;
    }

    @Override
    protected void doOneOrMore(Path path, Node node, Collection<Node> output) {
        Set<Node> visited = visitedAcc() ;
        // Do one step without including.
        Iterator<Node> iter1 = eval(path, node) ;
        for (; iter1.hasNext();) {
            Node n1 = iter1.next() ;
            ALP(n1, path, visited, output) ;
        }
    }

    // This is the worker function for path*
    private void ALP(Node node, Path path, Set<Node> visited, Collection<Node> output) {
        if ( visited.contains(node) )
            return ;

        // If output is a set, then no point going on if node has been added to
        // the results.
        // If output includes duplicates, more solutions are generated
        // "visited" is nodes on this path (see the matching .remove).
        if ( !output.add(node) )
            return ;

        visited.add(node) ;

        Iterator<Node> iter1 = eval(path, node) ;
        // For each step, add to results and recurse.
        for (; iter1.hasNext();) {
            Node n1 = iter1.next() ;
            ALP(n1, path, visited, output) ;
        }
        visited.remove(node) ;
    }
}