--- RiveScript.pm	2008-09-15 13:28:32.000000000 -0700
+++ RiveScript.pm	2008-09-21 16:05:39.000000000 -0700
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-our $VERSION = '1.17'; # Version of the Perl RiveScript interpreter.
+our $VERSION = '1.17.2'; # Version of the Perl RiveScript interpreter.
 our $SUPPORT = '2.0';  # Which RS standard we support.
 our $basedir = (__FILE__ =~ /^(.+?)\.pm$/i ? $1 : '.');
 
@@ -23,6 +23,7 @@
 		},
 		depth      => 50, # Recursion depth allowed.
 		topics     => {}, # Loaded replies under topics
+		lineage    => {}, # Keep track of topics that inherit other topics
 		sorted     => {}, # Sorted triggers
 		sortsthat  => {}, # Sorted %previous's.
 		sortedthat => {}, # Sorted triggers that go with %previous's
@@ -429,7 +430,7 @@
 		}
 		elsif ($cmd eq '>') {
 			# > LABEL
-			my ($type,$name,$lang) = split(/\s+/, $line, 3);
+			my ($type,$name,@fields) = split(/\s+/, $line);
 			$type = lc($type);
 
 			# Handle the label types.
@@ -444,8 +445,21 @@
 				$self->debug ("Set topic to $name.");
 				$ontrig = '';
 				$topic = $name;
+
+				# Does this topic inherit another one?
+				if (scalar(@fields) >= 2 && $fields[0] =~ /^inherits$/i) {
+					# Inheriting multiple topics and the topics must be separated
+					# by spaces.
+					for (my $i = 1; $i < scalar(@fields); $i++) {
+						my $inherits = $fields[$i];
+						$self->{lineage}->{$name}->{$inherits} = 1;
+					}
+				}
 			}
 			if ($type eq 'object') {
+				# If a field was provided, it should be the programming language.
+				my $lang = (scalar(@fields) ? $fields[0] : undef);
+
 				# Only try to parse a language we support.
 				$ontrig = '';
 				if (not defined $lang) {
@@ -569,7 +583,13 @@
 		my $prior = {
 			0 => [], # Default
 		};
-		foreach my $trig (keys %{$triglvl->{$topic}}) {
+
+		# Collect a list of all the triggers we're going to need to
+		# worry about. If this topic inherits another topic, we need to
+		# recursively add those to the list.
+		my @alltrig = $self->_topicTriggers($topic,$triglvl,0);
+		#foreach my $trig (keys %{$triglvl->{$topic}}) {
+		foreach my $trig (@alltrig) {
 			if ($trig =~ /\{weight=(\d+)\}/i) {
 				my $weight = $1;
 
@@ -895,6 +915,42 @@
 	return 1;
 }
 
+# Gather an array of all triggers in a topic. If the topic inherits other
+# topics, recursively collect those triggers too. Take care about recursion.
+sub _topicTriggers {
+	my ($self,$topic,$triglvl,$depth) = @_;
+
+	# Break if we're in too deep.
+	if ($depth > $self->{depth}) {
+		$self->issue ("Deep recursion while scanning topic inheritance (topic $topic was involved)");
+		return ();
+	}
+
+	$self->debug ("Collecting trigger list for topic $topic");
+
+	# topic:   the name of the topic
+	# triglvl: either $self->{topics} or $self->{thats}
+	# depth:   starts at 0 and ++'s with each recursion
+
+	# Collect an array of triggers to return.
+	my @triggers = ();
+
+	# Does this topic inherit others?
+	if (exists $self->{lineage}->{$topic}) {
+		# Check every inherited topic.
+		foreach my $inherits (sort { $a cmp $b } keys %{$self->{lineage}->{$topic}}) {
+			$self->debug ("Topic $topic inherits $inherits");
+			push (@triggers, $self->_topicTriggers($inherits,$triglvl,($depth + 1)));
+		}
+	}
+
+	# Collect the triggers.
+	push (@triggers, keys %{$triglvl->{$topic}});
+
+	# Return them.
+	return (@triggers);
+}
+
 ################################################################################
 ## Configuration Methods                                                      ##
 ################################################################################
@@ -1168,7 +1224,18 @@
 
 			if ($msg =~ /^$regexp$/i) {
 				$self->debug ("Found a match!");
+
+				# We found a match, but what if the trigger we matched belongs to
+				# an inherited topic? Check for that.
+				if (exists $self->{topics}->{$topic}->{$trig}) {
+					# No, the trigger does belong to our own topic.
 				$matched = $self->{topics}->{$topic}->{$trig};
+				}
+				else {
+					# Our topic doesn't have this trigger. Check inheritence.
+					$matched = $self->_findTriggerByInheritence ($topic,$trig,0);
+				}
+
 				$foundMatch = 1;
 
 				# Get the stars.
@@ -1309,6 +1376,47 @@
 	return $reply;
 }
 
+sub _findTriggerByInheritence {
+	my ($self,$topic,$trig,$depth) = @_;
+
+	# This sub was called because the user matched a trigger from the
+	# sorted array, but the trigger doesn't exist under the topic of
+	# which the user currently belongs. It probably was a trigger
+	# inherited from another topic. This subroutine finds that out,
+	# recursively, following the inheritence trail.
+
+	# Take care to prevent infinite recursion.
+	if ($depth > $self->{depth}) {
+		$self->issue("Deep recursion detected while following an inheritence trail (involving topic $topic and trigger $trig)");
+		return undef;
+	}
+
+	# See if this topic has an "inherits".
+	if (exists $self->{lineage}->{$topic}) {
+		foreach my $inherits (sort { $a cmp $b } keys %{$self->{lineage}->{$topic}}) {
+
+			# See if this inherited topic has our trigger.
+			if (exists $self->{topics}->{$inherits}->{$trig}) {
+				# Great!
+				return $self->{topics}->{$inherits}->{$trig};
+			}
+			else {
+				# Check what this topic inherits from.
+				my $match = $self->_findTriggerByInheritence (
+					$inherits, $trig, ($depth + 1),
+				);
+				if (defined $match) {
+					# Finally got a match.
+					return $match;
+				}
+			}
+		}
+	}
+
+	# Don't know what else we can do.
+	return undef;
+}
+
 sub _reply_regexp {
 	my ($self,$user,$regexp) = @_;
 
@@ -2017,6 +2125,11 @@
 
 =head1 CHANGES
 
+  1.18  xxx
+  - Added support for topics to inherit their triggers from other topics.
+    e.g. > topic alpha inherits beta
+  - Updated the RiveScript Working Draft.
+
   1.17  Sep 15 2008
   - Updated the rsdemo tool to be more flexible as a general debugging and
     developing program. Also updated rsdemo and rsup to include POD documentation
