text:
package service.auxiliary;

/**
 *
 * The configuration of atomic service with properties
 */
public @interface AtomicServiceConfiguration {
    public boolean MultipeThreads() default false;
    public int MaxNoOfThreads() default -1;
    public int MaxQueueSize() default 0;
}

redpajama_set_name: RedPajamaGithub


text:
package org.kie.workbench.common.stunner.bpmn.client.forms.fields.cm.roles;

import java.util.Objects;
import java.util.Optional;

import javax.annotation.PostConstruct;
import javax.enterprise.event.Event;
import javax.inject.Inject;

import elemental2.dom.HTMLTableRowElement;
import org.gwtbootstrap3.client.ui.Button;
import org.gwtbootstrap3.client.ui.constants.IconType;
import org.jboss.errai.databinding.client.api.DataBinder;
import org.jboss.errai.ui.client.local.api.IsElement;
import org.jboss.errai.ui.shared.api.annotations.AutoBound;
import org.jboss.errai.ui.shared.api.annotations.Bound;
import org.jboss.errai.ui.shared.api.annotations.DataField;
import org.jboss.errai.ui.shared.api.annotations.Templated;
import org.kie.workbench.common.stunner.bpmn.client.forms.fields.model.KeyValueRow;
import org.kie.workbench.common.stunner.bpmn.client.forms.fields.model.Variable.VariableType;
import org.kie.workbench.common.stunner.bpmn.client.forms.widgets.VariableNameTextBox;
import org.kie.workbench.common.stunner.client.widgets.canvas.actions.IntegerTextBox;
import org.kie.workbench.common.stunner.core.util.StringUtils;
import org.uberfire.workbench.events.NotificationEvent;

import static org.kie.workbench.common.stunner.bpmn.client.forms.util.StringUtils.ALPHA_NUM_REGEXP;

@Templated("RolesEditorWidget.html#tableRow")
public class RolesListItemWidgetViewImpl implements RolesListItemWidgetView,
                                                    IsElement {

    public static final String INVALID_CHARACTERS_MESSAGE = "Invalid characters";
    private static final String DUPLICATE_NAME_ERROR_MESSAGE = "A role with this name already exists";
    private static final String EMPTY_ERROR_MESSAGE = "Role name already cannot be empty";

    @Inject
    @AutoBound
    protected DataBinder<KeyValueRow> row;

    @Inject
    @Bound(property = "key")
    @DataField("roleInput")
    protected VariableNameTextBox role;

    @Inject
    @Bound(property = "value")
    @DataField("cardinalityInput")
    protected IntegerTextBox cardinality;

    private boolean allowDuplicateNames = false;

    private String previousRole;

    private String previousCardinality;

    @Inject
    protected Event<NotificationEvent> notification;

    @Inject
    @DataField
    protected Button deleteButton;

    @Inject
    @DataField("tableRow")
    protected HTMLTableRowElement tableRow;

    /**
     * Required for implementation of Delete button.
     */
    private Optional<RolesEditorWidgetView> parentWidget;

    protected RolesListItemWidgetViewImpl() {
    }

    public void setParentWidget(final RolesEditorWidgetView parentWidget) {
        this.parentWidget = Optional.ofNullable(parentWidget);
    }

    @PostConstruct
    public void init() {
        role.setRegExp(ALPHA_NUM_REGEXP, INVALID_CHARACTERS_MESSAGE, INVALID_CHARACTERS_MESSAGE);
        role.addChangeHandler((e) -> handleValueChanged());
        cardinality.addChangeHandler((e) -> handleValueChanged());
        cardinality.addFocusHandler((e) -> handleFocus());
        deleteButton.setIcon(IconType.TRASH);
        deleteButton.addClickHandler((e) -> handleDeleteButton());
        //show the widget that is hidden on the template
        tableRow.hidden = false;
    }

    private void handleFocus() {
        if (Objects.equals("0", cardinality.getText())) {
            cardinality.clear();
        }
    }

    private void handleValueChanged() {
        final String currentRole = row.getModel().getKey();
        final String currentCardinality = row.getModel().getValue();
        if (StringUtils.isEmpty(currentRole)) {
            notification.fire(new NotificationEvent(EMPTY_ERROR_MESSAGE,
                                                    NotificationEvent.NotificationType.ERROR));
            row.getModel().setKey(previousRole);
            return;
        }
        if (!allowDuplicateNames && isDuplicateName(currentRole)) {
            notification.fire(new NotificationEvent(DUPLICATE_NAME_ERROR_MESSAGE,
                                                    NotificationEvent.NotificationType.ERROR));
            row.getModel().setKey(previousRole);
            return;
        }

        //skip in case not modified values
        if ((Objects.equals(previousRole, currentRole) && Objects.equals(previousCardinality, currentCardinality))) {
            return;
        }
        previousRole = currentRole;
        previousCardinality = currentCardinality;
        notifyModelChanged();
    }

    @Override
    public VariableType getVariableType() {
        return VariableType.PROCESS;
    }

    @Override
    public void setReadOnly(final boolean readOnly) {
        deleteButton.setEnabled(!readOnly);
        role.setEnabled(!readOnly);
        cardinality.setEnabled(!readOnly);
    }

    @Override
    public boolean isDuplicateName(final String name) {
        return parentWidget.map(p -> p.isDuplicateName(name)).orElse(false);
    }

    public void handleDeleteButton() {
        parentWidget.ifPresent(p -> p.remove(getValue()));
    }

    @Override
    public void notifyModelChanged() {
        parentWidget.ifPresent(RolesEditorWidgetView::notifyModelChanged);
    }

    @Override
    public void setValue(KeyValueRow value) {
        //when first setting the value then set as previous as well
        if (Objects.isNull(previousRole)) {
            previousRole = value.getKey();
            previousCardinality = value.getValue();
        }
        row.setModel(value);
    }

    @Override
    public KeyValueRow getValue() {
        return row.getModel();
    }

    @Override
    public KeyValueRow getModel() {
        return getValue();
    }

    @Override
    public void setModel(KeyValueRow model) {
        setValue(model);
    }
}


text:
* Update the Python Editor version number in the editor.html file.
* Round-trip the translations
* If the release is for a beta version of the editor, set the "experimental" flag to `true`.
* If the MicroPython runtime is to be updated:
    * Update the firmware hex file from the `micropython` folder to the correct version.
    * Update the MicroPython version string in the editor.html file.
    * Update micropythonapi.js to be up-to-date with the API of the modules included with MicroPython.
* Ensure all CI tests pass
* Run the jasmine (help.html) tests
* Run the Manual Test Procedure
* Update the CHANGELOG file with an English description of all changes made.
* Create a tagged release using GitHub.


text:
package org.mycompany;

import java.util.List;
import org.netbeans.installer.product.components.ProductConfigurationLogic;
import org.netbeans.installer.utils.exceptions.InitializationException;
import org.netbeans.installer.utils.exceptions.InstallationException;
import org.netbeans.installer.utils.exceptions.UninstallationException;
import org.netbeans.installer.utils.helper.RemovalMode;
import org.netbeans.installer.utils.progress.Progress;
import org.netbeans.installer.wizard.Wizard;
import org.netbeans.installer.wizard.components.WizardComponent;
//normen - JDK launchers

public class ConfigurationLogic extends ProductConfigurationLogic {

    private List<WizardComponent> wizardComponents;

    // constructor //////////////////////////////////////////////////////////////////
    public ConfigurationLogic() throws InitializationException {
        wizardComponents = Wizard.loadWizardComponents(
                WIZARD_COMPONENTS_URI,
                getClass().getClassLoader());
    }

    public List<WizardComponent> getWizardComponents() {
        return wizardComponents;
    }

    @Override
    public boolean allowModifyMode() {
        return false;
    }

    @Override
    public void install(Progress progress) throws InstallationException {
    }

    @Override
    public void uninstall(Progress progress) throws UninstallationException {
        progress.setPercentage(Progress.COMPLETE);
    }

    @Override
    public String getExecutable() {
        return "";
    }

    @Override
    public String getIcon() {
        return "";
    }

    public RemovalMode getRemovalMode() {
        return RemovalMode.LIST;
    }

    @Override
    public boolean registerInSystem() {
        return false;
    }

    @Override
    public boolean requireLegalArtifactSaving() {
        return false;
    }

    @Override
    public boolean requireDotAppForMacOs() {
        return false;
    }

    @Override
    public boolean wrapForMacOs() {
        return false;
    }

    public static final String WIZARD_COMPONENTS_URI =
            "resource:" + // NOI18N
            "org/mycompany/wizard.xml"; // NOI18N
}


text:
<?xml version="1.0" encoding="windows-1251"?>
<config mode="{{ term.type }}" blacklist="{{ term.blacklist }}">
    <ntp>
        <server>{{ config.NTP_SERVER }}</server>
        <timezone>{{ term.tz }}</timezone>
    </ntp>
    {% if config.DOWNLOAD %}
    <download force_on_restart="1">
        <period>{{ term.download_period }}</period>
        <start time="{{ term.download['start'] }}"/>
        <stop time="{{ term.download['stop'] }}"/>
    </download>
    {% endif %}
    {% if config.UPLOAD %}
    <upload force_on_restart="1">
        <period>{{ term.upload_period }}</period>
        <start time="{{ term.upload['start'] }}"/>
        <stop time="{{ term.upload['stop'] }}"/>
    </upload>
    {% endif %}
    {% if config.UPDATE %}
    {% if term.version %}
    <update force_on_restart="1">
        <period>{{ config.UPDATE_PERIOD }}</period>
        <qid>{{term.version}}</qid>
    </update>
    {% endif %}
    {% endif %}
    {% if config.DOWNLOAD %}
    <server goal="download">
        <ip>{{ config.DOWNLOAD_IP }}</ip>
        <port>{{ config.DOWNLOAD_PORT }}</port>
        <proto upload_method="PUT">{{ config.DOWNLOAD_PROTO }}</proto>
        <link>{{ config.DOWNLOAD_LINK_TYPE }}</link>
    </server>
    {% endif %}
    {% if config.UPLOAD %}
    <server goal="upload">
        <ip>{{ config.UPLOAD_IP }}</ip>
        <port>{{ config.UPLOAD_PORT }}</port>
        <proto upload_method="PUT">{{ config.UPLOAD_PROTO }}</proto>
        <link>{{ config.UPLOAD_LINK_TYPE }}</link>
    </server>
    {% endif %}
    {% if config.LOGGER %}
    <server goal="logger">
        <ip>{{ config.LOGGER_IP }}</ip>
        <port>{{ config.LOGGER_PORT }}</port>
        <proto upload_method="PUT">{{ config.LOGGER_PROTO }}</proto>
        <link>{{ config.LOGGER_LINK_TYPE }}</link>
    </server>
    {% endif %}
    {% if config.UPDATE %}
    <server goal="update">
        <ip>{{ config.UPDATE_IP }}</ip>
        <port>{{ config.UPDATE_PORT }}</port>
        <proto upload_method="PUT">{{ config.UPDATE_PROTO }}</proto>
        <link>{{ config.UPDATE_LINK_TYPE }}</link>
    </server>
    {% endif %}
    {% for term_event in term_events %}
    <event type="{{term_event.event.key}}" translation="{{term_event.event.name}}" min_time="{{term_event.start}}" max_time="{{term_event.stop}}">
        {% for person_event in person_events %}
            {% if person_event.event_id == term_event.event_id %}
            {% set payment_id = person_event.person.payment_id %}
                {% if payment_id %}
                <card timeout="{{person_event.timeout}}" price="{{term_event.cost}}">
                {{ payment_id }}</card>
                {% endif %}
            {% endif %}
        {% endfor %}
    </event>
    {% endfor %}
</config>


text:
<!DOCTYPE HTML>

<textarea style="border:2px solid red;" id="huge_text">
</textarea>

<textarea id="destination">
</textarea>


text:
A blog system based on Python 2.7 and Redis. It's a *nix port from Google App Engine of [Doodle 1.x](https://bitbucket.org/keakon/doodle/).

## Installation
Doodle 2 requires Python 2.7 and Redis. It has been tested on Ubuntu 18.04.

