text:
[![Build Status](https://travis-ci.org/pdsoftplan/zap-maven-plugin.svg?branch=master)](https://travis-ci.org/pdsoftplan/zap-maven-plugin)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/br.com.softplan.security.zap/zap-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/br.com.softplan.security.zap/zap-maven-plugin)

> Check out the [ZAP SonarQube Plugin](https://github.com/pdsoftplan/sonar-zap)

This plugin makes it easier to integrate [OWASP Zed Attack Proxy (ZAP)](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project) security tests with the application development and build process for Maven users. With this plugin, you can:

- Run ZAP analysis during the build of your application;
- Run authenticated analysis on [CAS](http://jasig.github.io/cas/) and on many other applications with complex authentication strategies;
- Use your [Selenium](http://www.seleniumhq.org) integration tests navigation to feed ZAP;
- Easily run ZAP analysis during development.

## Contents

- [Usage](#usage)
- [Configuration Parameters](#configuration-parameters)
- [Authentication Strategies](#authentication-strategies)
- [Examples](#examples)
    - [Using a running instance of ZAP](#using-a-running-instance-of-zap)
    - [Starting ZAP automatically](#starting-zap-automatically)
    - [Starting ZAP with Docker](#starting-zap-with-docker)
    - [Form authentication example](#form-authentication-example)
    - [CAS authentication example](#cas-authentication-example)
    - [Selenium authentication example](#selenium-authentication-example)
- [Selenium Integration](#selenium-integration)

## Usage

Generally, the plugin configuration will follow the format below:

```xml
<plugin>
    <groupId>br.com.softplan.security.zap</groupId>
    <artifactId>zap-maven-plugin</artifactId>
    <version>${zap-maven-plugin.version}</version>
    <configuration>
        <!-- Configuration parameters -->
    </configuration>
    <executions>
        <execution>
            <phase>verify</phase>
            <goals><goal>analyze</goal></goals>
        </execution>
    </executions>
</plugin>
```

> If you want to bind the plugin execution to the build lifecycle, it is necessary to define the phase where the plugin will be executed, as well as the goal that will be executed. Optionally, the plugin can be executed by directly calling the desired goal:
> ```
> mvn br.com.softplan.security.zap:zap-maven-plugin:analyze
> ```

The main goal provided is *analyze*, responsible to execute a ZAP analysis according to the configuration parameters. However, the plugin also provides other goals for more specific situations. The list of available goals is presented bellow:

- ***analyze***: performs a complete analysis running (by default) the [Spider](https://github.com/zaproxy/zap-core-help/wiki/HelpStartConceptsSpider) before the [Active Scan](https://github.com/zaproxy/zap-core-help/wiki/HelpStartConceptsAscan) and starting ZAP automatically if necessary (and closing it after the analysis).
- ***startZap***: simply starts ZAP (via local installation or Docker).
- ***seleniumAnalyze***: assumes ZAP is already executing and simply runs the Active Scan, closing ZAP after the analysis. This goal is useful when there are [Selenium](http://www.seleniumhq.org) integration tests that are executed with a proxy to ZAP and the navigation done by the tests should be used instead of the Spider. More on that at [Selenium Integration](#selenium-integration).

The goals that run analysis save the generated reports in the end of the plugin execution. By default, the reports are saved in the directory `target/zap-reports` within the project. The parameter *reportPath* can be used to specify another directory (absolute or relative).

## Configuration Parameters

**Common parameters:**

Parameter | Description | Required? | Default
--- | --- | --- | ---
skip                           | Skip the plugin execution (equivalent CLI property: zap.skip)        | No  | false

**Analysis parameters:**

Parameter | Description | Required? | Default
--- | --- | --- | ---
targetUrl                      | URL of the application that will be scanned                          | Yes | -
spiderStartingPointUrl         | Starting point URL for the Spider (and AJAX Spider, in case it runs) | No  | *targetUrl*
activeScanStartingPointUrl     | Starting point URL for the Active Scan                               | No  | *targetUrl*
context                        | The URLs to be set on ZAP's context (absolute or relative)           | No  | *targetUrl*
analysisTimeoutInMinutes       | Analysis timeout in minutes                                          | No  | 480
shouldRunAjaxSpider            | Indicates whether ZAP should execute the [AJAX Spider](https://github.com/zaproxy/zap-core-help/wiki/HelpAddonsSpiderAjaxConcepts) after the default Spider (it can improve the scan on applications that rely on AJAX)     | No  | false
shouldRunPassiveScanOnly       | In case it's true, the Active Scan will not be executed | No | false
shouldStartNewSession          | Indicates whether a new session should be started on ZAP before the analysis | No | true

> If the options *spiderStartingPoint*, *activeScanStartingPoint* and *context* are all provided, *targetUrl* will be ignored. These options are useful when you want to spider through the whole application, but want to run the Active Scan for only a portion of it, for instance. These parameters are very sensitive and should be set accordingly.

**ZAP related parameters:**

Parameter | Description | Required? | Default
--- | --- | --- | ---
zapPort              | Port where ZAP is running or will run                                       | Yes | -
zapHost              | Host where ZAP is running                                                   | No  | localhost
zapApiKey            | API key needed to access ZAP's API, in case it's enabled                    | No  | -
zapPath              | Absolute path where ZAP is installed, used to automatically start ZAP       | No  | -
zapJvmOptions        | JVM options used to launch ZAP                                              | No  | -Xmx512m
shouldRunWithDocker  | Indicates whether ZAP should be automatically started with Docker           | No  | false
zapOptions           | Options that will be used to automatically start ZAP                        | No  | See bellow
initializationTimeoutInMillis | ZAP's automatic initialization timeout in milliseconds    | No  | 120000
reportPath  | Absolute or relative path where the generated reports will be saved         | No  | ${project.build.directory}/zap-reports

> To automatically start ZAP, it must be installed locally and the option *zapPath* must be provided. If the installation folder contains more than one Jar, *zapPath* should point to the core Jar file. To start ZAP with Docker, Docker must be locally installed and the option *shouldRunWithDocker* must be passed as *true*. In both cases, by default, ZAP is initialized with the following options:
> ```
> -daemon -config api.disablekey=true -config api.incerrordetails=true -config proxy.ip=0.0.0.0 -port ${zapPort}
> ```
> These options make ZAP start without a GUI, with its API key disabled, able to report errors details via API, and able to be accessed remotely. Besides that, it makes sure ZAP will run on the port specified by the *port* option. These options can be overridden by the *zapOptions* parameter.

**Authentication parameters:**

Parameter | Description | Required?
--- | --- | ---
authenticationType | Define the authentication type: 'http', 'form', 'cas' or 'selenium' | Yes, for authenticated analysis
loginUrl           | Login page URL                                                      | Yes, for authenticated analysis
username           | Username used in the authentication                                 | Yes, for authenticated analysis
password           | Password used in the authentication                                 | Yes, for authenticated analysis
extraPostData      | Used to define any extra parameters that must be passed in the authentication request (e.g. *domain=someDomain&param=value*) | No
loggedInRegex      | Regex that identifies a pattern in authenticated responses (needed to allow re-authentication)     | No
loggedOutRegex     | Regex that identifies a pattern in non-authenticated responses (needed to allow re-authentication) | No
excludeFromScan    | Define the URLs regexs that will be excluded from the scan | No

**HTTP authentication parameters:**

Parameter | Description | Required? | Default
--- | --- | --- | ---
hostname  | The host name of the server where the authentication is done | Yes | -
realm     | The realm the credentials apply to | Yes | -
port      | The port of the server where the authentication is done | No  | 80

**CAS authentication parameter:**

Parameter | Description | Required?
--- | --- | ---
protectedPages | Define the URL of a protected page of the application that will be scanned | Yes, if *authenticationType* is *CAS*

> As it was stated, the option *protectedPage* should have as value the URL of a protected page of the application that will be scanned. For CAS authentication, the login is done directly at the CAS server. Thus, in the first access to the application there will be a redirect to the server, that ends up redirecting the user back to the protected page, since the user is already authenticated. ZAP doesn't support this circular redirect, and because of that the application needs to be accessed at least once before the scan is started. This option defines the URL of a protected page that will be accessed after the authentication and before the scan to make sure the circular redirect won't happen during ZAP's analysis.

**Form and Selenium authentication parameters:**

Parameter | Description | Required? | Default
--- | --- | --- | ---
usernameParameter  | Name of the request parameter that holds the username | No | username
passwordParameter  | Name of the request parameter that holds the password | No | password

**Selenium authentication parameters:**

Parameter | Description | Required? | Default
--- | --- | --- | ---
httpSessionTokens  | Any additional session tokens that should be added to ZAP prior authentication | No | -
seleniumDriver     | The web driver that will be used to perform authentication: 'htmlunit', 'firefox', or 'phantomjs' | No | firefox

>
- It's important to realize that the `HtmlUnitDriver` lacks complete support for JavaScript. Therefore, it might not always work properly. If a GUI is not available, prefer to use [PhantomJS](http://phantomjs.org/).
- When using PhantomJS, make sure its executable is in the system's path.

Notice that the parameters *context*, *excludeFromScan*, *protectedPages* and *httpSessionTokens* accept multiple values, like in the example below:

```xml
<excludeFromScan>
    <!-- It doesn't matter how you name the inner tag -->
    <exclude1>http://myapp/logout</exclude1>
    <exclude2>http://myapp/forbidden</exclude2>
</excludeFromScan>
<httpSessionTokens>
    <!-- And even for only one item, the inner tag is necessary -->
    <token>LtpaToken2</token>
</httpSessionTokens>
```

## Authentication Strategies

There are three ways to perform authenticated scans with the ZAP Maven Plugin. The first and most simple one is the HTTP  authentication. According to ZAP, three authentication schemes are supported: Basic, Digest, and NTLM, and reauthentication is possible. The *hostname*, *realm* and (optional) *port* parameters are passed to ZAP, which handles the authentication process.

The second is the form based authentication. This should be used for very simple form authentications (like the one found in the [bodgeit](https://github.com/psiinon/bodgeit) application), where all you need to authenticate is a simple POST request. This strategy uses ZAP's form authentication mechanism, thus reauthentication is possible (through *loggedIn* and *loggedOutRegex* parameters).

It's also possible to run authenticated scans on applications that use [CAS](http://jasig.github.io/cas/). This strategy uses ZAP's script authentication mechanism with a script to perform the CAS authentication. It might not work for all possible CAS configurations (there are many), and, as with the form authentication, reauthentication is possible.

The last strategy uses [Selenium](http://www.seleniumhq.org). The idea is to perform the authentication via Selenium, and pass to ZAP the session created (i.e. the session cookie). This should work in most situations, including more complex form based authentications. However, reauthentication is not possible, so make sure you use the *excludeFromScan* parameter to exclude the logout URL and avoid logging out during the scan.

## Examples

### Using a running instance of ZAP

For this to work, ZAP must already be running.

```xml
<plugin>
    <groupId>br.com.softplan.security.zap</groupId>
    <artifactId>zap-maven-plugin</artifactId>
    <version>${zap-maven-plugin.version}</version>
    <configuration>
        <!-- If ZAP is running on localhost, there is no need to define zapHost -->
        <zapHost>10.10.3.4</zapHost>
        <zapPort>8080</zapPort>
        <targetUrl>http://localhost:8090/testwebapp</targetUrl>
    </configuration>
</plugin>
```

### Starting ZAP automatically

For ZAP to be automatically started, the option *zapPath* must be provided with the directory where ZAP is installed.

```xml
<plugin>
	<groupId>br.com.softplan.security.zap</groupId>
	<artifactId>zap-maven-plugin</artifactId>
	<version>${zap-maven-plugin.version}</version>
	<configuration>
		<zapPort>8080</zapPort>
		<targetUrl>http://localhost:8090/testwebapp</targetUrl>
		<zapPath>C:\Program Files (x86)\OWASP\Zed Attack Proxy</zapPath>
	</configuration>
</plugin>
```

> There is no need to inform the host in this case, since it will obviously be *localhost*.

### Starting ZAP with Docker

If ZAP is not installed, you can still start ZAP with Docker. For this, Docker must be installed and the option *shouldRunWithDocker* must be provided with value *true*.

```xml
<plugin>
	<groupId>br.com.softplan.security.zap</groupId>
	<artifactId>zap-maven-plugin</artifactId>
	<version>${zap-maven-plugin.version}</version>
	<configuration>
		<zapPort>8080</zapPort>
		<targetUrl>http://localhost:8090/testwebapp</targetUrl>
		<shouldRunWithDocker>true</shouldRunWithDocker>
	</configuration>
</plugin>
```

### Form authentication example

```xml
<plugin>
	<groupId>br.com.softplan.security.zap</groupId>
	<artifactId>zap-maven-plugin</artifactId>
	<version>${zap-maven-plugin.version}</version>
	<configuration>
    	<zapPort>8080</zapPort>
		<targetUrl>http://localhost:8180/bodgeit</targetUrl>

		<authenticationType>form</authenticationType>
		<username>user</username>
		<password>pass</password>
		<loginUrl>http://localhost:8180/bodgeit/login.jsp</loginUrl>
		<loggedInRegex><![CDATA[\\Q<a href=\"logout.jsp\">Logout</a>\\E]]></loggedInRegex>
	</configuration>
</plugin>
```

> Notice that it might be necessary to use the tag `<![CDATA[]]>` so the characters used within the parameter value are not parsed as part of the XML.

### CAS authentication example

```xml
<plugin>
	<groupId>br.com.softplan.security.zap</groupId>
	<artifactId>zap-maven-plugin</artifactId>
	<version>${zap-maven-plugin.version}</version>
	<configuration>
		<zapPort>8080</zapPort>
		<targetUrl>https://localhost:8443/myapp</targetUrl>

        <authenticationType>cas</authenticationType>
        <username>user</username>
        <password>pass</password>
        <loginUrl>https://localhost:8443/cas-server/login</loginUrl>
        <protectedPages>
            <protectedPage>https://localhost:8443/myapp/protected/index</protectedPage>
        </protectedPages>
        <loggedOutRegex><![CDATA[\\QLocation: https://localhost:8443/cas-server/\\E.*]]></loggedOutRegex>
	</configuration>
</plugin>
```

> A good way to achieve re-authentication with CAS is defining the *loggedOutRegex* with a value like `\QLocation: https://your.domain/your-cas-server\E.*`. Unauthenticated responses will be redirects to the CAS server, so this is the easiest way to identify that there was a redirection to the CAS server and thus the user is not logged in.

### Selenium authentication example

```xml
<plugin>
	<groupId>br.com.softplan.security.zap</groupId>
	<artifactId>zap-maven-plugin</artifactId>
	<version>${zap-maven-plugin.version}</version>
	<configuration>
		<zapPort>8080</zapPort>
		<targetUrl>http://localhost:8090/testwebapp</targetUrl>

        <authenticationType>selenium</authenticationType>
        <username>user</username>
        <password>pass</password>
        <loginUrl>http://localhost:8090/testwebapp/login</loginUrl>
        <httpSessionTokens>
            <token>LtpaToken2</token>
        </httpSessionTokens>
        <seleniumDriver>phantomjs</seleniumDriver>
	</configuration>
</plugin>
```

## Selenium Integration

If your application has [Selenium](http://www.seleniumhq.org) integration tests that navigate through the application, it might be interesting to feed ZAP with the visited pages instead of relying on ZAP's Spider. The Spider can't ensure a complete navigation through the application. Besides that, by feeding ZAP with the visited pages, it's possible to easily define the analysis scope, since ZAP's tests will only be executed on the pages that were visited during the tests.

With that in mind, the goals *startZap* and *seleniumAnalyze* were developed. With them, it's possible to start ZAP before the integration tests and execute the analysis after the tests, using the navigation done by the tests.

The first step to feed ZAP with your integration tests navigation is to ensure the tests use ZAP as a proxy. This way, all requests made during the tests execution go through ZAP. The configuration needed for the most common drivers are presented bellow:

```java
    WebDriver driver;

    // HtmlUnit
    driver = new HtmlUnitDriver();
	((HtmlUnitDriver) driver).setProxy(ZAP_HOST, ZAP_PORT);

	// Firefox
	FirefoxProfile profile = new FirefoxProfile();
	profile.setPreference("network.proxy.type", 1); // 1 = 'Manual proxy configuration'
	profile.setPreference("network.proxy.share_proxy_settings", true);
	profile.setPreference("network.proxy.no_proxies_on", "");
    profile.setPreference("network.proxy.http", ZAP_HOST);
    profile.setPreference("network.proxy.http_port", ZAP_PORT);
    driver = new FirefoxDriver(profile);

	// Chrome
	Proxy proxy = new Proxy(); // org.openqa.selenium.Proxy
	proxy.setHttpProxy(ZAP_HOST + ":" + ZAP_PORT);
	DesiredCapabilities capabilities = DesiredCapabilities.chrome();
	capabilities.setCapability("proxy", proxy);
	driver = new ChromeDriver(capabilities);
```

With that done, all that remains are the plugin goals configuration:

```xml
<plugin>
    <groupId>br.com.softplan.security.zap</groupId>
    <artifactId>zap-maven-plugin</artifactId>
    <version>${zap-maven-plugin.version}</version>
    <configuration>
		<!-- whatever configuration -->
	</configuration>
	<executions>
		<execution>
			<id>start-zap</id>
			<phase>pre-integration-test</phase>
			<goals><goal>startZap</goal></goals>
		</execution>
		<execution>
			<id>selenium-analyze</id>
			<phase>post-integration-test</phase>
			<goals><goal>seleniumAnalyze</goal></goals>
		</execution>
	</executions>
</plugin>
```

This will ensure that ZAP is started before the integration tests, so the tests can be proxied through it. Also, with that configuration ZAP will only execute the analysis after the tests execution.

:zap:


text:
(function (root) { var amdExports; define([], function () { (function () {

// lol. we already have a test for datalist built in! silly you.

// Helpful links while you're here, though..

// http://css-tricks.com/15346-relevant-dropdowns-polyfill-for-datalist/
// http://miketaylr.com/test/datalist.html
// http://miketaylr.com/code/datalist.html

Modernizr.addTest('datalistelem', Modernizr.input.list );

}.call(root));
    return amdExports;
}); }(this));

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Xidea\Bundle\BaseBundle\Event;

use Symfony\Component\EventDispatcher\Event,
    Symfony\Component\HttpFoundation\Request;

/**
 *
 * @author Artur Pszczółka <a.pszczolka@xidea.pl>
 */
class ModelEvent extends Event
{

    /**
     * @var TicketInterface
     */
    protected $model;

    /**
     * @var Request
     */
    protected $request;

    /**
     * Constructs an event.
     *
     * @param mixed $model The model
     */
    public function __construct($model, Request $request = null)
    {
        $this->model = $model;
        $this->request = $request;
    }

    /**
     * @return mixed
     */
    public function getModel()
    {
        return $this->model;
    }

    /**
     * @return Request
     */
    public function getRequest()
    {
        return $this->request;
    }

}


text:
package org.elasticsearch.index.mapper;

import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.suggest.document.CompletionAnalyzer;
import org.apache.lucene.search.suggest.document.ContextSuggestField;
import org.apache.lucene.search.suggest.document.FuzzyCompletionQuery;
import org.apache.lucene.search.suggest.document.PrefixCompletionQuery;
import org.apache.lucene.search.suggest.document.RegexCompletionQuery;
import org.apache.lucene.search.suggest.document.SuggestField;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.lucene.util.automaton.Operations;
import org.apache.lucene.util.automaton.RegExp;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.analysis.NamedAnalyzer;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.hamcrest.FeatureMatcher;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.core.CombinableMatcher;

import java.io.IOException;
import java.util.Map;
import java.util.function.Function;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;

public class CompletionFieldMapperTests extends ESSingleNodeTestCase {
    public void testDefaultConfiguration() throws IOException {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");
        assertThat(fieldMapper, instanceOf(CompletionFieldMapper.class));
        MappedFieldType completionFieldType = ((CompletionFieldMapper) fieldMapper).fieldType();

        NamedAnalyzer indexAnalyzer = completionFieldType.indexAnalyzer();
        assertThat(indexAnalyzer.name(), equalTo("simple"));
        assertThat(indexAnalyzer.analyzer(), instanceOf(CompletionAnalyzer.class));
        CompletionAnalyzer analyzer = (CompletionAnalyzer) indexAnalyzer.analyzer();
        assertThat(analyzer.preservePositionIncrements(), equalTo(true));
        assertThat(analyzer.preserveSep(), equalTo(true));

        NamedAnalyzer searchAnalyzer = completionFieldType.searchAnalyzer();
        assertThat(searchAnalyzer.name(), equalTo("simple"));
        assertThat(searchAnalyzer.analyzer(), instanceOf(CompletionAnalyzer.class));
        analyzer = (CompletionAnalyzer) searchAnalyzer.analyzer();
        assertThat(analyzer.preservePositionIncrements(), equalTo(true));
        assertThat(analyzer.preserveSep(), equalTo(true));
    }

    public void testCompletionAnalyzerSettings() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .field("analyzer", "simple")
                .field("search_analyzer", "standard")
                .field("preserve_separators", false)
                .field("preserve_position_increments", true)
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");
        assertThat(fieldMapper, instanceOf(CompletionFieldMapper.class));
        MappedFieldType completionFieldType = ((CompletionFieldMapper) fieldMapper).fieldType();

        NamedAnalyzer indexAnalyzer = completionFieldType.indexAnalyzer();
        assertThat(indexAnalyzer.name(), equalTo("simple"));
        assertThat(indexAnalyzer.analyzer(), instanceOf(CompletionAnalyzer.class));
        CompletionAnalyzer analyzer = (CompletionAnalyzer) indexAnalyzer.analyzer();
        assertThat(analyzer.preservePositionIncrements(), equalTo(true));
        assertThat(analyzer.preserveSep(), equalTo(false));

        NamedAnalyzer searchAnalyzer = completionFieldType.searchAnalyzer();
        assertThat(searchAnalyzer.name(), equalTo("standard"));
        assertThat(searchAnalyzer.analyzer(), instanceOf(CompletionAnalyzer.class));
        analyzer = (CompletionAnalyzer) searchAnalyzer.analyzer();
        assertThat(analyzer.preservePositionIncrements(), equalTo(true));
        assertThat(analyzer.preserveSep(), equalTo(false));

    }

    public void testTypeParsing() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .field("analyzer", "simple")
                .field("search_analyzer", "standard")
                .field("preserve_separators", false)
                .field("preserve_position_increments", true)
                .field("max_input_length", 14)
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");
        assertThat(fieldMapper, instanceOf(CompletionFieldMapper.class));

        XContentBuilder builder = jsonBuilder().startObject();
        fieldMapper.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject();
        builder.close();
        Map<String, Object> serializedMap = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)).map();
        Map<String, Object> configMap = (Map<String, Object>) serializedMap.get("completion");
        assertThat(configMap.get("analyzer").toString(), is("simple"));
        assertThat(configMap.get("search_analyzer").toString(), is("standard"));
        assertThat(Boolean.valueOf(configMap.get("preserve_separators").toString()), is(false));
        assertThat(Boolean.valueOf(configMap.get("preserve_position_increments").toString()), is(true));
        assertThat(Integer.valueOf(configMap.get("max_input_length").toString()), is(14));
    }

    public void testParsingMinimal() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                        .startObject()
                        .field("completion", "suggestion")
                        .endObject()),
                XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertSuggestFields(fields, 1);
    }

    public void testParsingFailure() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties").startObject("completion")
            .field("type", "completion")
            .endObject().endObject()
            .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        MapperParsingException e = expectThrows(MapperParsingException.class, () ->
            defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                    .bytes(XContentFactory.jsonBuilder()
                            .startObject()
                            .field("completion", 1.0)
                            .endObject()),
                XContentType.JSON)));
        assertEquals("failed to parse [completion]: expected text or object, but got VALUE_NUMBER", e.getCause().getMessage());
    }

    public void testKeywordWithSubCompletionAndContext() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties")
            .startObject("keywordfield")
                .field("type", "keyword")
                .startObject("fields")
                .startObject("subsuggest")
                    .field("type", "completion")
                    .startArray("contexts")
                        .startObject()
                            .field("name","place_type")
                            .field("type","category")
                            .field("path","cat")
                        .endObject()
                    .endArray()
                .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .array("keywordfield", "key1", "key2", "key3")
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();

        assertThat(indexableFields.getFields("keywordfield"), arrayContainingInAnyOrder(
            keywordField("key1"),
            sortedSetDocValuesField("key1"),
            keywordField("key2"),
            sortedSetDocValuesField("key2"),
            keywordField("key3"),
            sortedSetDocValuesField("key3")
        ));
        assertThat(indexableFields.getFields("keywordfield.subsuggest"), arrayContainingInAnyOrder(
            contextSuggestField("key1"),
            contextSuggestField("key2"),
            contextSuggestField("key3")
        ));
    }

    public void testCompletionWithContextAndSubCompletion() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties")
            .startObject("suggest")
                .field("type", "completion")
                .startArray("contexts")
                    .startObject()
                        .field("name","place_type")
                        .field("type","category")
                        .field("path","cat")
                    .endObject()
                .endArray()
                .startObject("fields")
                .startObject("subsuggest")
                    .field("type", "completion")
                    .startArray("contexts")
                        .startObject()
                            .field("name","place_type")
                            .field("type","category")
                            .field("path","cat")
                        .endObject()
                    .endArray()
                .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                        .startObject("suggest")
                            .array("input","timmy","starbucks")
                            .startObject("contexts")
                                .array("place_type","cafe","food")
                            .endObject()
                            .field("weight", 3)
                        .endObject()
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("suggest"), arrayContainingInAnyOrder(
            contextSuggestField("timmy"),
            contextSuggestField("starbucks")
        ));
        assertThat(indexableFields.getFields("suggest.subsuggest"), arrayContainingInAnyOrder(
            contextSuggestField("timmy"),
            contextSuggestField("starbucks")
        ));
        //unable to assert about context, covered in a REST test
    }

    public void testCompletionWithContextAndSubCompletionIndexByPath() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties")
            .startObject("suggest")
                .field("type", "completion")
                .startArray("contexts")
                    .startObject()
                        .field("name","place_type")
                        .field("type","category")
                        .field("path","cat")
                    .endObject()
                .endArray()
                .startObject("fields")
                .startObject("subsuggest")
                    .field("type", "completion")
                    .startArray("contexts")
                        .startObject()
                            .field("name","place_type")
                            .field("type","category")
                            .field("path","cat")
                        .endObject()
                    .endArray()
                .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .array("suggest", "timmy","starbucks")
                    .array("cat","cafe","food")
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("suggest"), arrayContainingInAnyOrder(
            contextSuggestField("timmy"),
            contextSuggestField("starbucks")
        ));
        assertThat(indexableFields.getFields("suggest.subsuggest"), arrayContainingInAnyOrder(
            contextSuggestField("timmy"),
            contextSuggestField("starbucks")
        ));
        //unable to assert about context, covered in a REST test
    }

    public void testKeywordWithSubCompletionAndStringInsert() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties").startObject("geofield")
            .field("type", "geo_point")
            .startObject("fields")
            .startObject("analyzed")
            .field("type", "completion")
            .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .field("geofield", "drm3btev3e86")//"41.12,-71.34"
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("geofield"), arrayWithSize(2));
        assertThat(indexableFields.getFields("geofield.analyzed"), arrayContainingInAnyOrder(
            suggestField("drm3btev3e86")
        ));
        //unable to assert about geofield content, covered in a REST test
    }

    public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties").startObject("suggest")
                .field("type", "completion")
                .startObject("fields")
                    .startObject("subsuggest")
                    .field("type", "completion")
                    .endObject()
                .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .field("suggest", "suggestion")
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("suggest"), arrayContainingInAnyOrder(
            suggestField("suggestion")
        ));
        assertThat(indexableFields.getFields("suggest.subsuggest"), arrayContainingInAnyOrder(
            suggestField("suggestion")
        ));
    }

    public void testCompletionTypeWithSubCompletionFieldAndObjectInsert() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties").startObject("completion")
            .field("type", "completion")
            .startObject("fields")
            .startObject("analyzed")
            .field("type", "completion")
            .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .startObject("completion")
                    .array("input","New York", "NY")
                    .field("weight",34)
                    .endObject()
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("completion"), arrayContainingInAnyOrder(
            suggestField("New York"),
            suggestField("NY")
        ));
        assertThat(indexableFields.getFields("completion.analyzed"), arrayContainingInAnyOrder(
            suggestField("New York"),
            suggestField("NY")
        ));
        //unable to assert about weight, covered in a REST test
    }

    public void testCompletionTypeWithSubKeywordFieldAndObjectInsert() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties").startObject("completion")
            .field("type", "completion")
            .startObject("fields")
            .startObject("analyzed")
            .field("type", "keyword")
            .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .startObject("completion")
                        .array("input","New York", "NY")
                        .field("weight",34)
                    .endObject()
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("completion"), arrayContainingInAnyOrder(
            suggestField("New York"),
            suggestField("NY")
        ));
        assertThat(indexableFields.getFields("completion.analyzed"), arrayContainingInAnyOrder(
            keywordField("New York"),
            sortedSetDocValuesField("New York"),
            keywordField("NY"),
            sortedSetDocValuesField("NY")
        ));
        //unable to assert about weight, covered in a REST test
    }

    public void testCompletionTypeWithSubKeywordFieldAndStringInsert() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
            .startObject("properties").startObject("completion")
            .field("type", "completion")
            .startObject("fields")
            .startObject("analyzed")
            .field("type", "keyword")
            .endObject()
            .endObject()
            .endObject().endObject()
            .endObject().endObject()
        );

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .field("completion", "suggestion")
                    .endObject()),
            XContentType.JSON));

        ParseContext.Document indexableFields = parsedDocument.rootDoc();
        assertThat(indexableFields.getFields("completion"), arrayContainingInAnyOrder(
            suggestField("suggestion")
        ));
        assertThat(indexableFields.getFields("completion.analyzed"), arrayContainingInAnyOrder(
            keywordField("suggestion"),
            sortedSetDocValuesField("suggestion")
        ));
    }

    public void testParsingMultiValued() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                        .startObject()
                        .array("completion", "suggestion1", "suggestion2")
                        .endObject()),
                XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertThat(fields, arrayContainingInAnyOrder(
            suggestField("suggestion1"),
            suggestField("suggestion2")
        ));
    }

    public void testParsingWithWeight() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                        .startObject()
                        .startObject("completion")
                        .field("input", "suggestion")
                        .field("weight", 2)
                        .endObject()
                        .endObject()),
                XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertThat(fields, arrayContainingInAnyOrder(
            suggestField("suggestion")
        ));
    }

    public void testParsingMultiValueWithWeight() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                        .startObject()
                        .startObject("completion")
                        .array("input", "suggestion1", "suggestion2", "suggestion3")
                        .field("weight", 2)
                        .endObject()
                        .endObject()),
                XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertThat(fields, arrayContainingInAnyOrder(
            suggestField("suggestion1"),
            suggestField("suggestion2"),
            suggestField("suggestion3")
        ));
    }

    public void testParsingWithGeoFieldAlias() throws Exception {
        XContentBuilder mapping = XContentFactory.jsonBuilder().startObject()
            .startObject("type1")
                .startObject("properties")
                    .startObject("completion")
                        .field("type", "completion")
                        .startObject("contexts")
                            .field("name", "location")
                            .field("type", "geo")
                            .field("path", "alias")
                        .endObject()
                    .endObject()
                    .startObject("birth-place")
                        .field("type", "geo_point")
                    .endObject()
                    .startObject("alias")
                        .field("type", "alias")
                        .field("path", "birth-place")
                    .endObject()
                .endObject()
            .endObject()
        .endObject();

        MapperService mapperService = createIndex("test", Settings.EMPTY, "type1", mapping).mapperService();
        Mapper fieldMapper = mapperService.documentMapper().mappers().getMapper("completion");

        ParsedDocument parsedDocument = mapperService.documentMapper().parse(SourceToParse.source("test", "type1", "1",
            BytesReference.bytes(XContentFactory.jsonBuilder()
                .startObject()
                    .startObject("completion")
                        .field("input", "suggestion")
                        .startObject("contexts")
                            .field("location", "37.77,-122.42")
                        .endObject()
                    .endObject()
                .endObject()), XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertSuggestFields(fields, 1);
    }

    public void testParsingFull() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                        .startObject()
                        .startArray("completion")
                        .startObject()
                        .field("input", "suggestion1")
                        .field("weight", 3)
                        .endObject()
                        .startObject()
                        .field("input", "suggestion2")
                        .field("weight", 4)
                        .endObject()
                        .startObject()
                        .field("input", "suggestion3")
                        .field("weight", 5)
                        .endObject()
                        .endArray()
                        .endObject()),
                XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertThat(fields, arrayContainingInAnyOrder(
            suggestField("suggestion1"),
            suggestField("suggestion2"),
            suggestField("suggestion3")
        ));
    }

    public void testParsingMixed() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");

        ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                        .startObject()
                        .startArray("completion")
                        .startObject()
                        .array("input", "suggestion1", "suggestion2")
                        .field("weight", 3)
                        .endObject()
                        .startObject()
                        .field("input", "suggestion3")
                        .field("weight", 4)
                        .endObject()
                        .startObject()
                        .array("input", "suggestion4", "suggestion5", "suggestion6")
                        .field("weight", 5)
                        .endObject()
                        .endArray()
                        .endObject()),
                XContentType.JSON));
        IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name());
        assertThat(fields, arrayContainingInAnyOrder(
            suggestField("suggestion1"),
            suggestField("suggestion2"),
            suggestField("suggestion3"),
            suggestField("suggestion4"),
            suggestField("suggestion5"),
            suggestField("suggestion6")
        ));
    }

    public void testNonContextEnabledParsingWithContexts() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("field1")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        try {
            defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                    .bytes(XContentFactory.jsonBuilder()
                            .startObject()
                            .startObject("field1")
                            .field("input", "suggestion1")
                            .startObject("contexts")
                            .field("ctx", "ctx2")
                            .endObject()
                            .field("weight", 3)
                            .endObject()
                            .endObject()),
                    XContentType.JSON));
            fail("Supplying contexts to a non context-enabled field should error");
        } catch (MapperParsingException e) {
            assertThat(e.getRootCause().getMessage(), containsString("field1"));
        }
    }

    public void testFieldValueValidation() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        CharsRefBuilder charsRefBuilder = new CharsRefBuilder();
        charsRefBuilder.append("sugg");
        charsRefBuilder.setCharAt(2, '\u001F');
        try {
            defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                    .bytes(XContentFactory.jsonBuilder()
                            .startObject()
                            .field("completion", charsRefBuilder.get().toString())
                            .endObject()),
                    XContentType.JSON));
            fail("No error indexing value with reserved character [0x1F]");
        } catch (MapperParsingException e) {
            Throwable cause = e.unwrapCause().getCause();
            assertThat(cause, instanceOf(IllegalArgumentException.class));
            assertThat(cause.getMessage(), containsString("[0x1f]"));
        }

        charsRefBuilder.setCharAt(2, '\u0000');
        try {
            defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                    .bytes(XContentFactory.jsonBuilder()
                            .startObject()
                            .field("completion", charsRefBuilder.get().toString())
                            .endObject()),
                    XContentType.JSON));
            fail("No error indexing value with reserved character [0x0]");
        } catch (MapperParsingException e) {
            Throwable cause = e.unwrapCause().getCause();
            assertThat(cause, instanceOf(IllegalArgumentException.class));
            assertThat(cause.getMessage(), containsString("[0x0]"));
        }

        charsRefBuilder.setCharAt(2, '\u001E');
        try {
            defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                    .bytes(XContentFactory.jsonBuilder()
                            .startObject()
                            .field("completion", charsRefBuilder.get().toString())
                            .endObject()),
                    XContentType.JSON));
            fail("No error indexing value with reserved character [0x1E]");
        } catch (MapperParsingException e) {
            Throwable cause = e.unwrapCause().getCause();
            assertThat(cause, instanceOf(IllegalArgumentException.class));
            assertThat(cause.getMessage(), containsString("[0x1e]"));
        }

        // empty inputs are ignored
        ParsedDocument doc = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .array("completion", "   ", "")
                    .endObject()),
            XContentType.JSON));
        assertThat(doc.docs().size(), equalTo(1));
        assertNull(doc.docs().get(0).get("completion"));
        assertNotNull(doc.docs().get(0).getField("_ignored"));
        IndexableField ignoredFields = doc.docs().get(0).getField("_ignored");
        assertThat(ignoredFields.stringValue(), equalTo("completion"));

        // null inputs are ignored
        ParsedDocument nullDoc = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference
                .bytes(XContentFactory.jsonBuilder()
                    .startObject()
                    .nullField("completion")
                    .endObject()),
            XContentType.JSON));
        assertThat(nullDoc.docs().size(), equalTo(1));
        assertNull(nullDoc.docs().get(0).get("completion"));
        assertNull(nullDoc.docs().get(0).getField("_ignored"));
    }

    public void testPrefixQueryType() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");
        CompletionFieldMapper completionFieldMapper = (CompletionFieldMapper) fieldMapper;
        Query prefixQuery = completionFieldMapper.fieldType().prefixQuery(new BytesRef("co"));
        assertThat(prefixQuery, instanceOf(PrefixCompletionQuery.class));
    }

    public void testFuzzyQueryType() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");
        CompletionFieldMapper completionFieldMapper = (CompletionFieldMapper) fieldMapper;
        Query prefixQuery = completionFieldMapper.fieldType().fuzzyQuery("co",
                Fuzziness.fromEdits(FuzzyCompletionQuery.DEFAULT_MAX_EDITS), FuzzyCompletionQuery.DEFAULT_NON_FUZZY_PREFIX,
                FuzzyCompletionQuery.DEFAULT_MIN_FUZZY_LENGTH, Operations.DEFAULT_MAX_DETERMINIZED_STATES,
                FuzzyCompletionQuery.DEFAULT_TRANSPOSITIONS, FuzzyCompletionQuery.DEFAULT_UNICODE_AWARE);
        assertThat(prefixQuery, instanceOf(FuzzyCompletionQuery.class));
    }

    public void testRegexQueryType() throws Exception {
        String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1")
                .startObject("properties").startObject("completion")
                .field("type", "completion")
                .endObject().endObject()
                .endObject().endObject());

        DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
        Mapper fieldMapper = defaultMapper.mappers().getMapper("completion");
        CompletionFieldMapper completionFieldMapper = (CompletionFieldMapper) fieldMapper;
        Query prefixQuery = completionFieldMapper.fieldType()
                .regexpQuery(new BytesRef("co"), RegExp.ALL, Operations.DEFAULT_MAX_DETERMINIZED_STATES);
        assertThat(prefixQuery, instanceOf(RegexCompletionQuery.class));
    }

    private static void assertSuggestFields(IndexableField[] fields, int expected) {
        assertFieldsOfType(fields, SuggestField.class, expected);
    }

    private static void assertFieldsOfType(IndexableField[] fields, Class<?> clazz, int expected) {
        int actualFieldCount = 0;
        for (IndexableField field : fields) {
            if (clazz.isInstance(field)) {
                actualFieldCount++;
            }
        }
        assertThat(actualFieldCount, equalTo(expected));
    }

    public void testEmptyName() throws IOException {
        IndexService indexService = createIndex("test");
        DocumentMapperParser parser = indexService.mapperService().documentMapperParser();
        String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
            .startObject("properties").startObject("").field("type", "completion").endObject().endObject()
            .endObject().endObject());

        IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
            () -> parser.parse("type", new CompressedXContent(mapping))
        );
        assertThat(e.getMessage(), containsString("name cannot be empty string"));
    }

    private Matcher<IndexableField> suggestField(String value) {
        return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)),
            Matchers.instanceOf(SuggestField.class));
    }

    private Matcher<IndexableField> contextSuggestField(String value) {
        return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)),
            Matchers.instanceOf(ContextSuggestField.class));
    }

    private CombinableMatcher<IndexableField> sortedSetDocValuesField(String value) {
        return Matchers.both(hasProperty(IndexableField::binaryValue, equalTo(new BytesRef(value))))
            .and(Matchers.instanceOf(SortedSetDocValuesField.class));
    }

    private CombinableMatcher<IndexableField> keywordField(String value) {
        return Matchers.both(hasProperty(IndexableField::binaryValue, equalTo(new BytesRef(value))))
            .and(hasProperty(IndexableField::fieldType, Matchers.instanceOf(KeywordFieldMapper.KeywordFieldType.class)));
    }

    private <T, V> Matcher<T> hasProperty(Function<? super T, ? extends V> property, Matcher<V> valueMatcher) {
        return new FeatureMatcher<T, V>(valueMatcher, "object with", property.toString()) {
            @Override
            protected V featureValueOf(T actual) {
                return property.apply(actual);
            }
        };
    }
}


