Fixed exclusion and renamed op to match in term
diff --git a/lib/Krawfish/Koral/Query.pm b/lib/Krawfish/Koral/Query.pm
index 18eb163..7673d61 100644
--- a/lib/Krawfish/Koral/Query.pm
+++ b/lib/Krawfish/Koral/Query.pm
@@ -52,9 +52,9 @@
 sub is_optional       { $_[0]->{optional}       // 0 };
 sub is_null           { $_[0]->{null}           // 0 };
 sub is_negative       { $_[0]->{negative}       // 0 };
-sub is_extended       { $_[0]->{extended}       // 0 };
 sub is_extended_right { $_[0]->{extended_right} // 0 };
 sub is_extended_left  { $_[0]->{extended_left}  // 0 };
+sub is_extended       { $_[0]->is_extended_right || $_[0]->is_extended_left // 0 };
 sub freq              { -1 };
 sub type              { '' };
 
diff --git a/lib/Krawfish/Koral/Query/Builder.pm b/lib/Krawfish/Koral/Query/Builder.pm
index d113441..9d7112a 100644
--- a/lib/Krawfish/Koral/Query/Builder.pm
+++ b/lib/Krawfish/Koral/Query/Builder.pm
@@ -62,6 +62,11 @@
   Krawfish::Koral::Query::TermGroup->new('or' => @_);
 };
 
+sub term_neg {
+  shift;
+  Krawfish::Koral::Query::Term->new(@_)->match('!=');
+};
+
 
 # Span construct
 sub span {
diff --git a/lib/Krawfish/Koral/Query/Exclusion.pm b/lib/Krawfish/Koral/Query/Exclusion.pm
index 952d0e6..831356f 100644
--- a/lib/Krawfish/Koral/Query/Exclusion.pm
+++ b/lib/Krawfish/Koral/Query/Exclusion.pm
@@ -97,25 +97,17 @@
 
 
 # Return if the query may result in an 'any' left extension
-# [][Der]
 sub is_extended_left {
   return $_[0]->{first}->is_extended_left;
 };
 
 
 # Return if the query may result in an 'any' right extension
-# [Der][]
 sub is_extended_right {
   return $_[0]->{first}->is_extended_right;
 };
 
 
-# return if the query is extended either to the left or to the right
-sub is_extended {
-    return $_[0]->{first}->is_extended;
-};
-
-
 1;
 
 
diff --git a/lib/Krawfish/Koral/Query/Position.pm b/lib/Krawfish/Koral/Query/Position.pm
index df44718..c684119 100644
--- a/lib/Krawfish/Koral/Query/Position.pm
+++ b/lib/Krawfish/Koral/Query/Position.pm
@@ -1,10 +1,13 @@
 package Krawfish::Koral::Query::Position;
 use parent 'Krawfish::Koral::Query';
 use Krawfish::Query::Position;
+use Krawfish::Log;
 use Mojo::JSON;
 use strict;
 use warnings;
 
+use constant DEBUG => 0;
+
 our %FRAME = (
   precedes => PRECEDES,
   precedesDirectly => PRECEDES_DIRECTLY,
@@ -68,7 +71,7 @@
 
   # Anything in positional relation to nothing
   if ($second->is_null) {
-    print "  ## Try to eliminate null query\n";
+    print_log('k_pos', 'Try to eliminate null query') if DEBUG;
 
     # This may be reducible to first span
     my $valid_frames =
@@ -77,16 +80,20 @@
 
     # Frames has at least one match with valid frames
     if ($frames & $valid_frames) {
-      print "  ## Frames match valid frames:\n";
-      print "     " . _bits($frames) . " & \n";
-      print "     " . _bits($valid_frames) . " = true\n";
+      if (DEBUG) {
+        print_log('k_pos', 'Frames match valid frames');
+        print_log('k_pos', '  ' . _bits($frames) . ' & ');
+        print_log('k_pos', '  ' . _bits($valid_frames) . ' = true');
+      };
 
       # Frames has no match with invalid frames
       unless ($frames & ~$valid_frames) {
-        print "  ## Frames don't match invalid frames:\n";
-        print "     " . _bits($frames) . " & \n";
-        print "     " . _bits(~$valid_frames) . " = false\n";
-        print "  ## Can eliminate null query\n";
+        if (DEBUG) {
+          print_log('k_pos', 'Frames don\'t match invalid frames');
+          print_log('k_pos', '  ' . _bits($frames) . ' & ');
+          print_log('k_pos', '  ' . _bits(~$valid_frames) . ' = false');
+          print_log('k_pos', 'Can eliminate null query');
+        };
         return $first->plan_for($index);
       };
     };
diff --git a/lib/Krawfish/Koral/Query/Term.pm b/lib/Krawfish/Koral/Query/Term.pm
index 6290efe..a97b5ec 100644
--- a/lib/Krawfish/Koral/Query/Term.pm
+++ b/lib/Krawfish/Koral/Query/Term.pm
@@ -85,7 +85,7 @@
 };
 
 # Operation
-sub op {
+sub match {
   if ($_[1]) {
     $_[0]->[4] = $_[1];
     return $_[0];
@@ -145,8 +145,11 @@
       $str .= '/' . $self->layer;
     };
     if ($self->key) {
-      $str .= $self->op ? $self->op : '=';
+      $str .= $self->match ? $self->match : '=';
     };
+  }
+  elsif ($self->is_negative) {
+    $str .= '!';
   };
   $str .= $self->key;
   if ($self->value) {
@@ -166,7 +169,7 @@
   };
   $str .= $self->prefix if $self->prefix;
   my $term = $self->to_string;
-  if ($self->op ne '=') {
+  if ($self->match ne '=') {
     $term =~ s/!=/=/i;
   };
   return $str . $term;
@@ -189,7 +192,7 @@
   return;
 };
 sub is_negative {
-  $_[0]->op eq '!=' ? 1 : 0;
+  $_[0]->match eq '!=' ? 1 : 0;
 };
 sub is_extended { 0 };
 sub is_extended_right { 0 };
diff --git a/lib/Krawfish/Koral/Query/TermGroup.pm b/lib/Krawfish/Koral/Query/TermGroup.pm
index 83cbbfb..e7d578d 100644
--- a/lib/Krawfish/Koral/Query/TermGroup.pm
+++ b/lib/Krawfish/Koral/Query/TermGroup.pm
@@ -145,13 +145,13 @@
       # Plan query with positivie element
       # TODO: Elements may be termgroups!
       my $neg_query =
-        pop(@negatives)->op('=')->plan_for($index);
+        pop(@negatives)->match('=')->plan_for($index);
 
       # Join all negative terms in an or-query
       foreach (@negatives) {
         $neg_query = Krawfish::Query::Or->new(
           $neg_query,
-          $_->op('=')->plan_for($index)
+          $_->match('=')->plan_for($index)
         )
       };
 
diff --git a/lib/Krawfish/Query/Base/Dual.pm b/lib/Krawfish/Query/Base/Dual.pm
index 73d1ee4..8b7cfbf 100644
--- a/lib/Krawfish/Query/Base/Dual.pm
+++ b/lib/Krawfish/Query/Base/Dual.pm
@@ -12,7 +12,7 @@
   NEXTA  => 1,
   NEXTB  => 2,
   MATCH  => 4,
-  DEBUG  => 1
+  DEBUG  => 0
 };
 
 @EXPORT = qw/NEXTA NEXTB MATCH/;
@@ -49,6 +49,7 @@
   while (1) {
     unless ($first = $self->{first}->current) {
       print_log('dual', 'No more first items, return false 1') if DEBUG;
+
       $self->{doc_id} = undef;
       return;
     };
@@ -56,17 +57,29 @@
     unless ($second = $self->{buffer}->current) {
       print_log('dual', 'Buffer is empty') if DEBUG;
 
-      # Forward span
-      unless ($self->{first}->next) {
-        # May point to no current
-        print_log('dual', 'Return false 2') if DEBUG;
-        $self->{doc_id} = undef;
-        return;
+      # Check configuration
+      my $check = $self->check($first, undef);
+
+      print_log('dual', 'Final check is '. (0+$check)) if DEBUG;
+
+      # Expect a next_a
+      if ($check & NEXTA) {
+
+        # Forward span
+        $self->{first}->next;
+      };
+
+      # The configuration matches
+      if ($check & MATCH) {
+        print_log('dual', 'MATCH!') if DEBUG;
+        return 1 ;
       };
 
       # Reset buffer
       $self->{buffer}->to_start;
-      next;
+      $self->{doc_id} = undef;
+      return;
+      # next;
     };
 
     # TODO: Check if second may not be at the end
@@ -80,7 +93,7 @@
       # Check configuration
       my $check = $self->check($first, $second);
 
-      print_log('dual', 'Plan next step based on ' . (0 + $check)) if DEBUG;
+      print_log('dual', 'Next step after check returned ' . (0 + $check)) if DEBUG;
 
       # next b is possible
       if ($check & NEXTB) {
@@ -92,14 +105,18 @@
 
           # Forget the current buffer
           $self->{buffer}->forget;
+        }
+        elsif (DEBUG) {
+          print_log('dual', 'Next A and next B is possible') if DEBUG;
         };
 
         # Forward buffer - or span
         if (!($self->{buffer}->next)) {
           # This will never be true
 
-          print_log('dual', 'Unable to forward buffer - get next') if DEBUG;
+          print_log('dual', 'Unable to forward buffer - get next posting') if DEBUG;
 
+          # Check next posting
           if ($self->{second}->next) {
             $self->{buffer}->remember(
               $self->{second}->current
@@ -108,7 +125,27 @@
             # Position finger to last item
             $self->{buffer}->to_end;
           }
+
+          # Check if nextA is supported
+          elsif ($check & NEXTA) {
+            print_log('dual', 'Second has no further postings') if DEBUG;
+
+            # Check configuration
+            my $check = $self->check($first, undef);
+
+            $self->{first}->next;
+            $self->{buffer}->to_start;
+
+            if ($check & MATCH) {
+              return 1;
+            };
+          }
+
+          # No, nothing
           else {
+            print_log('dual', 'There is no next second') if DEBUG;
+
+            # May be wrong (untested!)
             $self->{buffer}->forward;
           };
         };
@@ -125,6 +162,13 @@
 
         # Reset buffer
         $self->{buffer}->to_start;
+      }
+
+      # No forwarding
+      else {
+        $self->{buffer}->clear;
+        $self->{doc_id} = undef;
+        return;
       };
 
       # The configuration matches
diff --git a/lib/Krawfish/Query/Constraint/InDistanceSpan.pm b/lib/Krawfish/Query/Constraint/InDistanceSpan.pm
new file mode 100644
index 0000000..76a0809
--- /dev/null
+++ b/lib/Krawfish/Query/Constraint/InDistanceSpan.pm
@@ -0,0 +1,40 @@
+package Krawfish::Query::Constraint::InSpanDistance;
+use strict;
+use warnings;
+
+sub new {
+  my $class = shift;
+  bless {
+    span => shift,
+    buffer => shift,
+    min => shift,
+    max => shift
+  }, $class;
+}
+
+sub check {
+  my $self = shift;
+  my ($payload, $first, $second) = @_;
+
+  # TODO: init span
+
+  my $span = $self->{span};
+
+  my $buffer = $self->{buffer};
+
+  # No current element
+  return 0b0000 unless $span->current;
+
+  # Move span to correct position
+  while ($span->current->doc_id < $first->doc_id) {
+    $span->next or return NEXTA | NEXTB;
+  };
+
+  my $current = $span->current or return 0b0000;
+
+  my ($start, $end) = $first->start < $second->start ? ($first, $second) : ($second, $first);
+  
+  if ($first->end > $current->end)
+};
+
+1;
diff --git a/lib/Krawfish/Query/Constraint/Position.pm b/lib/Krawfish/Query/Constraint/Position.pm
index 35615f2..bd6df63 100644
--- a/lib/Krawfish/Query/Constraint/Position.pm
+++ b/lib/Krawfish/Query/Constraint/Position.pm
@@ -24,7 +24,7 @@
   NEXTA => 1,
   NEXTB => 2,
   MATCH => 4,
-  DEBUG => 1
+  DEBUG => 0
 };
 
 our (@EXPORT, @next_a, @next_b);
diff --git a/lib/Krawfish/Query/Constraints.pm b/lib/Krawfish/Query/Constraints.pm
index ef895f0..21614ec 100644
--- a/lib/Krawfish/Query/Constraints.pm
+++ b/lib/Krawfish/Query/Constraints.pm
@@ -8,7 +8,7 @@
   NEXTA => 1,
   NEXTB => 2,
   MATCH => 4,
-  DEBUG => 1
+  DEBUG => 0
 };
 
 # TODO: Improve by skipping to the same document
diff --git a/lib/Krawfish/Query/Exclusion.pm b/lib/Krawfish/Query/Exclusion.pm
index f003f5a..57cc574 100644
--- a/lib/Krawfish/Query/Exclusion.pm
+++ b/lib/Krawfish/Query/Exclusion.pm
@@ -33,7 +33,7 @@
 # If normal next_a is called,
 # a is truely exclusive.
 
-use constant DEBUG => 1;
+use constant DEBUG => 0;
 
 sub new {
   my $class = shift;
@@ -51,23 +51,44 @@
 
   # Get the current configuration
   my $case = Krawfish::Query::Position::case($first, $second);
+
   my $frames = $self->{frames};
 
-  # There is a machtch - so A does not exclude B
+  # There is a match - so A does not exclude B
   if ($case & $frames) {
+    if (DEBUG) {
+      print_log('excl', "Excluded span occurs - next with A");
+      print_log('excl', '     for frames '.Krawfish::Query::Position::_bits($frames));
+      print_log('excl', '     with case  '.Krawfish::Query::Position::_bits($case));
+    };
     return NEXTA;
   };
 
-  my $ret_val = 0b0000;
-
-  # Span may forward with a
-  if ($next_a[$case] & $frames) {
-    $ret_val |= NEXTA
-  }
+  my $ret_val = NEXTA;
 
   # Span may forward with b
   if ($next_b[$case] & $frames) {
-    $ret_val |= NEXTB
+    $ret_val |= NEXTB;
+  }
+
+  # Span may forward with a
+  elsif ($next_a[$case] & $frames) {
+    # Set current
+    $self->{doc_id} = $first->doc_id;
+    $self->{start} = $first->start;
+    $self->{end}   = $first->end;
+    $self->{payload} = $first->payload->clone;
+    print_log('excl', 'Set match to ' . $self->current->to_string) if DEBUG;
+    return NEXTA | NEXTB | MATCH;
+  }
+  elsif ($next_a[$case] == NULL_4) {
+    # Set current
+    $self->{doc_id} = $first->doc_id;
+    $self->{start} = $first->start;
+    $self->{end}   = $first->end;
+    $self->{payload} = $first->payload->clone;
+    print_log('excl', 'Set match to ' . $self->current->to_string) if DEBUG;
+    return NEXTA | MATCH;
   };
 
   if (DEBUG) {
diff --git a/lib/Krawfish/Query/Position.pm b/lib/Krawfish/Query/Position.pm
index 23b3e1c..3ba438b 100644
--- a/lib/Krawfish/Query/Position.pm
+++ b/lib/Krawfish/Query/Position.pm
@@ -41,6 +41,9 @@
 # next_a may result in configuration B and
 # next_b may result in configuration C
 # These configurations were precomputed
+$next_a[NULL_4] = NULL_4;
+$next_b[NULL_4] = NULL_4;
+
 $next_a[PRECEDES] =
   PRECEDES |
   PRECEDES_DIRECTLY |
@@ -347,6 +350,7 @@
     print_log('pos', "Next frames are "._bits($next_a[$case])." and ");
     print_log('pos', '                '._bits($next_b[$case]));
   };
+
   return $ret_val;
 };
 
@@ -362,6 +366,8 @@
   my $span_a = shift;
   my $span_b = shift;
 
+  return NULL_4 if !$span_a || !$span_b;
+
   # A starts after B
   # [b..[a..
   if ($span_a->start > $span_b->start) {
diff --git a/lib/Krawfish/Query/Repetition.pm b/lib/Krawfish/Query/Repetition.pm
index 5442183..ff29407 100644
--- a/lib/Krawfish/Query/Repetition.pm
+++ b/lib/Krawfish/Query/Repetition.pm
@@ -11,6 +11,10 @@
 # TODO: Support next_pos, in case current start position can not succeed
 # e.g. in case of position
 
+# TODO: Support steps:
+# []{1,30,2}
+# means valid: [][], [][][][], [][][][][], ...
+
 sub new {
   my $class = shift;
   bless {