1. Clone or download the source code:
  ```bash
  $ git clone https://github.com/keakon/Doodle.git
  ```
2. Install dependencies:
  ```bash
  $ sudo pip install virtualenv
  $ virtualenv .
  $ bin/pip install -r requirements.txt
  ```

## Usage
```bash
$ redis-server &
$ bin/python -m doodle.main
```
Then you can open [http://0.0.0.0:8080](http://0.0.0.0:8080) to check it.

## Run with docker

1. Install Docker
2. Clone or download the source code:
  ```bash
  $ git clone https://github.com/keakon/Doodle.git
  ```
3. Copy config files:
  ```bash
  $ mkdir doodle
  $ cp Doodle/docker-compose.yml doodle/docker-compose.yml
  $ cp -r Doodle/conf doodle/conf
  ```
4. Replace "localhost" into your own domain in conf/Caddyfile.
5. Start docker compose:
  ```bash
  $ cd doodle
  $ docker compose up -d
  ```

## License
Doodle is released under the MIT License. See the [LICENSE](https://raw.githubusercontent.com/keakon/Doodle/master/LICENSE) file for more details.


text:
package br.com.netbrasoft.gnuob.generic.content.mail;

public enum SubjectEnum {

  //@formatter:off
  CONFIRMATION_NEW_CUSTOMER_SUBJECT("confirmation_new_customer_subject.vm"),
  CONFIRMATION_NEW_ORDER_SUBJECT("confirmation_new_order_subject.vm"),
  NONE_SUBJECT("");
  //@formatter:on

  private String template;

  private SubjectEnum(final String template) {
    this.template = template;
  }

  public String getTemplate() {
    return template;
  }
}


text:
/**
 * TODO: 현재 수행하는 기능이 webpack으로 대체 가능하므로 제거 여부 고려
 */

var gulp = require('gulp');
var webpack = require('webpack-stream');

var paths = {
  sources: ['app/src/client/**/*', 'app/src/server/**/*'],
  assets: 'app/asset/**/*'
};

// webpack production build
gulp.task('webpack-production', function() {
  var webpackConfig = require('./webpack.production.config.js');

  return gulp.src('app/client/index.jsx')
    .pipe(webpack(webpackConfig))
    .pipe(gulp.dest('app/dist/production'));
});

// webpack development build
gulp.task('webpack-development', function() {
  var webpackConfig = require('./webpack.development.config.js');

  return gulp.src('app/client/index.jsx')
    .pipe(webpack(webpackConfig))
    .pipe(gulp.dest('app/dist/development'));
});

// webpack development watch
gulp.task('watch', function() {
  gulp.watch(paths.sources, ['webpack-development']);
});

gulp.task('default', ['webpack-production']);


text:
<!DOCTYPE html>

    <meta name='viewport' content='initial-scale=1 user-scalable=no width=device-width'>
    <meta charset="UTF-8">

    <link rel='stylesheet' type='text/css' href='/assets/css/reset.css'>
    <link rel='stylesheet' type='text/css' href='/assets/css/styles.css'>
    <title>About</title>

About

Home

About

culinary.af is a site by Soroush Khanlou. It's where he keeps his recipes. It's powered by an open-source JavaScript ingredient parsing library called pepin, which you can find on Github.


text:
package aggregator

import (
	"fmt"
	"reflect"
	"sort"
	"strings"

	"k8s.io/kube-openapi/pkg/validation/spec"

	"k8s.io/kube-openapi/pkg/util"
)

const gvkKey = "x-kubernetes-group-version-kind"

// usedDefinitionForSpec returns a map with all used definitions in the provided spec as keys and true as values.
func usedDefinitionForSpec(root *spec.Swagger) map[string]bool {
	usedDefinitions := map[string]bool{}
	walkOnAllReferences(func(ref *spec.Ref) {
		if refStr := ref.String(); refStr != "" && strings.HasPrefix(refStr, definitionPrefix) {
			usedDefinitions[refStr[len(definitionPrefix):]] = true
		}
	}, root)
	return usedDefinitions
}

// FilterSpecByPaths removes unnecessary paths and definitions used by those paths.
// i.e. if a Path removed by this function, all definitions used by it and not used
// anywhere else will also be removed.
func FilterSpecByPaths(sp *spec.Swagger, keepPathPrefixes []string) {
	*sp = *FilterSpecByPathsWithoutSideEffects(sp, keepPathPrefixes)
}

// FilterSpecByPathsWithoutSideEffects removes unnecessary paths and definitions used by those paths.
// i.e. if a Path removed by this function, all definitions used by it and not used
// anywhere else will also be removed.
// It does not modify the input, but the output shares data structures with the input.
func FilterSpecByPathsWithoutSideEffects(sp *spec.Swagger, keepPathPrefixes []string) *spec.Swagger {
	if sp.Paths == nil {
		return sp
	}

	// Walk all references to find all used definitions. This function
	// want to only deal with unused definitions resulted from filtering paths.
	// Thus a definition will be removed only if it has been used before but
	// it is unused because of a path prune.
	initialUsedDefinitions := usedDefinitionForSpec(sp)

	// First remove unwanted paths
	prefixes := util.NewTrie(keepPathPrefixes)
	ret := *sp
	ret.Paths = &spec.Paths{
		VendorExtensible: sp.Paths.VendorExtensible,
		Paths:            map[string]spec.PathItem{},
	}
	for path, pathItem := range sp.Paths.Paths {
		if !prefixes.HasPrefix(path) {
			continue
		}
		ret.Paths.Paths[path] = pathItem
	}

	// Walk all references to find all definition references.
	usedDefinitions := usedDefinitionForSpec(&ret)

	// Remove unused definitions
	ret.Definitions = spec.Definitions{}
	for k, v := range sp.Definitions {
		if usedDefinitions[k] || !initialUsedDefinitions[k] {
			ret.Definitions[k] = v
		}
	}

	return &ret
}

type rename struct {
	from, to string
}

// renameDefinition renames references, without mutating the input.
// The output might share data structures with the input.
func renameDefinition(s *spec.Swagger, renames map[string]string) *spec.Swagger {
	refRenames := make(map[string]string, len(renames))
	foundOne := false
	for k, v := range renames {
		refRenames[definitionPrefix+k] = definitionPrefix + v
		if _, ok := s.Definitions[k]; ok {
			foundOne = true
		}
	}

	if !foundOne {
		return s
	}

	ret := &spec.Swagger{}
	*ret = *s

	ret = replaceReferences(func(ref *spec.Ref) *spec.Ref {
		refName := ref.String()
		if newRef, found := refRenames[refName]; found {
			ret := spec.MustCreateRef(newRef)
			return &ret
		}
		return ref
	}, ret)

	renamedDefinitions := make(spec.Definitions, len(ret.Definitions))
	for k, v := range ret.Definitions {
		if newRef, found := renames[k]; found {
			k = newRef
		}
		renamedDefinitions[k] = v
	}
	ret.Definitions = renamedDefinitions

	return ret
}

// MergeSpecsIgnorePathConflict is the same as MergeSpecs except it will ignore any path
// conflicts by keeping the paths of destination. It will rename definition conflicts.
// The source is not mutated.
func MergeSpecsIgnorePathConflict(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, true, true)
}

// MergeSpecsFailOnDefinitionConflict is differ from MergeSpecs as it fails if there is
// a definition conflict.
// The source is not mutated.
func MergeSpecsFailOnDefinitionConflict(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, false, false)
}

// MergeSpecs copies paths and definitions from source to dest, rename definitions if needed.
// dest will be mutated, and source will not be changed. It will fail on path conflicts.
// The source is not mutated.
func MergeSpecs(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, true, false)
}

// mergeSpecs merges source into dest while resolving conflicts.
// The source is not mutated.
func mergeSpecs(dest, source *spec.Swagger, renameModelConflicts, ignorePathConflicts bool) (err error) {
	// Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
	if source.Paths == nil {
		// When a source spec does not have any path, that means none of the definitions
		// are used thus we should not do anything
		return nil
	}
	if dest.Paths == nil {
		dest.Paths = &spec.Paths{}
	}
	if ignorePathConflicts {
		keepPaths := []string{}
		hasConflictingPath := false
		for k := range source.Paths.Paths {
			if _, found := dest.Paths.Paths[k]; !found {
				keepPaths = append(keepPaths, k)
			} else {
				hasConflictingPath = true
			}
		}
		if len(keepPaths) == 0 {
			// There is nothing to merge. All paths are conflicting.
			return nil
		}
		if hasConflictingPath {
			source = FilterSpecByPathsWithoutSideEffects(source, keepPaths)
		}
	}

	// Check for model conflicts and rename to make definitions conflict-free (modulo different GVKs)
	usedNames := map[string]bool{}
	for k := range dest.Definitions {
		usedNames[k] = true
	}
	renames := map[string]string{}
DEFINITIONLOOP:
	for k, v := range source.Definitions {
		existing, found := dest.Definitions[k]
		if !found || deepEqualDefinitionsModuloGVKs(&existing, &v) {
			// skip for now, we copy them after the rename loop
			continue
		}

		if !renameModelConflicts {
			return fmt.Errorf("model name conflict in merging OpenAPI spec: %s", k)
		}

		// Reuse previously renamed model if one exists
		var newName string
		i := 1
		for found {
			i++
			newName = fmt.Sprintf("%s_v%d", k, i)
			existing, found = dest.Definitions[newName]
			if found && deepEqualDefinitionsModuloGVKs(&existing, &v) {
				renames[k] = newName
				continue DEFINITIONLOOP
			}
		}

		_, foundInSource := source.Definitions[newName]
		for usedNames[newName] || foundInSource {
			i++
			newName = fmt.Sprintf("%s_v%d", k, i)
			_, foundInSource = source.Definitions[newName]
		}
		renames[k] = newName
		usedNames[newName] = true
	}
	source = renameDefinition(source, renames)

	// now without conflict (modulo different GVKs), copy definitions to dest
	for k, v := range source.Definitions {
		if existing, found := dest.Definitions[k]; !found {
			if dest.Definitions == nil {
				dest.Definitions = spec.Definitions{}
			}
			dest.Definitions[k] = v
		} else if merged, changed, err := mergedGVKs(&existing, &v); err != nil {
			return err
		} else if changed {
			existing.Extensions[gvkKey] = merged
		}
	}

	// Check for path conflicts
	for k, v := range source.Paths.Paths {
		if _, found := dest.Paths.Paths[k]; found {
			return fmt.Errorf("unable to merge: duplicated path %s", k)
		}
		// PathItem may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
		if dest.Paths.Paths == nil {
			dest.Paths.Paths = map[string]spec.PathItem{}
		}
		dest.Paths.Paths[k] = v
	}

	return nil
}

// deepEqualDefinitionsModuloGVKs compares s1 and s2, but ignores the x-kubernetes-group-version-kind extension.
func deepEqualDefinitionsModuloGVKs(s1, s2 *spec.Schema) bool {
	if s1 == nil {
		return s2 == nil
	} else if s2 == nil {
		return false
	}
	if !reflect.DeepEqual(s1.Extensions, s2.Extensions) {
		for k, v := range s1.Extensions {
			if k == gvkKey {
				continue
			}
			if !reflect.DeepEqual(v, s2.Extensions[k]) {
				return false
			}
		}
		len1 := len(s1.Extensions)
		len2 := len(s2.Extensions)
		if _, found := s1.Extensions[gvkKey]; found {
			len1--
		}
		if _, found := s2.Extensions[gvkKey]; found {
			len2--
		}
		if len1 != len2 {
			return false
		}

		if s1.Extensions != nil {
			shallowCopy := *s1
			s1 = &shallowCopy
			s1.Extensions = nil
		}
		if s2.Extensions != nil {
			shallowCopy := *s2
			s2 = &shallowCopy
			s2.Extensions = nil
		}
	}

	return reflect.DeepEqual(s1, s2)
}