text:
//
//  ROItemCell.h
//  Test
//
//  This App has been generated using IBM Mobile UI Builder
//

#import <Foundation/Foundation.h>
#import "ROAction.h"

/**
 Model for the cell.
 Displays the contents of the cell regardless of the type of object that is.
 */
@interface ROItemCell : NSObject

/**
 Item text1
 */
@property (nonatomic, strong) NSString *text1;

/**
 Item text2
 */
@property (nonatomic, strong) NSString *text2;

/**
 Image resource name
 */
@property (nonatomic, strong) NSString *imageResource;

/**
 Image resource url
 */
@property (nonatomic, strong) NSString *imageUrl;

/**
 Action to do
 */
@property (nonatomic, strong) NSObject<ROAction> *action;

/**
 Constructor with text1
 @param text1 Item text1
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1;

/**
 Constructor with text1
 @param text1 Item
 @param aciton Action to do
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atAction:(NSObject<ROAction> *)action;

/**
 Constructor with text1 and text2
 @param text1 Item text1
 @param text2 Item text2
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2;

/**
 Constructor with text1, text2 and action
 @param text1 Item text1
 @param text2 Item text2
 @param action Action to do
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atAction:(NSObject<ROAction> *)action;

/**
 Constructor with text1 and image resource name
 @param text1 Item text1
 @param imageResource Image resource name
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atImageResource:(NSString *)imageResource;

/**
 Constructor with text1, image resource name and action
 @param text1 Item text1
 @param imageResource Image resource name
 @param action Action to do
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atImageResource:(NSString *)imageResource atAction:(NSObject<ROAction> *)action;

/**
 Constructor with image resource name
 @param imageResource Image resource name
 @return Class instance
 */
