text:
package org.appng.testsupport;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.xml.bind.JAXBException;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.appng.api.ActionProvider;
import org.appng.api.ApplicationConfigProvider;
import org.appng.api.BusinessException;
import org.appng.api.DataContainer;
import org.appng.api.DataProvider;
import org.appng.api.Environment;
import org.appng.api.FieldProcessor;
import org.appng.api.FileUpload.Unit;
import org.appng.api.InvalidConfigurationException;
import org.appng.api.ParameterSupport;
import org.appng.api.Path;
import org.appng.api.Platform;
import org.appng.api.ProcessingException;
import org.appng.api.Request;
import org.appng.api.Scope;
import org.appng.api.SiteProperties;
import org.appng.api.VHostMode;
import org.appng.api.config.RestConfig;
import org.appng.api.model.Application;
import org.appng.api.model.ApplicationSubject;
import org.appng.api.model.FeatureProvider;
import org.appng.api.model.Group;
import org.appng.api.model.Permission;
import org.appng.api.model.Property;
import org.appng.api.model.Resource;
import org.appng.api.model.Resources;
import org.appng.api.model.Role;
import org.appng.api.model.SimpleProperty;
import org.appng.api.model.Site;
import org.appng.api.model.Subject;
import org.appng.api.search.Consumer;
import org.appng.api.search.DocumentEvent;
import org.appng.api.search.DocumentProducer;
import org.appng.api.support.ApplicationConfigProviderImpl;
import org.appng.api.support.ApplicationRequest;
import org.appng.api.support.ApplicationResourceHolder;
import org.appng.api.support.CallableAction;
import org.appng.api.support.CallableDataSource;
import org.appng.api.support.DollarParameterSupport;
import org.appng.api.support.DummyPermissionProcessor;
import org.appng.api.support.FieldProcessorImpl;
import org.appng.api.support.OptionImpl;
import org.appng.api.support.OptionsImpl;
import org.appng.api.support.PropertyHolder;
import org.appng.api.support.environment.EnvironmentKeys;
import org.appng.forms.FormUpload;
import org.appng.forms.impl.FormUploadBean;
import org.appng.forms.impl.RequestBean;
import org.appng.testsupport.persistence.ConnectionHelper;
import org.appng.testsupport.validation.WritingXmlValidator;
import org.appng.tools.image.ImageProcessor;
import org.appng.xml.BaseObject;
import org.appng.xml.MarshallService;
import org.appng.xml.application.ApplicationInfo;
import org.appng.xml.application.PermissionRef;
import org.appng.xml.platform.Action;
import org.appng.xml.platform.ActionRef;
import org.appng.xml.platform.Datasource;
import org.appng.xml.platform.DatasourceRef;
import org.appng.xml.platform.Event;
import org.appng.xml.platform.FieldDef;
import org.appng.xml.platform.MetaData;
import org.appng.xml.platform.Param;
import org.appng.xml.platform.Params;
import org.custommonkey.xmlunit.DifferenceListener;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.convert.ConversionService;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;

/**
 * Base class for integration-testing an {@link Application}.

 * Example Usage (w/o JPA):
 *
 *

 * @org.springframework.test.context.ContextConfiguration(initializers = MyTest.class)
 * public class MyTest extends TestBase {
 *
 * 	public MyTest() {
 * 		super("myapplication", "application-home");
 * 	}
 *
 * }
 *

 *
 * Example Usage (with JPA):
 *
 *

 * @org.springframework.test.context.ContextConfiguration(locations = {
 * 		TestBase.TESTCONTEXT_JPA }, initializers = MyTest.class)
 * public class MyTest extends TestBase {
 *
 * 	public MyTest() {
 * 		super("myapplication", "application-home");
 * 		setEntityPackage("org.myapplication.domain");
 * 		setRepositoryBase("org.myapplication.repository");
 * 	}
 *
 * }
 *

 *
 * Testing {@link ActionProvider}s and {@link DataProvider}s is this simple:
 *
 *

 * @org.junit.Test
 * public void testShowPersons() throws ProcessingException, IOException {
 * 	addParameter("sortPersons", "name:desc");
 * 	initParameters();
 * 	CallableDataSource datasource = getDataSource("persons").getCallableDataSource();
 * 	datasource.perform("personPage");
 * 	validate(datasource.getDatasource());
 * }
 *
 * @org.junit.Test
 * public void testCreatePerson() throws ProcessingException, IOException {
 * 	CallableAction callableAction = getAction("personEvent", "create").withParam(FORM_ACTION, "create")
 * 			.getCallableAction(new Person("John", "Doe"));
 * 	FieldProcessor fieldProcessor = callableAction.perform();
 * 	validate(callableAction.getAction(), "-action");
 * 	validate(fieldProcessor.getMessages(), "-messages");
 * }
 *

 *
 * @author Matthias Müller
 */