// mergedGVKs merges the x-kubernetes-group-version-kind slices and returns the result, and whether
// s1's x-kubernetes-group-version-kind slice was changed at all.
func mergedGVKs(s1, s2 *spec.Schema) (interface{}, bool, error) {
	gvk1, found1 := s1.Extensions[gvkKey]
	gvk2, found2 := s2.Extensions[gvkKey]

	if !found1 {
		return gvk2, found2, nil
	}
	if !found2 {
		return gvk1, false, nil
	}

	slice1, ok := gvk1.([]interface{})
	if !ok {
		return nil, false, fmt.Errorf("expected slice of GroupVersionKinds, got: %+v", slice1)
	}
	slice2, ok := gvk2.([]interface{})
	if !ok {
		return nil, false, fmt.Errorf("expected slice of GroupVersionKinds, got: %+v", slice2)
	}

	ret := make([]interface{}, len(slice1), len(slice1)+len(slice2))
	keys := make([]string, 0, len(slice1)+len(slice2))
	copy(ret, slice1)
	seen := make(map[string]bool, len(slice1))
	for _, x := range slice1 {
		gvk, ok := x.(map[string]interface{})
		if !ok {
			return nil, false, fmt.Errorf(`expected {"group": <group>, "kind": <kind>, "version": <version>}, got: %#v`, x)
		}
		k := fmt.Sprintf("%s/%s.%s", gvk["group"], gvk["version"], gvk["kind"])
		keys = append(keys, k)
		seen[k] = true
	}
	changed := false
	for _, x := range slice2 {
		gvk, ok := x.(map[string]interface{})
		if !ok {
			return nil, false, fmt.Errorf(`expected {"group": <group>, "kind": <kind>, "version": <version>}, got: %#v`, x)
		}
		k := fmt.Sprintf("%s/%s.%s", gvk["group"], gvk["version"], gvk["kind"])
		if seen[k] {
			continue
		}
		ret = append(ret, x)
		keys = append(keys, k)
		changed = true
	}

	if changed {
		sort.Sort(byKeys{ret, keys})
	}

	return ret, changed, nil
}

type byKeys struct {
	values []interface{}
	keys   []string
}

func (b byKeys) Len() int {
	return len(b.values)
}

func (b byKeys) Less(i, j int) bool {
	return b.keys[i] < b.keys[j]
}

func (b byKeys) Swap(i, j int) {
	b.values[i], b.values[j] = b.values[j], b.values[i]
	b.keys[i], b.keys[j] = b.keys[j], b.keys[i]
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Entities;
using DAL.Mapper;
using System.DirectoryServices.AccountManagement;

namespace HRM.HR_Managment.Leaves.LeaveRequest
{
    public partial class Request : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void ProceedButton_Click(object sender, EventArgs e)
        {
            LeaveRequestEntity entity = new LeaveRequestEntity();
            entity.LeaveTypeId = Convert.ToInt32(LeaveTypeDropDownList.SelectedValue);
            entity.RequestDate = DateTime.Now;

            DateTime dt;
            if (DateTime.TryParseExact(StartDateTextBox.Text, "dd.MM.yyyy", null, System.Globalization.DateTimeStyles.None, out dt))
            {
                entity.StartDate = dt;
            }
            if (!IsHalfDayCheckBox.Checked)
            {
                if (DateTime.TryParseExact(EndDateTextBox.Text, "dd.MM.yyyy", null, System.Globalization.DateTimeStyles.None, out dt))
                {
                    entity.EndDate = dt;
                }
            }
            entity.Notes = OtherInfoTextBox.Text;

            entity.EmployeeId = new UserMapper().GetUserByUserName(UserPrincipal.Current.SamAccountName).EmployeeId;
            entity.AlternatePersonId = Convert.ToInt32(AlternateEmployeeDropDownList.SelectedValue);
            #warning set Manager to managerEmployeeId
            //entity.ManagerEmployeeId =
            entity.PaymentTypeId = Convert.ToInt32(PaymentTypeDropDownList.SelectedValue);

            entity.LeaveStatus = RequestsEnum.Request;

            new LeaveRequestMapper().RequestLeave(entity);

            #warning set this to a good mail message
            string[] to = {"gramoz.krasniqi@kpaonline.org"};
            SendMail.Send(to, "Hi", ("HR Test from system. LeaveRequest by employee Id" + entity.EmployeeId) );

            Response.Redirect("List.aspx");
        }

        protected void IsHalfDayCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (IsHalfDayCheckBox.Checked)
            {
                EndDateTextBox.Enabled = false;
            }
            else
            {
                EndDateTextBox.Enabled = true;
            }
        }
    }
}


text:
package org.apache.tomcat.websocket.pojo;

import java.util.Map;

import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpointConfig;

import org.apache.tomcat.util.res.StringManager;

/**
 * Wrapper class for instances of POJOs annotated with
 * {@link javax.websocket.server.ServerEndpoint} so they appear as standard
 * {@link javax.websocket.Endpoint} instances.
 */
public class PojoEndpointServer extends PojoEndpointBase {

    private static final StringManager sm =
            StringManager.getManager(PojoEndpointServer.class);

    @Override
    public void onOpen(Session session, EndpointConfig endpointConfig) {

        ServerEndpointConfig sec = (ServerEndpointConfig) endpointConfig;

        Object pojo;
        try {
            pojo = sec.getConfigurator().getEndpointInstance(
                    sec.getEndpointClass());
        } catch (InstantiationException e) {
            throw new IllegalArgumentException(sm.getString(
                    "pojoEndpointServer.getPojoInstanceFail",
                    sec.getEndpointClass().getName()), e);
        }
        setPojo(pojo);

        @SuppressWarnings("unchecked")
        Map<String,String> pathParameters =
                (Map<String, String>) sec.getUserProperties().get(
                        Constants.POJO_PATH_PARAM_KEY);
        setPathParameters(pathParameters);

        PojoMethodMapping methodMapping =
                (PojoMethodMapping) sec.getUserProperties().get(
                        Constants.POJO_METHOD_MAPPING_KEY);
        setMethodMapping(methodMapping);

        doOnOpen(session, endpointConfig);
    }
}


text:
package org.pantsbuild.jmake;

import java.io.DataInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * Basic operations for reading a byte array representing a binary file.
 *
 * @author  Misha Dmitriev
 *  10 November 2001
 */
public class BinaryFileReader {

    protected byte[] buf;
    protected int curBufPos;
    protected String fileFullPath;  // Required only for nice error reports

    protected void initBuf(byte[] buf, String fileFullPath) {
        this.buf = buf;
        curBufPos = 0;
        this.fileFullPath = fileFullPath;
    }

    protected char nextChar() {
        return (char) (((buf[curBufPos++] & 255) << 8) + (buf[curBufPos++] & 255));
    }

    protected char getChar(int bufPos) {
        return (char) (((buf[bufPos] & 255) << 8) + (buf[bufPos+1] & 255));
    }

    protected int nextInt() {
        return ((buf[curBufPos++] & 255) << 24) + ((buf[curBufPos++] & 255) << 16) +
                ((buf[curBufPos++] & 255) << 8) + (buf[curBufPos++] & 255);
    }

    protected int getInt(int bufPos) {
        return ((buf[bufPos] & 255) << 24) + ((buf[bufPos+1] & 255) << 16) +
                ((buf[bufPos+2] & 255) << 8) + (buf[bufPos+3] & 255);
    }

    protected long nextLong() {
        long res = getLong(curBufPos);
        curBufPos += 8;
        return res;
    }

    protected long getLong(int bufPos) {
        DataInputStream bufin =
                new DataInputStream(new ByteArrayInputStream(buf, bufPos, 8));
        try {
            return bufin.readLong();
        } catch (IOException e) {
            throw new PrivateException(e);
        }
    }

    protected float nextFloat() {
        float res = getFloat(curBufPos);
        curBufPos += 4;
        return res;
    }

    protected float getFloat(int bufPos) {
        DataInputStream bufin =
                new DataInputStream(new ByteArrayInputStream(buf, bufPos, 4));
        try {
            return bufin.readFloat();
        } catch (IOException e) {
            throw new PrivateException(e);
        }
    }

    protected double nextDouble() {
        double res = getDouble(curBufPos);
        curBufPos += 8;
        return res;
    }

    protected double getDouble(int bufPos) {
        DataInputStream bufin =
                new DataInputStream(new ByteArrayInputStream(buf, bufPos, 8));
        try {
            return bufin.readDouble();
        } catch (IOException e) {
            throw new PrivateException(e);
        }
    }
}


text:
@implementation UIAlertView (FLKit)
static char BB_KEY;
static char FL_DELEGATE_KEY;
@dynamic buttonsAndBlocks;
@dynamic flDelegate;

- (void)setButtonsAndBlocks:(NSMutableDictionary *)buttonsAndBlocks
{
    objc_setAssociatedObject(self, &BB_KEY, buttonsAndBlocks, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSMutableDictionary *)buttonsAndBlocks
{
    return (NSMutableDictionary *)objc_getAssociatedObject(self, &BB_KEY);
}

- (void)setFlDelegate:(id<UIAlertViewDelegate>)flDelegate
{
    objc_setAssociatedObject(self, &FL_DELEGATE_KEY, flDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id<UIAlertViewDelegate>)flDelegate
{
    return (id<UIAlertViewDelegate>)objc_getAssociatedObject(self, &FL_DELEGATE_KEY);
}

+ (UIAlertView *)alertViewWithTitle:(NSString *)title message:(NSString *)message
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
    return alert;
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if(self.flDelegate AND [self.flDelegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)])
        [self.flDelegate alertView:alertView clickedButtonAtIndex:buttonIndex];

    FLAlertViewBlock block = [[self buttonsAndBlocks] objectForKey:[NSNumber numberWithInteger:buttonIndex]];
    block();
}

#pragma mark - Delegate Methods
- (void)alertViewCancel:(UIAlertView *)alertView
{
    if(self.flDelegate AND [self.flDelegate respondsToSelector:@selector(alertViewCancel:)])
        [self.flDelegate alertViewCancel:alertView];

}

- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if(self.flDelegate AND [self.flDelegate respondsToSelector:@selector(alertView:willDismissWithButtonIndex:)])
        [self.flDelegate alertView:alertView willDismissWithButtonIndex:buttonIndex];
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if(self.flDelegate AND [self.flDelegate respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)])
        [self.flDelegate alertView:alertView didDismissWithButtonIndex:buttonIndex];
}

- (void)willPresentAlertView:(UIAlertView *)alertView
{
    if(self.flDelegate AND [self.flDelegate respondsToSelector:@selector(willPresentAlertView:)])
        [self.flDelegate willPresentAlertView:alertView];
}

- (void)didPresentAlertView:(UIAlertView *)alertView
{
    if(self.flDelegate AND [self.flDelegate respondsToSelector:@selector(didPresentAlertView:)])
        [self.flDelegate didPresentAlertView:alertView];
}

#pragma mark - Public Methods
- (void)setupAdditions
{
    if([self buttonsAndBlocks] == NULL)
    {
        NSMutableDictionary *tmp = [[NSMutableDictionary alloc] init];
        [self setButtonsAndBlocks:tmp];
    }

    if([self flDelegate] == NULL)
    {
        [self setFlDelegate:self.delegate];
        [self setDelegate:self];
    }
}

- (NSInteger)__addButtonWithTitle:(NSString *)title block:(FLAlertViewBlock)block
{
    [self setupAdditions];

    NSInteger idx = [self addButtonWithTitle:title];
    NSNumber *index = [NSNumber numberWithInteger:idx];
    [[self buttonsAndBlocks] setObject:block forKey:index];

    return idx;
}

- (void)cancelButtonWithTitle:(NSString *)title block:(FLAlertViewBlock)block
{
    self.cancelButtonIndex = [self __addButtonWithTitle:title block:block];
}

- (void)addButtonWithTitle:(NSString *)title block:(FLAlertViewBlock)block
{
    [self __addButtonWithTitle:title block:block];
}

@end


text:
#ifndef _ZONOTOPE_OTHEROPS_H_
#define _ZONOTOPE_OTHEROPS_H_

//#include "elina_var.h"
//#include "elina_abstract1.h"
#include "zonotope_internal.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Other functions */
/*******************/