- (id)initWithImageResource:(NSString *)imageResource;

/**
 Constructor with image resource name and action
 @param imageResource Image resource name
 @param action Action to do
 @return Class instance
 */
- (id)initWithImageResource:(NSString *)imageResource atAction:(NSObject<ROAction> *)action;

/**
 Constructor with text1, text2 and image resource name
 @param text1 Item text1
 @param text2 Item text2
 @param imageResource Image resource name
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atImageResource:(NSString *)imageResource;

/**
 Constructor with text1, text2, image resource name and action
 @param text1 Item text1
 @param text2 Item text2
 @param imageResource Image resource name
 @param action Action to do
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atImageResource:(NSString *)imageResource atAction:(NSObject<ROAction> *)action;

/**
 Constructor with text1, text2 and image resource name
 @param text1 Item text1
 @param text2 Item text2
 @param imageUrl Image resource url
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atImageUrl:(NSString *)imageUrl;

/**
 Constructor with text1, text2, image resource name and action
 @param text1 Item text1
 @param text2 Item text2
 @param imageResource Image resource url
 @param action Action to do
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atImageUrl:(NSString *)imageUrl atAction:(NSObject<ROAction> *)action;

/**
 Constructor with text1, text2, image resource name and image resource url
 @param text1 Item text1
 @param text2 Item text2
 @param imageResource Image resource name
 @param imageResource Image resource url
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atImageResource:(NSString *)imageResource atImageUrl:(NSString *)imageUrl;

/**
 Constructor with image resource url and action
 @param imageResource Image resource url
 @param action Action to do
 @return Class instance
 */
