text:
package org.xmlactions.action.config;

import java.util.Map;
import java.util.Properties;

import org.apache.commons.configuration.ConfigurationException;
import org.springframework.context.ApplicationContext;
import org.xmlactions.action.Action;
import org.xmlactions.action.actions.BaseAction;
import org.xmlactions.common.text.Html;
import org.xmlactions.common.theme.Theme;

/**
 * A Manager for an Application Context.
 *

 * This interface is used extensively throughout the framework code. It's purpose is to manage and maintain a set of static data and
 * also session and request data.
 *

 * @author mike.murphy
 *
 */
public interface IExecContext extends Map<String, Object> {

	/** use this to check if a Replacement string starts with "lang:" */
	public final static String PERSISTENCE_MAP = "persistence";

	/** List of stacked pages - used for pager:insert_into action */
	public static final String MAP_STACKED_PAGES = "stacked_pages";

	/** use this to check if a Replacement string starts with "lang:" */
	public final static String DEFAULT_ACTION_MAP = "default_action_map";

	/** This is the name of the Map that we use to store themes. The map is stored in the namedMaps. */
	public final static String DEFAULT_THEME_MAP = "default_theme_map";

	/** Use this to get a default_theme_name setting from the configuration. */
	public final static String DEFAULT_THEME_NAME = "default_theme_name";

	/** Use this to get a selected_theme_name setting from the configuration. */
	public final static String SELECTED_THEME_NAME = "selected_theme_name";

	/** Use this to get a default_theme_name setting from the configuration. */
	public final static String DEFAULT_STORAGE_CONFIG_REF = "default_storage_config_ref";

	/** use this to check if a Replacement string starts with "lang:" */
	public final static String LANG_REF = "lang";

	/** use this to check if a Replacement string starts with "replace:" */
	public final static String REPLACE_REF = "replace";

	/** use this to check if a Replacement string starts with "theme:" */
	public final static String THEME_REF = "theme";

	/** use this to check if a Replacement string starts with "spring_ac:" */
	public final static String APPLICATIONCONTEXT_REF = "spring_ac";

	/** use this to execute a code call "code:" */
	public final static String CODE_REF = "code";

	/** use this to get an java environment variable */
	public final static String ENV_REF = "env";

	/** use this to get an java property variable */
	public final static String PROP_REF = "prop";

    /** This is the default identifier when getting a key value. If we have a default value it will be returned when null is found*/
	public final static String DEFAULT_ID = "|";

    /** This is the key to the default locale file */
    public final static String DEFAULT_LOCALE_FILE = "default_locale_file";

    /** This is the key to the default rows for a list presentation */
    public final static String DEFAULT_ROWS = "default_rows";

    /** This is the key to the default locale file */
    public final static String DEBUG_LEVEL = "debug_level";

    /** Content Types that we may return to browser.  These are set in the HttpPager class */
    public final static String	CONTENT_TYPE_KEY = Html.CONTENT_TYPE_KEY,
    							CONTENT_TYPE_HTML = Html.CONTENT_TYPE_HTML,
    							CONTENT_TYPE_XML = Html.CONTENT_TYPE_XML,
    							CONTENT_TYPE_JSON = Html.CONTENT_TYPE_JSON,
    							CONTENT_TYPE_JS = Html.CONTENT_TYPE_JS,
    							CONTENT_TYPE_CSS = Html.CONTENT_TYPE_CSS;

	//public Object get(String key);
	//public void set(String key, Object value);

	public String getString(String key);

	/** Try and get a value for the key, if none found than return the key untouched */
	public String getStringQuietly(String key);

	public String getLocalizedString(String resource, String key);

	/**
	 * Calls StrSubstutitor to replace any ${...} replacement markers using the execContent for the replacement map.
	 * @param content
	 * @return the content with any replacement markers replaced.
	 */
	public String replace(String content);

	/** Append this xml resource to rootMap */
	public void addXmlConfig(String xmlResourceName) throws ConfigurationException;

	/** Append this map to rootMap */
	public void addProperties(Properties props);

	/** Append this map to rootMap */
	public void addMap(Map map);

	/** Append this properties to default actions */
	public void addActions(Properties props);

	/** Append this properties to actions as a named map */
	public void addNamedActions(String actionMapName, Properties props);

	/** Append this map to default actions */
	public void addActions(Map map);

	/** Append this map to actions as a named */
	public void addNamedActions(String actionMapName, Map map);

	/** Add this map to namedMaos */
	public void addNamedMap(String mapName, Map<String, Object> map);

	/** Get a Named Map */
	public Map<String,Object> getNamedMap(String mapName);

	/**
	 * Persist a value to permanent storage
	 *

	 * The permanent storage may be a HttpSession or database entry. Depends on how the persistence is managed.
	 *

	 */
	public void persist(String key, Object value);

	/**
	 * Get a persisted value from permanent storage
	 *

	 * The permanent storage may be a HttpSession or database entry. Depends on how the persistence is managed.
	 *

	 */
	public Object getPersisted(String key);

    public Map<String, Object> getPersistenceMap();

	public void loadFromPersistence();

	public void saveToPersistence();

    public void reset();

	public void setApplicationContext(ApplicationContext applicationContext);

	public ApplicationContext getApplicationContext();

	/**
	 * Get the class name associated with the action key
	 * @param actionMapName
	 * @param actionKey
	 * @return the class name i.e. org.xmlactions.pager.actions.Echo
	 */
	public String getAction(String actionMapName, String actionKey);

	public BaseAction getActionClass(String actionMapName, String actionKey) throws ClassNotFoundException, InstantiationException, IllegalAccessException;

	public Object getClassAsObject(String actionMapName, String actionKey) throws ClassNotFoundException, InstantiationException, IllegalAccessException;

	/**
	 * @return Root theme containing all loaded child themes
	 */
	public Theme getThemes();

	/**
	 * @return Selected or default theme. May be null
	 */
	public Theme getSelectedTheme();

	/**
	 *
	 * @param key used to select the theme css value
	 * @return the theme css value. May be empty if no theme has
	 * 		   been selected or there is no matching key found in the theme.
	 */
    public String getThemeValueQuietly(String key);

    public void addNotice(String msg);

    public void clearNotices();

    public void copyTo(IExecContext execContext);

    public Map<String, Object> getRootMap();

    public void setRootMap(Map<String, Object> rootMap);

    public Map<String, Map<String, Object>> getNamedMaps();

    public void setNamedMaps(Map<String, Map<String, Object>> namedMaps);

    public Map<String, Map<String, Object>> getActionMaps();

    public void setActionMaps(Map<String, Map<String, Object>> actionMaps);

    public String show();

}


text:
package com.netflix.zuul.proxy.framework.api;

public interface HttpRequestHandlerFactory {

    HttpRequestHandler getInstance(String tag, com.netflix.zuul.proxy.framework.api.Interrupts interrupts);

}

redpajama_set_name: RedPajamaGithub


text:
"""Compute the weighted sum of qubit states."""

from typing import List, Optional
import numpy as np

from qiskit.circuit import QuantumRegister, AncillaRegister, QuantumCircuit

from ..blueprintcircuit import BlueprintCircuit