int elina_manager_zonotope_get_nsym(elina_manager_t* man);

//void elina_abstract1_aff_build(elina_manager_t* man, elina_abstract1_t * abstract, elina_var_t var, unsigned int index, elina_interval_t *itv, bool isunion);
//void elina_abstract1_ns_meet_lincons_array(elina_manager_t* man, elina_abstract1_t* abstract1, elina_lincons0_array_t* lincons);
//void elina_abstract1_ns_meet_box_array(elina_manager_t* man, elina_abstract1_t* abstract1, elina_interval_t** box, size_t size);

zonotope_t* zonotope_forget_array(elina_manager_t* man,
		bool destructive, zonotope_t* a,
		elina_dim_t* tdim, size_t size,
		bool project);

//zonotope_t zonotope_expand(elina_manager_t* man,
//		bool destructive, zonotope_t* a,
//		elina_dim_t var,
//		elina_dim_t* tvar, size_t size);

//zonotope_t zonotope_fold(elina_manager_t* man,
//		bool destructive, zonotope_t* a,
//		elina_dim_t* tvar, size_t size);

//zonotope_t* zonotope_widening(elina_manager_t* man,
//		  zonotope_t* a1,
//		  zonotope_t* a2);

//zonotope_t zonotope_closure(elina_manager_t* man, bool destructive, zonotope_t* a);

/* retourne [0,+oo] */
/* for internal use */
/* pour test */
//elina_interval_t* zonotope_create_pos(elina_manager_t* man);

#ifdef __cplusplus
}
#endif

#endif


text:
from django.contrib import admin
from pyramidal.models import Gene,Isoform,Tss,Cds,Sample

admin.site.register(Gene)
admin.site.register(Isoform)
admin.site.register(Tss)
admin.site.register(Cds)
admin.site.register(Sample)


text:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using Enmarcha.SharePoint.Abstract.Enum;
using Enmarcha.SharePoint.Abstract.Interfaces.Artefacts;
using Enmarcha.SharePoint.Attribute;
using Enmarcha.SharePoint.Class.Logs;
using Enmarcha.SharePoint.Entities.Artefacts;
using Enmarcha.SharePoint.Helpers;
using Enmarcha.SharePoint.Helpers.Extensors;
using Enmarcha.SharePoint.Helpers.SiteColumn;
using Microsoft.SharePoint;

namespace Enmarcha.SharePoint.Extensors
{
    public static class List
    {
        private static readonly ILog Logger = new LogManager().GetLogger(new System.Diagnostics.StackTrace().GetFrame(0));

        /// <summary>
        /// Create List
        /// </summary>
        /// <param name="web"></param>
        /// <param name="title"></param>
        /// <param name="description"></param>
        /// <param name="typeList"></param>
        /// <param name="versionControl"></param>
        /// <returns></returns>
        public static bool CreateList(this SPWeb web, string title, string description, TypeList typeList,
            bool versionControl)
        {
            return CreateList(web, title, description, typeList, versionControl, null);
        }
        /// <summary>
        /// Create List
        /// </summary>
        /// <param name="web"></param>
        /// <param name="title"></param>
        /// <param name="description"></param>
        /// <param name="typeList"></param>
        /// <param name="versionControl"></param>
        /// <param name="genericClass"></param>
        /// <returns></returns>
        public static bool CreateList(this SPWeb web, string title, string description, TypeList typeList,
            bool versionControl, Type genericClass)
        {
            try
            {
                var list = new ListSharePoint(web, Logger, title);
                ListTemplateType type;
                switch (typeList)
                {
                    case TypeList.DocumentLibrary:
                        type = ListTemplateType.DocumentLibrary;
                        break;
                    case TypeList.PictureLibrary:
                        type = ListTemplateType.PictureLibrary;
                        break;
                    case TypeList.CalendarList:
                        type = ListTemplateType.Events;
                        break;
                    default:
                        type = ListTemplateType.GenericList;
                        break;
                }
                var result = list.Create(description, type, versionControl);
                if (genericClass != null) AddFieldInList(list, genericClass);

                return result;
            }
            catch (Exception exception)
            {
                Logger.Error(string.Concat("Error Create List:", exception.Message));
                return false;
            }
        }

        /// <summary>
        /// Add permissions to the library
        /// </summary>
        /// <param name="list"></param>
        /// <param name="group"></param>
        /// <param name="role"></param>
        /// <returns></returns>
        public static bool AddPermisionLibrary(this SPList list, string group, RoleType role)
        {
            try
            {

                var listSharePoint = new ListSharePoint(list.ParentWeb, Logger, list.Title);
                return listSharePoint.AddPermissionsGroup(group, role);
            }
            catch (Exception exception)
            {
                Logger.Error(string.Concat("Error AddPermisionLibrary:", exception.Message));
                return false;
            }
        }

        /// <summary>
        /// Add ContentType in Library
        /// </summary>
        /// <param name="list"></param>
        /// <param name="contentType"></param>
        /// <returns></returns>
        public static bool AddContentTypeLibrary(this SPList list, string contentType)
        {
            try
            {
                var listSharePoint = new ListSharePoint(list.ParentWeb,Logger, list.Title);
                if (listSharePoint.ExistContentType("Item")) listSharePoint.DeleteContentType("Item");
                if (listSharePoint.ExistContentType("Document")) listSharePoint.DeleteContentType("Document");
                if (listSharePoint.ExistContentType("Element")) listSharePoint.DeleteContentType("Element");
                return !listSharePoint.ExistContentType(contentType) && listSharePoint.AddContentType(contentType);
            }
            catch (Exception exception)
            {
                Logger.Error(string.Concat("Error AddContentTypeLibrary", exception.Message));
                return false;
            }
        }

        #region Functions Privadas
        /// <summary>
        /// Add Field in List
        /// </summary>
        /// <param name="list"></param>
        /// <param name="genericClass"></param>
        private static void AddFieldInList(ListSharePoint list, Type genericClass)
        {
            var props = genericClass.GetProperties();
            foreach (var prop in props)
            {
                var fieldType = "Text";
                var create = true;
                var choice = new StringCollection();
                var term = string.Empty;
                var displayName = string.Empty;
                var hidden = false;
                var multiValue = false;
                var required = false;
                var group = Constants.Prefix;
                var defaultValue = string.Empty;
                var addPrefix = true;

                foreach (
                    var enmarcha in
                        prop.GetCustomAttributes(true).Select(attribute => attribute as EnmarchaAttribute))
                {
                    fieldType = enmarcha.Type.ToString();
                    create = enmarcha.Create;
                    term = enmarcha.Term;
                    multiValue = enmarcha.MultiValue;
                    displayName = enmarcha.DisplayName;
                    hidden = enmarcha.Hidden;
                    required = enmarcha.Required;
                    try
                    {
                        group = enmarcha.Group;
                        addPrefix = enmarcha.AddPrefeix;
                        defaultValue = enmarcha.ValueDefault;

                    }

                    catch (Exception exception)
                    {

                        Logger.Error(string.Concat("ENMARCHA Error :", exception.Message));
                    }

                    try
                    {
                        if (enmarcha.Choice != null) choice.AddRange(enmarcha.Choice);
                    }
                    catch (Exception exception)
                    {
                        Logger.Error(string.Concat("Error :", exception.Message));
                    }
                }

                if (!create) continue;
                CreateColumnInList(new ParamsColumnSite
                {
                    List = list,
                    Name = prop.Name,
                    FieldType = fieldType,
                    Requiered = required,
                    DefaultValue = defaultValue,
                    Choice = choice,
                    Group = group,
                    MultiValue = multiValue,
                    AddPrefix = addPrefix,
                    DisplayName = displayName
                });
            }
        }

        private static void CreateColumnInList(ParamsColumnSite args)
        {
            var type = GetFieldType(args.FieldType);
            if (args.FieldType.Equals("Taxonomy"))
            {
                var columnSite = new SiteColumn
                    (new ParamsSiteColumnDefaultValue
                    {
                        Name = args.Name,
                        FieldType = type,
                        Requiered = args.Requiered,
                        Group = args.Group,
                        DefaultValue = args.DefaultValue,
                        AddPrefix = args.AddPrefix,
                        DisplayName = args.DisplayName
                    });
                args.List.AddField(columnSite);

            }
            else
            {
                SiteColumn columnSite;
                switch (type)
                {
                    case SPFieldType.MultiChoice:
                    case SPFieldType.Choice:
                        columnSite = new SiteColumn(new ParamsSiteColumnChoices
                        {
                            Web = args.List.Web,
                            Name = args.Name,
                            FieldType = type,
                            Choices = args.Choice,
                            Group = args.Group,
                            AddPrefix = args.AddPrefix,
                            DisplayName = args.DisplayName
                        },
                           args.DefaultValue, args.Requiered);
                        break;
                    default:
                        columnSite = new SiteColumn(new ParamsSiteColumnDefaultValue
                        {
                            Web = args.List.Web,
                            Name = args.Name,
                            FieldType = type,
                            Requiered = args.Requiered,
                            Group = args.Group,
                            DefaultValue = args.DefaultValue,
                            MultiValue = args.MultiValue,
                            AddPrefix = args.AddPrefix,
                            DisplayName = args.DisplayName
                        });
                        break;
                }

                if (!args.List.ExistField(columnSite))
                {
                    args.List.AddField(columnSite);
                }

            }
        }

        private static SPFieldType GetFieldType(string fieldType)
        {

            SPFieldType result;
            GenerateCommand().TryGetValue(fieldType, out result);
            if (result == SPFieldType.Invalid) result = SPFieldType.Text;
            return result;
        }

        private static Dictionary<string, SPFieldType> GenerateCommand()
        {
            return new Dictionary<string, SPFieldType>
            {
                {Constants.FieldTypeColumns.Boolean,SPFieldType.Boolean},
                {Constants.FieldTypeColumns.Choice,SPFieldType.Choice},
                {Constants.FieldTypeColumns.MultiChoice,SPFieldType.MultiChoice},
                {Constants.FieldTypeColumns.DateTime,SPFieldType.DateTime},
                {Constants.FieldTypeColumns.Lookup,SPFieldType.User},
                {Constants.FieldTypeColumns.Note,SPFieldType.Note},
                {Constants.FieldTypeColumns.Number,SPFieldType.Number},
                {Constants.FieldTypeColumns.Currency,SPFieldType.Currency},
                {Constants.FieldTypeColumns.Url,SPFieldType.URL},
                {Constants.FieldTypeColumns.Calculated,SPFieldType.Calculated},
                {Constants.FieldTypeColumns.User,SPFieldType.User}
            };

        }
        #endregion
    }
}


text:
local BaseClass = require "NJLI.STATEMACHINE.NodeEntity"

local Switch = {}
Switch.__index = Switch

--#############################################################################
--DO NOT EDIT ABOVE
--#############################################################################

--#############################################################################
--Begin Custom Code
--Required local functions:
-- __ctor()
-- __dtor()
-- __load()
-- __unLoad()
--#############################################################################

