func (p *PolicyLine) Match(source *Resource, target *Resource, when time.Time, where *Location) (bool, bool, bool) {
	if p.OOperator == NONE {
		return p.PPolicy.Match(source, target, when, where)
	}
	if p.OOperator == AND {
		lValid, lAccept, lMatch := p.LArg.Match(source, target, when, where)
		if !lValid {
			return false, false, false
		}
		rValid, rAccept, rMatch := p.RArg.Match(source, target, when, where)
		if !rValid {
			return false, false, false
		}
		return true, lAccept && rAccept, lMatch && rMatch
	}
	if p.OOperator == OR {
		lValid, lAccept, lMatch := p.LArg.Match(source, target, when, where)
		if lValid && lAccept && lMatch {
			return true, true, true
		}
		rValid, rAccept, rMatch := p.RArg.Match(source, target, when, where)
		return lValid || rValid, lAccept || rAccept, lMatch || rMatch
	}
	return false, false, false
}
Match tests a request against a policy line. This works identically
to the Match function on policies, except that boolean operators are allowed.

Note that you can realy shoot yourself in the foot with OR operator, so
be carefull.

See (p* Policy) Match for inputs and outputs
package policy
import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"
)
var logger = log.New(os.Stdout, "", log.Lshortfile)
type Rule struct {
	Layer    string `json:"layer"`
	LType    string `json:"layer_type"`
	Pattern  string `json:"pattern"`
	disabled bool
}
var AllowedOperators = []string{"=", ">", "<", "in", "!=", ">=", "<="}
type Expression struct {
	Field string
	Value string
	Op    string
}
func (r *Rule) Match(r1 *Rule) (bool, bool) {
	if strings.Compare(r.Layer, r1.Layer) == 0 &&
		strings.Compare(r.LType, r1.LType) == 0 {
		return true, strings.Compare(r.Pattern, r1.Pattern) == 0
	}
	return false, false
}
func (r *Rule) Expression() Expression {
	var expr Expression
	for _, op := range AllowedOperators {
		if idx := strings.Index(r.Pattern, op); idx != -1 {
			expr = Expression{
				Op:    op,
				Field: r.Pattern[:idx],
				Value: r.Pattern[idx+len(op):],
			}
		}
	}
	return expr
}
func (r *Rule) String() string {
	return fmt.Sprintf("Rule: %v/%v/%v", r.Layer, r.LType, r.Pattern)
}
type Operator int
const (
	AND = Operator(iota)
	OR
	NONE
)
type RuleSet struct {
	OOperator Operator
	RRule     *Rule
	LArg      *RuleSet
	RArg      *RuleSet
}
func (rs *RuleSet) MatchRule(r *Rule) (bool, bool) {
	if r.disabled {
		return true, true
	}
	if rs.OOperator == NONE {
		return rs.RRule.Match(r)
	}
	if rs.OOperator == AND {
		lAccept, lMatch := rs.LArg.MatchRule(r)
		rAccept, rMatch := rs.RArg.MatchRule(r)
		if rAccept && lAccept {
			return true, rMatch && lMatch
		}
		return lAccept || rAccept, lMatch || rMatch
	}
	if rs.OOperator == OR {
		lAccept, lMatch := rs.LArg.MatchRule(r)
		if lAccept && lMatch {
			return true, true
		}
		rAccept, rMatch := rs.RArg.MatchRule(r)
		if rAccept && rMatch {
			return true, true
		}
		if lAccept || rAccept {
			return true, false
		}
	}
	return false, false
}
func (rs *RuleSet) Match(rs1 *RuleSet) (bool, bool) {
	if rs1.OOperator == NONE {
		return rs.MatchRule(rs1.RRule)
	}
	if rs1.OOperator == AND {
		lAccept, lMatch := rs.Match(rs1.LArg)
		if !lAccept {
			return false, false
		}
		rAccept, rMatch := rs.Match(rs1.RArg)
		if !rAccept {
			return false, false
		}
		return true, lMatch && rMatch
	}
	if rs1.OOperator == OR {
		lAccept, lMatch := rs.Match(rs1.LArg)
		if lAccept && lMatch {
			return true, true
		}
		rAccept, rMatch := rs.Match(rs1.RArg)
		if rAccept && rMatch {
			return true, true
		}
		if lAccept || rAccept {
			return true, false
		}
	}
	return false, false
}
func (rs *RuleSet) And(rs1 *RuleSet) *RuleSet {
	var ruleSet = RuleSet{OOperator: AND, RRule: nil, LArg: rs, RArg: rs1}
	return &ruleSet
}
func (rs *RuleSet) Or(rs1 *RuleSet) *RuleSet {
	var ruleSet = RuleSet{OOperator: OR, RRule: nil, LArg: rs, RArg: rs1}
	return &ruleSet
}
func (rs *RuleSet) Map(function func(*Rule) Rule) *RuleSet {
	var rule Rule
	var left, right *RuleSet
	if rs.RRule != nil {
		rule = function(rs.RRule)
	}
	if rs.LArg != nil {
		left = rs.LArg.Map(function)
	}
	if rs.RArg != nil {
		right = rs.RArg.Map(function)
	}
	return &RuleSet{OOperator: rs.OOperator, RRule: &rule, LArg: left, RArg: right}
}
func (rs *RuleSet) Foreach(function func(*Rule)) {
	if rs.RRule != nil {
		function(rs.RRule)
	}
	if rs.LArg != nil {
		rs.LArg.Foreach(function)
	}
	if rs.RArg != nil {
		rs.RArg.Foreach(function)
	}
}
func (rs *RuleSet) String() string {
	if rs.OOperator == NONE {
		return rs.RRule.String()
	}
	if rs.OOperator == AND {
		return fmt.Sprintf("(%v AND %v)", rs.LArg.String(), rs.RArg.String())
	}
	return fmt.Sprintf("(%v OR %v)", rs.LArg.String(), rs.RArg.String())
}
type Credential struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}
func (c *Credential) Accept(c1 *Credential) bool {
	return strings.Compare(c.Name, c1.Name) == 0 &&
		strings.Compare(c.Value, c1.Value) == 0
}
func (c *Credential) String() string {
	return fmt.Sprintf("Credential: %v/%v", c.Name, c.Value)
}
type Resource struct {
	Name         *RuleSet    `json:"rules"`
	IdentifiedBy *Credential `json:"identified_by"`
	fieldsToMatch []string
}
func getRulesToMatch(fieldsToMatch []string, input *Resource) *RuleSet {
	return input.Name.Map(func(rule *Rule) Rule {
		expr := rule.Expression()
		r := Rule{
			LType:    rule.LType,
			Layer:    rule.Layer,
			Pattern:  rule.Pattern,
			disabled: true,
		}
		for _, f := range fieldsToMatch {
			if f == expr.Field {
				r.disabled = false
			}
		}
		return r
	})
}
func processRuleFields(r *Resource) {
	if len(r.fieldsToMatch) == 0 {
		r.Name.Foreach(func(rule *Rule) {
			r.fieldsToMatch = append(r.fieldsToMatch, rule.Expression().Field)
		})
	}
}
func (r *Resource) Match(r1 *Resource) (bool, bool) {
	processRuleFields(r)
	rulesToMatch := getRulesToMatch(r.fieldsToMatch, r1)
	accept, match := r.Name.Match(rulesToMatch)
	if !accept {
		return false, false
	}
	if match {
		if r.IdentifiedBy.Accept(r1.IdentifiedBy) {
			return true, true
		}
		return true, false
	}
	return true, false
}
func (r *Resource) String() string {
	return fmt.Sprintf("Resource: %v id by %v", r.Name.String(), r.IdentifiedBy.String())
}
type Duration struct {
	Start time.Time `json:"start"`
	End   time.Time `json:"end"`
}
func (d *Duration) String() string {
	return fmt.Sprintf("%v to %v", d.Start, d.End)
}
type Location struct {
	Name string `json:"name"`
}
func (l *Location) Match(l1 *Location) bool {
	if strings.Compare(l.Name, l1.Name) == 0 {
		return true
	}
	return false
}
func (l *Location) String() string {
	return fmt.Sprintf("%v", l.Name)
}
type Contents struct {
	PluginID string
	Blob     []byte
}
type PolicyBase interface {
	Match(source *Resource, target *Resource, when time.Time, where *Location) (bool, bool, bool)
	String() string
}
const PolicyFormatVersion uint64 = 0
type Policy struct {
	UUID          string      `json:"uuid"`
	FormatVersion uint64      `json:"format_version"`
	PolicyVersion uint64      `json:"policy_version"`
	Description   string      `json:"description"`
	Target        Resource    `json:"target"`
	Allowed       []*Resource `json:"allowed"`
	Disallowed    []*Resource `json:"disallowed"`
	Timeline      Duration    `json:"timeline"`
	Rate          uint64      `json:"rate"`
	LLocation     Location    `json:"location"`
	CContents     []*Contents `json:"contents,omitempty"`
	Signature     string      `json:"signature"`
}
func (p *Policy) Match(source *Resource, target *Resource, when time.Time, where *Location) (bool, bool, bool) {
	if when.Before(p.Timeline.Start) || when.After(p.Timeline.End) {
		return false, false, false
	}
	if !p.LLocation.Match(where) {
		return true, false, false
	}
	_, match := p.Target.Match(target)
	if match == true {
		for _, element := range p.Disallowed {
			if element == nil {
				continue
			}
			_, matchElement := element.Match(source)
			if matchElement == true {
				return true, true, false
			}
		}
		for _, element := range p.Allowed {
			if element == nil {
				continue
			}
			_, matchElement := element.Match(source)
			if matchElement == true {
				return true, true, true
			}
		}
		return true, true, false
	}
	return true, false, false
}
func (p *Policy) String() string {
	return fmt.Sprintf("%v:%v:%v\n\ttarget: %v",
		p.FormatVersion,
		p.PolicyVersion,
		p.Description,
		p.Target.String())
}
type PolicyLine struct {
	OOperator Operator
	PPolicy   *Policy
	LArg      *PolicyLine
	RArg      *PolicyLine
}