class WeightedAdder(BlueprintCircuit):
    r"""A circuit to compute the weighted sum of qubit registers.

    Given :math:`n` qubit basis states :math:`q_0, \ldots, q_{n-1} \in \{0, 1\}` and non-negative
    integer weights :math:`\lambda_0, \ldots, \lambda_{n-1}`, this circuit performs the operation

    .. math::

        |q_0 \ldots q_{n-1}\rangle |0\rangle_s
        \mapsto |q_0 \ldots q_{n-1}\rangle |\sum_{j=0}^{n-1} \lambda_j q_j\rangle_s

    where :math:`s` is the number of sum qubits required.
    This can be computed as

    .. math::

        s = 1 + \left\lfloor \log_2\left( \sum_{j=0}^{n-1} \lambda_j \right) \right\rfloor

    or :math:`s = 1` if the sum of the weights is 0 (then the expression in the logarithm is
    invalid).

    For qubits in a circuit diagram, the first weight applies to the upper-most qubit.
    For an example where the state of 4 qubits is added into a sum register, the circuit can
    be schematically drawn as

    .. parsed-literal::

                   ┌────────┐
          state_0: ┤0       ├ | state_0 * weights[0]
                   │        │ |
          state_1: ┤1       ├ | + state_1 * weights[1]
                   │        │ |
          state_2: ┤2       ├ | + state_2 * weights[2]
                   │        │ |
          state_3: ┤3       ├ | + state_3 * weights[3]
                   │        │
            sum_0: ┤4       ├ |
                   │  Adder │ |
            sum_1: ┤5       ├ | = sum_0 * 2^0 + sum_1 * 2^1 + sum_2 * 2^2
                   │        │ |
            sum_2: ┤6       ├ |
                   │        │
          carry_0: ┤7       ├
                   │        │
          carry_1: ┤8       ├
                   │        │
        control_0: ┤9       ├
                   └────────┘
    """

    def __init__(
        self,
        num_state_qubits: Optional[int] = None,
        weights: Optional[List[int]] = None,
        name: str = "adder",
    ) -> None:
        """Computes the weighted sum controlled by state qubits.

        Args:
            num_state_qubits: The number of state qubits.
            weights: List of weights, one for each state qubit. If none are provided they
                default to 1 for every qubit.
            name: The name of the circuit.
        """
        super().__init__(name=name)

        self._weights = None
        self._num_state_qubits = None

        self.weights = weights
        self.num_state_qubits = num_state_qubits

    @property
    def num_sum_qubits(self) -> int:
        """The number of sum qubits in the circuit.

        Returns:
            The number of qubits needed to represent the weighted sum of the qubits.
        """
        if sum(self.weights) > 0:
            return int(np.floor(np.log2(sum(self.weights))) + 1)
        return 1

    @property
    def weights(self) -> List[int]:
        """The weights for the qubit states.

        Returns:
            The weight for the qubit states.
        """
        if self._weights:
            return self._weights
        if self.num_state_qubits:
            return [1] * self.num_state_qubits
        return None

    @weights.setter
    def weights(self, weights: List[int]) -> None:
        """Set the weights for summing the qubit states.

        Args:
            weights: The new weights.

        Raises:
            ValueError: If not all weights are close to an integer.
        """
        if weights:
            for i, weight in enumerate(weights):
                if not np.isclose(weight, np.round(weight)):
                    raise ValueError("Non-integer weights are not supported!")
                weights[i] = np.round(weight)

        self._invalidate()
        self._weights = weights
        self._reset_registers()

    @property
    def num_state_qubits(self) -> int:
        """The number of qubits to be summed.

        Returns:
            The number of state qubits.
        """
        return self._num_state_qubits

    @num_state_qubits.setter
    def num_state_qubits(self, num_state_qubits: int) -> None:
        """Set the number of state qubits.

        Args:
            num_state_qubits: The new number of state qubits.
        """
        if self._num_state_qubits is None or num_state_qubits != self._num_state_qubits:
            self._invalidate()
            self._num_state_qubits = num_state_qubits
            self._reset_registers()

    def _reset_registers(self):
        """Reset the registers."""
        self.qregs = []

        if self.num_state_qubits:
            qr_state = QuantumRegister(self.num_state_qubits, name="state")
            qr_sum = QuantumRegister(self.num_sum_qubits, name="sum")
            self.qregs = [qr_state, qr_sum]

            if self.num_carry_qubits > 0:
                qr_carry = AncillaRegister(self.num_carry_qubits, name="carry")
                self.add_register(qr_carry)

            if self.num_control_qubits > 0:
                qr_control = AncillaRegister(self.num_control_qubits, name="control")
                self.add_register(qr_control)

    @property
    def num_carry_qubits(self) -> int:
        """The number of carry qubits required to compute the sum.

        Note that this is not necessarily equal to the number of ancilla qubits, these can
        be queried using ``num_ancilla_qubits``.

        Returns:
            The number of carry qubits required to compute the sum.
        """
        return self.num_sum_qubits - 1

    @property
    def num_control_qubits(self) -> int:
        """The number of additional control qubits required.

        Note that the total number of ancilla qubits can be obtained by calling the
        method ``num_ancilla_qubits``.

        Returns:
            The number of additional control qubits required (0 or 1).
        """
        return int(self.num_sum_qubits > 2)

    def _check_configuration(self, raise_on_failure=True):
        """Check if the current configuration is valid."""
        valid = True
        if self._num_state_qubits is None:
            valid = False
            if raise_on_failure:
                raise AttributeError("The number of state qubits has not been set.")

        if self._num_state_qubits != len(self.weights):
            valid = False
            if raise_on_failure:
                raise ValueError("Mismatching number of state qubits and weights.")

        return valid

    def _build(self):
        """If not already built, build the circuit."""
        if self._is_built:
            return

        super()._build()

        num_result_qubits = self.num_state_qubits + self.num_sum_qubits

        circuit = QuantumCircuit(*self.qregs)
        qr_state = circuit.qubits[: self.num_state_qubits]
        qr_sum = circuit.qubits[self.num_state_qubits : num_result_qubits]
        qr_carry = circuit.qubits[num_result_qubits : num_result_qubits + self.num_carry_qubits]
        qr_control = circuit.qubits[num_result_qubits + self.num_carry_qubits :]

        # loop over state qubits and corresponding weights
        for i, weight in enumerate(self.weights):
            # only act if non-trivial weight
            if np.isclose(weight, 0):
                continue

            # get state control qubit
            q_state = qr_state[i]

            # get bit representation of current weight
            weight_binary = f"{int(weight):b}".rjust(self.num_sum_qubits, "0")[::-1]

            # loop over bits of current weight and add them to sum and carry registers
            for j, bit in enumerate(weight_binary):
                if bit == "1":
                    if self.num_sum_qubits == 1:
                        circuit.cx(q_state, qr_sum[j])
                    elif j == 0:
                        # compute (q_sum[0] + 1) into (q_sum[0], q_carry[0])
                        # - controlled by q_state[i]
                        circuit.ccx(q_state, qr_sum[j], qr_carry[j])
                        circuit.cx(q_state, qr_sum[j])
                    elif j == self.num_sum_qubits - 1:
                        # compute (q_sum[j] + q_carry[j-1] + 1) into (q_sum[j])
                        # - controlled by q_state[i] / last qubit,
                        # no carry needed by construction
                        circuit.cx(q_state, qr_sum[j])
                        circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
                    else:
                        # compute (q_sum[j] + q_carry[j-1] + 1) into (q_sum[j], q_carry[j])
                        # - controlled by q_state[i]
                        circuit.x(qr_sum[j])
                        circuit.x(qr_carry[j - 1])
                        circuit.mct(
                            [q_state, qr_sum[j], qr_carry[j - 1]],
                            qr_carry[j],
                            qr_control,
                            mode="v-chain",
                        )
                        circuit.cx(q_state, qr_carry[j])
                        circuit.x(qr_sum[j])
                        circuit.x(qr_carry[j - 1])
                        circuit.cx(q_state, qr_sum[j])
                        circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
                else:
                    if self.num_sum_qubits == 1:
                        pass  # nothing to do, since nothing to add
                    elif j == 0:
                        pass  # nothing to do, since nothing to add
                    elif j == self.num_sum_qubits - 1:
                        # compute (q_sum[j] + q_carry[j-1]) into (q_sum[j])
                        # - controlled by q_state[i] / last qubit,
                        # no carry needed by construction
                        circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
                    else:
                        # compute (q_sum[j] + q_carry[j-1]) into (q_sum[j], q_carry[j])
                        # - controlled by q_state[i]
                        circuit.mcx(
                            [q_state, qr_sum[j], qr_carry[j - 1]],
                            qr_carry[j],
                            qr_control,
                            mode="v-chain",
                        )
                        circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])

            # uncompute carry qubits
            for j in reversed(range(len(weight_binary))):
                bit = weight_binary[j]
                if bit == "1":
                    if self.num_sum_qubits == 1:
                        pass
                    elif j == 0:
                        circuit.x(qr_sum[j])
                        circuit.ccx(q_state, qr_sum[j], qr_carry[j])
                        circuit.x(qr_sum[j])
                    elif j == self.num_sum_qubits - 1:
                        pass
                    else:
                        circuit.x(qr_carry[j - 1])
                        circuit.mcx(
                            [q_state, qr_sum[j], qr_carry[j - 1]],
                            qr_carry[j],
                            qr_control,
                            mode="v-chain",
                        )
                        circuit.cx(q_state, qr_carry[j])
                        circuit.x(qr_carry[j - 1])
                else:
                    if self.num_sum_qubits == 1:
                        pass
                    elif j == 0:
                        pass
                    elif j == self.num_sum_qubits - 1:
                        pass
                    else:
                        # compute (q_sum[j] + q_carry[j-1]) into (q_sum[j], q_carry[j])
                        # - controlled by q_state[i]
                        circuit.x(qr_sum[j])
                        circuit.mcx(
                            [q_state, qr_sum[j], qr_carry[j - 1]],
                            qr_carry[j],
                            qr_control,
                            mode="v-chain",
                        )
                        circuit.x(qr_sum[j])

        self.append(circuit.to_gate(), self.qubits)


text:
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'strings_xml_localizer'