local __ctor = function(self, init)
    assert(init, "init variable is nil.")
    assert(type(init) == "table", "Init variable is expecting a states table")
    assert(init.atlas ~= nil, "init.atlas variable is nil")
    assert(init.geometry ~= nil, "init.geometry variable is nil")

    self._touchUpOutside = init.touchUpOutside
    self._touchUpInside = init.touchUpInside
    self._touchDownInside = init.touchDownInside
    self._touchDragOutside = init.touchDragOutside
    self._touchDragInside = init.touchDragInside
    self._touchCancelled = init.touchCancelled

    self._scale = init.scale or 1.0
    self._disabled = init.disabled or false
    self._on = init.on or false

    local node = self:getNode()

    node:setGeometry(init.geometry)

    self._spriteFrameAtlas = init.atlas

    self._physicsShape = njli.PhysicsShapeBox.create()

    self._physicsBody = njli.PhysicsBodyRigid.create()
    self._physicsBody:setStaticPhysics()
    self._physicsBody:setPhysicsShape(self._physicsShape)

    node:setPhysicsBody(self._physicsBody)

    self._soundTouchUpOutside = njli.Sound.create()
    if init.soundTouchUpOutside and type(init.soundTouchUpOutside) == "string" then
        njli.World.getInstance():getWorldResourceLoader():load(init.soundTouchUpOutside, self._soundTouchUpOutside)
    end

    self._soundTouchUpInside = njli.Sound.create()
    if init.soundTouchUpInside and type(init.soundTouchUpInside) == "string" then
        njli.World.getInstance():getWorldResourceLoader():load(init.soundTouchUpInside, self._soundTouchUpInside)
    end

    self._soundTouchDownInside = njli.Sound.create()
    if init.soundTouchDownInside and type(init.soundTouchDownInside) == "string" then
        njli.World.getInstance():getWorldResourceLoader():load(init.soundTouchDownInside, self._soundTouchDownInside)
    end

    self._soundTouchDragOutside = njli.Sound.create()
    if init.soundTouchDragOutside and type(init.soundTouchDragOutside) == "string" then
        njli.World.getInstance():getWorldResourceLoader():load(init.soundTouchDragOutside, self._soundTouchDragOutside)
    end

    self._soundTouchDragInside = njli.Sound.create()
    if init.soundTouchDragInside and type(init.soundTouchDragInside) == "string" then
        njli.World.getInstance():getWorldResourceLoader():load(init.soundTouchDragInside, self._soundTouchDragInside)
    end

    self._soundTouchCancelled = njli.Sound.create()
    if init.soundTouchCancelled and type(init.soundTouchCancelled) == "string" then
        njli.World.getInstance():getWorldResourceLoader():load(init.soundTouchCancelled, self._soundTouchCancelled)
    end
end

local __dtor = function(self)

    njli.Sound.destroy(self._soundTouchUpOutside)
    self._soundTouchUpOutside = nil

    njli.Sound.destroy(self._soundTouchUpInside)
    self._soundTouchUpInside = nil

    njli.Sound.destroy(self._soundTouchDownInside)
    self._soundTouchDownInside = nil

    njli.Sound.destroy(self._soundTouchDragOutside)
    self._soundTouchDragOutside = nil

    njli.Sound.destroy(self._soundTouchDragInside)
    self._soundTouchDragInside = nil

    njli.Sound.destroy(self._soundTouchCancelled)
    self._soundTouchCancelled = nil

    njli.PhysicsBodyRigid.destroy(self._physicsBody)
    self._physicsBody = nil

    njli.PhysicsShapeBox.destroy(self._physicsShape)
    self._physicsShape = nil

    self._spriteFrameAtlas = nil

    self:getNode():removeGeometry()
end

local __load = function(self)
  --TODO: load this Entity
end

local __unLoad = function(self)
  --TODO: unload this Entity
end

--#############################################################################
--Switch Specific
--#############################################################################

function Switch:scale(s)
    if s ~= nil then
        self._scale = s
    end
    return self._scale
end

function Switch:disabled(b)
    if b ~= nil then

        self._disabled = b

        if self._disabled then
            self:pushState("NJLI.STATEMACHINE.UI.SWITCH.STATES.Disabled")
        else
            if self:on() then
                self:pushState("NJLI.STATEMACHINE.UI.SWITCH.STATES.On")
            else
                self:pushState("NJLI.STATEMACHINE.UI.SWITCH.STATES.Off")
            end
        end
    end

    return self._disabled
end

function Switch:on(b)
    if b ~= nil then

        self._on = b

        if self._on then
            self:pushState("NJLI.STATEMACHINE.UI.SWITCH.STATES.On")
        else
            self:pushState("NJLI.STATEMACHINE.UI.SWITCH.STATES.Off")
        end
    end

    return self._on
end

function Switch:setSpriteAtlasFrame(nodeStateName, match)
	local parts = nodeStateName:split("[^,%s]+")

	local name = nodeStateName
	if #parts ~= 1 then
		name = parts[1] .. parts[3]
	end
    self:getNode():getGeometry():setSpriteAtlasFrame(self:getNode(), self._spriteFrameAtlas, name, match)
end

function Switch:getDimensions()
    return self:getNode():getGeometry():getDimensions(self:getNode())
end

function Switch:setDimensions(dimension)
  self:getNode():getGeometry():setDimensions(self:getNode(), dimension)
  self._physicsShape:setHalfExtends(bullet.btVector3( dimension:x(), dimension:y(), 1.0 ))
end

function Switch:show(camera)
  self:getNode():show(camera)
end

function Switch:hide(camera)
  self:getNode():hide(camera)
end

function Switch:display(enable)
  if nil ~= enable and nil ~= OrthographicCameraNode and OrthographicCameraNode:getCamera() then
    if enable then
      self:show(OrthographicCameraNode:getCamera())
    else
      self:hide(OrthographicCameraNode:getCamera())
    end
  end
end

function Switch:touchUpOutside(touches)
    if not self._touchedUp then
        if self._touchUpOutside then
            self._touchUpOutside(touches)
        else
            print(self:getNode():getName() .. ":touchUpOutside")
        end
    end
    self._soundTouchUpOutside:play()
end

function Switch:touchUpInside(rayContact)
    if self._touchUpInside then
        self._touchUpInside(rayContact)
    else
        print(self:getNode():getName() .. ":touchUpInside")
    end
    self._touchedUp = true
    self._soundTouchUpInside:play()
end

function Switch:touchDownInside(rayContact)
    if self._touchDownInside then
        self._touchDownInside(rayContact)
    else
        print(self:getNode():getName() .. ":touchDownInside")
    end
    self._touchedUp = false
    self._soundTouchDownInside:play()
end

function Switch:touchDragOutside()
    if self._touchDragOutside then
        self._touchDragOutside()
    else
        print(self:getNode():getName() .. ":touchDragOutside")
    end
    self._soundTouchDragOutside:play()
end

function Switch:touchDragInside(rayContact)
    if self._touchDragInside then
        self._touchDragInside(rayContact)
    else
        print(self:getNode():getName() .. ":touchDragInside")
    end
    self._soundTouchDragInside:play()
end

function Switch:touchCancelled(rayContact)
    if self._touchCancelled then
        self._touchCancelled(rayContact)
    else
        print(self:getNode():getName() .. ":touchCancelled")
    end
    self._soundTouchCancelled:play()
end

--#############################################################################

function Switch:enter()
  BaseClass.enter(self)
end

function Switch:update(timeStep)
  BaseClass.update(self, timeStep)
end

function Switch:exit()
  BaseClass.exit(self)
end

function Switch:onMessage()
  BaseClass.onMessage(self)
end

function Switch:rayTouchesDown(rayContact)
  BaseClass.rayTouchesDown(self, rayContact)

  if not self:disabled() then
      self:touchDownInside(rayContact)
  end
end

function Switch:rayTouchesUp(rayContact)
  BaseClass.rayTouchesUp(self, rayContact)

  if not self:disabled() then
      self:touchUpInside(rayContact)
  end
end

function Switch:rayTouchesMove(rayContact)
  BaseClass.rayTouchesMove(self, rayContact)

  if not self:disabled() then
      self:touchDragInside(rayContact)
  end
end

function Switch:rayTouchesCancelled(rayContact)
  BaseClass.rayTouchesCancelled(self, rayContact)

  if not self:disabled() then
      self:touchCancelled(rayContact)
  end
end

function Switch:rayTouchesMissed(node)
  BaseClass.rayTouchesMissed(self, node)
end

function Switch:rayTouchDown(rayContact)
  BaseClass.rayTouchDown(self, rayContact)

  if not self:disabled() then
      self:touchDownInside(rayContact)
  end
end

function Switch:rayTouchUp(rayContact)
  BaseClass.rayTouchUp(self, rayContact)

  if not self:disabled() then
      self:touchUpInside(rayContact)
  end
end

function Switch:rayTouchMove(rayContact)
  BaseClass.rayTouchMove(self, rayContact)

  if not self:disabled() then
      self:touchDragInside(rayContact)
  end
end

function Switch:rayTouchCancelled(rayContact)
  BaseClass.rayTouchCancelled(self, rayContact)

  if not self:disabled() then
      self:touchCancelled(rayContact)
  end
end

function Switch:rayTouchMissed(node)
  BaseClass.rayTouchMissed(self, node)
end

function Switch:rayMouseDown(rayContact)
  BaseClass.rayMouseDown(self, rayContact)

  if not self:disabled() then
      self:touchDownInside(rayContact)
  end
end

function Switch:rayMouseUp(rayContact)
  BaseClass.rayMouseUp(self, rayContact)

  if not self:disabled() then
      self:touchUpInside(rayContact)
  end
end

function Switch:rayMouseMove(rayContact)
  BaseClass.rayMouseMove(self, rayContact)

  if not self:disabled() then
      self:touchDragInside(rayContact)
  end
end

function Switch:rayMouseMissed(node)
  BaseClass.rayMouseMissed(self, node)
end

function Switch:collide(otherNode, collisionPoint)
  BaseClass.collide(self, otherNode, collisionPoint)
end

function Switch:near(otherNode)
  BaseClass.near(self, otherNode)
end

function Switch:actionUpdate(action, timeStep)
  BaseClass.actionUpdate(self, action, timeStep)
end

function Switch:actionComplete(action)
  BaseClass.actionComplete(self, action)
end

function Switch:keyboardShow()
  BaseClass.keyboardShow(self)
end

function Switch:keyboardCancel()
  BaseClass.keyboardCancel(self)
end

function Switch:keyboardReturn()
    BaseClass.keyboardReturn(self)
end

function Switch:renderHUD()
    BaseClass.renderHUD(self)
end

function Switch:gamePause()
    BaseClass.gamePause(self)
end

function Switch:gameUnPause()
    BaseClass.gameUnPause(self)
end

function Switch:touchesDown(touches)
    BaseClass.touchesDown(self, touches)
end

function Switch:touchesUp(touches)
    BaseClass.touchesUp(self, touches)
end

function Switch:touchesMove(touches)
    BaseClass.touchesMove(self, touches)
end

function Switch:touchesCancelled(touches)
    BaseClass.touchesCancelled(self, touches)
end

function Switch:touchDown(touch)
    BaseClass.touchDown(self, touch)
end

function Switch:touchUp(touch)
    BaseClass.touchUp(self, touch)
end

function Switch:touchMove(touch)
    BaseClass.touchMove(self, touch)
end

function Switch:touchCancelled(touch)
    BaseClass.touchCancelled(self, touch)
end

function Switch:mouseDown(mouse)
    BaseClass.mouseDown(self, mouse)
end

function Switch:mouseUp(mouse)
    BaseClass.mouseUp(self, mouse)
end

function Switch:mouseMove(mouse)
    BaseClass.mouseMove(self, mouse)
end

--#############################################################################
--End Custom Code
--#############################################################################

--#############################################################################
--DO NOT EDIT BELOW
--#############################################################################

setmetatable(Switch, {
    __index = BaseClass,
    __call = function (cls, ...)
      local self = setmetatable({}, cls)
      --Create the base first
      BaseClass._create(self, ...)
      self:_create(...)
      return self
    end,
  })

function Switch:className()
  return "Switch"
end

function Switch:class()
  return self
end

function Switch:superClass()
  return BaseClass
end

function Switch:__gc()
  --Destroy derived class first
  Switch._destroy(self)
  --Destroy base class after derived class
  BaseClass._destroy(self)
end

function Switch:__tostring()
  local ret = self:className() .. " =\n{\n"

  for pos,val in pairs(self) do
    ret = ret .. "\t" .. "["..pos.."]" .. " => " .. type(val) .. " = " .. tostring(val) .. "\n"
  end

  ret = ret .. "\n\t" .. tostring_r(BaseClass) .. "\n}"
  return ret .. "\n\t" .. tostring_r(getmetatable(self)) .. "\n}"
end

function Switch:_destroy()
  assert(not self.__ButtonCalledLoad, "Must unload before you destroy")
  __dtor(self)
end

function Switch:_create(init)
  self.__ButtonCalledLoad = false
  __ctor(self, init)
end