@ContextConfiguration(locations = { TestBase.BEANS_PATH, TestBase.TESTCONTEXT })
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class TestBase implements ApplicationContextInitializer<GenericApplicationContext> {

	private static final String SITE_PROP_PREFIX = "platform.site.localhost.";

	public static final String TESTCONTEXT = "classpath:org/appng/testsupport/application-testcontext.xml";

	public static final String TESTCONTEXT_CORE = "classpath:org/appng/testsupport/application-testcontext-core.xml";

	public static final String TESTCONTEXT_JPA = "classpath:org/appng/testsupport/application-testcontext-jpa.xml";

	public static final String BEANS_PATH = "file:application-home/beans.xml";

	protected static final String APPLICATION_HOME = "application-home";

	protected static final String FORM_ACTION = "form_action";

	private static final String SITE_MANAGER_PATH = "/manager";

	private static final String SITE_SERVICE_PATH = "/service";

	private static String PLATFORM_PREFIX = "platform.";

	@Autowired
	protected ServletContext servletContext;

	protected HttpSession session;

	@Autowired
	protected MockHttpServletRequest servletRequest;

	@Autowired
	protected MockHttpServletResponse servletResponse;

	@Autowired
	protected ConfigurableApplicationContext context;

	@Autowired
	protected MessageSource messageSource;

	@Autowired
	protected ConversionService conversionService;

	@Autowired
	protected MarshallService marshallService;

	@Autowired
	@Qualifier("applicationMarshallService")
	private MarshallService applicationMarshallService;

	protected Environment environment;

	protected ApplicationRequest request;

	protected Application application;

	protected Site site;

	@Mock
	protected Subject subject;

	@Mock
	protected Path path;

	private String applicationName;

	private String applicationLocation;

	private String entityPackage;

	private String repositoryBase;

	private boolean useFullClassname = false;

	private Map<String, String> parameters = new HashMap<>();

	public TestBase() {
		this("application", APPLICATION_HOME);
	}

	public TestBase(String name) {
		this(name, APPLICATION_HOME);
	}

	protected void subjectWithRole(String roleName) {
		Group group = Mockito.mock(Group.class);
		Mockito.when(group.getRoles()).thenReturn(new HashSet<>());
		for (Role role : application.getRoles()) {
			if (role.getName().equals(roleName)) {
				group.getRoles().add(role);
			}
		}
		List<Group> groups = new ArrayList<>();
		groups.add(group);
		Mockito.when(subject.getGroups()).thenReturn(groups);
	}

	public TestBase(String applicationName, String applicationLocation) {
		Locale.setDefault(Locale.ENGLISH);
		this.applicationName = applicationName;
		this.applicationLocation = applicationLocation;
	}

	public void initialize(GenericApplicationContext applicationContext) {
		Properties properties = getProperties();
		PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();
		placeholderConfigurer.setProperties(properties);
		applicationContext.addBeanFactoryPostProcessor(placeholderConfigurer);

		File dictFolder = new File(applicationLocation + "/dictionary").getAbsoluteFile();
		final List<String> baseNames = new ArrayList<>();
		if (dictFolder.exists() && dictFolder.list() != null) {

			for (String file : dictFolder.list()) {
				if (FilenameUtils.getExtension(file).equalsIgnoreCase("properties")) {
					String name = FilenameUtils.getBaseName(file).replaceAll("_(.)*", "");
					if (!baseNames.contains(name)) {
						baseNames.add(name);
					}
				}
			}
			try {
				URL dictUrl = dictFolder.toURI().toURL();
				URLClassLoader classLoader = new URLClassLoader(new URL[] { dictUrl }, getClass().getClassLoader());
				applicationContext.setClassLoader(classLoader);
			} catch (MalformedURLException e) {
				// impossible!
			}
		}

		applicationContext.addBeanFactoryPostProcessor(pp -> {
			baseNames.add("messages-core");
			ResourceBundleMessageSource bean = pp.getBean(ResourceBundleMessageSource.class);
			bean.setBasenames(baseNames.toArray(new String[baseNames.size()]));
		});
		application = mockApplication(applicationContext);
		mockSite(applicationContext);
	}

	protected void mockSite(GenericApplicationContext applicationContext) {
		if (null == site) {
			site = Mockito.mock(Site.class);
		}
		Mockito.when(site.getName()).thenReturn("localhost");
		Mockito.when(site.getDomain()).thenReturn("localhost");
		Mockito.when(site.getHost()).thenReturn("localhost");
		Mockito.when(site.getApplication(applicationName)).thenReturn(application);
		Mockito.when(site.getSiteClassLoader()).thenReturn(new URLClassLoader(new URL[0]));
		List<Property> siteProperties = getSiteProperties(SITE_PROP_PREFIX);
		Mockito.when(site.getProperties()).thenReturn(new PropertyHolder(SITE_PROP_PREFIX, siteProperties));
		if (null != applicationContext) {
			applicationContext.addBeanFactoryPostProcessor(pp -> pp.registerSingleton("site", site));
		}
	}

	protected Application mockApplication(GenericApplicationContext applicationContext) {
		return mockApplication(applicationContext, true);
	}

	@SuppressWarnings("unchecked")
	protected Application mockApplication(GenericApplicationContext applicationContext, boolean checkResources) {
		if (null == application) {
			application = Mockito.mock(Application.class);
		}
		Mockito.when(application.getName()).thenReturn(applicationName);
		Mockito.when(application.isFileBased()).thenReturn(true);
		if (checkResources && new File(applicationLocation).exists()) {
			try {
				Resources resources = getApplicationResources(MarshallService.getApplicationMarshallService());
				Mockito.when(application.getResources()).thenReturn(resources);
				ApplicationInfo applicationInfo = resources.getApplicationInfo();
				org.appng.api.model.Properties properties = extractProperties(getProperties(), applicationInfo);
				Mockito.when(application.getProperties()).thenReturn(properties);
			} catch (JAXBException e) {
				throw new RuntimeException("error reading resources", e);
			}
		}
		Mockito.when(application.getBean(Mockito.any(Class.class)))
				.thenAnswer(i -> applicationContext.getBean(i.getArgumentAt(0, Class.class)));
		Mockito.when(application.getBean(Mockito.any(String.class)))
				.thenAnswer(i -> applicationContext.getBean(i.getArgumentAt(0, String.class)));
		Mockito.when(application.getBean(Mockito.any(String.class), Mockito.any(Class.class))).thenAnswer(
				i -> applicationContext.getBean(i.getArgumentAt(0, String.class), i.getArgumentAt(1, Class.class)));
		applicationContext.addBeanFactoryPostProcessor(pp -> pp.registerSingleton("application", application));

		return application;
	}

	protected Resources getApplicationResources(MarshallService applicationMarshallService) {
		try {
			return new ApplicationResourceHolder(application, applicationMarshallService, new File(applicationLocation),
					new File("target/temp"));
		} catch (InvalidConfigurationException e) {
			throw new RuntimeException("error reading resources", e);
		}
	}

	protected Resources mockResources() {
		return Mockito.mock(Resources.class);
	}

	/**
	 * Returns the {@link Properties} used by
	 * {@link ApplicationContextInitializer#initialize(ConfigurableApplicationContext)} and also for the
	 * {@link Application}'s properties. Override in subclasses to add custom values.
	 *
	 * @return the properties to use
	 *
	 * @see Application#getProperties()
	 * @see #initialize(GenericApplicationContext)
	 */
	protected Properties getProperties() {
		Properties properties = new Properties();
		properties.put("entityPackage", entityPackage);
		properties.put("hsqlPort", ConnectionHelper.getHsqlPort());
		properties.put("repositoryBase", repositoryBase);
		return properties;
	}

	/**
	 * Adds a parameter to the {@link org.appng.api.Request} used in the testcase.

	 * After all parameters have been added, {@link #initParameters()} (or {@link #initParameters(boolean)}) has to be
	 * called.

	 * Not to confiuse with {@link DataSourceCall#withParam(String, String)} and
	 * {@link ActionCall#withParam(String, String)}!
	 *
	 * @param name
	 *              the name of the parameter
	 * @param value
	 *              the value of the parameter
	 */
	protected void addParameter(String name, String value) {
		parameters.put(name, value);
	}

	protected FormUpload getFormUpload(String resourceName) throws URISyntaxException {
		URL resource = getClass().getClassLoader().getResource(resourceName);
		File file = new File(resource.toURI());
		String extension = FilenameUtils.getExtension(resourceName);
		long maxSize = 10 * Unit.MB.getFactor();
		return new FormUploadBean(file, file.getName(), extension, Arrays.asList(extension), maxSize);
	}

	@Before
	public void setup() throws Exception {
		MockitoAnnotations.initMocks(this);
		initEnvironment();
		application = new SimpleApplication(applicationName, context, getApplicationSubjects());
		initRequest();
		((SimpleApplication) application).init(getProperties(), request.getApplicationConfig().getApplicationInfo());
	}

	protected List<ApplicationSubject> getApplicationSubjects() {
		return new ArrayList<>();
	}

	protected void initRequest() throws InvalidConfigurationException, JAXBException {
		Resources applicationResources = getApplicationResources(applicationMarshallService);
		ApplicationConfigProvider applicationConfigProvider = new ApplicationConfigProviderImpl(marshallService,
				applicationName, applicationResources, false);
		request = (ApplicationRequest) context.getBean(Request.class);
		request.setPermissionProcessor(new DummyPermissionProcessor(subject, site, application));
		request.setApplicationConfig(applicationConfigProvider);
	}

	/**
	 * Initializes the {@link org.appng.api.Request} for the testcase. Before, some paramters can be added using
	 * {@link #addParameter(String, String)}
	 */
	protected void initParameters() {
		initParameters(false);
	}

	protected void initParameters(boolean isPost) {
		servletRequest.setParameters(parameters);
		init(isPost);
	}

	protected void init(boolean isPost) {
		if (isPost) {
			servletRequest.setMethod("POST");
		}
		RequestBean requestBean = new RequestBean();
		requestBean.process(servletRequest);
		request.setWrappedRequest(requestBean);
	}

	protected void initEnvironment() {
		Map<String, Object> platformEnv = new ConcurrentHashMap<>();
		platformEnv.put(Platform.Environment.PLATFORM_CONFIG, getPlatformConfig());

		mockSite(null);
		Map<String, Site> sites = new HashMap<>();
		sites.put(site.getHost(), site);
		platformEnv.put(Platform.Environment.SITES, sites);

		session = new MockHttpSession(servletContext);
		servletRequest.setSession(session);
		servletContext.setAttribute(Scope.PLATFORM.name(), platformEnv);

		environment = context.getBean("environment", Environment.class);
		environment.setAttribute(Scope.REQUEST, EnvironmentKeys.PATH_INFO, path);
		Mockito.when(path.getServicePath()).thenReturn(SITE_SERVICE_PATH);
		Mockito.when(path.getGuiPath()).thenReturn(SITE_MANAGER_PATH);

		RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(servletRequest, servletResponse));
	}

	protected List<Property> getSiteProperties(String prefix) {
		List<Property> siteProperties = new ArrayList<>();
		siteProperties.add(new SimpleProperty(prefix + SiteProperties.SERVICE_PATH, SITE_SERVICE_PATH));
		siteProperties.add(new SimpleProperty(prefix + SiteProperties.MANAGER_PATH, SITE_MANAGER_PATH));
		siteProperties.add(new SimpleProperty(prefix + SiteProperties.DEFAULT_PAGE_SIZE, "25"));
		return siteProperties;
	}

	/**
	 * Returns a list of the platform's essential {@link Property}s.
	 *
	 * @param prefix
	 *               the prefix to use
	 *
	 * @return a list of the platform's {@link Property}s
	 *
	 * @deprecated use {@link #getPlatformProperties()}
	 */
	@Deprecated
	protected List<Property> getPlatformProperties(String prefix) {
		return getPlatformProperties();
	}

	/**
	 * Returns a list of the platform's essential {@link Property}s.
	 *
	 * @return a list of the platform's {@link Property}s
	 */
	protected static List<Property> getPlatformProperties() {
		List<Property> props = new ArrayList<>();
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.VHOST_MODE, VHostMode.NAME_BASED.name()));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.LOCALE, "en"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.TIME_ZONE, "Europe/Berlin"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.PLATFORM_ROOT_PATH, "target/ROOT"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.CACHE_FOLDER, "cache"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.APPLICATION_CACHE_FOLDER, "application"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.PLATFORM_CACHE_FOLDER, "platform"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.UPLOAD_DIR, "/target/uploads"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.MAX_UPLOAD_SIZE, "10485760"));
		props.add(new SimpleProperty(PLATFORM_PREFIX + Platform.Property.XSS_PROTECT, "false"));
		return props;
	}

	/**
	 * Returns the platform's {@link org.appng.api.model.Properties}.
	 *
	 * @return the platform's {@link org.appng.api.model.Properties}
	 */
	public static org.appng.api.model.Properties getPlatformConfig() {
		List<Property> platformProperties = getPlatformProperties();
		return new PropertyHolder(PLATFORM_PREFIX, platformProperties);
	}

	public void validate(BaseObject object) throws IOException {
		String controlFile = getControlFileName(null);
		WritingXmlValidator.validateXml(object, controlFile);
	}

	public void validate(BaseObject object, DifferenceListener differenceListener) throws IOException {
		String controlFile = getControlFileName(null);
		WritingXmlValidator.validateXml(object, controlFile, differenceListener);
	}

	public void validate(BaseObject object, String suffix, DifferenceListener differenceListener) throws IOException {
		String controlFile = getControlFileName(suffix);
		WritingXmlValidator.validateXml(object, controlFile, differenceListener);
	}

	public void validate(BaseObject object, String suffix) throws IOException {
		String controlFile = getControlFileName(suffix);
		WritingXmlValidator.validateXml(object, controlFile);
	}

	private String getControlFileName(String suffix) {
		StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
		StackTraceElement stackTraceElement = stackTrace[3];
		String className = stackTraceElement.getClassName();
		if (!useFullClassname) {
			className = className.substring(className.lastIndexOf('.') + 1);
		}
		String controlFile = "xml" + File.separator + className + "-" + stackTraceElement.getMethodName()
				+ (suffix == null ? "" : suffix) + ".xml";
		return controlFile;
	}

	class CallableTestAction extends CallableAction {
		private Object form;

		CallableTestAction(Site site, Application application, ApplicationRequest applicationRequest,
				ActionRef actionRef, Object form) throws ProcessingException {
			super(site, application, applicationRequest, actionRef);
			this.form = form;
		}

		@Override
		protected Object getBindObject(FieldProcessor fieldProcessor) throws BusinessException {
			if (null != form) {
				BeanWrapper original = new BeanWrapperImpl(form);
				BeanWrapper copy = new BeanWrapperImpl(form.getClass());
				for (FieldDef fieldDef : fieldProcessor.getMetaData().getFields()) {
					copy.setPropertyValue(fieldDef.getBinding(), original.getPropertyValue(fieldDef.getBinding()));
				}
				return copy.getWrappedInstance();
			}
			return null;
		}

		private Action initialize() throws ProcessingException {
			retrieveData(false);
			return getAction();
		}
	}

	protected String getEntityPackage() {
		return entityPackage;
	}

	protected void setEntityPackage(String entityPackage) {
		this.entityPackage = entityPackage;
	}

	protected String getRepositoryBase() {
		return repositoryBase;
	}

	protected void setRepositoryBase(String repositoryBase) {
		this.repositoryBase = repositoryBase;
	}

	protected boolean isUseFullClassname() {
		return useFullClassname;
	}

	protected void setUseFullClassname(boolean useFullClassname) {
		this.useFullClassname = useFullClassname;
	}

	class ParametrizedCall {
		private Map<String, String> configParams = new HashMap<>();
		private Params params;

		ParametrizedCall(Params params) {
			this.params = params;
		}

		Params getParams() {
			for (String key : configParams.keySet()) {
				Param param = new Param();
				param.setName(key);
				param.setValue(configParams.get(key));
				params.getParam().add(param);
			}
			return params;
		}

		ParameterSupport getParameterSupport() {
			return new DollarParameterSupport(configParams);
		}

		ParametrizedCall clearParams() {
			configParams.clear();
			getParams().getParam().clear();
			return this;
		}

		ParametrizedCall withParam(String name, String value) {
			configParams.put(name, value);
			return this;
		}
	}

	/**
	 * Returns a {@link DataSourceCall} that wraps a {@link DatasourceRef}, using the given id for a {@link Datasource}
	 *
	 * @param id
	 *           the id of the {@link Datasource}
	 *
	 * @return the {@link DataSourceCall}
	 */
	protected DataSourceCall getDataSource(String id) {
		return new DataSourceCall(id);
	}

	/**
	 * Returns an {@link ActionCall} that wraps an {@link ActionRef}, using the given id for an {@link Action}.
	 *
	 * @param eventId
	 *                the id of the {@link Event}
	 * @param id
	 *                the id of the {@link Action}
	 *
	 * @return the {@link ActionCall}
	 */
	protected ActionCall getAction(String eventId, String id) {
		return new ActionCall(eventId, id);
	}

	org.appng.api.model.Properties extractProperties(Properties overrides, ApplicationInfo applicationInfo) {
		Set<Property> props = new HashSet<>();
		for (org.appng.xml.application.Property prop : applicationInfo.getProperties().getProperty()) {
			String propName = prop.getId();
			String value = overrides.containsKey(propName) ? overrides.getProperty(propName) : prop.getValue();
			SimpleProperty property;
			if (Boolean.TRUE.equals(prop.isClob())) {
				property = new SimpleProperty(propName, null);
				property.setClob(value);
			} else {
				property = new SimpleProperty(propName, value);
			}
			property.setDescription(prop.getDescription());
			props.add(property);
		}
		return new PropertyHolder(StringUtils.EMPTY, props);
	}

	/**
	 * Returns a {@link HandlerMethodArgumentResolver} that can resolve a(n)
	 *

	 *
{@link Environment}
	 *
{@link Site}
	 *
{@link Application}
	 *

	 * Useful when testing a {@link Controller}/ {@link RestController} with {@link MockMvc}:
	 *
	 *

	 * MockMvc mockMvc = MockMvcBuilders.standaloneSetup(context.getBean(MyRestController.class))
	 * 		.setCustomArgumentResolvers(getHandlerMethodArgumentResolver()).build();
	 *

	 *
	 * @return the resolver
	 */
	public HandlerMethodArgumentResolver getHandlerMethodArgumentResolver() {
		return new RestConfig.SiteAwareHandlerMethodArgumentResolver(site, environment, application);
	}

	/**
	 * A wrapper for a {@link DatasourceRef}, allowing to add {@link Param}eters and to retrieve the actual
	 * {@link CallableDataSource}.
	 */
	protected class DataSourceCall extends DatasourceRef {

		private ParametrizedCall parametrizedCall;

		DataSourceCall(String id) {
			setId(id);
			setParams(new Params());
			this.parametrizedCall = new ParametrizedCall(super.getParams());
		}

		@Override
		public Params getParams() {
			return parametrizedCall.getParams();
		}

		ParameterSupport getParameterSupport() {
			return parametrizedCall.getParameterSupport();
		}

		public DataSourceCall clearParams() {
			parametrizedCall.clearParams();
			return this;
		}

		/**
		 * Adds a {@link Param} to the wrapped {@link DatasourceRef}.
		 *
		 * @param name
		 *              the name of the {@link Param}
		 * @param value
		 *              the value
		 *
		 * @return
		 */
		public DataSourceCall withParam(String name, String value) {
			parametrizedCall.withParam(name, value);
			return this;
		}

		/**
		 * Returns the {@link CallableDataSource}.
		 *
		 * @return the {@link CallableDataSource}
		 *
		 * @throws ProcessingException
		 *                             if an error occurs while assembling the CallableDataSource
		 */
		public CallableDataSource getCallableDataSource() throws ProcessingException {
			return new CallableDataSource(site, application, request, getParameterSupport(), this);
		}
	}

	/**
	 * A wrapper for an {@link ActionRef}, allowing to add {@link Param}eters and to retrieve the actual
	 * {@link CallableAction}.
	 */
	protected class ActionCall extends ActionRef {

		private ParametrizedCall parametrizedCall;

		ActionCall(String eventId, String id) {
			setEventId(eventId);
			setId(id);
			setParams(new Params());
			this.parametrizedCall = new ParametrizedCall(super.getParams());
		}

		@Override
		public Params getParams() {
			return parametrizedCall.getParams();
		}

		ParameterSupport getParameterSupport() {
			return parametrizedCall.getParameterSupport();
		}

		public ActionCall clearParams() {
			parametrizedCall.clearParams();
			return this;
		}

		/**
		 * Adds a {@link Param} to the wrapped {@link ActionRef}.
		 *
		 * @param name
		 *              the name of the {@link Param}
		 * @param value
		 *              the value
		 *
		 * @return
		 */
		public ActionCall withParam(String name, String value) {
			parametrizedCall.withParam(name, value);
			return this;
		}

		/**
		 * Returns the {@link CallableAction}.
		 *
		 * @param form
		 *             an instance of the bind-object used by the {@link Action}. The type must be compatible with
		 *             {@link MetaData#getBindClass()} of the {@link Datasource} that is used by the {@link Action}.
		 *
		 * @return the {@link CallableAction}
		 *
		 * @throws ProcessingException
		 *                             if an error occurs while assembling the CallableAction
		 */
		public CallableAction getCallableAction(Object form) throws ProcessingException {
			return new CallableTestAction(site, application, request, this, form);
		}

		/**
		 * Returns the {@link Action} in it's initial state, meaning the action is initialized with the original data
		 * coming from {@link DataProvider}, but not performed.
		 *
		 * @return the {@link Action}
		 *
		 * @throws ProcessingException
		 *                             if an error occurs while assembling the Action
		 */
		public Action initialize() throws ProcessingException {
			return new CallableTestAction(site, application, request, this, null).initialize();
		}

		/**
		 * Returns the initial form for the action, i.e. of the underlying {@link Datasource}, if any. This is done by
		 * directly calling
		 * {@link DataProvider#getData(Site, Application, Environment, org.appng.api.Options, Request, FieldProcessor)}
		 * and then returning the result of {@link DataContainer#getItem()}.
		 *
		 * @return the initial form, may be {@code null}
		 *
		 * @throws ProcessingException
		 *                             if an error occurs while retrieving the data
		 */
		@SuppressWarnings("unchecked")
		public <T> T getForm() throws ProcessingException {
			CallableTestAction callableTestAction = new CallableTestAction(site, application, request, this, null);
			DatasourceRef datasourceRef = callableTestAction.getAction().getDatasource();
			if (null != datasourceRef) {
				DataSourceCall dataSourceCall = new DataSourceCall(datasourceRef.getId());
				if (null != datasourceRef.getParams()) {
					Map<String, String> parameters = getParameterSupport().getParameters();
					datasourceRef.getParams().getParam()
							.forEach(p -> dataSourceCall.withParam(p.getName(), parameters.get(p.getName())));
				}
				Datasource datasource = dataSourceCall.getCallableDataSource().getDatasource();

				OptionsImpl options = new OptionsImpl();
				datasource.getBean().getOptions().forEach(o -> {
					OptionImpl opt = new OptionImpl(o.getName());
					o.getOtherAttributes().entrySet()
							.forEach(e -> opt.addAttribute(e.getKey().getLocalPart(), e.getValue()));
					options.addOption(opt);
				});

				MetaData metaData = datasource.getConfig().getMetaData();
				FieldProcessorImpl fp = new FieldProcessorImpl(id, metaData);
				fp.addLinkPanels(datasource.getConfig().getLinkpanel());

				DataProvider dataProvider = application.getBean(datasource.getBean().getId(), DataProvider.class);
				DataContainer dataContainer = dataProvider.getData(site, application, environment, options, request,
						fp);
				return (T) dataContainer.getItem();
			}
			return null;
		}
	}

	protected class SimpleApplication implements Application {

		private String name;
		private ConfigurableApplicationContext context;
		private Map<String, Permission> permissionMap = new HashMap<>();
		private Set<Role> roleSet;
		private org.appng.api.model.Properties properties;
		private List<ApplicationSubject> applicationSubjects;
		private SimpleFeatureProvider featureProvider;
		private ApplicationInfo applicationInfo;

		protected SimpleApplication(String name, ConfigurableApplicationContext context) {
			this(name, context, new ArrayList<>());
		}

		protected SimpleApplication(String name, ConfigurableApplicationContext context,
				List<ApplicationSubject> applicationSubjects) {
			this.name = name;
			this.context = context;
			this.applicationSubjects = applicationSubjects;
		}

		protected void init(Properties overrides, ApplicationInfo applicationInfo) {
			this.applicationInfo = applicationInfo;
			for (org.appng.xml.application.Permission p : applicationInfo.getPermissions().getPermission()) {
				Permission simplePermission = new SimplePermission(p);
				permissionMap.put(p.getId(), simplePermission);
			}

			roleSet = new HashSet<>();
			int roleId = 1;
			for (org.appng.xml.application.Role r : applicationInfo.getRoles().getRole()) {
				SimpleRole role = new SimpleRole(r, roleId++);
				List<PermissionRef> permission = r.getPermission();
				for (PermissionRef permissionRef : permission) {
					Permission e = permissionMap.get(permissionRef.getId());
					role.getPermissions().add(e);
				}
				roleSet.add(role);
			}
			properties = extractProperties(overrides, applicationInfo);
			featureProvider = new SimpleFeatureProvider(properties);
		}

		public String getName() {
			return name;
		}

		public String getDisplayName() {
			return applicationInfo.getDisplayName();
		}

		public String getPackageVersion() {
			return applicationInfo.getVersion();
		}

		public String getTimestamp() {
			return applicationInfo.getTimestamp();
		}

		public String getLongDescription() {
			return applicationInfo.getLongDescription();
		}

		public String getAppNGVersion() {
			return applicationInfo.getAppngVersion();
		}

		public boolean isInstalled() {
			return true;
		}

		public boolean isSnapshot() {
			return getPackageVersion().endsWith("-SNAPSHOT");
		}

		public String getDescription() {
			return applicationInfo.getDescription();
		}

		public Integer getId() {
			return null;
		}

		public Date getVersion() {
			return null;
		}

		public Set<Permission> getPermissions() {
			return new HashSet<>(permissionMap.values());
		}

		public Set<Role> getRoles() {
			return roleSet;
		}

		public Resources getResources() {
			return request.getApplicationConfig().getResources();
		}

		public Set<Resource> getResourceSet() {
			return getResources().getResources();
		}

		public org.appng.api.model.Properties getProperties() {
			return properties;
		}

		public <T> T getBean(String name, Class<T> clazz) {
			return context.getBean(name, clazz);
		}

		public String[] getBeanNames(Class<?> clazz) {
			return context.getBeanNamesForType(clazz);
		}

		public <T> T getBean(Class<T> clazz) {
			return context.getBean(clazz);
		}

		public Object getBean(String beanName) {
			return context.getBean(beanName);
		}

		public boolean containsBean(String beanName) {
			return context.containsBean(name);
		}

		public boolean isFileBased() {
			return true;
		}

		public boolean isPrivileged() {
			return false;
		}

		@Deprecated
		public boolean isCoreApplication() {
			return isPrivileged();
		}

		public boolean isHidden() {
			return false;
		}

		public String getMessage(Locale locale, String key, Object... args) {
			return messageSource.getMessage(key, args, locale);
		}

		public String getSessionParamKey(Site site) {
			return site.getName() + "." + getName();
		}

		public Map<String, String> getSessionParams(Site site, Environment environment) {
			String sessionParamKey = getSessionParamKey(site);
			Map<String, String> sessionsParams = environment.getAttribute(Scope.SESSION, sessionParamKey);
			if (null == sessionsParams) {
				sessionsParams = new HashMap<>();
				environment.setAttribute(Scope.SESSION, sessionParamKey, sessionsParams);
			}
			return sessionsParams;
		}

		public SimpleFeatureProvider getFeatureProvider() {
			return featureProvider;
		}

		public List<ApplicationSubject> getApplicationSubjects() {
			return applicationSubjects;
		}

	}

	protected class SimpleFeatureProvider implements FeatureProvider {

		private int documentCount = 0;
		private org.appng.api.model.Properties properties;

		SimpleFeatureProvider(org.appng.api.model.Properties properties) {
			this.properties = properties;
		}

		public Consumer<DocumentEvent, DocumentProducer> getIndexer() {
			if (properties.getString("featureIndexing", "false").equalsIgnoreCase("true")) {
				return new Consumer<DocumentEvent, DocumentProducer>() {

					@Override
					public void put(DocumentProducer element) throws InterruptedException {
						super.put(element);
						documentCount++;
					}

					@Override
					public boolean put(DocumentProducer element, long timeoutMillis) throws InterruptedException {
						documentCount++;
						return super.put(element, timeoutMillis);
					}

					@Override
					public void putWithTimeout(DocumentProducer element, long timeoutMillis)
							throws InterruptedException, TimeoutException {
						super.putWithTimeout(element, timeoutMillis);
						documentCount++;
					}

				};
			}
			return null;
		}

		public Integer getDocumentCount() {
			return documentCount;
		}

		public ImageProcessor getImageProcessor(File sourceFile, String targetFile) {
			if (properties.getString("featureImageProcessing", "false").equalsIgnoreCase("true")) {
				return new ImageProcessor(sourceFile, new File(getImageCache(), targetFile));
			}
			return null;
		}

		public File getImageCache() {
			if (properties.getString("featureImageProcessing", "false").equalsIgnoreCase("true")) {
				return new File("target/imageCache");
			}
			return null;
		}

	}

	class SimpleRole implements Role {

		private org.appng.xml.application.Role role;
		private Set<Permission> permissions = new HashSet<>();
		private Integer id;

		public SimpleRole(org.appng.xml.application.Role role, Integer id) {
			this.role = role;
			this.id = id;
		}

		public String getName() {
			return role.getName();
		}

		public String getDescription() {
			return role.getDescription();
		}

		public Integer getId() {
			return id;
		}

		public Application getApplication() {
			return application;
		}

		public Set<Permission> getPermissions() {
			return permissions;
		}

	}

	class SimplePermission implements Permission {

		private org.appng.xml.application.Permission permission;

		SimplePermission(org.appng.xml.application.Permission permission) {
			this.permission = permission;
		}

		public String getName() {
			return permission.getId();
		}

		public String getDescription() {
			return permission.getValue();
		}

		public Integer getId() {
			return null;
		}

		public Application getApplication() {
			return application;
		}

	}

}