text:
This is a `JVM` (`Java`, `Kotlin`) and `Android` library, implementing the API of the [Proxer.Me](https://proxer.me/) website. This is currently `v1`. Built on [Retrofit](https://github.com/square/retrofit), [OkHttp](https://github.com/square/okhttp) and [Moshi](https://github.com/square/moshi), it offers great performance and flexibility.

## Including in your project

The preferred build system is [Gradle](https://gradle.org/).

Add this to your project wide build.gradle:

```groovy
repositories {
    maven { url "https://jitpack.io" }
}
```

And this to your module build.gradle:

```groovy
dependencies {
    implementation 'com.github.proxer:ProxerLibJava:5.3.0'
}
```

You can also download the `jar` directly
from [here](https://jitpack.io/com/github/proxer/ProxerLibJava/5.3.0/ProxerLibJava-5.3.0.jar), if you prefer.

> Note that this jar does not come with the required dependencies. You have to include those manually in that case.

## Usage

### Initialization

All requests are done through the `ProxerApi` class. You initialize an instance with the `ProxerApi.Builder`.

The most simple initialization looks like this:

```java
ProxerApi api = new ProxerApi.Builder("yourApiKey").build();
```

You can customize the `ProxerApi` in the following ways:

Method              | Description
------------------- | -----------------------------------------------------------------------------------------------------------------------------------------------------
`loginTokenManager` | Sets an own `LoginTokenManager` for automatic login. This will covered later.
`userAgent`         | Sets a custom Http `User-Agent` to be used. This defaults to `ProxerLibJava/<Version>` otherwise. Pass an empty String if you don't want to sent one.
`moshi`             | Sets a custom `Moshi` instance, used for parsing. Note, that various adapters are still applied, to make the API work properly.
`client`            | Sets a custom `OkHttpClient` instance, used for Http requests. Note, that various interceptors are still applied, to make the API work properly.
`retrofit`          | Sets a custom `Retrofit` instance.

> The API feature a test mode, which does not require a key. For most calls, this returns a predefined result and
> ignores the actual input. To enable the test mode, pass `ProxerApi.Test_KEY` or simply `"test"` to the constructor.

### Sending a request

The API is divided in classes for the various request, similar to the actual REST-API.

A simple query for the latest news looks like this:

```java
List<NewsArticle> result = api.notifications()
                .news()
                .build()
                .execute();
```

The `build` method returns a `ProxerCall` object. If you are familiar with `OkHttp`, this works exactly the same. The `ProxerCall` object also allows for asynchronous requests:

```java
api.notifications().news()
        .page(0)
        .limit(10)
        .build()
        .enqueue(result -> {
            // Show the result.
        }, error -> {
            // Show the error.
        });
```

As you can see in the example above, the individual endpoints also allow for various options.

##### Coroutines

It is also possible to execute requests in a coroutine context when using Kotlin. Use the `await` extension function on
the `ProxerCall`:

```kt
val result = api.notifications().news().build().await()
```

### Cancelling a request

You might want to cancel a request, especially if using on `Android`:

```java
ProxerCall call = api.[...].build()

call.cancel();
```

> It is an error to execute a cancelled `ProxerCall`.

### Error handling

All errors are encapsulated in a `ProxerException`. It offers the following info about the error:

Method               | Description
-------------------- | -------------------------------------------------------------------------------------
`getErrorType`       | Returns the general error type.
`getServerErrorType` | Returns the type of server error.
`getMessage`         | Returns the associated message of the error if it was a server error. Otherwise null.

These are the available general error types:

Type      | Description
--------- | ----------------------------------------------------------------------------------------------------------------------------------------------------
`SERVER`  | An error on the server occurred. This can for example be `LOGIN_INVALID_CREDENTIALS`, signaling that incorrect credentials were passed during login.
`TIMEOUT` | The server did not respond in time.
`IO`      | The data transfer failed. This can happen if no network connectivity is present for example.
`PARSING` | The server sent broken data. This happens mostly when the REST-API changed and this library was not adjusted yet.
`UNKNOWN` | Any other type of error. This is an internal error in most cases.

There is a wide range of server errors. Consult the [ProxerException](https://github.com/proxer/ProxerLibJava/blob/master/library/src/main/java/me/proxer/library/api/ProxerException.java) class for details.

Here is a selection of important ones:

Type                       | Description
-------------------------- | ------------------------------------------------------
`INSUFFICIENT_PERMISSIONS` | Your API-key is not allowed to access the API.
`IP_BLOCKED`               | You sent to many request in a specific time duration.
`*_INVALID_*`              | The passed data was not correct.
`*_LOGIN_REQUIRED`         | This section can only be accessed as a logged in user.

You catch errors like this (synchronous):

```java
try {
    api.notifications().news()
            .build()
            .execute();
} catch (ProxerException error) {
    // Handle the error here.
}
```

Or like this (asynchronous):

```java
api.notifications().news()
        .build()
        .enqueue(result -> {
            // No error occurred.
        }, error -> {
            // Handler the error here.
        });
```

If you just want to present the error to the user, it can be done like so:

```java
void handleError(ProxerException error) {
    switch (error.getErrorType()) {
        case SERVER:
            print(error.getMessage());

            break;
        case TIMEOUT:
            print("The server did not respond in time.");

            break;
        case IO:
            print("Data transfer failed. Check your network connection.");

            break;
        case PARSING:
            print("The server sent broken data.");

            break;
        case UNKNOWN:
            print("An unkown error occurred.");

            break;
    }
}
```

### Login

The `ProxerApi` offers a mechanism for automatic login.

If you call the `user.login` API, the relevant information is stored automatically. If you then call `user.logout`, is is also removed automatically.

You can customize this behaviour through a custom `LoginTokenManager`.

The most simple one looks like this (Such a `LoginTokenManager` is used if you do not pass one):

```java
ProxerApi api = new ProxerApi.Builder("yourApiKey")
        .loginTokenManager(new LoginTokenManager() {

            private String token;

            @Nullable
            @Override
            public String provide() {
                return token;
            }

            @Override
            public void persist(@Nullable String loginToken) {
                token = loginToken;
            }
        })
        .build();
```

> The token is only stored in memory with the default `LoginTokenManager`. This means, that you lose the login information when the application terminates. You may want to persist it into a `File` or `SharedPreferences` on `Android`.

### Rate limiting

The api has rate limiting in place with individual limits for each api class. If more requests than the limit are performed,
a `ProxerException` (with the `ServerErrorType.IP_BLOCKED`) is thrown and the user has to solve a captcha. The link to the captcha page can be obtained with
`ProxerUrls.captchaWeb()`.

##### Rate limit protection

Recent versions have a mechanism for protecting against rate limiting implemented. It can be enabled by calling the method:

```java
ProxerApi api = new ProxerApi.Builder("yourApiKey")
        .enableRateLimitProtection()
        .build();
```

This cancels requests which would trigger the rate limit and throw a `ProxerException` (with the `ServerErrorType.RATE_LIMIT`).
The user does not need to solve the captcha but simply wait then.

> This does not completely captcha errors. If multiple users call from the same network, the rate limit can still be hit and thus the error needs to be handled properly.

### Utils

This library offers two utility classes: `ProxerUrls` and `ProxerUtils`.

#### ProxerUrls

The `ProxerUrls` class has various static methods for getting often needed urls.

These are returned as an [HttpUrl](https://medium.com/square-corner-blog/okhttps-new-url-class-515460eea661), which has various advantages above the default `Java` classes.

Retrieving the url to the image of an user can be done like so:

```java
HttpUrl url = ProxerUrls.userImage("image property of the UserInfo entity here");
```

#### ProxerUtils

The API often returns entities, which have enums as properties. You may want to get the `String` representation, which is actually used for communication. To do so, you can use the `getApiEnumName` method:

```java
String genreAsString = ProxerUtils.getApiEnumName(Genre.ACTION);
```

The other way around is also available:

```java
Genre genreAsEnum = ProxerUtils.toApiEnum(Genre.class, "Action");
```

### ProGuard/R8

In recent versions of the library, the required config is bundled in the jar.

If you need to provide the config yourself (e.g. when using an older ProGuard version), see the config [here](https://github.com/proxer/ProxerLibJava/blob/master/library/src/main/resources/META-INF/proguard/proxerlibjava.pro) and also look for the configs of the used libraries.

### More

You can find detailed JavaDoc [here](https://jitpack.io/com/github/proxer/ProxerLibJava/5.3.0/javadoc/).

## Working on the library

Recommended development environment is [IntelliJ IDEA](https://www.jetbrains.com/idea/).

Make sure to run `./gradlew build` before importing, so the IDE can pick up generated code.

## Dependencies

This library is written in [Kotlin](https://kotlinlang.org/) and highly relies on [Retrofit](https://github.com/square/retrofit) and [OkHttp](http://square.github.io/okhttp/) by [Square](https://github.com/square) for the network communication.

Moreover it uses [Moshi](https://github.com/square/moshi) for response parsing.

## Contributions and contributors

A guide for contribution can be found [here](.github/CONTRIBUTING.md).

- [@Desnoo](https://github.com/desnoo) for implementing several APIs.


text:
"use strict";

window.addEventListener("DOMContentLoaded", onLoad);
window.addEventListener("gamepadconnected", e => {
    console.log("Gamepad connected %d %s %d buttons %d axes",
            e.gamepad.index, e.gamepad.id,
            e.gamepad.buttons.length, e.gamepad.axes.length);
});

var loadFired = false;

function onLoad() {
    if (loadFired) return;
    loadFired = true;

    let screen = document.getElementById('screen');
    let canvasContext = screen.getContext('2d');
    let imageData = canvasContext.getImageData(0, 0, screen.width,
            screen.height);

    document.getElementById("rom")
            .addEventListener("change",
                ev => handleNewRom(
                    ev.target.files[0],
                    canvasContext,
                    imageData
                ));

    console.log("Loaded!");
}

var UI_BUTTON_MAPPING = {
    "left-button": "left",
    "right-button": "right",
    "up-button": "up",
    "down-button": "down",
    "a-button": "a",
    "b-button": "b",
    "start-button": "start",
    "select-button": "select"
};

var KEYBOARD_MAPPING = {
    "ArrowLeft": "left",
    "ArrowRight": "right",
    "ArrowUp": "up",
    "ArrowDown": "down",
    "a": "a",
    "s": "b",
    "d": "start",
    "f": "select"
};

var FPS = 60;
var SAMPLE_RATE = 44100;
var AUDIO_FRAMES_PER_SEC = SAMPLE_RATE / FPS;
var INTERNAL_AUDIO_FRAMES_PER_SEC = 256;
var SCREEN_X = 160;
var SCREEN_Y = 144;

function pollGamepad() {
    if (!navigator.getGamepads().length) {
        return null;
    }

    let gamepad = navigator.getGamepads()[0];
    if (!gamepad) {
        return null;
    }

    // This is for a PS4 gamepad
    let buttons = {
        a: false, // Button 1
        b: false, // Button 2
        start: false, // Button 8
        select: false, // Button 9
        up: false, // Axis 7 == -1
        down: false, // Axis 7 == 1
        left: false, // Axis 6 == -1
        right: false, // Axis 6 == 1
    };

    buttons.a = gamepad.buttons[2].pressed;
    buttons.b = gamepad.buttons[1].pressed;
    buttons.select = gamepad.buttons[8].pressed;
    buttons.start = gamepad.buttons[9].pressed;
    buttons.up = gamepad.axes[7] == -1;
    buttons.down = gamepad.axes[7] == 1;
    buttons.left = gamepad.axes[6] == -1;
    buttons.right = gamepad.axes[6] == 1;

    return buttons;
}

function convertSoundToStereoF16(sound) {
    let channels = [
      new Float32Array(AUDIO_FRAMES_PER_SEC),
      new Float32Array(AUDIO_FRAMES_PER_SEC)
    ];

    for (let channel = 0; channel < 2; channel++) {
        for (let i = 0; i < AUDIO_FRAMES_PER_SEC; i++) {
            channels[channel][i] = sound[i * 2 + channel] / 32768;
        }
    }

    return channels;
}

function refreshScreen(screen, img) {
    for (let i = 0; i < SCREEN_X; i++) {
        for (let j = 0; j < SCREEN_Y; j++) {
            let color = 255 - screen[i * SCREEN_Y + j] * 64;
            img[j * SCREEN_X * 4 + i * 4    ] = color;
            img[j * SCREEN_X * 4 + i * 4 + 1] = color;
            img[j * SCREEN_X * 4 + i * 4 + 2] = color;
            img[j * SCREEN_X * 4 + i * 4 + 3] = 255;
        }
    }
}

function refreshGamepad(gamepad, keyboard, ui_buttons) {
    let poll = pollGamepad();
    if (poll === null) {
        let combined = {};
        for (let key of Object.keys(keyboard)) {
            combined[key] = keyboard[key] || ui_buttons[key];
        }
        poll = combined;
    }

    gamepad[0] = poll.a + 0;
    gamepad[1] = poll.b + 0;
    gamepad[2] = poll.start + 0;
    gamepad[3] = poll.select + 0;
    gamepad[4] = poll.up + 0;
    gamepad[5] = poll.down + 0;
    gamepad[6] = poll.left + 0;
    gamepad[7] = poll.right + 0;
}

/* ScriptProcessor only supports buffers of power-of-2 length:
 * 256, 512, 1024, 2048, 4096. The emulator runs off of buffers of length
 * 735 (one frame worth of sound data, SAMPLE_RATE / 60 fps). This class
 * allows consumers to play music buffered for arbitrary-sized chunk of data.
 */
class ArbitraryAudioProcessor {
    constructor(bufferSize, internalBufferSize, channels) {
        if (bufferSize < internalBufferSize) {
            // bufferSize cannot be smaller than our update value in the
            // script processor, otherwise we may not have enough data
            // when the audio stack asks us for audio frames.
            console.error("bufferSize cannot be smaller than " +
                    "internalBufferSize.");
        }

        this.bufferSize = bufferSize;
        this.audioContext = new AudioContext({
            sampleRate: SAMPLE_RATE,
        });
        this.channels = channels;
        this.buffers = [];
        for (let i = 0; i < this.channels; i++) {
            this.buffers.push(new Float32Array(this.bufferSize * 16));
        }
        this.index = 0;
        this.startIndex = 0;
        this.remaining = 0;
        this.running = true;

        let scriptProcessor = this.audioContext.createScriptProcessor(
            internalBufferSize, this.channels, this.channels);
        scriptProcessor.onaudioprocess = e =>
            this._refreshAudio(e.outputBuffer);
        scriptProcessor.connect(this.audioContext.destination);
    }

    /* This method will provide audio data when requested by the
     * ScriptProcessor. The buffer is cyclic so it will wrap around it
     * when it reaches the end. */
    _refreshAudio(buffer) {
        do {
            this._loadBuffer(buffer);
        // If we're running too much ahead we'll skip some frames
        } while (this.remaining > buffer.length * 6)
    }

    _loadBuffer(buffer) {
        let bufferData = [];
        for (let i = 0; i < this.channels; i++) {
            bufferData[i] = buffer.getChannelData(i);
        }

        if (!this.running || this.remaining < buffer.length) {
            return;
        }
        let next = this.index + buffer.length;
        let dataLength = this.buffers[0].length;
        let end = next < dataLength ? next : dataLength;

        for (let i = 0; i < this.channels; i++) {
            bufferData[i].set(this.buffers[i].subarray(this.index, end));
        }

        this.remaining -= buffer.length;

        let remaining = next - end;
        if (remaining == 0) {
            this.index = next;
            return;
        }

        this.index = 0;

        for (let i = 0; i < this.channels; i++) {
            bufferData[i].set(
                this.buffers[i].subarray(this.index, remaining),
                buffer.length - remaining);
        }

        this.index = remaining;
    }

    pause() {
        this.running = false;
    }

    resume() {
        this.running = true;
    }

    /* Enqueue data to be played.
     *
     * data = [
     *      Float32Array(bufferSize), // left channel data
     *      Float32Array(bufferSize)  // right channel data
     * ]
     */
    pushData(data) {
        for (let i = 0; i < this.channels; i++) {
            if (data[i].length != this.bufferSize) {
                console.error("Data buffer size error.");
                return;
            }
            this.buffers[i].set(data[i], this.startIndex);
        }
        this.startIndex =
            (this.startIndex + data[0].length) % this.buffers[0].length;
        this.remaining += data[0].length;
    }
}

function romLoaded(rom, exports, canvasContext, imageData) {
    let Emu = {
        _memory: exports.memory,
        _alloc: exports.alloc,
        init: exports.init,
        copy_save: exports.copy_save,
        main_loop: exports.main_loop,
        audio_processor: new ArbitraryAudioProcessor(
                AUDIO_FRAMES_PER_SEC,
                INTERNAL_AUDIO_FRAMES_PER_SEC,
                2 /* channels */),
        // Allocates and copies obj to the heap, obj is a Typed array
        // e.g. Uint8Array, Int16Array, etc
        alloc: function(obj /* TypedArray */) {
            let size = obj.length * obj.BYTES_PER_ELEMENT;
            let ptr = this._alloc(size);
            let heap = new Uint8Array(this._memory.buffer, ptr, size);
            heap.set(new Uint8Array(obj.buffer));
            return {
                size: size,
                ptr: ptr
            };
        },
        // Gives a view of the heap object, it will return a Uint8Array
        // view which should be only used locally and not stored as any
        // allocation may invalidate it.
        view_u8: function(heap_ref) {
            return new Uint8Array(
                this._memory.buffer, heap_ref.ptr,
                heap_ref.size / Uint8Array.BYTES_PER_ELEMENT);
        },
        view_i16: function(heap_ref) {
            return new Int16Array(
                this._memory.buffer, heap_ref.ptr,
                heap_ref.size / Int16Array.BYTES_PER_ELEMENT);
        },
    };

    let romHeap = Emu.alloc(rom);

    let save = Uint8Array.from(
            (window.localStorage.getItem('save') || '').split(','));
    if (save.length != 32768) {
        console.error('invalid sized save.');
        save = new Uint8Array(32768);
    }
    let saveHeap = Emu.alloc(save);

    let screenHeap = Emu.alloc(new Uint8Array(SCREEN_X * SCREEN_Y));
    // Sound data is interleaved in the emulator
    //    sound = [left, right, left, right, ...]
    // for a frame of execution
    let soundHeap = Emu.alloc(new Int16Array(AUDIO_FRAMES_PER_SEC * 2));
    let gamepadHeap = Emu.alloc(new Uint8Array(8));

    Emu.init(romHeap.ptr, romHeap.size, saveHeap.ptr, screenHeap.ptr,
             soundHeap.ptr, gamepadHeap.ptr);

    let keyboard = {
        a: false,
        b: false,
        start: false,
        select: false,
        up: false,
        down: false,
        left: false,
        right: false,
    };
    let ui_buttons = Object.assign({}, keyboard);

    let running = true;
    window.addEventListener("focus", e => {
        running = true;
        Emu.audio_processor.resume();
    });

    window.addEventListener("blur", e => {
        running = false;
        Emu.audio_processor.pause();
    });

    window.addEventListener("keyup", e => {
        let key = KEYBOARD_MAPPING[e.key];
        if (key) {
            keyboard[key] = false;
            e.preventDefault();
        }
    });

    window.addEventListener("keydown", e => {
        let key = KEYBOARD_MAPPING[e.key];
        if (key) {
            keyboard[key] = true;
            e.preventDefault();
        }
    });

    for (let id of Object.keys(UI_BUTTON_MAPPING)) {
        let button = document.getElementById(id);
        let key = UI_BUTTON_MAPPING[id];
        let on_button_pressed = e => {
            ui_buttons[key] = true;
            e.preventDefault();
        };
        let on_button_released = e => {
            ui_buttons[key] = false;
            e.preventDefault();
        };
        button.addEventListener("mousedown", on_button_pressed);
        button.addEventListener("touchstart", on_button_pressed);
        button.addEventListener("mouseup", on_button_released);
        button.addEventListener("touchend", on_button_released);
        button.addEventListener("click", e => e.preventDefault());
        button.addEventListener("touch", e => e.preventDefault());
        button.addEventListener("contextmenu", e => e.preventDefault());
    }

    function mainLoop() {
        if (running) {
            Emu.main_loop();

            let screen = Emu.view_u8(screenHeap);
            let img = imageData.data;
            refreshScreen(screen, img);

            let gamepad = Emu.view_u8(gamepadHeap);
            refreshGamepad(gamepad, keyboard, ui_buttons);

            let sound = Emu.view_i16(soundHeap);
            Emu.audio_processor
                .pushData(convertSoundToStereoF16(sound));

            canvasContext.putImageData(imageData, 0, 0);
        }

        window.requestAnimationFrame(mainLoop);
    };

    function saveState() {
        Emu.copy_save();
        let save = Emu.view_u8(saveHeap);
        window.localStorage.setItem('save', save.toString());
        window.localStorage.setItem('saveTimestamp', new Date());
        window.setTimeout(saveState, 1000);
    }

    mainLoop();
    saveState();
}

function handleNewRom(rom, canvasContext, imageData) {
    let reader = new FileReader();

    reader.onload = () => {
        let rom = new Uint8Array(reader.result);
        WebAssembly.instantiateStreaming(fetch('emu.wasm'), {
            imports: {
                date_now: () => new Date().getTime() / 1000,
            }
        })
        .then(r => {
            romLoaded(rom, r.instance.exports, canvasContext,
                      imageData);
        });
    };

    reader.readAsArrayBuffer(rom);
}


text:
{% if site.web-app-mode %}

  <!-- iOS Web App mode -->

  <meta name="apple-mobile-web-app-capable" content="yes">
  <link rel="apple-touch-icon" sizes="36x36" href="{{site.baseurl}}{{site.icon-36p | cdn}}">
  <link rel="apple-touch-icon" sizes="48x48" href="{{site.baseurl}}{{site.icon-48p | cdn}}">
  <link rel="apple-touch-icon" sizes="72x72" href="{{site.baseurl}}{{site.icon-72p | cdn}}">
  <link rel="apple-touch-icon" sizes="96x96" href="{{site.baseurl}}{{site.icon-96p | cdn}}">
  <link rel="apple-touch-icon" sizes="144x144" href="{{site.baseurl}}{{site.icon-144p | cdn}}">
  <link rel="apple-touch-icon" sizes="192x192" href="{{site.baseurl}}{{site.icon-192p | cdn}}">

  <!-- Android Web App mode -->

  <link rel="manifest" href="{{site.baseurl | cdn}}/manifest.json">

{% endif %}


text:
package org.jboss.pnc.rest.endpoint;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.jboss.pnc.model.RepositoryConfiguration;
import org.jboss.pnc.rest.provider.RepositoryConfigurationProvider;
import org.jboss.pnc.rest.restmodel.RepositoryConfigurationRest;
import org.jboss.pnc.rest.restmodel.response.error.ErrorResponseRest;
import org.jboss.pnc.rest.swagger.response.RepositoryConfigurationPage;
import org.jboss.pnc.rest.swagger.response.RepositoryConfigurationSingleton;
import org.jboss.pnc.rest.validation.exceptions.RestValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.lang.invoke.MethodHandles;

import static org.jboss.pnc.rest.configuration.SwaggerConstants.CONFLICTED_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.CONFLICTED_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.ENTITY_CREATED_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.ENTITY_CREATED_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.INVALID_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.INVALID_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.NOT_FOUND_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.NOT_FOUND_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.NO_CONTENT_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.NO_CONTENT_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.PAGE_INDEX_DEFAULT_VALUE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.PAGE_INDEX_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.PAGE_INDEX_QUERY_PARAM;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.PAGE_SIZE_DEFAULT_VALUE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.PAGE_SIZE_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.PAGE_SIZE_QUERY_PARAM;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.QUERY_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.QUERY_QUERY_PARAM;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SEARCH_QUERY_PARAM;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SERVER_ERROR_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SERVER_ERROR_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SORTING_DESCRIPTION;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SORTING_QUERY_PARAM;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SUCCESS_CODE;
import static org.jboss.pnc.rest.configuration.SwaggerConstants.SUCCESS_DESCRIPTION;

/**
 * @author Jakub Bartecek
 */
@Api(value = "/repository-configurations", description = "Repository configuration entities")
@Path("/repository-configurations")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class RepositoryConfigurationEndpoint extends AbstractEndpoint<RepositoryConfiguration, RepositoryConfigurationRest> {

    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    private RepositoryConfigurationProvider repositoryConfigurationProvider;

    public RepositoryConfigurationEndpoint() {
    }

    @Inject
    public RepositoryConfigurationEndpoint(RepositoryConfigurationProvider repositoryConfigurationProvider) {
        super(repositoryConfigurationProvider);
        this.repositoryConfigurationProvider = repositoryConfigurationProvider;
    }

    @ApiOperation(value = "Gets all Repository Configurations")
    @ApiResponses(value = {
            @ApiResponse(code = SUCCESS_CODE, message = SUCCESS_DESCRIPTION, response = RepositoryConfigurationPage.class),
            @ApiResponse(code = NO_CONTENT_CODE, message = NO_CONTENT_DESCRIPTION, response = RepositoryConfigurationPage.class),
            @ApiResponse(code = INVALID_CODE, message = INVALID_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_DESCRIPTION, response = ErrorResponseRest.class)
    })
    @GET
    public Response getAll(@ApiParam(value = PAGE_INDEX_DESCRIPTION) @QueryParam(PAGE_INDEX_QUERY_PARAM) @DefaultValue(PAGE_INDEX_DEFAULT_VALUE) int pageIndex,
                           @ApiParam(value = PAGE_SIZE_DESCRIPTION) @QueryParam(PAGE_SIZE_QUERY_PARAM) @DefaultValue(PAGE_SIZE_DEFAULT_VALUE) int pageSize,
                           @ApiParam(value = SORTING_DESCRIPTION) @QueryParam(SORTING_QUERY_PARAM) String sort,
                           @ApiParam(value = QUERY_DESCRIPTION, required = false) @QueryParam(QUERY_QUERY_PARAM) String q) {
        return fromCollection(repositoryConfigurationProvider.getAll(pageIndex, pageSize, sort, q));
    }

    @ApiOperation(value = "Creates a new Repository Configuration.")
    @ApiResponses(value = {
            @ApiResponse(code = ENTITY_CREATED_CODE, message = ENTITY_CREATED_DESCRIPTION, response = RepositoryConfigurationSingleton.class),
            @ApiResponse(code = INVALID_CODE, message = INVALID_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = CONFLICTED_CODE, message = CONFLICTED_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_DESCRIPTION, response = ErrorResponseRest.class)
    })
    @POST
    public Response createNew(RepositoryConfigurationRest repositoryConfigurationRest, @Context UriInfo uriInfo)
            throws RestValidationException {
        return super.createNew(repositoryConfigurationRest, uriInfo);
    }

    @ApiOperation(value = "Gets a specific Repository Configuration")
    @ApiResponses(value = {
            @ApiResponse(code = SUCCESS_CODE, message = SUCCESS_DESCRIPTION, response = RepositoryConfigurationSingleton.class),
            @ApiResponse(code = NOT_FOUND_CODE, message = NOT_FOUND_DESCRIPTION, response = RepositoryConfigurationSingleton.class),
            @ApiResponse(code = INVALID_CODE, message = INVALID_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_DESCRIPTION, response = ErrorResponseRest.class)
    })
    @GET
    @Path("/{id}")
    public Response getSpecific(
            @ApiParam(value = "Repository Configuration id", required = true) @PathParam("id") Integer id) {
        return super.getSpecific(id);
    }

    @ApiOperation(value = "Updates an existing Repository Configuration")
    @ApiResponses(value = {
            @ApiResponse(code = SUCCESS_CODE, message = SUCCESS_DESCRIPTION),
            @ApiResponse(code = INVALID_CODE, message = INVALID_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = CONFLICTED_CODE, message = CONFLICTED_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_DESCRIPTION, response = ErrorResponseRest.class)
    })
    @PUT
    @Path("/{id}")
    public Response update(@ApiParam(value = "Repository Configuration id", required = true) @PathParam("id") Integer id,
                           RepositoryConfigurationRest repositoryConfigurationRest) throws RestValidationException {
        return super.update(id, repositoryConfigurationRest);
    }

    @ApiOperation(value = "Search for Repository Configurations based on internal or external url, ignoring the protocol and \".git\" suffix. " +
            "The matching is done using LIKE.")
    @ApiResponses(value = {
            @ApiResponse(code = SUCCESS_CODE, message = SUCCESS_DESCRIPTION, response = RepositoryConfigurationPage.class),
            @ApiResponse(code = NO_CONTENT_CODE, message = NO_CONTENT_DESCRIPTION, response = RepositoryConfigurationPage.class),
            @ApiResponse(code = INVALID_CODE, message = INVALID_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_DESCRIPTION, response = ErrorResponseRest.class)
    })
    @GET
    @Path("/search-by-scm-url")
    public Response search(@ApiParam(value = PAGE_INDEX_DESCRIPTION) @QueryParam(PAGE_INDEX_QUERY_PARAM) @DefaultValue(PAGE_INDEX_DEFAULT_VALUE) int pageIndex,
            @ApiParam(value = PAGE_SIZE_DESCRIPTION) @QueryParam(PAGE_SIZE_QUERY_PARAM) @DefaultValue(PAGE_SIZE_DEFAULT_VALUE) int pageSize,
            @ApiParam(value = SORTING_DESCRIPTION) @QueryParam(SORTING_QUERY_PARAM) String sort,
            @ApiParam(value = "Url part to search for", required = true) @QueryParam(SEARCH_QUERY_PARAM) String scmUrl) {
        return fromCollection(repositoryConfigurationProvider.searchByScmUrl(pageIndex, pageSize, sort, scmUrl));
    }

    @ApiOperation(value = "Searches for Repository Configurations based on internal or external url, ignoring the protocol and \".git\" suffix. " +
            "Only exact matches are returned.")
    @ApiResponses(value = {
            @ApiResponse(code = SUCCESS_CODE, message = SUCCESS_DESCRIPTION, response = RepositoryConfigurationPage.class),
            @ApiResponse(code = NO_CONTENT_CODE, message = NO_CONTENT_DESCRIPTION, response = RepositoryConfigurationPage.class),
            @ApiResponse(code = INVALID_CODE, message = INVALID_DESCRIPTION, response = ErrorResponseRest.class),
            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_DESCRIPTION, response = ErrorResponseRest.class)
    })
    @GET
    @Path("/match-by-scm-url")
    public Response match(@ApiParam(value = PAGE_INDEX_DESCRIPTION) @QueryParam(PAGE_INDEX_QUERY_PARAM) @DefaultValue(PAGE_INDEX_DEFAULT_VALUE) int pageIndex,
                           @ApiParam(value = PAGE_SIZE_DESCRIPTION) @QueryParam(PAGE_SIZE_QUERY_PARAM) @DefaultValue(PAGE_SIZE_DEFAULT_VALUE) int pageSize,
                           @ApiParam(value = SORTING_DESCRIPTION) @QueryParam(SORTING_QUERY_PARAM) String sort,
                           @ApiParam(value = "Url to search for", required = true) @QueryParam(SEARCH_QUERY_PARAM) String scmUrl) {
        return fromCollection(repositoryConfigurationProvider.matchByScmUrl(pageIndex, pageSize, sort, scmUrl));
    }

}


text:
package cp.server.util;
import com.jcraft.jsch.UserInfo;

public class PublicKeyAuthUserInfo implements UserInfo
{

    public PublicKeyAuthUserInfo(final String passphrase, final String password)
    {
        super();
        this.passphrase = passphrase;
        this.password = password;
    }

    private String passphrase;
    private String password;

    @Override
    public String getPassphrase()
    {
        return this.passphrase;
    }

    @Override
    public String getPassword()
    {
        return this.password;
    }

    @Override
    public boolean promptPassword(final String s)
    {
        return false;
    }

    @Override
    public boolean promptPassphrase(final String s)
    {
        return true;
    }

    @Override
    public boolean promptYesNo(final String s)
    {
        // ?

        // trust
        return true;
    }

    @Override
    public void showMessage(final String s)
    {
        // log message
    }

    public void setPassphrase(final String passphrase)
    {
        this.passphrase = passphrase;
    }

    public void setPassword(final String password)
    {
        this.password = password;
    }
}


text:
const std::string MapBoxLayer::description() const {
  return "[MapBoxLayer]";
}

bool MapBoxLayer::rawIsEquals(const Layer* that) const {
  MapBoxLayer* t = (MapBoxLayer*) that;
  return (_domain == t->_domain);
}

MapBoxLayer* MapBoxLayer::copy() const {
  return new MapBoxLayer(_mapKey,
                         TimeInterval::fromMilliseconds(_timeToCacheMS),
                         _readExpired,
                         _initialLevel,
                         _maxLevel,
                         (_condition == NULL) ? NULL : _condition->copy());
}

RenderState MapBoxLayer::getRenderState() {
  _errors.clear();
  if (_mapKey.compare("") == 0) {
    _errors.push_back("Missing layer parameter: mapKey");
  }

  if (_errors.size() > 0) {
    return RenderState::error(_errors);
  }
  return RenderState::ready();
}


text:
declare module Molvwr {
    interface IViewMode {
        createScene(context: BabylonContext): any;
        sphereMaterial(context: BabylonContext, mesh: BABYLON.Mesh, material: BABYLON.StandardMaterial, useEffects: boolean): any;
        cylinderMaterial(context: BabylonContext, mesh: BABYLON.Mesh, material: BABYLON.StandardMaterial, useEffects: boolean): any;
    }
    class BabylonContext {
        engine: BABYLON.Engine;
        scene: BABYLON.Scene;
        camera: BABYLON.Camera;
        canvas: HTMLCanvasElement;
        viewmode: IViewMode;
        bindedResize: any;
        constructor(canvas: any);
        resize(): void;
        exportScreenshot(): string;
        dispose(): void;
        sphereMaterial(mesh: BABYLON.Mesh, atomMat: BABYLON.StandardMaterial, useEffects: boolean): void;
        cylinderMaterial(mesh: BABYLON.Mesh, atomMat: BABYLON.StandardMaterial, useEffects: boolean): void;
        createScene(): void;
    }
}

declare module Molvwr.Config {
    interface IMolvwrConfig {
        allowLOD: boolean;
        renderers: string[];
        atomScaleFactor: number;
        cylinderScale: number;
        cylinderLOD?: any[];
        sphereSegments: number;
        cylinderSegments?: number;
        sphereLOD?: any[];
    }
    function defaultConfig(): IMolvwrConfig;
    function spheres(): IMolvwrConfig;
    function sticks(): IMolvwrConfig;
    function ballsAndSticks(): IMolvwrConfig;
}

declare var __global: any;
declare module Molvwr {
    interface IAtom {
        kind: Elements.IPeriodicElement;
        x: number;
        y: number;
        z: number;
    }
    interface IAtomBinding {
        key: string;
        d: number;
        atomA: IAtom;
        atomB: IAtom;
    }
    interface IMolecule {
        atoms: IAtom[];
        bonds: IAtomBinding[];
        kinds: any;
        bondkinds: any;
        batchSize: number;
    }
    interface IMoleculeRenderer {
        render(molecule: any): Molvwr.Utils.Promise;
    }
    function process(): void;
    class Viewer {
        element: HTMLElement;
        canvas: HTMLCanvasElement;
        config: Molvwr.Config.IMolvwrConfig;
        viewmode: IViewMode;
        context: BabylonContext;
        molecule: IMolecule;
        constructor(element: HTMLElement, config?: Molvwr.Config.IMolvwrConfig, viewmode?: IViewMode);
        dispose(): void;
        private _loadContentFromString(content, contentFormat, dataReadyCallback);
        private _renderMolecule(molecule);
        setOptions(options: any, completedcallback?: any): void;
        setViewMode(viewmode: IViewMode, completedcallback?: any): void;
        refresh(completedcallback: any): void;
        private _createContext();
        exportScreenshot(): string;
        static endsWith(str: any, suffix: any): boolean;
        static getMoleculeFileFormat(filename: string): string;
        loadContentFromString(content: string, contentFormat: string, datareadycallback?: any, completedcallback?: any): void;
        loadContentFromUrl(url: string, contentFormat?: string, datareadycallback?: any, completedcallback?: any): void;
        private _postProcessMolecule(molecule);
        private _calculateAtomsBondsAsync(molecule);
        private _getCentroid(molecule);
        private _center(molecule);
    }
}

declare module Molvwr.Elements {
    interface IPeriodicElement {
        symbol: string;
        name: string;
        mass: number;
        radius: number;
        color: number[];
        number: number;
    }
    var elements: IPeriodicElement[];
    var elementsBySymbol: {};
    var elementsByNumber: {};
    var MIN_ATOM_RADIUS: number;
    var MAX_ATOM_RADIUS: number;
}

declare module Molvwr.Parser {
    var mol: {
        parse: (content: string) => {
            atoms: any[];
            title: any;
        };
    };
}

declare module Molvwr.Parser {
    var pdb: {
        parse: (content: string) => {
            atoms: any[];
            title: any;
        };
        parseHETATM(molecule: any, line: any): void;
    };
}

declare module Molvwr.Parser {
    var xyz: {
        parse: (content: string) => {
            atoms: any[];
            title: any;
        };
    };
}

declare var __global: any;
declare module Molvwr.Utils {
    function runBatch(offset: any, size: any, itemslist: any, itemcallback: any, batchname?: string): Promise;
    class Promise {
        private _state;
        private _value;
        private _deferreds;
        constructor(fn: any);
        catch(onRejected: any): Promise;
        then(onFulfilled: any, onRejected?: any): Promise;
        static timeout(timeoutTime: number): Promise;
        static all(fake: any): Promise;
        static resolve(value?: any): Promise;
        static reject(value?: any): Promise;
        static race(values: any): Promise;
        /**
        * Set the immediate function to execute callbacks
        * @param fn {function} Function to execute
        * @private
        */
        private static _setImmediateFn(fn);
    }
}

declare module Molvwr.Renderer {
    class BondsCylinder {
        ctx: Molvwr.BabylonContext;
        config: Molvwr.Config.IMolvwrConfig;
        viewer: Molvwr.Viewer;
        meshes: any;
        constructor(viewer: Molvwr.Viewer, ctx: Molvwr.BabylonContext, config: Molvwr.Config.IMolvwrConfig);
        render(molecule: IMolecule): Molvwr.Utils.Promise;
        prepareBonds(molecule: IMolecule, diameter: number): Utils.Promise;
        createMesh(binding: any, diameter: any): BABYLON.Mesh;
        createCylinder(binding: any, diameter: number, lodIndex: number, segments: any, useeffects: any, coloroverride: any): BABYLON.Mesh;
        alignCylinderToBinding(atomA: any, atomB: any, distance: any, cylinder: any): void;
        vectorEqualsCloseEnough(v1: any, v2: any, tolerance?: number): boolean;
    }
}

declare module Molvwr.Renderer {
    class BondsLines {
        ctx: Molvwr.BabylonContext;
        config: Molvwr.Config.IMolvwrConfig;
        viewer: Molvwr.Viewer;
        meshes: any;
        constructor(viewer: Molvwr.Viewer, ctx: Molvwr.BabylonContext, config: Molvwr.Config.IMolvwrConfig);
        render(molecule: IMolecule): Molvwr.Utils.Promise;
    }
}

declare module Molvwr.Renderer {
    class Sphere {
        ctx: Molvwr.BabylonContext;
        config: Molvwr.Config.IMolvwrConfig;
        viewer: Molvwr.Viewer;
        meshes: any;
        constructor(viewer: Molvwr.Viewer, ctx: Molvwr.BabylonContext, config: Molvwr.Config.IMolvwrConfig);
        render(molecule: IMolecule): Molvwr.Utils.Promise;
        prepareMeshes(molecule: IMolecule): Molvwr.Utils.Promise;
        createMesh(atomkind: any): BABYLON.Mesh;
        createSphere(atomkind: any, segments: any, useEffects: any, overridecolor: any): BABYLON.Mesh;
        renderAtom(atom: any, index: any): any;
    }
}

declare module Molvwr.Renderer {
    class Sticks {
        ctx: Molvwr.BabylonContext;
        config: Molvwr.Config.IMolvwrConfig;
        viewer: Molvwr.Viewer;
        meshes: any;
        constructor(viewer: Molvwr.Viewer, ctx: Molvwr.BabylonContext, config: Molvwr.Config.IMolvwrConfig);
        render(molecule: IMolecule): Molvwr.Utils.Promise;
        prepareBonds(molecule: IMolecule, diameter: number): Utils.Promise;
        createMesh(binding: any, diameter: number): any;
        createStickMergemesh(binding: any, diameter: any, lodIndex: any, segments: any, texture: any, useeffects: any, coloroverride: any): BABYLON.Mesh;
        alignCylinderToBinding(atomA: any, atomB: any, distance: any, cylinder: any): void;
        vectorEqualsCloseEnough(v1: any, v2: any, tolerance?: number): boolean;
    }
}

declare module Molvwr.ViewModes {
    interface StandardViewModeOptions {
        texture?: boolean;
        onpreparescene?: (ctx: BabylonContext) => void;
        clearColor?: number[];
        fogDensity?: number;
        fogColor?: number[];
        groundColor?: number[];
        specular?: number[];
        wheelPrecision?: number;
        pinchPrecision?: number;
        panningSensibility?: number;
        emisivefresnel?: BABYLON.FresnelParameters;
        sphere?: {
            diffuseTexture?: string;
            specularTexture?: string;
            bumpTexture?: string;
            textureScale?: number;
        };
        cylinder?: {
            diffuseTexture?: string;
            specularTexture?: string;
            bumpTexture?: string;
            textureScale?: number;
        };
    }
    class Standard implements Molvwr.IViewMode {
        options: StandardViewModeOptions;
        constructor(viewoptions?: StandardViewModeOptions);
        static defaultConfig(): StandardViewModeOptions;
        getColor(config: any, defaultColor: any): BABYLON.Color3;
        createScene(context: BabylonContext): void;
        applyTexture(context: BabylonContext, material: BABYLON.StandardMaterial, texture: any): void;
        sphereMaterial(context: BabylonContext, mesh: BABYLON.Mesh, material: BABYLON.StandardMaterial, useEffects: boolean): void;
        cylinderMaterial(context: BabylonContext, mesh: BABYLON.Mesh, material: BABYLON.StandardMaterial, useEffects: boolean): void;
    }
}

declare module Molvwr.ViewModes {
    class Experiments implements Molvwr.IViewMode {
        constructor();
        createScene(context: BabylonContext): void;
        sphereMaterial(context: BabylonContext, mesh: BABYLON.Mesh, material: BABYLON.StandardMaterial, useEffects: boolean): void;
        cylinderMaterial(context: BabylonContext, mesh: BABYLON.Mesh, material: BABYLON.StandardMaterial, useEffects: boolean): void;
        useAmbientOcclusion(context: BabylonContext): void;
        useHDR(context: BabylonContext): void;
        useLensEffect(context: BabylonContext): void;
    }
}


text:
/* NOTE: Template files (including this one) are application specific and therefore expected to
   be copied into the application project folder prior to its use! */

#include <stdint.h>
#include <stdbool.h>
#include <syscfg/syscfg.h>
#include <nrf.h>
#include <nrf_erratas.h>
#include <system_nrf5340_application.h>
#include <mcu/cmsis_nvic.h>
#include "system_nrf53_approtect.h"

/*lint ++flb "Enter library region" */

/* NRF5340 application core uses a variable System Clock Frequency that starts at 64MHz */
#define __SYSTEM_CLOCK_MAX      (128000000UL)
#define __SYSTEM_CLOCK_INITIAL  ( 64000000UL)

#define TRACE_PIN_CNF_VALUE (   (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | \
                                (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | \
                                (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | \
                                (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | \
                                (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | \
                                (GPIO_PIN_CNF_MCUSEL_TND << GPIO_PIN_CNF_MCUSEL_Pos))

#define TRACE_TRACECLK_PIN   TAD_PSEL_TRACECLK_PIN_Traceclk
#define TRACE_TRACEDATA0_PIN TAD_PSEL_TRACEDATA0_PIN_Tracedata0
#define TRACE_TRACEDATA1_PIN TAD_PSEL_TRACEDATA1_PIN_Tracedata1
#define TRACE_TRACEDATA2_PIN TAD_PSEL_TRACEDATA2_PIN_Tracedata2
#define TRACE_TRACEDATA3_PIN TAD_PSEL_TRACEDATA3_PIN_Tracedata3

#if defined ( __CC_ARM )
    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_INITIAL;
#elif defined ( __ICCARM__ )
    __root uint32_t SystemCoreClock = __SYSTEM_CLOCK_INITIAL;
#elif defined   ( __GNUC__ )
    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_INITIAL;
#endif

void SystemCoreClockUpdate(void)
{
#if defined(NRF_TRUSTZONE_NONSECURE)
    SystemCoreClock = __SYSTEM_CLOCK_MAX >> (NRF_CLOCK_NS->HFCLKCTRL & (CLOCK_HFCLKCTRL_HCLK_Msk));
#else
    SystemCoreClock = __SYSTEM_CLOCK_MAX >> (NRF_CLOCK_S->HFCLKCTRL & (CLOCK_HFCLKCTRL_HCLK_Msk));
#endif
}

void SystemInit(void)
{
    #if !defined(NRF_TRUSTZONE_NONSECURE)
        /* Perform Secure-mode initialization routines. */

        /* Set all ARM SAU regions to NonSecure if TrustZone extensions are enabled.
        * Nordic SPU should handle Secure Attribution tasks */
        #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
          SAU->CTRL |= (1 << SAU_CTRL_ALLNS_Pos);
        #endif

        /* Workaround for Errata 97 "ERASEPROTECT, APPROTECT, or startup problems" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_97())
        {
            if (*((volatile uint32_t *)0x50004A20ul) == 0)
            {
                *((volatile uint32_t *)0x50004A20ul) = 0xDul;
                *((volatile uint32_t *)0x5000491Cul) = 0x1ul;
                *((volatile uint32_t *)0x5000491Cul) = 0x0ul;
            }
        }

        /* Trimming of the device. Copy all the trimming values from FICR into the target addresses. Trim
         until one ADDR is not initialized. */
        uint32_t index = 0;
        for (index = 0; index < 32ul && NRF_FICR_S->TRIMCNF[index].ADDR != (uint32_t *)0xFFFFFFFFul; index++){
            #if defined ( __ICCARM__ )
                /* IAR will complain about the order of volatile pointer accesses. */
                #pragma diag_suppress=Pa082
            #endif
            *NRF_FICR_S->TRIMCNF[index].ADDR = NRF_FICR_S->TRIMCNF[index].DATA;
            #if defined ( __ICCARM__ )
                #pragma diag_default=Pa082
            #endif
        }

        /* errata 64 must be before errata 42, as errata 42 is dependant on the changes in errata 64*/
        /* Workaround for Errata 64 "VREGMAIN has invalid configuration when CPU is running at 128 MHz" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_64())
        {
            *((volatile uint32_t *)0x5000470Cul) = 0x29ul;
            *((volatile uint32_t *)0x5000473Cul) = 0x3ul;
        }

        /* Workaround for Errata 42 "Reset value of HFCLKCTRL is invalid" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_42())
        {
            *((volatile uint32_t *)0x50039530ul) = 0xBEEF0044ul;
            NRF_CLOCK_S->HFCLKCTRL = CLOCK_HFCLKCTRL_HCLK_Div2 << CLOCK_HFCLKCTRL_HCLK_Pos;
        }

        /* Workaround for Errata 46 "Higher power consumption of LFRC" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_46())
        {
            *((volatile uint32_t *)0x5003254Cul) = 0;
        }

        /* Workaround for Errata 49 "SLEEPENTER and SLEEPEXIT events asserted after pin reset" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_49())
        {
            if (NRF_RESET_S->RESETREAS & RESET_RESETREAS_RESETPIN_Msk)
            {
                NRF_POWER_S->EVENTS_SLEEPENTER = 0;
                NRF_POWER_S->EVENTS_SLEEPEXIT = 0;
            }
        }

        /* Workaround for Errata 55 "Bits in RESETREAS are set when they should not be" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_55())
        {
            if (NRF_RESET_S->RESETREAS & RESET_RESETREAS_RESETPIN_Msk){
                NRF_RESET_S->RESETREAS = ~RESET_RESETREAS_RESETPIN_Msk;
            }
        }

        /* Workaround for Errata 69 "VREGMAIN configuration is not retained in System OFF" found at the Errata document
           for your device located at https://infocenter.nordicsemi.com/index.jsp  */
        if (nrf53_errata_69())
        {
            *((volatile uint32_t *)0x5000470Cul) =0x65ul;
        }

        #if defined(CONFIG_NFCT_PINS_AS_GPIOS)

            if ((NRF_UICR_S->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos))
            {
                NRF_NVMC_S->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;

                while (NRF_NVMC_S->READY == NVMC_READY_READY_Busy);
                NRF_UICR_S->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;

                while (NRF_NVMC_S->READY == NVMC_READY_READY_Busy);
                NRF_NVMC_S->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;

                while (NRF_NVMC_S->READY == NVMC_READY_READY_Busy);
                NVIC_SystemReset();
            }

        #endif

        /* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product
           Specification to see which one). */
        #if defined (ENABLE_SWO)
            // Enable Trace And Debug peripheral
            NRF_TAD_S->ENABLE = TAD_ENABLE_ENABLE_Msk;
            NRF_TAD_S->CLOCKSTART = TAD_CLOCKSTART_START_Msk;

            // Set up Trace pad SPU firewall
            NRF_SPU_S->GPIOPORT[0].PERM &= ~(1 << TRACE_TRACEDATA0_PIN);

            // Configure trace port pad
            NRF_P0_S->PIN_CNF[TRACE_TRACEDATA0_PIN] = TRACE_PIN_CNF_VALUE;

            // Select trace pin
            NRF_TAD_S->PSEL.TRACEDATA0 = TRACE_TRACEDATA0_PIN;

            // Set trace port speed to 64 MHz
            NRF_TAD_S->TRACEPORTSPEED = TAD_TRACEPORTSPEED_TRACEPORTSPEED_64MHz;
        #endif

        /* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
           Specification to see which ones). */
        #if defined (ENABLE_TRACE)
            // Enable Trace And Debug peripheral
            NRF_TAD_S->ENABLE = TAD_ENABLE_ENABLE_Msk;
            NRF_TAD_S->CLOCKSTART = TAD_CLOCKSTART_START_Msk;

            // Set up Trace pads SPU firewall
            NRF_SPU_S->GPIOPORT[0].PERM &= ~(1 << TRACE_TRACECLK_PIN);
            NRF_SPU_S->GPIOPORT[0].PERM &= ~(1 << TRACE_TRACEDATA0_PIN);
            NRF_SPU_S->GPIOPORT[0].PERM &= ~(1 << TRACE_TRACEDATA1_PIN);
            NRF_SPU_S->GPIOPORT[0].PERM &= ~(1 << TRACE_TRACEDATA2_PIN);
            NRF_SPU_S->GPIOPORT[0].PERM &= ~(1 << TRACE_TRACEDATA3_PIN);

            // Configure trace port pads
            NRF_P0_S->PIN_CNF[TRACE_TRACECLK_PIN] =   TRACE_PIN_CNF_VALUE;
            NRF_P0_S->PIN_CNF[TRACE_TRACEDATA0_PIN] = TRACE_PIN_CNF_VALUE;
            NRF_P0_S->PIN_CNF[TRACE_TRACEDATA1_PIN] = TRACE_PIN_CNF_VALUE;
            NRF_P0_S->PIN_CNF[TRACE_TRACEDATA2_PIN] = TRACE_PIN_CNF_VALUE;
            NRF_P0_S->PIN_CNF[TRACE_TRACEDATA3_PIN] = TRACE_PIN_CNF_VALUE;

            // Select trace pins
            NRF_TAD_S->PSEL.TRACECLK   = TRACE_TRACECLK_PIN;
            NRF_TAD_S->PSEL.TRACEDATA0 = TRACE_TRACEDATA0_PIN;
            NRF_TAD_S->PSEL.TRACEDATA1 = TRACE_TRACEDATA1_PIN;
            NRF_TAD_S->PSEL.TRACEDATA2 = TRACE_TRACEDATA2_PIN;
            NRF_TAD_S->PSEL.TRACEDATA3 = TRACE_TRACEDATA3_PIN;

            // Set trace port speed to 64 MHz
            NRF_TAD_S->TRACEPORTSPEED = TAD_TRACEPORTSPEED_TRACEPORTSPEED_64MHz;

        #endif

        /* Allow Non-Secure code to run FPU instructions.
         * If only the secure code should control FPU power state these registers should be configured accordingly in the secure application code. */
        SCB->NSACR |= (3UL << 10);

        /* Handle fw-branch APPROTECT setup. */
        nrf53_handle_approtect();

    #endif

    /* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
    * compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
    * operations are not used in your code. */
    #if (__FPU_USED == 1)
        SCB->CPACR |= (3UL << 20) | (3UL << 22);
        __DSB();
        __ISB();
    #endif

    if (MYNEWT_VAL(MCU_HFCLK_DIV) == 1) {
        NRF_CLOCK_S->HFCLKCTRL = CLOCK_HFCLKCTRL_HCLK_Div1 << CLOCK_HFCLKCTRL_HCLK_Pos;
    } else {
        NRF_CLOCK_S->HFCLKCTRL = CLOCK_HFCLKCTRL_HCLK_Div2 << CLOCK_HFCLKCTRL_HCLK_Pos;
    }

    SystemCoreClockUpdate();

    NVIC_Relocate();
}

/*lint --flb "Leave library region" */


text:
layout: post
title: AndFix原理浅析(二)之补丁合并原理
categories: 热修复技术
description:
keywords: AndFix, 热修复技术
---

  上一遍写了[AndFix原理浅析(一)之补丁生成原理](http://www.jianshu.com/p/57c150b47ffc),本篇来分析补丁过程原理。如果还没有了解如何使用AndFix可以看之前的文章[AndFix 实战以及遇到的坑](http://www.jianshu.com/p/8d5685bc2661)。回顾之前文章,AndFix使用上主要是如下代码:

```
        //1)初始化PatchManager
        mPatchManager = new PatchManager(this);
        mPatchManager.init(AppInfoUtils.getVersionCode(this));
        //2)load patch
        mPatchManager.loadPatch();
        try {
        // .apatch file path ,这里一定要注意每台手机sd卡路径不同
        String patchFileString = "sdcard" + Environment.getExternalStorageDirectory()
                .getAbsolutePath() + APATCH_PATH;
        //3)添加patch
        mPatchManager.addPatch(patchFileString);
        Log.d(TAG, "apatch:" + patchFileString + " added.");
    } catch (IOException e) {
        Log.e(TAG, "", e);
    }
```
##### JAVA源码分析
  首先到github上把[AndFix源码](https://github.com/alibaba/AndFix)clone下来。按照顺序先来看`com.alipay.euler.andfix.patch`包下`PatchManager.init()`
```
public void init(String appVersion) {
		if (!mPatchDir.exists() && !mPatchDir.mkdirs()) {// make directory fail
			Log.e(TAG, "patch dir create error.");
			return;
		} else if (!mPatchDir.isDirectory()) {// not directory
			mPatchDir.delete();
			return;
		}
		SharedPreferences sp = mContext.getSharedPreferences(SP_NAME,
				Context.MODE_PRIVATE);
		String ver = sp.getString(SP_VERSION, null);
                //获取之前存储的版本号与当前版本号对比、如果不同清除patch,并存储当前版本号
		if (ver == null || !ver.equalsIgnoreCase(appVersion)) {
			cleanPatch();
			sp.edit().putString(SP_VERSION, appVersion).commit();
		} else {
                        //如果相同初始化patchs
			initPatchs();
		}
	}
```
  看初始化patchs方法`PatchManager.initPatchs()`
```
	private void initPatchs() {
        // 缓存目录data/data/package/file/apatch/会缓存补丁文件
		// 即使原目录被删除也可以打补丁
		File[] files = mPatchDir.listFiles();
		for (File file : files) {
			addPatch(file);
		}
	}
```
  这里可以看下`mPatchDir `变量的定义
`mPatchDir = new File(mContext.getFilesDir(), DIR);`
  是沙盒中data/data/package/file/apatch/ 目录下的文件夹目录。这一步逻辑我们可以试想肯定有patch文件会存入此目录下。 每次程序初始化加载patch文件都会从沙盒的缓存目录下读取, 而不用担心patch文件被删除。

  继续来看`PatchManager.addPatch()`
```
private Patch addPatch(File file) {
		Patch patch = null;
		if (file.getName().endsWith(SUFFIX)) {
			try {
				patch = new Patch(file);
				mPatchs.add(patch);
			} catch (IOException e) {
				Log.e(TAG, "addPatch", e);
			}
		}
		return patch;
	}
```
  这里逻辑比较简单,检测只要文件后缀为.apatch就加入到mPatchs数组中。至此`PatchManager.initPatchs()`走完了。往下走来看`PatchManager.loadPatch()`
```
public void loadPatch() {
		mLoaders.put("*", mContext.getClassLoader());// wildcard
		Set<String> patchNames;
		List<String> classes;
		for (Patch patch : mPatchs) {
			patchNames = patch.getPatchNames();
			for (String patchName : patchNames) {
				classes = patch.getClasses(patchName);
				mAndFixManager.fix(patch.getFile(), mContext.getClassLoader(),
						classes);
			}
		}
	}
```
  这个函数对所有的patchs进行了遍历,并取出每个patch内的class数组,然后传入`AndFixManager.fix()`。

```
public synchronized void fix(File file, ClassLoader classLoader,
			List<String> classes) {
		 ......省略安全性检测相关代码
            //读取dex文件
			final DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),
					optfile.getAbsolutePath(), Context.MODE_PRIVATE);

			if (saveFingerprint) {
				mSecurityChecker.saveOptSig(optfile);
			}
            //初始化类加载器
			ClassLoader patchClassLoader = new ClassLoader(classLoader) {
				@Override
				protected Class<?> findClass(String className)
						throws ClassNotFoundException {
					Class<?> clazz = dexFile.loadClass(className, this);
					if (clazz == null
							&& className.startsWith("com.alipay.euler.andfix")) {
						return Class.forName(className);// annotation's class
														// not found
					}
					if (clazz == null) {
						throw new ClassNotFoundException(className);
					}
					return clazz;
				}
			};
			Enumeration<String> entrys = dexFile.entries();
			Class<?> clazz = null;
            //遍历dex中条目(类名称)
			while (entrys.hasMoreElements()) {
				String entry = entrys.nextElement();
				if (classes != null && !classes.contains(entry)) {
					continue;// skip, not need fix
				}
                //load 需要fix的Class
				clazz = dexFile.loadClass(entry, patchClassLoader);
				if (clazz != null) {
                    //fix class
					fixClass(clazz, classLoader);
				}
			}
		} catch (IOException e) {
			Log.e(TAG, "pacth", e);
		}
	}
```
   前面都是安全性检测代码略过, 后面检测出需要fix的Class然后执行到`AndFixManager.fixClass()`
```
private void fixClass(Class<?> clazz, ClassLoader classLoader) {
		Method[] methods = clazz.getDeclaredMethods();
		MethodReplace methodReplace;
		String clz;
		String meth;
		for (Method method : methods) {
           //获取到MethodReplace注解(需要被替换的方法)
			methodReplace = method.getAnnotation(MethodReplace.class);
			if (methodReplace == null)
				continue;
           //注解的类
			clz = methodReplace.clazz();
           //需要被替换的方法
			meth = methodReplace.method();
			if (!isEmpty(clz) && !isEmpty(meth)) {
            //替换方法
				replaceMethod(classLoader, clz, meth, method);
			}
		}
	}
```

继续看 `replaceMethod`方法
```
private void replaceMethod(ClassLoader classLoader, String clz,
			String meth, Method method) {
		try {
			String key = clz + "@" + classLoader.toString();
			Class<?> clazz = mFixedClass.get(key);
			if (clazz == null) {// class not load
                //load 需要修复的class
				Class<?> clzz = classLoader.loadClass(clz);
				// 初始化并且更改class 访问权限public
				clazz = AndFix.initTargetClass(clzz);
			}
			if (clazz != null) {// initialize class OK
                //放入缓存map
				mFixedClass.put(key, clazz);
               //获取原method
				Method src = clazz.getDeclaredMethod(meth,
						method.getParameterTypes());
              //进行替换操作
				AndFix.addReplaceMethod(src, method);
			}
		} catch (Exception e) {
			Log.e(TAG, "replaceMethod", e);
		}
	}
```
继续看`AndFix.addReplaceMethod()`
```
	public static void addReplaceMethod(Method src, Method dest) {
		try {
            //替换方法为native方法
			replaceMethod(src, dest);
            //修改类成员变量访问权限为public
			initFields(dest.getDeclaringClass());
		} catch (Throwable e) {
			Log.e(TAG, "addReplaceMethod", e);
		}
	}
```
`private static native void replaceMethod(Method dest, Method src);`
replaceMethod的定义可知它为 native方法
##### Native层分析
NatIve源码在jni目录下 如图:
![9A5C27B4-6085-4222-86B9-F68B9C3B76DC.png](http://upload-images.jianshu.io/upload_images/2229793-4601137053986bb7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
来看`andfix.cpp`
```
static void replaceMethod(JNIEnv* env, jclass clazz, jobject src,
		jobject dest) {
	if (isArt) {
		art_replaceMethod(env, src, dest);
	} else {
		dalvik_replaceMethod(env, src, dest);
	}
}
```
根据不同的模式 art  or dalvik 调用不同的方法。这里我们只看dalvik ,art  与dalvik原理都差不多。
打开`dalvik`文件夹下`dalvik_method_replace.cpp` 来看`dalvik_replaceMethod ()`
```
extern void __attribute__ ((visibility ("hidden"))) dalvik_replaceMethod(
		JNIEnv* env, jobject src, jobject dest) {
	jobject clazz = env->CallObjectMethod(dest, jClassMethod);
	ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef_fnPtr(
			dvmThreadSelf_fnPtr(), clazz);
	clz->status = CLASS_INITIALIZED;
    //旧的方法(需要被替换的方法)
	Method* meth = (Method*) env->FromReflectedMethod(src);
    //新的方法
	Method* target = (Method*) env->FromReflectedMethod(dest);
	LOGD("dalvikMethod: %s", meth->name);

//	meth->clazz = target->clazz;
    //旧的方法访问权限设置为public
	meth->accessFlags |= ACC_PUBLIC;
	meth->methodIndex = target->methodIndex;
	meth->jniArgInfo = target->jniArgInfo;
	meth->registersSize = target->registersSize;
	meth->outsSize = target->outsSize;
	meth->insSize = target->insSize;
	meth->prototype = target->prototype;
    //替换方法信息
	meth->insns = target->insns;
    //旧的方法设置为native
	meth->nativeFunc = target->nativeFunc;
}
```

##### 总结
AndFix热补丁原理就是在native动态替换方法java层的代码,通过native层hook java层的代码。


text:
<?php

final class PHUIActionPanelView extends AphrontTagView {

  private $href;
  private $fontIcon;
  private $image;
  private $header;
  private $subHeader;
  private $bigText;
  private $state;
  private $status;

  const COLOR_RED = 'phui-action-panel-red';
  const COLOR_ORANGE = 'phui-action-panel-orange';
  const COLOR_YELLOW = 'phui-action-panel-yellow';
  const COLOR_GREEN = 'phui-action-panel-green';
  const COLOR_BLUE = 'phui-action-panel-blue';
  const COLOR_INDIGO = 'phui-action-panel-indigo';
  const COLOR_VIOLET = 'phui-action-panel-violet';
  const COLOR_PINK = 'phui-action-panel-pink';

  public function setHref($href) {
    $this->href = $href;
    return $this;
  }

  public function setIcon($image) {
    $this->fontIcon = $image;
    return $this;
  }

  public function setImage($image) {
    $this->image = $image;
    return $this;
  }

  public function setBigText($text) {
    $this->bigText = $text;
    return $this;
  }

  public function setHeader($header) {
    $this->header = $header;
    return $this;
  }

  public function setSubHeader($sub) {
    $this->subHeader = $sub;
    return $this;
  }

  public function setState($state) {
    $this->state = $state;
    return $this;
  }

  public function setStatus($text) {
    $this->status = $text;
    return $this;
  }

  protected function getTagName() {
    return 'div';
  }

  protected function getTagAttributes() {
    require_celerity_resource('phui-action-panel-css');

    $classes = array();
    $classes[] = 'phui-action-panel';
    if ($this->state) {
      $classes[] = $this->state;
    }
    if ($this->bigText) {
      $classes[] = 'phui-action-panel-bigtext';
    }

    return array(
      'class' => implode(' ', $classes),
    );
  }

  protected function getTagContent() {

    $icon = null;
    if ($this->fontIcon) {
      $fonticon = id(new PHUIIconView())
        ->setIcon($this->fontIcon);
      $icon = phutil_tag(
        'span',
        array(
          'class' => 'phui-action-panel-icon',
        ),
        $fonticon);
    }

    if ($this->image) {
      $image = phutil_tag(
        'img',
        array(
          'class' => 'phui-action-panel-image',
          'src' => $this->image,
        ));
      $icon = phutil_tag(
        'span',
        array(
          'class' => 'phui-action-panel-icon',
        ),
        $image);
    }

    $header = null;
    if ($this->header) {
      $header = phutil_tag(
        'span',
        array(
          'class' => 'phui-action-panel-header',
        ),
        $this->header);
    }

    $subheader = null;
    if ($this->subHeader) {
      $subheader = phutil_tag(
        'span',
        array(
          'class' => 'phui-action-panel-subheader',
        ),
        $this->subHeader);
    }

    $row = phutil_tag(
      'span',
      array(
        'class' => 'phui-action-panel-row',
      ),
      array(
        $icon,
        $subheader,
      ));

    $table = phutil_tag(
      'span',
      array(
        'class' => 'phui-action-panel-table',
      ),
      $row);

    return phutil_tag(
      'a',
      array(
        'href' => $this->href,
        'class' => 'phui-action-panel-hitarea',
      ),
      array($header, $table));

  }

}


text:
package tester_test

import (
	"os"
	"strings"
	"testing"

	"github.com/go-acme/lego/v3/platform/tester"
	"github.com/stretchr/testify/assert"
)

const (
	envNamespace = "LEGO_TEST_"
	envVar01     = envNamespace + "01"
	envVar02     = envNamespace + "02"
	envVarDomain = envNamespace + "DOMAIN"
)

func TestMain(m *testing.M) {
	exitCode := m.Run()
	clearEnv()
	os.Exit(exitCode)
}

func applyEnv(envVars map[string]string) {
	for key, value := range envVars {
		if len(value) == 0 {
			os.Unsetenv(key)
		} else {
			os.Setenv(key, value)
		}
	}
}

func clearEnv() {
	environ := os.Environ()
	for _, key := range environ {
		if strings.HasPrefix(key, envNamespace) {
			os.Unsetenv(strings.Split(key, "=")[0])
		}
	}
	os.Unsetenv("EXTRA_LEGO_TEST")
}

func TestEnvTest(t *testing.T) {
	testCases := []struct {
		desc         string
		envVars      map[string]string
		envTestSetup func() *tester.EnvTest
		expected     func(t *testing.T, envTest *tester.EnvTest)
	}{
		{
			desc: "simple",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "missing env var",
			envVars: map[string]string{
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithDomain",
			envVars: map[string]string{
				envVar01:     "A",
				envVar02:     "B",
				envVarDomain: "D",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).WithDomain(envVarDomain)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetValue(envVarDomain))
				assert.Equal(t, "D", envTest.GetDomain())
			},
		},
		{
			desc: "WithDomain missing env var",
			envVars: map[string]string{
				envVar01:     "A",
				envVarDomain: "D",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).WithDomain(envVarDomain)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetValue(envVarDomain))
				assert.Equal(t, "D", envTest.GetDomain())
			},
		},
		{
			desc: "WithDomain missing domain",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).WithDomain(envVarDomain)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetValue(envVarDomain))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).WithLiveTestRequirements(envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements non required var missing",
			envVars: map[string]string{
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).WithLiveTestRequirements(envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements required var missing",
			envVars: map[string]string{
				envVar01: "A",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).WithLiveTestRequirements(envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements WithDomain",
			envVars: map[string]string{
				envVar01:     "A",
				envVar02:     "B",
				envVarDomain: "D",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithDomain(envVarDomain).
					WithLiveTestRequirements(envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetValue(envVarDomain))
				assert.Equal(t, "D", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements WithDomain without domain",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithDomain(envVarDomain).
					WithLiveTestRequirements(envVar02)
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetValue(envVarDomain))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestExtra true",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithLiveTestExtra(func() bool { return true })
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestExtra false",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithLiveTestExtra(func() bool { return false })
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements WithLiveTestExtra true",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithLiveTestRequirements(envVar02).
					WithLiveTestExtra(func() bool { return true })
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.True(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements WithLiveTestExtra false",
			envVars: map[string]string{
				envVar01: "A",
				envVar02: "B",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithLiveTestRequirements(envVar02).
					WithLiveTestExtra(func() bool { return false })
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "B", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
		{
			desc: "WithLiveTestRequirements require env var missing WithLiveTestExtra true",
			envVars: map[string]string{
				envVar01: "A",
			},
			envTestSetup: func() *tester.EnvTest {
				return tester.NewEnvTest(envVar01, envVar02).
					WithLiveTestRequirements(envVar02).
					WithLiveTestExtra(func() bool { return true })
			},
			expected: func(t *testing.T, envTest *tester.EnvTest) {
				assert.False(t, envTest.IsLiveTest())
				assert.Equal(t, "A", envTest.GetValue(envVar01))
				assert.Equal(t, "", envTest.GetValue(envVar02))
				assert.Equal(t, "", envTest.GetDomain())
			},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			defer clearEnv()
			applyEnv(test.envVars)

			envTest := test.envTestSetup()

			test.expected(t, envTest)
		})
	}
}

func TestEnvTest_RestoreEnv(t *testing.T) {
	os.Setenv(envVar01, "A")
	os.Setenv(envVar02, "B")

	envTest := tester.NewEnvTest(envVar01, envVar02)

	clearEnv()

	envTest.RestoreEnv()

	assert.Equal(t, "A", os.Getenv(envVar01))
	assert.Equal(t, "B", os.Getenv(envVar02))
}

func TestEnvTest_ClearEnv(t *testing.T) {
	os.Setenv(envVar01, "A")
	os.Setenv(envVar02, "B")
	os.Setenv("EXTRA_LEGO_TEST", "X")

	envTest := tester.NewEnvTest(envVar01, envVar02)

	envTest.ClearEnv()

	assert.Equal(t, "", os.Getenv(envVar01))
	assert.Equal(t, "", os.Getenv(envVar02))
	assert.Equal(t, "X", os.Getenv("EXTRA_LEGO_TEST"))
}


text:
using System;
using Guidelines.Core.Commands;
using StructureMap.Configuration.DSL;

namespace Guidelines.Ioc.StructureMap.Conventions
{
	public class CommandPreprocessorConvention : FacadeConvention
	{
		public override void Process(Type type, Registry registry)
		{
			ProcessFacade(type, registry, typeof(ICommandPreprocessor), typeof(ICommandPreprocessor<>), typeof(TypedCommandPreprocessorFacade<>));
		}
	}
}