function Switch:load()
  --load base first
  BaseClass.load(self)

  --load derived last...
  __load(self)

  self.__ButtonCalledLoad = true
end

function Switch:unLoad()
  assert(self.__ButtonCalledLoad, "Must load before unloading")

  --unload derived first...
  __unLoad(self)
  self.__ButtonCalledLoad = false

  --unload base last...
  BaseClass.unLoad(self)
end

return Switch


text:
var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var babel = require('gulp-babel');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');

gulp.task('default', ['compile', 'min']);

gulp.task('watch', function () {
  gulp.watch('src/**/*.js', ['compile', 'min']);
})

gulp.task('compile', function () {
  return gulp.src('src/**/*.js')
    .pipe(sourcemaps.init())
    .pipe(babel())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist'));
});

gulp.task('min', function () {
  return gulp.src('src/**/*.js')
    .pipe(sourcemaps.init())
    .pipe(babel())
    .pipe(uglify())
    .pipe(rename('BoolMap.min.js'))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist'));
});


text:
from inspectors.extensions import db
from inspectors.app import create_app
from pprint import pprint

from inspectors.inspections.models import Inspection
from inspectors.registration.models import User
from inspectors.registration.mock import make_generator

def run():
    app = create_app()
    with app.app_context():
        fake = make_generator()
        users = fake.inspections_users(40)
        for u in users:
            db.session.add(u)
        db.session.commit()

if __name__ == '__main__':
    run()


text:
package org.apache.camel.component.cxf;

import org.apache.camel.CamelContext;
import org.apache.camel.component.cxf.common.CXFTestSupport;
import org.apache.camel.component.cxf.common.DataFormat;
import org.apache.camel.component.cxf.jaxws.CxfEndpoint;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * Unit test to verify using '#' notation to reference serviceClass.
 */
@ContextConfiguration
@ExtendWith(SpringExtension.class)
public class ServiceClassRefTest {

    static {
        CXFTestSupport.getPort1();
    }

    @Autowired
    protected CamelContext context;

    @Test
    public void testServiceClassNameCreatedByRefNotation() throws Exception {
        // verify the '#' notation works
        CxfEndpoint endpoint = context.getEndpoint("cxf:bean:fromEndpoint", CxfEndpoint.class);
        assertEquals("org.apache.camel.component.cxf.HelloServiceImpl",
                endpoint.getServiceClass().getName());
        assertEquals(DataFormat.POJO, endpoint.getDataFormat());

        // verify values in bean properties are ok
        endpoint = context.getEndpoint("cxf:bean:fromEndpointWithProps", CxfEndpoint.class);
        assertEquals(DataFormat.PAYLOAD, endpoint.getDataFormat());
    }

}


text:
All the values from the Material Design guidelines defined in resources for Android.

---

## Documentation

All the values in this documentation use the xml reference representation.

You can also use them programmatically using `material.values.R`

For example:

| Xml reference | Code reference |
| :--- | :--- |
| `@color/material_color_green_primary`                | `R.color.material_color_green_primary`
| `@dimen/material_list_two_line_dense_height`         | `R.dimen.material_list_two_line_dense_height`
| `@dimen/material_elevation_card_raised`              | `R.dimen.material_elevation_card_raised`
| `@dimen/material_typography_regular_title_text_size` | `R.dimen.material_typography_regular_title_text_size`

---

## Missing values

If a section of the Material Design specs is not included, it may be because it has no values or is only available on desktop.

Note that the values for the following components are not available as they are already well implemented in Android:

- Selection controls
- Sliders
- Snackbars & toasts
- Tabs
- Text fields

---

## Disclaimer

Most of the visuals come directly from the [Material design specifications](https://material.google.com), and are property of Google.


text:
module Sequel
  class Dataset
    # ---------------------
    # :section: 6 - Miscellaneous methods
    # These methods don't fit cleanly into another section.
    # ---------------------

    NOTIMPL_MSG = "This method must be overridden in Sequel adapters".freeze
    ARRAY_ACCESS_ERROR_MSG = 'You cannot call Dataset#[] with an integer or with no arguments.'.freeze
    ARG_BLOCK_ERROR_MSG = 'Must use either an argument or a block, not both'.freeze
    IMPORT_ERROR_MSG = 'Using Sequel::Dataset#import an empty column array is not allowed'.freeze

    # The database related to this dataset.  This is the Database instance that
    # will execute all of this dataset's queries.
    attr_reader :db

    # The hash of options for this dataset, keys are symbols.
    attr_reader :opts

    # Constructs a new Dataset instance with an associated database and
    # options. Datasets are usually constructed by invoking the Database#[] method:
    #
    #   DB[:posts]
    #
    # Sequel::Dataset is an abstract class that is not useful by itself. Each
    # database adapter provides a subclass of Sequel::Dataset, and has
    # the Database#dataset method return an instance of that subclass.
    def initialize(db)
      @db = db
      @opts = OPTS
    end

    # Define a hash value such that datasets with the same DB, opts, and SQL
    # will be considered equal.
    def ==(o)
      o.is_a?(self.class) && db == o.db && opts == o.opts && sql == o.sql
    end

    # An object representing the current date or time, should be an instance
    # of Sequel.datetime_class.
    def current_datetime
      Sequel.datetime_class.now
    end

    # Alias for ==
    def eql?(o)
      self == o
    end

    # Similar to #clone, but returns an unfrozen clone if the receiver is frozen.
    def dup
      o = clone
      o.opts.delete(:frozen)
      o
    end

    # Yield a dataset for each server in the connection pool that is tied to that server.
    # Intended for use in sharded environments where all servers need to be modified
    # with the same data:
    #
    #   DB[:configs].where(:key=>'setting').each_server{|ds| ds.update(:value=>'new_value')}
    def each_server
      db.servers.each{|s| yield server(s)}
    end

    # Returns the string with the LIKE metacharacters (% and _) escaped.
    # Useful for when the LIKE term is a user-provided string where metacharacters should not
    # be recognized. Example:
    #
    #   ds.escape_like("foo\\%_") # 'foo\\\%\_'
    def escape_like(string)
      string.gsub(/[\\%_]/){|m| "\\#{m}"}
    end

    # Sets the frozen flag on the dataset, so you can't modify it. Returns the receiver.
    def freeze
      @opts[:frozen] = true
      self
    end

    # Whether the object is frozen.
    def frozen?
      @opts[:frozen]
    end

    # Alias of +first_source_alias+
    def first_source
      first_source_alias
    end

    # The first source (primary table) for this dataset.  If the dataset doesn't
    # have a table, raises an +Error+.  If the table is aliased, returns the aliased name.
    #
    #   DB[:table].first_source_alias
    #   # => :table
    #
    #   DB[:table___t].first_source_alias
    #   # => :t
    def first_source_alias
      source = @opts[:from]
      if source.nil? || source.empty?
        raise Error, 'No source specified for query'
      end
      case s = source.first
      when SQL::AliasedExpression
        s.alias
      when Symbol
        _, _, aliaz = split_symbol(s)
        aliaz ? aliaz.to_sym : s
      else
        s
      end
    end

    # The first source (primary table) for this dataset.  If the dataset doesn't
    # have a table, raises an error.  If the table is aliased, returns the original
    # table, not the alias
    #
    #   DB[:table].first_source_table
    #   # => :table
    #
    #   DB[:table___t].first_source_table
    #   # => :table
    def first_source_table
      source = @opts[:from]
      if source.nil? || source.empty?
        raise Error, 'No source specified for query'
      end
      case s = source.first
      when SQL::AliasedExpression
        s.expression
      when Symbol
        sch, table, aliaz = split_symbol(s)
        aliaz ? (sch ? SQL::QualifiedIdentifier.new(sch, table) : table.to_sym) : s
      else
        s
      end
    end

    # Define a hash value such that datasets with the same DB, opts, and SQL
    # will have the same hash value
    def hash
      [db, opts, sql].hash
    end

    # The String instance method to call on identifiers before sending them to
    # the database.
    def identifier_input_method
      if defined?(@identifier_input_method)
        @identifier_input_method
      else
        @identifier_input_method = db.identifier_input_method
      end
    end

    # The String instance method to call on identifiers before sending them to
    # the database.
    def identifier_output_method
      if defined?(@identifier_output_method)
        @identifier_output_method
      else
        @identifier_output_method = db.identifier_output_method
      end
    end

    # Returns a string representation of the dataset including the class name
    # and the corresponding SQL select statement.
    def inspect
      "#<#{visible_class_name}: #{sql.inspect}>"
    end

    # The alias to use for the row_number column, used when emulating OFFSET
    # support and for eager limit strategies
    def row_number_column
      :x_sequel_row_number_x
    end

    # Splits a possible implicit alias in +c+, handling both SQL::AliasedExpressions
    # and Symbols.  Returns an array of two elements, with the first being the
    # main expression, and the second being the alias.
    def split_alias(c)
      case c
      when Symbol
        c_table, column, aliaz = split_symbol(c)
        [c_table ? SQL::QualifiedIdentifier.new(c_table, column.to_sym) : column.to_sym, aliaz]
      when SQL::AliasedExpression
        [c.expression, c.alias]
      when SQL::JoinClause
        [c.table, c.table_alias]
      else
        [c, nil]
      end
    end

    # Creates a unique table alias that hasn't already been used in the dataset.
    # table_alias can be any type of object accepted by alias_symbol.
    # The symbol returned will be the implicit alias in the argument,
    # possibly appended with "_N" if the implicit alias has already been
    # used, where N is an integer starting at 0 and increasing until an
    # unused one is found.
    #
    # You can provide a second addition array argument containing symbols
    # that should not be considered valid table aliases.  The current aliases
    # for the FROM and JOIN tables are automatically included in this array.
    #
    #   DB[:table].unused_table_alias(:t)
    #   # => :t
    #
    #   DB[:table].unused_table_alias(:table)
    #   # => :table_0
    #
    #   DB[:table, :table_0].unused_table_alias(:table)
    #   # => :table_1
    #
    #   DB[:table, :table_0].unused_table_alias(:table, [:table_1, :table_2])
    #   # => :table_3
    def unused_table_alias(table_alias, used_aliases = [])
      table_alias = alias_symbol(table_alias)
      used_aliases += opts[:from].map{|t| alias_symbol(t)} if opts[:from]
      used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
      if used_aliases.include?(table_alias)
        i = 0
        loop do
          ta = :"#{table_alias}_#{i}"
          return ta unless used_aliases.include?(ta)
          i += 1
        end
      else
        table_alias
      end
    end

    private

    # Return the class name for this dataset, but skip anonymous classes
    def visible_class_name
      c = self.class
      c = c.superclass while c.name.nil? || c.name == ''
      c.name
    end
  end
end


text:
<?php declare(strict_types = 1);

namespace Nextras\Orm\Exception;

class InvalidStateException extends RuntimeException
{
}


text:
This is a custom Uptime plugin for Slack. The main function of this plugin
is to send Uptime notifications (up/down/pause/start/etc.) to Slack through
its incoming message API.

- Uptime: https://github.com/fzaninotto/uptime
- Slack: https://slack.com/

## Getting Started

To install the plugin, you have to install Uptime first, and then execute the
following commands.

```shell
$ cd /path/to/your/uptime/installation/folder
$ git clone git@github.com:waltzofpearls/uptime-plugin-slack.git plugins/slack
# Read the next section for plugin configuration first, then properly enable
# and configure the plugin, and then restart Uptime app.
```

## Configuration

In config file `config/production.yaml`, add the following line under `plugins`
to enable the geckoboard plugin.

```yaml
  - ./plugins/slack
```

Also add the following geckoboard config to `config/production.yaml`.

```yaml
slack:
  webhook: [slack webhook url]
  channel: '[slack channel name]' # default '#general'
  username: [slack username] # default 'Uptime Alert'
  icon_emoji: [emoji icon for [username]] # default ':turtle:'
  icon_url: [optional, icon_url for [username]] # default empty, icon_url overrides icon_emoji
  event:
    up:        true
    down:      true
    paused:    false
    restarted: false
```

Restart Uptime app after changing the configuration.

## License

The MIT License (MIT)

Copyright (c) 2015 Rollie Ma @ Topbass Labs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


text:
=head1 NAME

DNSEVAL - look up URLs against DNS blocklists

=head1 SYNOPSIS

 loadplugin Mail::SpamAssassin::Plugin::DNSEval

 rbl_headers EnvelopeFrom,Reply-To,Disposition-Notification-To
 header     RBL_IP    eval:check_rbl_headers('rbl', 'rbl.example.com.', '127.0.0.2')
 describe   RBL_IP    From address associated with spam domains
 tflags     RBL_IP    net
 reuse      RBL_IP

 Supported extra tflags from SpamAssassin 3.4.3:
  domains_only - only non-IP-address "host" components are queried
  ips_only - only IP addresses as the "host" component will be queried

=head1 DESCRIPTION

The DNSEval plugin queries dns to see if a domain or an ip address
present on one of email's headers is on a particular rbl.

=cut

package Mail::SpamAssassin::Plugin::DNSEval;

use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::Logger;
use Mail::SpamAssassin::Constants qw(:ip);
use Mail::SpamAssassin::Util qw(reverse_ip_address idn_to_ascii compile_regexp is_fqdn_valid);

use strict;
use warnings;
# use bytes;
use re 'taint';

our @ISA = qw(Mail::SpamAssassin::Plugin);

my $IP_ADDRESS = IP_ADDRESS;

# constructor: register the eval rule
sub new {
  my $class = shift;
  my $mailsaobject = shift;

  # some boilerplate...
  $class = ref($class) || $class;
  my $self = $class->SUPER::new($mailsaobject);
  bless ($self, $class);

  # this is done this way so that the same list can be used here and in
  # check_start()
  $self->{'evalrules'} = [
    'check_rbl_accreditor',
    'check_rbl',
    'check_rbl_ns_from',
    'check_rbl_txt',
    'check_rbl_sub',
    'check_rbl_from_host',
    'check_rbl_from_domain',
    'check_rbl_envfrom',
    'check_rbl_headers',
    'check_rbl_rcvd',
    'check_dns_sender',
  ];

  $self->set_config($mailsaobject->{conf});
  foreach(@{$self->{'evalrules'}}) {
    $self->register_eval_rule($_, $Mail::SpamAssassin::Conf::TYPE_RBL_EVALS);
  }

  return $self;
}

=head1 USER PREFERENCES

The following options can be used in both site-wide (C<local.cf>) and
user-specific (C<user_prefs>) configuration files to customize how
SpamAssassin handles incoming email messages.

=over

=item rbl_headers

 This option tells SpamAssassin in which headers to check for content
 used to query the specified rbl.
 If on the headers content there is an email address, an ip address
 or a domain name, it will be checked on the specified rbl.
 The configuration option can be overridden by passing an headers list as
 last parameter to check_rbl_headers.
 The default headers checked are:

=back

=over

=item *

EnvelopeFrom

=item *

Reply-To

=item *

Disposition-Notification-To

=item *

X-WebmailclientIP

=item *

X-Source-IP

=back

=cut

sub set_config {
    my ($self, $conf) = @_;
    my @cmds;
    push(@cmds, {
        setting => 'rbl_headers',
        default => 'EnvelopeFrom,Reply-To,Disposition-Notification-To,X-WebmailclientIP,X-Source-IP',
        type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
        }
    );
    $conf->{parser}->register_commands(\@cmds);
}

# this is necessary because PMS::run_rbl_eval_tests() calls these functions
# directly as part of PMS
sub check_start {
  my ($self, $opts) = @_;
  my $pms = $opts->{permsgstatus};

  foreach(@{$self->{'evalrules'}}) {
    $pms->register_plugin_eval_glue($_);
  }

  # Initialize check_rbl_sub tests
  $self->_init_rbl_subs($pms);
}

sub _init_rbl_subs {
  my ($self, $pms) = @_;
  my $conf = $pms->{conf};

  # Very hacky stuff and direct rbl_evals usage for now, TODO rewrite everything
  foreach my $rule (@{$conf->{eval_to_rule}->{check_rbl_sub}||[]}) {
    next if !exists $conf->{rbl_evals}->{$rule};
    next if !$conf->{scores}->{$rule};
    # rbl_evals is [$function,[@args]]
    my $args = $conf->{rbl_evals}->{$rule}->[1];
    my ($set, $subtest) = @$args;
    if (!defined $subtest) {
      warn("dnseval: missing subtest for rule $rule\n");
      next;
    }
    if ($subtest =~ /^sb:/) {
      warn("dnseval: ignored $rule, SenderBase rules are deprecated\n");
      next;
    }
    # Compile as regex if not pure ip/bitmask (same check in process_dnsbl_result)
    if ($subtest !~ /^\d+(?:\.\d+\.\d+\.\d+)?$/) {
      my ($rec, $err) = compile_regexp($subtest, 0);
      if (!$rec) {
        warn("dnseval: invalid rule $rule subtest regexp '$subtest': $err\n");
        next;
      }
      $subtest = $rec;
    }
    dbg("dnseval: initialize check_rbl_sub for rule $rule, set $set, subtest $subtest");
    push @{$pms->{rbl_subs}{$set}}, [$subtest, $rule];
  }
}

sub parsed_metadata {
  my ($self, $opts) = @_;

  my $pms = $opts->{permsgstatus};

  return 1 if $self->{main}->{conf}->{skip_rbl_checks};
  return 1 if !$pms->is_dns_available();

  # Process relaylists only once, not everytime in check_rbl_backend
  #
  # ok, make a list of all the IPs in the untrusted set
  my @fullips = map { $_->{ip} } @{$pms->{relays_untrusted}};
  # now, make a list of all the IPs in the external set, for use in
  # notfirsthop testing.  This will often be more IPs than found
  # in @fullips.  It includes the IPs that are trusted, but
  # not in internal_networks.
  my @fullexternal = map {
	(!$_->{internal}) ? ($_->{ip}) : ()
      } @{$pms->{relays_trusted}};
  push @fullexternal, @fullips; # add untrusted set too
  # Make sure a header significantly improves results before adding here
  # X-Sender-Ip: could be worth using (very low occurence for me)
  # X-Sender: has a very low bang-for-buck for me
  my @originating;
  foreach my $header (@{$pms->{conf}->{originating_ip_headers}}) {
    my $str = $pms->get($header, undef);
    next unless defined $str && $str ne '';
    push @originating, ($str =~ m/($IP_ADDRESS)/g);
  }
  # Let's go ahead and trim away all private ips (KLC)
  # also uniq the list and strip dups. (jm)
  my @ips = $self->ip_list_uniq_and_strip_private(@fullips);
  # if there's no untrusted IPs, it means we trust all the open-internet
  # relays, so we skip checks
  if (scalar @ips + scalar @originating > 0) {
    dbg("dnseval: IPs found: full-external: ".join(", ", @fullexternal).
      " untrusted: ".join(", ", @ips).
      " originating: ".join(", ", @originating));
    @{$pms->{dnseval_fullexternal}} = @fullexternal;
    @{$pms->{dnseval_ips}} = @ips;
    @{$pms->{dnseval_originating}} = @originating;
  }

  return 1;
}

sub ip_list_uniq_and_strip_private {
  my ($self, @origips) = @_;
  my @ips;
  my %seen;
  foreach my $ip (@origips) {
    next unless $ip;
    next if exists $seen{$ip};
    $seen{$ip} = 1;
    next if $ip =~ IS_IP_PRIVATE;
    push(@ips, $ip);
  }
  return @ips;
}

# check an RBL if the message contains an "accreditor assertion,"
# that is, the message contains the name of a service that will vouch
# for their practices.
#
sub check_rbl_accreditor {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest, $accreditor) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  if (!defined $pms->{accreditor_tag}) {
    $self->message_accreditor_tag($pms);
  }
  if ($pms->{accreditor_tag}->{$accreditor}) {
    # return undef for async status
    return $self->_check_rbl_backend($pms, $rule, $set, $rbl_server, 'A', $subtest);
  }

  return 0;
}