text:
# Touch keyboard sample

Shows both the default display behavior of the touch keyboard and how that behavior can be customized in a UWP app.

> **Note:** This sample is part of a large collection of UWP feature samples.
> If you are unfamiliar with Git and GitHub, you can download the entire collection as a
> [ZIP file](https://github.com/Microsoft/Windows-universal-samples/archive/master.zip), but be
> sure to unzip everything to access shared dependencies. For more info on working with the ZIP file,
> the samples collection, and GitHub, see [Get the UWP samples from GitHub](https://aka.ms/ovu2uq).
> For more samples, see the [Samples portal](https://aka.ms/winsamples) on the Windows Dev Center.

Specifically, this sample shows how:

* XAML text controls (such as TextBox, RichTextBox, and PaswordBox) display the touch keyboard by default.
* Controls derived from XAML text controls display the touch keyboard by default.
* Apps can subscribe to events indicating when the touch keyboard is shown and hidden.
* Apps can request that the touch keyboard be shown or hidden.

**Note** The touch keyboard does not automatically display if a hardware keyboard is connected,
or the device is in Desktop mode and "Show the touch keyboard when not in tablet mode and there's no keyboard attached" is set to "Off" in **Settings -> Devices -> Typing**.

**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.

**Note** Custom text edit control sample shows how to manage the visibility of the touch keyboard programatically.

To obtain information about Windows 10, go to [Windows 10](http://go.microsoft.com/fwlink/?LinkID=532421)

To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)

## System requirements

**Client:** Windows 10

**Server:** Windows Server 2016 Technical Preview

**Phone:** Windows 10. (KeyboardEnabledTextBox not supported; see remarks above.)

## Build the sample

1. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the language you desire - either C++, C#, or JavaScript. Double-click the Visual Studio Solution (.sln) file.
3. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.

## Run the sample

The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it.

### Deploying the sample

- Select Build > Deploy Solution.

### Deploying and running the sample

- To debug the sample and then run it, press F5 or select Debug >  Start Debugging. To run the sample without debugging, press Ctrl+F5 or select Debug > Start Without Debugging.

redpajama_set_name: RedPajamaGithub


text:
/*
 * Braille Utils (C) 2010-2011 Daisy Consortium
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.daisy.braille.utils.pef;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.DocAttributeSet;

import org.daisy.dotify.api.embosser.Device;

/**
 * Printer device class of type DocFlavor.INPUT_STREAM.AUTOSENSE
 *
 * This class can be used when sending a file to a printer.
 *
 * @author  Joel Håkansson
 * @version 3 jul 2008
 */
public class PrinterDevice implements Device {
	//private static final DocFlavor FLAVOR = DocFlavor.BYTE_ARRAY.AUTOSENSE;
	private static final DocFlavor FLAVOR = DocFlavor.INPUT_STREAM.AUTOSENSE;
	private PrintService service;

	/**
	 * Create a device with the provided name.
	 * @param deviceName the name of the device
	 * @param fuzzyLookup If true, the returned device is any device whose name contains the
	 * supplied deviceName. If false, the returned device name equals the supplied deviceName.
	 * @throws IllegalArgumentException if no device is found.
	 */
	public PrinterDevice(String deviceName, boolean fuzzyLookup) {
		PrintService[] printers = PrintServiceLookup.lookupPrintServices(FLAVOR, null);
		for (PrintService p : printers) {
			if (p.getName().equals(deviceName)) {
				service = p;
				return;
			}
		}
		if (fuzzyLookup) {
			PrintService match = null;
			double currentMatch = 0;
			for (PrintService p : printers) {
				if (p.getName().contains(deviceName)) {
					double thisMatch = deviceName.length() / (double)p.getName().length();
					if (thisMatch > currentMatch) {
						currentMatch = thisMatch;
						match = p;
					}
				}
			}
			if (match != null) {
				service = match;
				return;
			}
		}
		throw new IllegalArgumentException("Could not find embosser.");
	}

	/**
	 * List available devices
	 * @return returns a list of available devices that accepts DocFlavor.INPUT_STREAM.AUTOSENSE
	 */
	public static PrintService[] getDevices() {
		PrintService[] printers = PrintServiceLookup.lookupPrintServices(FLAVOR, null);
		return printers;
	}

	/**
	 * Transmit a file to the device
	 * @param file the file to transmit
	 * @throws PrintException if a print exception occurs
	 */
	@Override
	public void transmit(File file) throws PrintException {
		try {
			transmit(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			throw new PrintException(e);
		}
	}

	private void transmit(InputStream is) throws PrintException {
		InputStreamDoc doc = new InputStreamDoc(is);
		DocPrintJob dpj = service.createPrintJob();
		dpj.print(doc, null);
	}

	private class InputStreamDoc implements Doc {
		private InputStream stream;

		/**
		 * Creates a new input stream document.
		 * @param stream the input stream
		 */
		public InputStreamDoc(InputStream stream) {
			this.stream = stream;
		}

		@Override
		public DocAttributeSet getAttributes() {
			return null;
		}

		@Override
		public DocFlavor getDocFlavor() {
			return FLAVOR;
		}

		@Override
		public Object getPrintData() throws IOException {
			return getStreamForBytes();
		}

		@Override
		public Reader getReaderForText() throws IOException {
			return null;
		}

		@Override
		public InputStream getStreamForBytes() throws IOException {
			return stream;
		}
	}
}


text:
/*!
 * perfect-scrollbar v1.3.0
 * (c) 2017 Hyunje Jun
 * @license MIT
 */
function get(element) {
  return getComputedStyle(element);
}

function set(element, obj) {
  for (var key in obj) {
    var val = obj[key];
    if (typeof val === 'number') {
      val = val + "px";
    }
    element.style[key] = val;
  }
  return element;
}

function div(className) {
  var div = document.createElement('div');
  div.className = className;
  return div;
}

var elMatches =
  typeof Element !== 'undefined' &&
  (Element.prototype.matches ||
    Element.prototype.webkitMatchesSelector ||
    Element.prototype.msMatchesSelector);

function matches(element, query) {
  if (!elMatches) {
    throw new Error('No element matching method supported');
  }

  return elMatches.call(element, query);
}

function remove(element) {
  if (element.remove) {
    element.remove();
  } else {
    if (element.parentNode) {
      element.parentNode.removeChild(element);
    }
  }
}

function queryChildren(element, selector) {
  return Array.prototype.filter.call(element.children, function (child) { return matches(child, selector); }
  );
}

var cls = {
  main: 'ps',
  element: {
    thumb: function (x) { return ("ps__thumb-" + x); },
    rail: function (x) { return ("ps__rail-" + x); },
    consuming: 'ps__child--consume',
  },
  state: {
    focus: 'ps--focus',
    active: function (x) { return ("ps--active-" + x); },
    scrolling: function (x) { return ("ps--scrolling-" + x); },
  },
};

/*
 * Helper methods
 */
var scrollingClassTimeout = { x: null, y: null };

function addScrollingClass(i, x) {
  var classList = i.element.classList;
  var className = cls.state.scrolling(x);

  if (classList.contains(className)) {
    clearTimeout(scrollingClassTimeout[x]);
  } else {
    classList.add(className);
  }
}

function removeScrollingClass(i, x) {
  scrollingClassTimeout[x] = setTimeout(
    function () { return i.isAlive && i.element.classList.remove(cls.state.scrolling(x)); },
    i.settings.scrollingThreshold
  );
}

function setScrollingClassInstantly(i, x) {
  addScrollingClass(i, x);
  removeScrollingClass(i, x);
}

var EventElement = function EventElement(element) {
  this.element = element;
  this.handlers = {};
};

var prototypeAccessors = { isEmpty: { configurable: true } };

EventElement.prototype.bind = function bind (eventName, handler) {
  if (typeof this.handlers[eventName] === 'undefined') {
    this.handlers[eventName] = [];
  }
  this.handlers[eventName].push(handler);
  this.element.addEventListener(eventName, handler, false);
};

EventElement.prototype.unbind = function unbind (eventName, target) {
    var this$1 = this;

  this.handlers[eventName] = this.handlers[eventName].filter(function (handler) {
    if (target && handler !== target) {
      return true;
    }
    this$1.element.removeEventListener(eventName, handler, false);
    return false;
  });
};

EventElement.prototype.unbindAll = function unbindAll () {
    var this$1 = this;

  for (var name in this$1.handlers) {
    this$1.unbind(name);
  }
};

prototypeAccessors.isEmpty.get = function () {
    var this$1 = this;

  return Object.keys(this.handlers).every(
    function (key) { return this$1.handlers[key].length === 0; }
  );
};

Object.defineProperties( EventElement.prototype, prototypeAccessors );

var EventManager = function EventManager() {
  this.eventElements = [];
};

EventManager.prototype.eventElement = function eventElement (element) {
  var ee = this.eventElements.filter(function (ee) { return ee.element === element; })[0];
  if (!ee) {
    ee = new EventElement(element);
    this.eventElements.push(ee);
  }
  return ee;
};

EventManager.prototype.bind = function bind (element, eventName, handler) {
  this.eventElement(element).bind(eventName, handler);
};

EventManager.prototype.unbind = function unbind (element, eventName, handler) {
  var ee = this.eventElement(element);
  ee.unbind(eventName, handler);

  if (ee.isEmpty) {
    // remove
    this.eventElements.splice(this.eventElements.indexOf(ee), 1);
  }
};

EventManager.prototype.unbindAll = function unbindAll () {
  this.eventElements.forEach(function (e) { return e.unbindAll(); });
  this.eventElements = [];
};

EventManager.prototype.once = function once (element, eventName, handler) {
  var ee = this.eventElement(element);
  var onceHandler = function (evt) {
    ee.unbind(eventName, onceHandler);
    handler(evt);
  };
  ee.bind(eventName, onceHandler);
};

function createEvent(name) {
  if (typeof window.CustomEvent === 'function') {
    return new CustomEvent(name);
  } else {
    var evt = document.createEvent('CustomEvent');
    evt.initCustomEvent(name, false, false, undefined);
    return evt;
  }
}

var processScrollDiff = function(
  i,
  axis,
  diff,
  useScrollingClass,
  forceFireReachEvent
) {
  if ( useScrollingClass === void 0 ) useScrollingClass = true;
  if ( forceFireReachEvent === void 0 ) forceFireReachEvent = false;

  var fields;
  if (axis === 'top') {
    fields = [
      'contentHeight',
      'containerHeight',
      'scrollTop',
      'y',
      'up',
      'down' ];
  } else if (axis === 'left') {
    fields = [
      'contentWidth',
      'containerWidth',
      'scrollLeft',
      'x',
      'left',
      'right' ];
  } else {
    throw new Error('A proper axis should be provided');
  }

  processScrollDiff$1(i, diff, fields, useScrollingClass, forceFireReachEvent);
};

function processScrollDiff$1(
  i,
  diff,
  ref,
  useScrollingClass,
  forceFireReachEvent
) {
  var contentHeight = ref[0];
  var containerHeight = ref[1];
  var scrollTop = ref[2];
  var y = ref[3];
  var up = ref[4];
  var down = ref[5];
  if ( useScrollingClass === void 0 ) useScrollingClass = true;
  if ( forceFireReachEvent === void 0 ) forceFireReachEvent = false;

  var element = i.element;

  // reset reach
  i.reach[y] = null;

  // 1 for subpixel rounding
  if (element[scrollTop] < 1) {
    i.reach[y] = 'start';
  }

  // 1 for subpixel rounding
  if (element[scrollTop] > i[contentHeight] - i[containerHeight] - 1) {
    i.reach[y] = 'end';
  }

  if (diff) {
    element.dispatchEvent(createEvent(("ps-scroll-" + y)));

    if (diff < 0) {
      element.dispatchEvent(createEvent(("ps-scroll-" + up)));
    } else if (diff > 0) {
      element.dispatchEvent(createEvent(("ps-scroll-" + down)));
    }

    if (useScrollingClass) {
      setScrollingClassInstantly(i, y);
    }
  }

  if (i.reach[y] && (diff || forceFireReachEvent)) {
    element.dispatchEvent(createEvent(("ps-" + y + "-reach-" + (i.reach[y]))));
  }
}

function toInt(x) {
  return parseInt(x, 10) || 0;
}

function isEditable(el) {
  return (
    matches(el, 'input,[contenteditable]') ||
    matches(el, 'select,[contenteditable]') ||
    matches(el, 'textarea,[contenteditable]') ||
    matches(el, 'button,[contenteditable]')
  );
}

function outerWidth(element) {
  var styles = get(element);
  return (
    toInt(styles.width) +
    toInt(styles.paddingLeft) +
    toInt(styles.paddingRight) +
    toInt(styles.borderLeftWidth) +
    toInt(styles.borderRightWidth)
  );
}

var env = {
  isWebKit:
    typeof document !== 'undefined' &&
    'WebkitAppearance' in document.documentElement.style,
  supportsTouch:
    typeof window !== 'undefined' &&
    ('ontouchstart' in window ||
      (window.DocumentTouch && document instanceof window.DocumentTouch)),
  supportsIePointer:
    typeof navigator !== 'undefined' && navigator.msMaxTouchPoints,
  isChrome:
    typeof navigator !== 'undefined' &&
    /Chrome/i.test(navigator && navigator.userAgent),
};

var updateGeometry = function(i) {
  var element = i.element;

  i.containerWidth = element.clientWidth;
  i.containerHeight = element.clientHeight;
  i.contentWidth = element.scrollWidth;
  i.contentHeight = element.scrollHeight;

  if (!element.contains(i.scrollbarXRail)) {
    // clean up and append
    queryChildren(element, cls.element.rail('x')).forEach(function (el) { return remove(el); }
    );
    element.appendChild(i.scrollbarXRail);
  }
  if (!element.contains(i.scrollbarYRail)) {
    // clean up and append
    queryChildren(element, cls.element.rail('y')).forEach(function (el) { return remove(el); }
    );
    element.appendChild(i.scrollbarYRail);
  }

  if (
    !i.settings.suppressScrollX &&
    i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth
  ) {
    i.scrollbarXActive = true;
    i.railXWidth = i.containerWidth - i.railXMarginWidth;
    i.railXRatio = i.containerWidth / i.railXWidth;
    i.scrollbarXWidth = getThumbSize(
      i,
      toInt(i.railXWidth * i.containerWidth / i.contentWidth)
    );
    i.scrollbarXLeft = toInt(
      (i.negativeScrollAdjustment + element.scrollLeft) *
        (i.railXWidth - i.scrollbarXWidth) /
        (i.contentWidth - i.containerWidth)
    );
  } else {
    i.scrollbarXActive = false;
  }

  if (
    !i.settings.suppressScrollY &&
    i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight
  ) {
    i.scrollbarYActive = true;
    i.railYHeight = i.containerHeight - i.railYMarginHeight;
    i.railYRatio = i.containerHeight / i.railYHeight;
    i.scrollbarYHeight = getThumbSize(
      i,
      toInt(i.railYHeight * i.containerHeight / i.contentHeight)
    );
    i.scrollbarYTop = toInt(
      element.scrollTop *
        (i.railYHeight - i.scrollbarYHeight) /
        (i.contentHeight - i.containerHeight)
    );
  } else {
    i.scrollbarYActive = false;
  }

  if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
    i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;
  }
  if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {
    i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;
  }

  updateCss(element, i);

  if (i.scrollbarXActive) {
    element.classList.add(cls.state.active('x'));
  } else {
    element.classList.remove(cls.state.active('x'));
    i.scrollbarXWidth = 0;
    i.scrollbarXLeft = 0;
    element.scrollLeft = 0;
  }
  if (i.scrollbarYActive) {
    element.classList.add(cls.state.active('y'));
  } else {
    element.classList.remove(cls.state.active('y'));
    i.scrollbarYHeight = 0;
    i.scrollbarYTop = 0;
    element.scrollTop = 0;
  }
};

function getThumbSize(i, thumbSize) {
  if (i.settings.minScrollbarLength) {
    thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);
  }
  if (i.settings.maxScrollbarLength) {
    thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);
  }
  return thumbSize;
}

function updateCss(element, i) {
  var xRailOffset = { width: i.railXWidth };
  if (i.isRtl) {
    xRailOffset.left =
      i.negativeScrollAdjustment +
      element.scrollLeft +
      i.containerWidth -
      i.contentWidth;
  } else {
    xRailOffset.left = element.scrollLeft;
  }
  if (i.isScrollbarXUsingBottom) {
    xRailOffset.bottom = i.scrollbarXBottom - element.scrollTop;
  } else {
    xRailOffset.top = i.scrollbarXTop + element.scrollTop;
  }
  set(i.scrollbarXRail, xRailOffset);

  var yRailOffset = { top: element.scrollTop, height: i.railYHeight };
  if (i.isScrollbarYUsingRight) {
    if (i.isRtl) {
      yRailOffset.right =
        i.contentWidth -
        (i.negativeScrollAdjustment + element.scrollLeft) -
        i.scrollbarYRight -
        i.scrollbarYOuterWidth;
    } else {
      yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
    }
  } else {
    if (i.isRtl) {
      yRailOffset.left =
        i.negativeScrollAdjustment +
        element.scrollLeft +
        i.containerWidth * 2 -
        i.contentWidth -
        i.scrollbarYLeft -
        i.scrollbarYOuterWidth;
    } else {
      yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
    }
  }
  set(i.scrollbarYRail, yRailOffset);

  set(i.scrollbarX, {
    left: i.scrollbarXLeft,
    width: i.scrollbarXWidth - i.railBorderXWidth,
  });
  set(i.scrollbarY, {
    top: i.scrollbarYTop,
    height: i.scrollbarYHeight - i.railBorderYWidth,
  });
}

var clickRail = function(i) {
  i.event.bind(i.scrollbarY, 'mousedown', function (e) { return e.stopPropagation(); });
  i.event.bind(i.scrollbarYRail, 'mousedown', function (e) {
    var positionTop =
      e.pageY -
      window.pageYOffset -
      i.scrollbarYRail.getBoundingClientRect().top;
    var direction = positionTop > i.scrollbarYTop ? 1 : -1;

    i.element.scrollTop += direction * i.containerHeight;
    updateGeometry(i);

    e.stopPropagation();
  });

  i.event.bind(i.scrollbarX, 'mousedown', function (e) { return e.stopPropagation(); });
  i.event.bind(i.scrollbarXRail, 'mousedown', function (e) {
    var positionLeft =
      e.pageX -
      window.pageXOffset -
      i.scrollbarXRail.getBoundingClientRect().left;
    var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;

    i.element.scrollLeft += direction * i.containerWidth;
    updateGeometry(i);

    e.stopPropagation();
  });
};

var dragThumb = function(i) {
  bindMouseScrollHandler(i, [
    'containerWidth',
    'contentWidth',
    'pageX',
    'railXWidth',
    'scrollbarX',
    'scrollbarXWidth',
    'scrollLeft',
    'x' ]);
  bindMouseScrollHandler(i, [
    'containerHeight',
    'contentHeight',
    'pageY',
    'railYHeight',
    'scrollbarY',
    'scrollbarYHeight',
    'scrollTop',
    'y' ]);
};

function bindMouseScrollHandler(
  i,
  ref
) {
  var containerHeight = ref[0];
  var contentHeight = ref[1];
  var pageY = ref[2];
  var railYHeight = ref[3];
  var scrollbarY = ref[4];
  var scrollbarYHeight = ref[5];
  var scrollTop = ref[6];
  var y = ref[7];

  var element = i.element;

  var startingScrollTop = null;
  var startingMousePageY = null;
  var scrollBy = null;

  function mouseMoveHandler(e) {
    element[scrollTop] =
      startingScrollTop + scrollBy * (e[pageY] - startingMousePageY);
    addScrollingClass(i, y);
    updateGeometry(i);

    e.stopPropagation();
    e.preventDefault();
  }

  function mouseUpHandler() {
    removeScrollingClass(i, y);
    i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
  }

  i.event.bind(i[scrollbarY], 'mousedown', function (e) {
    startingScrollTop = element[scrollTop];
    startingMousePageY = e[pageY];
    scrollBy =
      (i[contentHeight] - i[containerHeight]) /
      (i[railYHeight] - i[scrollbarYHeight]);

    i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
    i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);

    e.stopPropagation();
    e.preventDefault();
  });
}