- (id)initWithImageUrl:(NSString *)imageUrl atAction:(NSObject<ROAction> *)action;

/**
 Constructor with image resource url
 @param imageResource Image resource url
 @return Class instance
 */
- (id)initWithImageUrl:(NSString *)imageUrl;

/**
 Constructor with text1, text2, image resource name, image resource url and action
 @param text1 Item text 1
 @param text2 Item text 2
 @param imageResource Image resource name
 @param imageResource Image resource url
 @param action Action to do
 @return Class instance
 */
- (id)initWithText1:(NSString *)text1 atText2:(NSString *)text2 atImageResource:(NSString *)imageResource atImageUrl:(NSString *)imageUrl atAction:(NSObject<ROAction> *)action;

/**
 Check if item is empty
 @return YES if item is empty.
 */
- (BOOL)isEmpty;

@end


text:
package com.osrce.sitrep.domain;

import com.vividsolutions.jts.geom.Geometry;
import flexjson.JSONSerializer;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.annotations.Type;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.ejb.HibernateEntityManager;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.roo.addon.dbre.RooDbManaged;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.json.RooJson;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooJpaActiveRecord(versionField = "", table = "entity_status", schema = "public")
@RooDbManaged(automaticallyDelete = true)
@RooJson
public class EntityStatus {