# Check for an Accreditor Assertion within the message, that is, the name of
#	a third-party who will vouch for the sender's practices. The accreditor
#	can be asserted in the EnvelopeFrom like this:
#
#	    listowner@a--accreditor.mail.example.com
#
#	or in an 'Accreditor" Header field, like this:
#
#	    Accreditor: accreditor1, parm=value; accreditor2, parm-value
#
#	This implementation supports multiple accreditors, but ignores any
#	parameters in the header field.
#
sub message_accreditor_tag {
  my ($self, $pms) = @_;
  my %acctags;

  if ($pms->get('EnvelopeFrom:addr') =~ /[@.]a--([a-z0-9]{3,})\./i) {
    (my $tag = $1) =~ tr/A-Z/a-z/;
    $acctags{$tag} = -1;
  }
  my $accreditor_field = $pms->get('Accreditor',undef);
  if (defined $accreditor_field) {
    my @accreditors = split(/,/, $accreditor_field);
    foreach my $accreditor (@accreditors) {
      my @terms = split(' ', $accreditor);
      if ($#terms >= 0) {
	  my $tag = $terms[0];
	  $tag =~ tr/A-Z/a-z/;
	  $acctags{$tag} = -1;
      }
    }
  }
  $pms->{accreditor_tag} = \%acctags;
}

sub _check_rbl_backend {
  my ($self, $pms, $rule, $set, $rbl_server, $type, $subtest) = @_;

  return if !exists $pms->{dnseval_ips}; # no untrusted ips

  $rbl_server =~ s/\.+\z//; # strip unneeded trailing dot
  dbg("dnseval: checking RBL $rbl_server, set $set, rule $rule");

  my $trusted = $self->{main}->{conf}->{trusted_networks};
  my @ips = @{$pms->{dnseval_ips}};

  # If name is foo-notfirsthop, check all addresses except for
  # the originating one.  Suitable for use with dialup lists, like the PDL.
  # note that if there's only 1 IP in the untrusted set, do NOT pop the
  # list, since it'd remove that one, and a legit user is supposed to
  # use their SMTP server (ie. have at least 1 more hop)!
  # If name is foo-lastexternal, check only the Received header just before
  # it enters our internal networks; we can trust it and it's the one that
  # passed mail between networks
  if ($set =~ /-(notfirsthop|lastexternal)$/)
  {
    # use the external IP set, instead of the trusted set; the user may have
    # specified some third-party relays as trusted.  Also, don't use
    # @originating; those headers are added by a phase of relaying through
    # a server like Hotmail, which is not going to be in dialup lists anyway.
    @ips = $self->ip_list_uniq_and_strip_private(@{$pms->{dnseval_fullexternal}});
    if ($1 eq "lastexternal") {
      @ips = defined $ips[0] ? ($ips[0]) : ();
    } else {
	pop @ips if (scalar @ips > 1);
    }
  }
  # If name is foo-firsttrusted, check only the Received header just
  # after it enters our trusted networks; that's the only one we can
  # trust the IP address from (since our relay added that header).
  # And if name is foo-untrusted, check any untrusted IP address.
  elsif ($set =~ /-(first|un)trusted$/)
  {
    my @tips;
    foreach my $ip (@{$pms->{dnseval_originating}}) {
      if ($ip && !$trusted->contains_ip($ip)) {
        push(@tips, $ip);
      }
    }
    @ips = $self->ip_list_uniq_and_strip_private(@ips, @tips);
    if ($1 eq "first") {
      @ips = defined $ips[0] ? ($ips[0]) : ();
    } else {
      shift @ips;
    }
  }
  else
  {
    my @tips;
    foreach my $ip (@{$pms->{dnseval_originating}}) {
      if ($ip && !$trusted->contains_ip($ip)) {
        push(@tips, $ip);
      }
    }

    # add originating IPs as untrusted IPs (if they are untrusted)
    @ips = reverse $self->ip_list_uniq_and_strip_private (@ips, @tips);
  }

  # How many IPs max you check in the received lines
  my $checklast = $self->{main}->{conf}->{num_check_received};

  if (scalar @ips > $checklast) {
    splice (@ips, $checklast);	# remove all others
  }

  # Trusted relays should only be checked against nice rules (dnswls)
  if (($pms->{conf}->{tflags}->{$rule}||'') !~ /\bnice\b/) {
    # remove trusted hosts from beginning
    while (@ips && $trusted->contains_ip($ips[0])) { shift @ips }
  }

  unless (scalar @ips > 0) {
    dbg("dnseval: no untrusted IPs to check");
    return 0;
  }

  dbg("dnseval: only inspecting the following IPs: ".join(", ", @ips));

  my $queries;
  foreach my $ip (@ips) {
    if (defined(my $revip = reverse_ip_address($ip))) {
      my $ret = $pms->do_rbl_lookup($rule, $set, $type, $revip.'.'.$rbl_server, $subtest);
      $queries++ if defined $ret;
    }
  }

  # note that results are not handled here, hits are handled directly
  # as DNS responses are harvested
  return 0 if !$queries; # no query started
  return; # return undef for async status
}