var keyboard = function(i) {
  var element = i.element;

  var elementHovered = function () { return matches(element, ':hover'); };
  var scrollbarFocused = function () { return matches(i.scrollbarX, ':focus') || matches(i.scrollbarY, ':focus'); };

  function shouldPreventDefault(deltaX, deltaY) {
    var scrollTop = element.scrollTop;
    if (deltaX === 0) {
      if (!i.scrollbarYActive) {
        return false;
      }
      if (
        (scrollTop === 0 && deltaY > 0) ||
        (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)
      ) {
        return !i.settings.wheelPropagation;
      }
    }

    var scrollLeft = element.scrollLeft;
    if (deltaY === 0) {
      if (!i.scrollbarXActive) {
        return false;
      }
      if (
        (scrollLeft === 0 && deltaX < 0) ||
        (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)
      ) {
        return !i.settings.wheelPropagation;
      }
    }
    return true;
  }

  i.event.bind(i.ownerDocument, 'keydown', function (e) {
    if (
      (e.isDefaultPrevented && e.isDefaultPrevented()) ||
      e.defaultPrevented
    ) {
      return;
    }

    if (!elementHovered() && !scrollbarFocused()) {
      return;
    }

    var activeElement = document.activeElement
      ? document.activeElement
      : i.ownerDocument.activeElement;
    if (activeElement) {
      if (activeElement.tagName === 'IFRAME') {
        activeElement = activeElement.contentDocument.activeElement;
      } else {
        // go deeper if element is a webcomponent
        while (activeElement.shadowRoot) {
          activeElement = activeElement.shadowRoot.activeElement;
        }
      }
      if (isEditable(activeElement)) {
        return;
      }
    }

    var deltaX = 0;
    var deltaY = 0;

    switch (e.which) {
      case 37: // left
        if (e.metaKey) {
          deltaX = -i.contentWidth;
        } else if (e.altKey) {
          deltaX = -i.containerWidth;
        } else {
          deltaX = -30;
        }
        break;
      case 38: // up
        if (e.metaKey) {
          deltaY = i.contentHeight;
        } else if (e.altKey) {
          deltaY = i.containerHeight;
        } else {
          deltaY = 30;
        }
        break;
      case 39: // right
        if (e.metaKey) {
          deltaX = i.contentWidth;
        } else if (e.altKey) {
          deltaX = i.containerWidth;
        } else {
          deltaX = 30;
        }
        break;
      case 40: // down
        if (e.metaKey) {
          deltaY = -i.contentHeight;
        } else if (e.altKey) {
          deltaY = -i.containerHeight;
        } else {
          deltaY = -30;
        }
        break;
      case 32: // space bar
        if (e.shiftKey) {
          deltaY = i.containerHeight;
        } else {
          deltaY = -i.containerHeight;
        }
        break;
      case 33: // page up
        deltaY = i.containerHeight;
        break;
      case 34: // page down
        deltaY = -i.containerHeight;
        break;
      case 36: // home
        deltaY = i.contentHeight;
        break;
      case 35: // end
        deltaY = -i.contentHeight;
        break;
      default:
        return;
    }

    if (i.settings.suppressScrollX && deltaX !== 0) {
      return;
    }
    if (i.settings.suppressScrollY && deltaY !== 0) {
      return;
    }

    element.scrollTop -= deltaY;
    element.scrollLeft += deltaX;
    updateGeometry(i);

    if (shouldPreventDefault(deltaX, deltaY)) {
      e.preventDefault();
    }
  });
};