    @Id
    @Column(name = "id", columnDefinition = "bigserial")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Type(type = "hstore")
    @Column(name = "data", columnDefinition = "hstore")
    private Hstore data = new Hstore();

    @Column(name = "updated", updatable = false)
    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "M-")
    private Date updated;

    public String toJson() {
        return new JSONSerializer().transform(new GeometryTransformer(), Geometry.class).serialize(this);
    }

    public String toString() {
        return this.toJson();
    }

    public static String toJsonArray(Collection<com.osrce.sitrep.domain.EntityStatus> collection) {
        Iterator<com.osrce.sitrep.domain.EntityStatus> iterator = collection.iterator();
        while (iterator.hasNext()) {
            EntityStatus theEnt = iterator.next();
        }
        return new JSONSerializer().transform(new GeometryTransformer(), Geometry.class).serialize(collection);
    }

    public static List<com.osrce.sitrep.domain.EntityStatus> findAllWithParams(Map<java.lang.String, java.lang.String[]> theParams) {
        HibernateEntityManager hem = entityManager().unwrap(HibernateEntityManager.class);
        Session session = hem.getSession();
        Criteria theCriteria = session.createCriteria(EntityStatus.class);
        theCriteria.createAlias("entity", "entity");
        if (theParams.containsKey("entity.groupId")) {
            theCriteria.add(Restrictions.eq("entity.groupId", Long.valueOf(theParams.get("entity.groupId")[0])));
        }
        if (theParams.containsKey("hasEnd")) {
            theCriteria.add(Restrictions.eq("hasEnd", Boolean.valueOf(theParams.get("hasEnd")[0])));
        }
        if (theParams.containsKey("hasLocation")) {
            theCriteria.add(Restrictions.eq("hasLocation", Boolean.valueOf(theParams.get("hasLocation")[0])));
        }
        return theCriteria.list();
    }
}