sub check_rbl {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  # return undef for async status
  return $self->_check_rbl_backend($pms, $rule, $set, $rbl_server, 'A', $subtest);
}

sub check_rbl_txt {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  # return undef for async status
  return $self->_check_rbl_backend($pms, $rule, $set, $rbl_server, 'TXT', $subtest);
}

sub check_rbl_sub {
  my ($self, $pms, $rule, $set, $subtest) = @_;
  # just a dummy, _init_rbl_subs/do_rbl_lookup handles the subs

  return; # return undef for async status
}

# this only checks the address host name and not the domain name because
# using the domain name had much worse results for dsn.rfc-ignorant.org
sub check_rbl_from_host {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  # return undef for async status
  return $self->_check_rbl_addresses($pms, $rule, $set, $rbl_server,
                                     $subtest, $pms->all_from_addrs());
}

sub check_rbl_headers {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest, $test_headers) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  my @env_hdr;
  my $conf = $self->{main}->{conf};

  if ( defined $test_headers ) {
    @env_hdr = split(/,/, $test_headers);
  } else {
    @env_hdr = split(/,/, $conf->{rbl_headers});
  }

  my $queries;
  foreach my $rbl_headers (@env_hdr) {
    my $addr = $pms->get($rbl_headers.':addr', undef);
    if ( defined $addr && $addr =~ /\@([^\@\s]+)/ ) {
      my $ret = $self->_check_rbl_addresses($pms, $rule, $set, $rbl_server,
                                            $subtest, $addr);
      $queries++ if defined $ret;
    } else {
      my $unsplitted_host = $pms->get($rbl_headers);
      chomp($unsplitted_host);
      foreach my $host (split(/\n/, $unsplitted_host)) {
        if ($host =~ IS_IP_ADDRESS) {
          next if ($conf->{tflags}->{$rule}||'') =~ /\bdomains_only\b/;
          $host = reverse_ip_address($host);
        } else {
          next if ($conf->{tflags}->{$rule}||'') =~ /\bips_only\b/;
          next unless is_fqdn_valid($host);
          next unless $pms->{main}->{registryboundaries}->is_domain_valid($host);
        }
        my $ret = $pms->do_rbl_lookup($rule, $set, 'A', "$host.$rbl_server", $subtest);
        $queries++ if defined $ret;
      }
    }
  }

  return 0 if !$queries; # no query started
  return; # return undef for async status
}

=over 4

=item check_rbl_from_domain

This checks all the from addrs domain names as an alternate to
check_rbl_from_host.  As of v3.4.1, it has been improved to include a
subtest for a specific octet.

=back

=cut

sub check_rbl_from_domain {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  # return undef for async status
  return $self->_check_rbl_addresses($pms, $rule, $set, $rbl_server,
                                     $subtest, $pms->all_from_addrs_domains());
}
=over 4

=item check_rbl_ns_from

This checks the dns server of the from addrs domain name.
It is possible to include a subtest for a specific octet.

=back

=cut

sub check_rbl_ns_from {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;
  my $domain;
  my @nshost = ();

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 unless $pms->is_dns_available();

  dbg("dnseval: EnvelopeFrom header not found") unless defined (($pms->get("EnvelopeFrom:addr"))[0]);
  for my $from ($pms->get('EnvelopeFrom:addr')) {
    next unless defined $from;
    $from =~ tr/././s;          # bug 3366
    if ($from =~ m/ \@ ( [^\@\s]+ \. [^\@\s]+ )/x ) {
      $domain = lc($1);
      last;
    }
  }
  return 0 unless defined $domain;

  dbg("dnseval: checking NS for host $domain");

  my $obj = { dom => $domain, rule => $rule, set => $set, rbl_server => $rbl_server, subtest => $subtest };
  my $ent = {
    rulename => $rule, zone => $domain, obj => $obj, type => "URI-NS",
  };
  # dig $dom ns
  my $ret = $pms->{async}->bgsend_and_start_lookup(
    $domain, 'NS', undef, $ent,
    sub { my ($ent2,$pkt) = @_;
          $self->complete_ns_lookup($pms, $ent2, $pkt, $domain) },
    master_deadline => $pms->{master_deadline} );
  return 0 if !defined $ret; # no query started
  return; # return undef for async status
}

sub complete_ns_lookup {
  my ($self, $pms, $ent, $pkt, $host) = @_;

  my $rule = $ent->{obj}->{rule};
  my $set = $ent->{obj}->{set};
  my $rbl_server = $ent->{obj}->{rbl_server};
  my $subtest = $ent->{obj}->{subtest};

  if (!$pkt) {
    # $pkt will be undef if the DNS query was aborted (e.g. timed out)
    dbg("dnseval: complete_ns_lookup aborted %s", $ent->{key});
    return;
  }

  dbg("dnseval: complete_ns_lookup %s", $ent->{key});
  my @ns = $pkt->authority;

  foreach my $rr (@ns) {
    my $nshost = $rr->mname;
    next unless defined $nshost;
    chomp($nshost);
    if (is_fqdn_valid($nshost)) {
      if ( defined $subtest ) {
        dbg("dnseval: checking [$nshost] / $rule / $set / $rbl_server / $subtest");
      } else {
        dbg("dnseval: checking [$nshost] / $rule / $set / $rbl_server");
      }
      $pms->do_rbl_lookup($rule, $set, 'A',
        "$nshost.$rbl_server", $subtest);
    }
  }
}

=over 4

=item check_rbl_rcvd

This checks all received headers domains or ip addresses against a specific rbl.
It is possible to include a subtest for a specific octet.

=back

=cut

sub check_rbl_rcvd {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;
  my %seen;
  my @udnsrcvd = ();

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  my $rcvd = $pms->{relays_untrusted}->[$pms->{num_relays_untrusted} - 1];
  my @dnsrcvd = ( $rcvd->{ip}, $rcvd->{by}, $rcvd->{helo}, $rcvd->{rdns} );
  # unique values
  foreach my $value (@dnsrcvd) {
    if ( ( defined $value ) && (! $seen{$value}++ ) ) {
      push @udnsrcvd, $value;
    }
  }

  my $queries;
  foreach my $host ( @udnsrcvd ) {
    if((defined $host) and ($host ne "")) {
      chomp($host);
      if ($host =~ IS_IP_ADDRESS) {
        next if ($pms->{conf}->{tflags}->{$rule}||'') =~ /\bdomains_only\b/;
        $host = reverse_ip_address($host);
      } else {
        next if ($pms->{conf}->{tflags}->{$rule}||'') =~ /\bips_only\b/;
        $host =~ s/\.$//;
        next unless is_fqdn_valid($host);
        next unless $pms->{main}->{registryboundaries}->is_domain_valid($host);
      }
      if ( defined $subtest ) {
        dbg("dnseval: checking [$host] / $rule / $set / $rbl_server / $subtest");
      } else {
        dbg("dnseval: checking [$host] / $rule / $set / $rbl_server");
      }
      my $ret = $pms->do_rbl_lookup($rule, $set, 'A', "$host.$rbl_server", $subtest);
      $queries++ if defined $ret;
    }
  }

  return 0 if !$queries; # no query started
  return; # return undef for async status
}

# this only checks the address host name and not the domain name because
# using the domain name had much worse results for dsn.rfc-ignorant.org
sub check_rbl_envfrom {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  # return undef for async status
  return $self->_check_rbl_addresses($pms, $rule, $set, $rbl_server,
                                 $subtest, $pms->get('EnvelopeFrom:addr',undef));
}

sub _check_rbl_addresses {
  my ($self, $pms, $rule, $set, $rbl_server, $subtest, @addresses) = @_;

  $rbl_server =~ s/\.+\z//; # strip unneeded trailing dot

  my %hosts;
  for (@addresses) {
    next if !defined($_) || !/\@([^\@\s]+)/;
    my $address = $1;
    # strip leading & trailing dots (as seen in some e-mail addresses)
    $address =~ s/^\.+//;
    $address =~ s/\.+\z//;
    # squash duplicate dots to avoid an invalid DNS query with a null label
    # Also checks it's FQDN
    if ($address =~ tr/.//s) {
      $hosts{lc($address)} = 1;
    }
  }
  return unless scalar keys %hosts;

  my $queries;
  for my $host (keys %hosts) {
    if ($host =~ IS_IP_ADDRESS) {
      next if ($pms->{conf}->{tflags}->{$rule}||'') =~ /\bdomains_only\b/;
      $host = reverse_ip_address($host);
    } else {
      next if ($pms->{conf}->{tflags}->{$rule}||'') =~ /\bips_only\b/;
      next unless is_fqdn_valid($host);
      next unless $pms->{main}->{registryboundaries}->is_domain_valid($host);
    }
    dbg("dnseval: checking [$host] / $rule / $set / $rbl_server");
    my $ret = $pms->do_rbl_lookup($rule, $set, 'A', "$host.$rbl_server", $subtest);
    $queries++ if defined $ret;
  }

  return 0 if !$queries; # no async
  return; # return undef for async status
}

sub check_dns_sender {
  my ($self, $pms, $rule) = @_;

  return 0 if $self->{main}->{conf}->{skip_rbl_checks};
  return 0 if !$pms->is_dns_available();

  my $host;
  foreach my $from ($pms->get('EnvelopeFrom:addr', undef)) {
    next unless defined $from;
    $from =~ tr/.//s; # bug 3366
    if ($from =~ m/\@([^\@\s]+\.[^\@\s]+)/) {
      $host = lc($1);
      last;
    }
  }
  return 0 unless defined $host;

  if ($host eq 'compiling.spamassassin.taint.org') {
    # only used when compiling
    return 0;
  }

  $host = idn_to_ascii($host);
  dbg("dnseval: checking A and MX for host $host");

  my $queries;
  my $ret = $self->do_sender_lookup($pms, $rule, 'A', $host);
  $queries++ if defined $ret;
  $ret = $self->do_sender_lookup($pms, $rule, 'MX', $host);
  $queries++ if defined $ret;

  return 0 if !$queries; # no query started
  return; # return undef for async status
}

sub do_sender_lookup {
  my ($self, $pms, $rule, $type, $host) = @_;

  my $ent = {
    rulename => $rule,
    type => "DNSBL-Sender",
  };
  return $pms->{async}->bgsend_and_start_lookup(
    $host, $type, undef, $ent, sub {
      my ($ent, $pkt) = @_;
      return if !$pkt; # aborted / timed out
      $pms->rule_ready($ent->{rulename}); # mark as run, could still hit
      foreach my $answer ($pkt->answer) {
        next if !$answer;
        next if $answer->type ne 'A' && $answer->type ne 'MX';
        if ($pkt->header->rcode eq 'NXDOMAIN' ||
            $pkt->header->rcode eq 'SERVFAIL')
        {
          if (++$pms->{sender_host_fail} == 2) {
            $pms->got_hit($ent->{rulename}, "DNS: ", ruletype => "dns");
          }
        }
      }
    },
    master_deadline => $self->{master_deadline},
  );
}

# capability checks for "if can(Mail::SpamAssassin::Plugin::DNSEval::XXX)":
#
sub has_tflags_domains_only { 1 }
sub has_tflags_ips_only { 1 }

1;