var wheel = function(i) {
  var element = i.element;

  function shouldPreventDefault(deltaX, deltaY) {
    var isTop = element.scrollTop === 0;
    var isBottom =
      element.scrollTop + element.offsetHeight === element.scrollHeight;
    var isLeft = element.scrollLeft === 0;
    var isRight =
      element.scrollLeft + element.offsetWidth === element.offsetWidth;

    var hitsBound;

    // pick axis with primary direction
    if (Math.abs(deltaY) > Math.abs(deltaX)) {
      hitsBound = isTop || isBottom;
    } else {
      hitsBound = isLeft || isRight;
    }

    return hitsBound ? !i.settings.wheelPropagation : true;
  }

  function getDeltaFromEvent(e) {
    var deltaX = e.deltaX;
    var deltaY = -1 * e.deltaY;

    if (typeof deltaX === 'undefined' || typeof deltaY === 'undefined') {
      // OS X Safari
      deltaX = -1 * e.wheelDeltaX / 6;
      deltaY = e.wheelDeltaY / 6;
    }

    if (e.deltaMode && e.deltaMode === 1) {
      // Firefox in deltaMode 1: Line scrolling
      deltaX *= 10;
      deltaY *= 10;
    }

    if (deltaX !== deltaX && deltaY !== deltaY /* NaN checks */) {
      // IE in some mouse drivers
      deltaX = 0;
      deltaY = e.wheelDelta;
    }

    if (e.shiftKey) {
      // reverse axis with shift key
      return [-deltaY, -deltaX];
    }
    return [deltaX, deltaY];
  }

  function shouldBeConsumedByChild(target, deltaX, deltaY) {
    // FIXME: this is a workaround for <select> issue in FF and IE #571
    if (!env.isWebKit && element.querySelector('select:focus')) {
      return true;
    }

    if (!element.contains(target)) {
      return false;
    }

    var cursor = target;

    while (cursor && cursor !== element) {
      if (cursor.classList.contains(cls.element.consuming)) {
        return true;
      }

      var style = get(cursor);
      var overflow = [style.overflow, style.overflowX, style.overflowY].join(
        ''
      );

      // if scrollable
      if (overflow.match(/(scroll|auto)/)) {
        var maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
        if (maxScrollTop > 0) {
          if (
            !(cursor.scrollTop === 0 && deltaY > 0) &&
            !(cursor.scrollTop === maxScrollTop && deltaY < 0)
          ) {
            return true;
          }
        }
        var maxScrollLeft = cursor.scrollLeft - cursor.clientWidth;
        if (maxScrollLeft > 0) {
          if (
            !(cursor.scrollLeft === 0 && deltaX < 0) &&
            !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
          ) {
            return true;
          }
        }
      }

      cursor = cursor.parentNode;
    }

    return false;
  }

  function mousewheelHandler(e) {
    var ref = getDeltaFromEvent(e);
    var deltaX = ref[0];
    var deltaY = ref[1];

    if (shouldBeConsumedByChild(e.target, deltaX, deltaY)) {
      return;
    }

    var shouldPrevent = false;
    if (!i.settings.useBothWheelAxes) {
      // deltaX will only be used for horizontal scrolling and deltaY will
      // only be used for vertical scrolling - this is the default
      element.scrollTop -= deltaY * i.settings.wheelSpeed;
      element.scrollLeft += deltaX * i.settings.wheelSpeed;
    } else if (i.scrollbarYActive && !i.scrollbarXActive) {
      // only vertical scrollbar is active and useBothWheelAxes option is
      // active, so let's scroll vertical bar using both mouse wheel axes
      if (deltaY) {
        element.scrollTop -= deltaY * i.settings.wheelSpeed;
      } else {
        element.scrollTop += deltaX * i.settings.wheelSpeed;
      }
      shouldPrevent = true;
    } else if (i.scrollbarXActive && !i.scrollbarYActive) {
      // useBothWheelAxes and only horizontal bar is active, so use both
      // wheel axes for horizontal bar
      if (deltaX) {
        element.scrollLeft += deltaX * i.settings.wheelSpeed;
      } else {
        element.scrollLeft -= deltaY * i.settings.wheelSpeed;
      }
      shouldPrevent = true;
    }

    updateGeometry(i);

    shouldPrevent = shouldPrevent || shouldPreventDefault(deltaX, deltaY);
    if (shouldPrevent && !e.ctrlKey) {
      e.stopPropagation();
      e.preventDefault();
    }
  }

  if (typeof window.onwheel !== 'undefined') {
    i.event.bind(element, 'wheel', mousewheelHandler);
  } else if (typeof window.onmousewheel !== 'undefined') {
    i.event.bind(element, 'mousewheel', mousewheelHandler);
  }
};