text:
class Shop < ActiveRecord::Base
  def self.store(session)
    #add code here to keep it from adding a new shop if one is there already
    shop = Shop.find_by(:domain => session.url)
    if shop == nil
      shop = Shop.new(domain: session.url, token: session.token)
      shop.save!
    else
      shop.token = session.token
      shop.save!
      ShopifyAPI::Session.new(shop.domain, shop.token)
    end
    shop.id
  end

  def self.retrieve(id)
    if shop = Shop.where(id: id).first
      ShopifyAPI::Session.new(shop.domain, shop.token)
    end
  end

  def shopify_api_path
    "https://#{ShopifyApp.configuration.api_key}:#{self.token}@#{self.domain}/admin"
  end

  def new_sess
    ShopifyAPI::Base.activate_session(Shop.retrieve(self.id))
  end
end


text:
module.exports = {
  userRegister: require('./core/user-register'),
  userLogin: require('./core/user-login')
}


text:
This is a step by step tutorial how to build a real application with the
[Symfony2 CMF](http://cmf.symfony.com). Each step is explained as a pull
request against the previous step.

If you are interested in having me do a CMF tutorial for you, please get in
[contact](mailto:mail@davidbu.ch).

## Documentation

The master branch is the Symfony2 Standard Edition without the DemoBundle. It
has no routes configured and will give you a 404 for the homepage. See the
branches and pull requests for the actual data.

For further information and setup instructions, see the [project wiki](https://github.com/dbu/conference-tutorial/wiki/Home)
and the pull requests.

See also:

* [All Symfony CMF documentation](http://symfony.com/doc/master/cmf/index.html) - complete Symfony CMF reference
* [Symfony CMF Website](http://cmf.symfony.com/) - introduction, live demo, support and community links


text:
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="test-to-html.xsl" type="text/xml"?>

<!--

Copyright (c) 2001-2004 World Wide Web Consortium,
(Massachusetts Institute of Technology, Institut National de
Recherche en Informatique et en Automatique, Keio University).  All
Rights Reserved.  This program is distributed under the W3C's Software
Intellectual Property License.  This program is distributed in the
hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

See W3C License http://www.w3.org/Consortium/Legal/ for more details.

-->
<!DOCTYPE test SYSTEM "dom3.dtd">
<test xmlns="http://www.w3.org/2001/DOM-Test-Suite/Level-3" name="elementsetidattributens01">
  <metadata>
    <title>elementsetidattributens01</title>
    <creator>IBM</creator>
    <description>
     Invoke setIdAttributeNS on an existing namespace attribute with a namespace URI and a qualified name.  Verify by calling
     isId on the attribute node and getElementById on document node.  Call setIdAttributeNS with isId=false to reset.
     isId should now return false.
    </description>
    <contributor>Jenny Hsu</contributor>
    <date qualifier="created">2003-02-26</date>
    <subject resource="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core#ID-ElSetIdAttrNS"/>
  </metadata>
  <implementationAttribute name="namespaceAware" value="true"/>
  <var name="doc" type="Document"/>
  <var name="elemList" type="NodeList"/>
  <var name="employeeElem" type="Element"/>
  <var name="attributesMap" type="NamedNodeMap"/>
  <var name="attr" type="Attr"/>
  <var name="id" type="boolean" value="false"/>
  <var name="elem" type="Element"/>
  <var name="elemName" type="DOMString"/>
  <load var="doc" href="hc_staff" willBeModified="true"/>
  <getElementsByTagName var="elemList" obj="doc" tagname='"p"' interface="Document"/>
  <item var="employeeElem" obj="elemList" index="2" interface="NodeList"/>
  <setIdAttributeNS obj="employeeElem" localName='"dmstc"' namespaceURI='"http://www.w3.org/2000/xmlns/"' isId="true"/>
  <attributes var="attributesMap" obj="employeeElem"/>
  <getNamedItem var="attr" obj="attributesMap" name='"xmlns:dmstc"'/>
  <isId var="id" obj="attr"/>
  <assertTrue actual="id" id="elementsetidattributensIsIdTrue01"/>
  <getElementById obj="doc" var="elem" elementId='"http://www.netzero.com"'/>
  <tagName obj="elem" var="elemName"/>
  <assertEquals actual="elemName" expected='"p"' id="elementsetidattributensGetElementById01" ignoreCase="false"/>
  <setIdAttributeNS obj="employeeElem" localName='"dmstc"' namespaceURI='"http://www.w3.org/2000/xmlns/"' isId="false"/>
  <isId var="id" obj="attr"/>
  <assertFalse actual="id" id="elementsetidattributensIsIdFalse01"/>
</test>


text:
#include <aws/route53-recovery-readiness/model/DeleteResourceSetRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::Route53RecoveryReadiness::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DeleteResourceSetRequest::DeleteResourceSetRequest() :
    m_resourceSetNameHasBeenSet(false)
{
}

Aws::String DeleteResourceSetRequest::SerializePayload() const
{
  return {};
}


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

namespace Catalogo.Web.Models
{
    public class Person
    {
        public int id { get; set; }

        public string Name { get; set; }
    }
}


text:
.siteorigin-widget-form .siteorigin-widget-field input {
  margin: 1px;
  padding: 2px 5px;
}
.siteorigin-widget-form .siteorigin-widget-field input[type="radio"] {
  width: inherit;
}
.siteorigin-widget-form .siteorigin-widget-field select {
  padding: 2px;
  height: 28px;
  width: inherit;
  margin: 1px;
}
.vc_element-icon.so-widget-icon {
  background-size: cover;
  background-image: url("../../base/css/img/bundle-icon.png");
}


text:
<?php

namespace Test\Behat\Mink\Element;

use Behat\Mink\Element\NodeElement;

require_once 'ElementTest.php';

/**
 * @group unittest
 */
class NodeElementTest extends ElementTest
{

    public function testGetXpath()
    {
        $node = new NodeElement('some custom xpath', $this->session);

        $this->assertEquals('some custom xpath', $node->getXpath());
        $this->assertNotEquals('not some custom xpath', $node->getXpath());
    }

    public function testGetText()
    {
        $expected = 'val1';
        $node = new NodeElement('text_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getText')
            ->with('text_tag')
            ->will($this->returnValue($expected));

        $this->assertEquals($expected, $node->getText());
    }

    public function testElementIsValid()
    {
        $elementXpath = 'some xpath';
        $node = new NodeElement($elementXpath, $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('find')
            ->with($elementXpath)
            ->will($this->returnValue(array($elementXpath)));

        $this->assertTrue($node->isValid());
    }

    public function testElementIsNotValid()
    {
        $node = new NodeElement('some xpath', $this->session);

        $this->session->getDriver()
            ->expects($this->exactly(2))
            ->method('find')
            ->with('some xpath')
            ->will($this->onConsecutiveCalls(array(), array('xpath1', 'xpath2')));

        $this->assertFalse($node->isValid(), 'no elements found is invalid element');
        $this->assertFalse($node->isValid(), 'more then 1 element found is invalid element');
    }

    public function testWaitForSuccess()
    {
        $callCounter = 0;
        $node = new NodeElement('some xpath', $this->session);

        $result = $node->waitFor(5000, function ($givenNode) use (&$callCounter) {
            $callCounter++;

            if (1 === $callCounter) {
                return null;
            } elseif (2 === $callCounter) {
                return false;
            } elseif (3 === $callCounter) {
                return array();
            }

            return $givenNode;
        });

        $this->assertEquals(4, $callCounter, '->waitFor() tries to locate element several times before failing');
        $this->assertSame($node, $result, '->waitFor() returns node found in callback');
    }

    public function testWaitForTimeout()
    {
        $node = new NodeElement('some xpath', $this->session);

        $expectedTimeout = 2;
        $startTime = microtime(true);
        $result = $node->waitFor($expectedTimeout * 1000, function ($givenNode) {
            return null;
        });
        $endTime = microtime(true);

        $this->assertNull($result, '->waitFor() returns whatever callback gives');
        $this->assertEquals($expectedTimeout, round($endTime - $startTime));
    }

    /**
     * @expectedException \InvalidArgumentException
     */
    public function testWaitForFailure()
    {
        $node = new NodeElement('some xpath', $this->session);
        $node->waitFor(5000, 'not a callable');
    }

    public function testHasAttribute()
    {
        $node = new NodeElement('input_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->exactly(2))
            ->method('getAttribute')
            ->with('input_tag', 'href')
            ->will($this->onConsecutiveCalls(null, 'http://...'));

        $this->assertFalse($node->hasAttribute('href'));
        $this->assertTrue($node->hasAttribute('href'));
    }

    public function testGetAttribute()
    {
        $expected = 'http://...';
        $node = new NodeElement('input_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getAttribute')
            ->with('input_tag', 'href')
            ->will($this->returnValue($expected));

        $this->assertEquals($expected, $node->getAttribute('href'));
    }

    public function testHasClass()
    {
        $node = new NodeElement('input_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->exactly(6))
            ->method('getAttribute')
            ->with('input_tag', 'class')
            ->will($this->returnValue('class1 class2'));

        $this->assertTrue($node->hasClass('class1'));
        $this->assertTrue($node->hasClass('class2'));
        $this->assertFalse($node->hasClass('class3'));
    }

    public function testHasClassWithoutArgument()
    {
        $node = new NodeElement('input_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getAttribute')
            ->with('input_tag', 'class')
            ->will($this->returnValue(null));

        $this->assertFalse($node->hasClass('class3'));
    }

    public function testGetValue()
    {
        $expected = 'val1';
        $node = new NodeElement('input_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getValue')
            ->with('input_tag')
            ->will($this->returnValue($expected));

        $this->assertEquals($expected, $node->getValue());
    }

    public function testSetValue()
    {
        $expected = 'new_val';
        $node = new NodeElement('input_tag', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('setValue')
            ->with('input_tag', $expected);

        $node->setValue($expected);
    }

    public function testClick()
    {
        $node = new NodeElement('link_or_button', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('click')
            ->with('link_or_button');

        $node->click();
    }

    public function testPress()
    {
        $node = new NodeElement('link_or_button', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('click')
            ->with('link_or_button');

        $node->press();
    }

    public function testRightClick()
    {
        $node = new NodeElement('elem', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('rightClick')
            ->with('elem');

        $node->rightClick();
    }

    public function testDoubleClick()
    {
        $node = new NodeElement('elem', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('doubleClick')
            ->with('elem');

        $node->doubleClick();
    }

    public function testCheck()
    {
        $node = new NodeElement('checkbox_or_radio', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('check')
            ->with('checkbox_or_radio');

        $node->check();
    }

    public function testUncheck()
    {
        $node = new NodeElement('checkbox_or_radio', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('uncheck')
            ->with('checkbox_or_radio');

        $node->uncheck();
    }

    public function testSelectOption()
    {
        $node = new NodeElement('select', $this->session);
        $option = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
            ->disableOriginalConstructor()
            ->getMock();
        $option
            ->expects($this->once())
            ->method('getValue')
            ->will($this->returnValue('item1'));

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getTagName')
            ->with('select')
            ->will($this->returnValue('select'));

        $this->session->getDriver()
            ->expects($this->once())
            ->method('find')
            ->with('select/option')
            ->will($this->returnValue(array($option)));

        $this->selectors
            ->expects($this->once())
            ->method('selectorToXpath')
            ->with('named_exact', array('option', 'item1'))
            ->will($this->returnValue('option'));

        $this->session->getDriver()
            ->expects($this->once())
            ->method('selectOption')
            ->with('select', 'item1', false);

        $node->selectOption('item1');
    }

    /**
     * @expectedException \Behat\Mink\Exception\ElementNotFoundException
     */
    public function testSelectOptionNotFound()
    {
        $node = new NodeElement('select', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getTagName')
            ->with('select')
            ->will($this->returnValue('select'));

        $this->session->getDriver()
            ->expects($this->exactly(2))
            ->method('find')
            ->with('select/option')
            ->will($this->returnValue(array()));

        $this->selectors
            ->expects($this->exactly(2))
            ->method('selectorToXpath')
            ->with($this->logicalOr('named_exact', 'named_partial'), array('option', 'item1'))
            ->will($this->returnValue('option'));

        $node->selectOption('item1');
    }

    public function testSelectOptionOtherTag()
    {
        $node = new NodeElement('div', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getTagName')
            ->with('div')
            ->will($this->returnValue('div'));

        $this->session->getDriver()
            ->expects($this->once())
            ->method('selectOption')
            ->with('div', 'item1', false);

        $node->selectOption('item1');
    }

    public function testGetTagName()
    {
        $node = new NodeElement('html//h3', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('getTagName')
            ->with('html//h3')
            ->will($this->returnValue('h3'));

        $this->assertEquals('h3', $node->getTagName());
    }

    public function testGetParent()
    {
        $node = new NodeElement('elem', $this->session);
        $parent = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
            ->disableOriginalConstructor()
            ->getMock();

        $this->session->getDriver()
            ->expects($this->once())
            ->method('find')
            ->with('elem/..')
            ->will($this->returnValue(array($parent)));

        $this->selectors
            ->expects($this->once())
            ->method('selectorToXpath')
            ->with('xpath', '..')
            ->will($this->returnValue('..'));

        $this->assertSame($parent, $node->getParent());
    }

    public function testAttachFile()
    {
        $node = new NodeElement('elem', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('attachFile')
            ->with('elem', 'path');

        $node->attachFile('path');
    }

    public function testIsVisible()
    {
        $node = new NodeElement('some_xpath', $this->session);

        $this->session->getDriver()
            ->expects($this->exactly(2))
            ->method('isVisible')
            ->with('some_xpath')
            ->will($this->onConsecutiveCalls(true, false));

        $this->assertTrue($node->isVisible());
        $this->assertFalse($node->isVisible());
    }

    public function testIsChecked()
    {
        $node = new NodeElement('some_xpath', $this->session);

        $this->session->getDriver()
            ->expects($this->exactly(2))
            ->method('isChecked')
            ->with('some_xpath')
            ->will($this->onConsecutiveCalls(true, false));

        $this->assertTrue($node->isChecked());
        $this->assertFalse($node->isChecked());
    }

    public function testIsSelected()
    {
        $node = new NodeElement('some_xpath', $this->session);

        $this->session->getDriver()
            ->expects($this->exactly(2))
            ->method('isSelected')
            ->with('some_xpath')
            ->will($this->onConsecutiveCalls(true, false));

        $this->assertTrue($node->isSelected());
        $this->assertFalse($node->isSelected());
    }

    public function testFocus()
    {
        $node = new NodeElement('some-element', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('focus')
            ->with('some-element');

        $node->focus();
    }

    public function testBlur()
    {
        $node = new NodeElement('some-element', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('blur')
            ->with('some-element');

        $node->blur();
    }

    public function testMouseOver()
    {
        $node = new NodeElement('some-element', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('mouseOver')
            ->with('some-element');

        $node->mouseOver();
    }

    public function testDragTo()
    {
        $node = new NodeElement('some_tag1', $this->session);

        $target = $this->getMock('Behat\Mink\Element\ElementInterface');
        $target->expects($this->any())
            ->method('getXPath')
            ->will($this->returnValue('some_tag2'));

        $this->session->getDriver()
            ->expects($this->once())
            ->method('dragTo')
            ->with('some_tag1', 'some_tag2');

        $node->dragTo($target);
    }

    public function testKeyPress()
    {
        $node = new NodeElement('elem', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('keyPress')
            ->with('elem', 'key');

        $node->keyPress('key');
    }

    public function testKeyDown()
    {
        $node = new NodeElement('elem', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('keyDown')
            ->with('elem', 'key');

        $node->keyDown('key');
    }

    public function testKeyUp()
    {
        $node = new NodeElement('elem', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('keyUp')
            ->with('elem', 'key');

        $node->keyUp('key');
    }

    public function testSubmitForm()
    {
        $node = new NodeElement('some_xpath', $this->session);

        $this->session->getDriver()
            ->expects($this->once())
            ->method('submitForm')
            ->with('some_xpath');

        $node->submit();
    }

    public function testFindAllUnion()
    {
        $node = new NodeElement('some_xpath', $this->session);
        $xpath = "some_tag1 | some_tag2[@foo =\n 'bar|'']\n | some_tag3[foo | bar]";
        $expectedPrefixed = "some_xpath/some_tag1 | some_xpath/some_tag2[@foo =\n 'bar|''] | some_xpath/some_tag3[foo | bar]";

        $this->session->getDriver()
            ->expects($this->exactly(1))
            ->method('find')
            ->will($this->returnValueMap(array(
                array($expectedPrefixed, array(2, 3, 4)),
            )));

        $this->selectors
            ->expects($this->exactly(1))
            ->method('selectorToXpath')
            ->will($this->returnValueMap(array(
                array('xpath', $xpath, $xpath),
            )));

        $this->assertEquals(3, count($node->findAll('xpath', $xpath)));
    }

    public function testFindAllParentUnion()
    {
        $node = new NodeElement('some_xpath | another_xpath', $this->session);
        $xpath = "some_tag1 | some_tag2";
        $expectedPrefixed = "(some_xpath | another_xpath)/some_tag1 | (some_xpath | another_xpath)/some_tag2";

        $this->session->getDriver()
            ->expects($this->exactly(1))
            ->method('find')
            ->will($this->returnValueMap(array(
                array($expectedPrefixed, array(2, 3, 4)),
            )));

        $this->selectors
            ->expects($this->exactly(1))
            ->method('selectorToXpath')
            ->will($this->returnValueMap(array(
                array('xpath', $xpath, $xpath),
            )));

        $this->assertEquals(3, count($node->findAll('xpath', $xpath)));
    }
}


text:
class AonProjectMachine < FlexProjectMachine
  def self.basic_validation_states
    %i(in_analysis approved online waiting_funds successful failed).freeze
  end

  def self.need_expiration_states
    %i(waiting_funds successful failed).freeze
  end

  def self.finished_states
    %i(successful failed).freeze
  end

  setup_machine do
    state :in_analysis
    state :approved
    state :failed

    transition from: :rejected, to: %i(draft deleted)
    transition from: :draft, to: %i(rejected deleted in_analysis)
    transition from: :in_analysis, to: %i(approved rejected draft deleted)
    transition from: :approved, to: %i(online in_analysis)
    transition from: :online, to: %i(waiting_funds successful failed)
    transition from: :waiting_funds, to: %i(successful failed)

    guard_transition(to: :failed) do |project|
      !project.reached_goal?
    end

    guard_transition(to: :successful) do |project|
      project.reached_goal?
    end
  end

  def send_to_analysis
    transition_to :in_analysis, to_state: 'in_analysis'
  end

  def approve
    transition_to :approved, to_state: 'approved'
  end

  def finish
    transition_to(:waiting_funds, to_state: 'waiting_funds') || transition_to(:failed, to_state: 'failed') || transition_to(:successful, to_state: 'successful') || send_errors_to_admin
  end

  def can_approve?
    can_transition_to? :approved
  end

  def can_reject?
    can_transition_to? :rejected
  end

  def can_push_to_draft?
    can_transition_to? :draft
  end

  def can_push_to_trash?
    can_transition_to? :deleted
  end

  def can_push_to_online?
    can_transition_to? :online
  end
end