var touch = function(i) {
  if (!env.supportsTouch && !env.supportsIePointer) {
    return;
  }

  var element = i.element;

  function shouldPrevent(deltaX, deltaY) {
    var scrollTop = element.scrollTop;
    var scrollLeft = element.scrollLeft;
    var magnitudeX = Math.abs(deltaX);
    var magnitudeY = Math.abs(deltaY);

    if (magnitudeY > magnitudeX) {
      // user is perhaps trying to swipe up/down the page

      if (
        (deltaY < 0 && scrollTop === i.contentHeight - i.containerHeight) ||
        (deltaY > 0 && scrollTop === 0)
      ) {
        // set prevent for mobile Chrome refresh
        return window.scrollY === 0 && deltaY > 0 && env.isChrome;
      }
    } else if (magnitudeX > magnitudeY) {
      // user is perhaps trying to swipe left/right across the page

      if (
        (deltaX < 0 && scrollLeft === i.contentWidth - i.containerWidth) ||
        (deltaX > 0 && scrollLeft === 0)
      ) {
        return true;
      }
    }

    return true;
  }

  function applyTouchMove(differenceX, differenceY) {
    element.scrollTop -= differenceY;
    element.scrollLeft -= differenceX;

    updateGeometry(i);
  }

  var startOffset = {};
  var startTime = 0;
  var speed = {};
  var easingLoop = null;

  function getTouch(e) {
    if (e.targetTouches) {
      return e.targetTouches[0];
    } else {
      // Maybe IE pointer
      return e;
    }
  }

  function shouldHandle(e) {
    if (e.pointerType && e.pointerType === 'pen' && e.buttons === 0) {
      return false;
    }
    if (e.targetTouches && e.targetTouches.length === 1) {
      return true;
    }
    if (
      e.pointerType &&
      e.pointerType !== 'mouse' &&
      e.pointerType !== e.MSPOINTER_TYPE_MOUSE
    ) {
      return true;
    }
    return false;
  }

  function touchStart(e) {
    if (!shouldHandle(e)) {
      return;
    }

    var touch = getTouch(e);

    startOffset.pageX = touch.pageX;
    startOffset.pageY = touch.pageY;

    startTime = new Date().getTime();

    if (easingLoop !== null) {
      clearInterval(easingLoop);
    }
  }

  function shouldBeConsumedByChild(target, deltaX, deltaY) {
    if (!element.contains(target)) {
      return false;
    }

    var cursor = target;

    while (cursor && cursor !== element) {
      if (cursor.classList.contains(cls.element.consuming)) {
        return true;
      }

      var style = get(cursor);
      var overflow = [style.overflow, style.overflowX, style.overflowY].join(
        ''
      );

      // if scrollable
      if (overflow.match(/(scroll|auto)/)) {
        var maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
        if (maxScrollTop > 0) {
          if (
            !(cursor.scrollTop === 0 && deltaY > 0) &&
            !(cursor.scrollTop === maxScrollTop && deltaY < 0)
          ) {
            return true;
          }
        }
        var maxScrollLeft = cursor.scrollLeft - cursor.clientWidth;
        if (maxScrollLeft > 0) {
          if (
            !(cursor.scrollLeft === 0 && deltaX < 0) &&
            !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
          ) {
            return true;
          }
        }
      }

      cursor = cursor.parentNode;
    }

    return false;
  }

  function touchMove(e) {
    if (shouldHandle(e)) {
      var touch = getTouch(e);

      var currentOffset = { pageX: touch.pageX, pageY: touch.pageY };

      var differenceX = currentOffset.pageX - startOffset.pageX;
      var differenceY = currentOffset.pageY - startOffset.pageY;

      if (shouldBeConsumedByChild(e.target, differenceX, differenceY)) {
        return;
      }

      applyTouchMove(differenceX, differenceY);
      startOffset = currentOffset;

      var currentTime = new Date().getTime();

      var timeGap = currentTime - startTime;
      if (timeGap > 0) {
        speed.x = differenceX / timeGap;
        speed.y = differenceY / timeGap;
        startTime = currentTime;
      }

      if (shouldPrevent(differenceX, differenceY)) {
        e.preventDefault();
      }
    }
  }
  function touchEnd() {
    if (i.settings.swipeEasing) {
      clearInterval(easingLoop);
      easingLoop = setInterval(function() {
        if (i.isInitialized) {
          clearInterval(easingLoop);
          return;
        }

        if (!speed.x && !speed.y) {
          clearInterval(easingLoop);
          return;
        }

        if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
          clearInterval(easingLoop);
          return;
        }

        applyTouchMove(speed.x * 30, speed.y * 30);

        speed.x *= 0.8;
        speed.y *= 0.8;
      }, 10);
    }
  }

  if (env.supportsTouch) {
    i.event.bind(element, 'touchstart', touchStart);
    i.event.bind(element, 'touchmove', touchMove);
    i.event.bind(element, 'touchend', touchEnd);
  } else if (env.supportsIePointer) {
    if (window.PointerEvent) {
      i.event.bind(element, 'pointerdown', touchStart);
      i.event.bind(element, 'pointermove', touchMove);
      i.event.bind(element, 'pointerup', touchEnd);
    } else if (window.MSPointerEvent) {
      i.event.bind(element, 'MSPointerDown', touchStart);
      i.event.bind(element, 'MSPointerMove', touchMove);
      i.event.bind(element, 'MSPointerUp', touchEnd);
    }
  }
};

var defaultSettings = function () { return ({
  handlers: ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],
  maxScrollbarLength: null,
  minScrollbarLength: null,
  scrollingThreshold: 1000,
  scrollXMarginOffset: 0,
  scrollYMarginOffset: 0,
  suppressScrollX: false,
  suppressScrollY: false,
  swipeEasing: true,
  useBothWheelAxes: false,
  wheelPropagation: false,
  wheelSpeed: 1,
}); };

var handlers = {
  'click-rail': clickRail,
  'drag-thumb': dragThumb,
  keyboard: keyboard,
  wheel: wheel,
  touch: touch,
};

var PerfectScrollbar = function PerfectScrollbar(element, userSettings) {
  var this$1 = this;
  if ( userSettings === void 0 ) userSettings = {};

  if (typeof element === 'string') {
    element = document.querySelector(element);
  }

  if (!element || !element.nodeName) {
    throw new Error('no element is specified to initialize PerfectScrollbar');
  }

  this.element = element;

  element.classList.add(cls.main);

  this.settings = defaultSettings();
  for (var key in userSettings) {
    this$1.settings[key] = userSettings[key];
  }

  this.containerWidth = null;
  this.containerHeight = null;
  this.contentWidth = null;
  this.contentHeight = null;

  var focus = function () { return element.classList.add(cls.state.focus); };
  var blur = function () { return element.classList.remove(cls.state.focus); };

  this.isRtl = get(element).direction === 'rtl';
  this.isNegativeScroll = (function () {
    var originalScrollLeft = element.scrollLeft;
    var result = null;
    element.scrollLeft = -1;
    result = element.scrollLeft < 0;
    element.scrollLeft = originalScrollLeft;
    return result;
  })();
  this.negativeScrollAdjustment = this.isNegativeScroll
    ? element.scrollWidth - element.clientWidth
    : 0;
  this.event = new EventManager();
  this.ownerDocument = element.ownerDocument || document;

  this.scrollbarXRail = div(cls.element.rail('x'));
  element.appendChild(this.scrollbarXRail);
  this.scrollbarX = div(cls.element.thumb('x'));
  this.scrollbarXRail.appendChild(this.scrollbarX);
  this.scrollbarX.setAttribute('tabindex', 0);
  this.event.bind(this.scrollbarX, 'focus', focus);
  this.event.bind(this.scrollbarX, 'blur', blur);
  this.scrollbarXActive = null;
  this.scrollbarXWidth = null;
  this.scrollbarXLeft = null;
  var railXStyle = get(this.scrollbarXRail);
  this.scrollbarXBottom = parseInt(railXStyle.bottom, 10);
  if (isNaN(this.scrollbarXBottom)) {
    this.isScrollbarXUsingBottom = false;
    this.scrollbarXTop = toInt(railXStyle.top);
  } else {
    this.isScrollbarXUsingBottom = true;
  }
  this.railBorderXWidth =
    toInt(railXStyle.borderLeftWidth) + toInt(railXStyle.borderRightWidth);
  // Set rail to display:block to calculate margins
  set(this.scrollbarXRail, { display: 'block' });
  this.railXMarginWidth =
    toInt(railXStyle.marginLeft) + toInt(railXStyle.marginRight);
  set(this.scrollbarXRail, { display: '' });
  this.railXWidth = null;
  this.railXRatio = null;

  this.scrollbarYRail = div(cls.element.rail('y'));
  element.appendChild(this.scrollbarYRail);
  this.scrollbarY = div(cls.element.thumb('y'));
  this.scrollbarYRail.appendChild(this.scrollbarY);
  this.scrollbarY.setAttribute('tabindex', 0);
  this.event.bind(this.scrollbarY, 'focus', focus);
  this.event.bind(this.scrollbarY, 'blur', blur);
  this.scrollbarYActive = null;
  this.scrollbarYHeight = null;
  this.scrollbarYTop = null;
  var railYStyle = get(this.scrollbarYRail);
  this.scrollbarYRight = parseInt(railYStyle.right, 10);
  if (isNaN(this.scrollbarYRight)) {
    this.isScrollbarYUsingRight = false;
    this.scrollbarYLeft = toInt(railYStyle.left);
  } else {
    this.isScrollbarYUsingRight = true;
  }
  this.scrollbarYOuterWidth = this.isRtl ? outerWidth(this.scrollbarY) : null;
  this.railBorderYWidth =
    toInt(railYStyle.borderTopWidth) + toInt(railYStyle.borderBottomWidth);
  set(this.scrollbarYRail, { display: 'block' });
  this.railYMarginHeight =
    toInt(railYStyle.marginTop) + toInt(railYStyle.marginBottom);
  set(this.scrollbarYRail, { display: '' });
  this.railYHeight = null;
  this.railYRatio = null;

  this.reach = {
    x:
      element.scrollLeft <= 0
        ? 'start'
        : element.scrollLeft >= this.contentWidth - this.containerWidth
          ? 'end'
          : null,
    y:
      element.scrollTop <= 0
        ? 'start'
        : element.scrollTop >= this.contentHeight - this.containerHeight
          ? 'end'
          : null,
  };

  this.isAlive = true;

  this.settings.handlers.forEach(function (handlerName) { return handlers[handlerName](this$1); });

  this.lastScrollTop = element.scrollTop; // for onScroll only
  this.lastScrollLeft = element.scrollLeft; // for onScroll only
  this.event.bind(this.element, 'scroll', function (e) { return this$1.onScroll(e); });
  updateGeometry(this);
};

PerfectScrollbar.prototype.update = function update () {
  if (!this.isAlive) {
    return;
  }

  // Recalcuate negative scrollLeft adjustment
  this.negativeScrollAdjustment = this.isNegativeScroll
    ? this.element.scrollWidth - this.element.clientWidth
    : 0;

  // Recalculate rail margins
  set(this.scrollbarXRail, { display: 'block' });
  set(this.scrollbarYRail, { display: 'block' });
  this.railXMarginWidth =
    toInt(get(this.scrollbarXRail).marginLeft) +
    toInt(get(this.scrollbarXRail).marginRight);
  this.railYMarginHeight =
    toInt(get(this.scrollbarYRail).marginTop) +
    toInt(get(this.scrollbarYRail).marginBottom);

  // Hide scrollbars not to affect scrollWidth and scrollHeight
  set(this.scrollbarXRail, { display: 'none' });
  set(this.scrollbarYRail, { display: 'none' });

  updateGeometry(this);

  processScrollDiff(this, 'top', 0, false, true);
  processScrollDiff(this, 'left', 0, false, true);

  set(this.scrollbarXRail, { display: '' });
  set(this.scrollbarYRail, { display: '' });
};

PerfectScrollbar.prototype.onScroll = function onScroll (e) {
  if (!this.isAlive) {
    return;
  }

  updateGeometry(this);
  processScrollDiff(this, 'top', this.element.scrollTop - this.lastScrollTop);
  processScrollDiff(
    this,
    'left',
    this.element.scrollLeft - this.lastScrollLeft
  );

  this.lastScrollTop = this.element.scrollTop;
  this.lastScrollLeft = this.element.scrollLeft;
};

PerfectScrollbar.prototype.destroy = function destroy () {
  if (!this.isAlive) {
    return;
  }

  this.event.unbindAll();
  remove(this.scrollbarX);
  remove(this.scrollbarY);
  remove(this.scrollbarXRail);
  remove(this.scrollbarYRail);
  this.removePsClasses();

  // unset elements
  this.element = null;
  this.scrollbarX = null;
  this.scrollbarY = null;
  this.scrollbarXRail = null;
  this.scrollbarYRail = null;

  this.isAlive = false;
};

PerfectScrollbar.prototype.removePsClasses = function removePsClasses () {
  this.element.className = this.element.className
    .split(' ')
    .filter(function (name) { return !name.match(/^ps([-_].+|)$/); })
    .join(' ');
};

export default PerfectScrollbar;


text:
import {Component, ChangeDetectionStrategy, OnInit} from '@angular/core';
import {TAB_DIRECTIVES, CollapseDirective} from 'ng2-bootstrap/ng2-bootstrap';
import {CORE_DIRECTIVES, COMMON_DIRECTIVES, FORM_DIRECTIVES} from "@angular/common";
import {PersonService} from '../person/PersonService';

import {BarChartDemoComponent} from './chart/charts-section.component';
import {Properties} from "./properties/properties";
import {TableDemoComponent} from "./subtable/subtable";

@Component({
  selector: 'entity',
  styles: [ '' ],
  template: require('./entitydetail.html'),
  directives: [CORE_DIRECTIVES, TAB_DIRECTIVES, FORM_DIRECTIVES, COMMON_DIRECTIVES, CollapseDirective,
    BarChartDemoComponent, Properties, TableDemoComponent],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    PersonService,
  ],
})

export class EntityDetailInformation{

}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.11"/>
<title>QTicTacToe: Game Class Reference</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>

<link href="navtree.css" rel="stylesheet" type="text/css"/>

<link href="search/search.css" rel="stylesheet" type="text/css"/>

<link href="doxygen.css" rel="stylesheet" type="text/css" />

QTicTacToe

Main Page

Classes

Files

          <input type="text" id="MSearchField" value="Search" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)"
               onblur="searchBox.OnSearchFieldFocus(false)"
               onkeyup="searchBox.OnSearchFieldChange(event)"/>

Class List

Class Index

Class Hierarchy

Class Members

Public Member Functions |
Static Public Member Functions |
List of all members

Game Class Referencefinal

#include <Game.h>

Public Member Functions

 	Game ()

 	~Game ()

void 	handleReturn ()

void 	handlePlay2v2 ()

void 	handlePlayMulti ()

void 	handlePlaySingle ()

Static Public Member Functions

static void 	logger (QString msg)

Detailed Description

Definition at line 7 of file Game.h.

Constructor & Destructor Documentation

          Game::Game
          (
          	)

Definition at line 27 of file Game.cpp.

          Game::~Game
          (
          	)

Definition at line 34 of file Game.cpp.

Member Function Documentation

          void Game::handlePlay2v2
          (
          	)

Definition at line 54 of file Game.cpp.

          void Game::handlePlayMulti
          (
          	)

Definition at line 64 of file Game.cpp.

          void Game::handlePlaySingle
          (
          	)

Definition at line 74 of file Game.cpp.

          void Game::handleReturn
          (
          	)

Definition at line 41 of file Game.cpp.

          void Game::logger
          (
          QString
          msg	)

static

Definition at line 17 of file Game.cpp.

The documentation for this class was generated from the following files:

include/Game.h

src/Game.cpp

Game

Generated by

     1.8.11


text:
import React, { useState } from 'react';
import {
  Accordion,
  AccordionBody,
  AccordionHeader,
  AccordionItem,
} from 'reactstrap';

function Example(props) {
  const [open, setOpen] = useState('1');
  const toggle = (id) => {
    if (open === id) {
      setOpen();
    } else {
      setOpen(id);
    }
  };

  return (

      <Accordion open={open} toggle={toggle}>
        <AccordionItem>
          <AccordionHeader targetId="1">Accordion Item 1</AccordionHeader>
          <AccordionBody accordionId="1">
            This is the first item's accordion body.
            You can modify any of this with custom CSS or overriding our default
            variables. It's also worth noting that just about any HTML can
            go within the .accordion-body, though the transition
            does limit overflow.
          </AccordionBody>
        </AccordionItem>
        <AccordionItem>
          <AccordionHeader targetId="2">Accordion Item 2</AccordionHeader>
          <AccordionBody accordionId="2">
            This is the second item's accordion body.
            You can modify any of this with custom CSS or overriding our default
            variables. It's also worth noting that just about any HTML can
            go within the .accordion-body, though the transition
            does limit overflow.
          </AccordionBody>
        </AccordionItem>
        <AccordionItem>
          <AccordionHeader targetId="3">Accordion Item 3</AccordionHeader>
          <AccordionBody accordionId="3">
            This is the third item's accordion body.
            You can modify any of this with custom CSS or overriding our default
            variables. It's also worth noting that just about any HTML can
            go within the .accordion-body, though the transition
            does limit overflow.
          </AccordionBody>
        </AccordionItem>
      </Accordion>

  );
}

export default Example;


text:
package net.afnf.blog.service;

import net.afnf.blog.domain.User;
import net.afnf.blog.mapper.UserMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Throwable.class)
public class UserService {

    @Autowired
    private UserMapper um;

    @Autowired
    private PasswordEncoder passwordEncoder;

    public int getUserCount() {
        return um.countByExample(null);
    }

    public void registerAdmin(String username, String password) {

        if (getUserCount() != 0) {
            throw new IllegalStateException("illegal1");
        }

        User user = new User();
        user.setUsername(username);
        user.setPassword(passwordEncoder.encode(password));
        user.setRole("ROLE_ADMIN");
        um.insertSelective(user);

        if (getUserCount() != 1) {
            throw new IllegalStateException("illegal2");
        }
    }

}


text:
package org.apache.ignite.internal.visor.query;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.cache.QueryIndex;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.visor.VisorDataTransferObject;

/**
 * Data transfer object for {@link QueryEntity}.
 */
public class VisorQueryIndexField extends VisorDataTransferObject {
    /** */
    private static final long serialVersionUID = 0L;

    /** Index field name. */
    private String name;

    /** Index field sort order. */
    private boolean sort;

    /**
     * Create data transfer object for given cache type metadata.
     */
    public VisorQueryIndexField() {
        // No-op.
    }

    /**
     * Create data transfer object for index field.
     *
     * @param name Index field name.
     * @param sort Index field sort order.
     */
    public VisorQueryIndexField(String name, boolean sort) {
        this.name = name;
        this.sort = sort;
    }

    /**
     * @param idx Query entity index.
     * @return Data transfer object for query entity index fields.
     */
    public static List<VisorQueryIndexField> list(QueryIndex idx) {
        List<VisorQueryIndexField> res = new ArrayList<>();

        for (Map.Entry<String, Boolean> field: idx.getFields().entrySet())
            res.add(new VisorQueryIndexField(field.getKey(), !field.getValue()));

        return res;
    }

    /**
     * @return Index field name.
     */
    public String getName() {
        return name;
    }

    /**
     * @return Index field sort order.
     */
    public boolean getSortOrder() {
        return sort;
    }

    /** {@inheritDoc} */
    @Override protected void writeExternalData(ObjectOutput out) throws IOException {
        U.writeString(out, name);
        out.writeBoolean(sort);
    }

    /** {@inheritDoc} */
    @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
        name = U.readString(in);
        sort = in.readBoolean();
    }

    /** {@inheritDoc} */
    @Override public String toString() {
        return S.toString(VisorQueryIndexField.class, this);
    }
}


text:
For **help**, **support**, **questions** and **ideas** please use **[our forum](https://forum.ghost.org)**  🚑.

---

## Where to Start

If you're a developer looking to contribute, but you're not sure where to begin: Check out the [good first issue](https://github.com/TryGhost/Ghost/labels/good%20first%20issue) label on Github, which contains small piece of work that have been specifically flagged as being friendly to new contributors.

After that, if you're looking for something a little more challenging to sink your teeth into, there's a broader [help wanted](https://github.com/TryGhost/Ghost/labels/help%20wanted) label encompassing issues which need some love.

If you've got an idea for a new feature, please start by suggesting it in the [forum](https://forum.ghost.org), as adding new features to Ghost first requires generating consensus around a design and spec.

## Working on Ghost Core

If you're going to work on Ghost core you'll need to go through a slightly more involved install and setup process than the usual Ghost CLI version.

First you'll need to fork both [Ghost](https://github.com/tryghost/ghost) and [Ghost-Admin](https://github.com/tryghost/ghost-admin) to your personal Github account, and then follow the detailed [install from source](https://ghost.org/docs/install/source/) setup guide.

### Branching Guide

`main` on the main repository always contains the latest changes. This means that it is WIP for the next minor version and should NOT be considered stable. Stable versions are tagged using [semantic versioning](http://semver.org/).

On your local repository, you should always work on a branch to make keeping up-to-date and submitting pull requests easier, but in most cases you should submit your pull requests to `main`. Where necessary, for example if multiple people are contributing on a large feature, or if a feature requires a database change, we make use of feature branches.

### Commit Messages

We have a handful of simple standards for commit messages which help us to generate readable changelogs. Please follow this wherever possible and mention the associated issue number.

- **1st line:** Max 80 character summary written in past tense
- **2nd line:** [Always blank]
- **3rd line:** `refs/closes #000` or `no issue`
- **4th line:** Why this change was made - the code includes the what, the commit message should describe the context of why - why this, why now, why not something else?

If your change is **user-facing** please prepend the first line of your commit with **an emoji key**.
We are following [gitmoji](https://gitmoji.carloscuesta.me/).

**Main emojis we are using:**

- ✨ Feature
- 🎨 Improvement / change
- 🐛 Bug Fix
- 💡 Anything else flagged to users or whoever is writing release notes

Good commit message examples: [one](https://github.com/TryGhost/Ghost/commit/61db6defde3b10a4022c86efac29cf15ae60983f), [two](https://github.com/TryGhost/Ghost/commit/b392d1925a9f961d7b4bf781ee86393a7773ed4b) and [three](https://github.com/TryGhost/Ghost/commit/e4807a779c28a754e3f8ae871a26a8aad12ca9a9).

### Submitting Pull Requests

We aim to merge any straightforward, well-understood bug fixes or improvements immediately, as long as they pass our tests (run `yarn test` to check locally). We generally don't merge new features and larger changes without prior discussion with the core product team for tech/design specification.

Please provide plenty of context and reasoning around your changes, to help us merge quickly. Closing an already open issue is our preferred workflow. If your PR gets out of date, we may ask you to rebase as you are more familiar with your changes than we will be.

---

## Contributor License Agreement

By contributing your code to Ghost you grant the Ghost Foundation a non-exclusive, irrevocable, worldwide, royalty-free, sublicenseable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation:
(a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution.

You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions.

You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license.

The Ghost Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.


text:
from django.core import validators
from django.core.exceptions import ValidationError
from django.core.urlresolvers import resolve
from cobra.core.loading import get_model
from django.http import Http404
from django.utils.translation import ugettext_lazy as _

class ExtendedURLValidator(validators.URLValidator):

    def __init__(self, *args, **kwargs):
        # 'verify_exists' has been removed in Django 1.5 and so we no longer
        # pass it up to the core validator class
        self.is_local_url = False
        verify_exists = kwargs.pop('verify_exists', False)
        super(ExtendedURLValidator, self).__init__(*args, **kwargs)
        self.verify_exists = verify_exists

    def __call__(self, value):
        try:
            super(ExtendedURLValidator, self).__call__(value)
        except ValidationError:
            # The parent validator will raise an exception if the URL does not
            # exist and so we test here to see if the value is a local URL.
            if value:
                self.validate_local_url(value)
            else:
                raise

    def validate_local_url(self, value):
        value = self.clean_url(value)
        try:
            resolve(value)
        except Http404:
            # We load flatpages here as it causes a circular reference problem
            # sometimes.  FlatPages is None if not installed
            FlatPage = get_model('flatpages', 'FlatPage')
            if FlatPage is not None:
                try:
                    FlatPage.objects.get(url=value)
                except FlatPage.DoesNotExist:
                    self.is_local_url = True
                else:
                    return
            raise ValidationError(_('The URL "%s" does not exist') % value)
        else:
            self.is_local_url = True

    def clean_url(self, value):
        """
        Ensure url has a preceding slash and no query string
        """
        if value != '/':
            value = '/' + value.lstrip('/')
        q_index = value.find('?')
        if q_index > 0:
            value = value[:q_index]
        return value

class URLDoesNotExistValidator(ExtendedURLValidator):

    def __call__(self, value):
        """
        Validate that the URLdoes not already exist.

        The URL will be verified first and raises ``ValidationError`` when
        it is invalid. A valid URL is checked for existance and raises
        ``ValidationError`` if the URL already exists. Setting attribute
        ``verify_exists`` has no impact on validation.
        This validation uses two calls to ExtendedURLValidator which can
        be slow. Be aware of this, when you use it.

        Returns ``None`` if URL is valid and does not exist.
        """
        try:
            self.validate_local_url(value)
        except ValidationError:
            # Page exists - that is what we want
            return
        raise ValidationError(
            _('Specified page already exists!'), code='invalid')

def non_whitespace(value):
    stripped = value.strip()
    if not stripped:
        raise ValidationError(
            _("This field is required"))
    return stripped

class CommonPasswordValidator(validators.BaseValidator):
    # See
    # http://www.smartplanet.com/blog/business-brains/top-20-most-common-passwords-of-all-time-revealed-8216123456-8216princess-8216qwerty/4519  # noqa
    forbidden_passwords = [
        'password',
        '1234',
        '12345'
        '123456',
        '123456y',
        '123456789',
        'iloveyou',
        'princess',
        'monkey',
        'rockyou',
        'babygirl',
        'monkey',
        'qwerty',
        '654321',
        'dragon',
        'pussy',
        'baseball',
        'football',
        'letmein',
        'monkey',
        '696969',
        'abc123',
        'qwe123',
        'qweasd',
        'mustang',
        'michael',
        'shadow',
        'master',
        'jennifer',
        '111111',
        '2000',
        'jordan',
        'superman'
        'harley'
    ]
    message = _("Please choose a less common password")
    code = 'password'

    def __init__(self, password_file=None):
        self.limit_value = password_file

    def clean(self, value):
        return value.strip()

    def compare(self, value, limit):
        return value in self.forbidden_passwords

    def get_forbidden_passwords(self):
        if self.limit_value is None:
            return self.forbidden_passwords

# List all requirements for password, site wide
password_validators = [
    validators.MinLengthValidator(6),
    CommonPasswordValidator(),
]


text:
#pragma once
//------------------------------------------------------------------------------
/**
    @class Oryol::HTTPMethod
    @ingroup HTTP
    @brief HTTP methods enum class (GET, PUT, POST, ...)

    See http://tools.ietf.org/html/rfc2616
*/
#include "Core/Types.h"

namespace Oryol {

class HTTPMethod {
public:
    /// methods enum
    enum Code {
        Options = 0,
        Get,
        Head,
        Post,
        Put,
        Delete,
        Trace,
        Connect,

        NumHTTPMethods,
        InvalidHTTPMethod,
    };

    /// convert to string
    static const char* ToString(Code c);
    /// convert to wide-string
    static const wchar_t* ToWideString(Code c);
    /// convert from string
    static Code FromString(const char* str);
};

} // namespace Oryol