#!/usr/bin/env python
#
# Copyright 2007 John Wiseman <jjwiseman@yahoo.com>
#
# 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.

import re
import sys
import io
import getopt


class RegressiveImageryDictionary:
  """
  To use:
    1. Load a dictionary.
    2. Load an exclusion list (optional).
    3. Call analyze.
    4. Call display_results with the value returned by analyze.    
  """
  def __init__(self):
    self.category_tree = CategoryRoot()
    self.exclusion_patterns = []
    self.exclusion_pattern = None
    self.pattern_tree = DiscriminationTree('root', None)

  def load_dictionary_from_file(self, path):
    rid_in = open(path, "r")
    try:
      self.load_dictionary(rid_in)
    finally:
      rid_in.close()

  def load_dictionary_from_string(self, string):
    rid_in = io.StringIO(string)
    self.load_dictionary(rid_in)
      
  def load_dictionary(self, stream):
    primary_category = None
    secondary_category = None
    tertiary_category = None

    for line in stream:
      num_tabs = count_leading_tabs(line)
      # The dictionary is in kind of a weird format.
      if num_tabs == 0:
        primary_category = line.strip()
        secondary_category = None
        tertiary_category = None
      elif num_tabs == 1:
        secondary_category = line.strip()
        tertiary_category = None
      elif num_tabs == 2 and not '(' in line:
        tertiary_category = line.strip()
      else:
        # We have a word pattern.
        pattern = line.strip().split(' ')[0].lower()
        category = self.ensure_category(primary_category, secondary_category, tertiary_category)
        category.add_word_pattern(pattern)
        self.pattern_tree.put(pattern, category)

  def load_exclusion_list_from_file(self, path):
    exc_in = open(path, "r")
    try:
      self.load_exclusion_list(exc_in)
    finally:
      exc_in.close()
      
  def load_exclusion_list_from_string(self, string):
    exc_in = io.StringIO(string)
    self.load_exclusion_list(exc_in)

  def load_exclusion_list(self, stream):
    for line in stream:
      pattern = line.strip().lower()
      pattern = pattern.replace("*", ".*")
      self.exclusion_patterns.append(pattern)
    # One megapattern to exclude them all
    self.exclusion_pattern = re.compile('^(' + '|'.join(self.exclusion_patterns) + ')$')

  def token_is_excluded(self, token):
    return self.exclusion_pattern.match(token)

  def get_category(self, word):
    categories = self.pattern_tree.retrieve(word)
    if categories:
      return categories[0]
          
  def analyze(self, text):
    results = RIDResults()
    def increment_category(category, token):
      if not category in results.category_count:
        results.category_count[category] = 0
        results.category_words[category] = []
      results.category_count[category] += 1
      results.category_words[category].append(token)
    
    tokens = tokenize(text)
    results.word_count = len(tokens)
    for token in tokens:
      if not self.token_is_excluded(token):
        category = self.get_category(token)
        if category != None:
          increment_category(category, token)
    return results

  def display_results(self, results):
    # Detailed category breakout 
    total_count = 0
    for (category, count) in sorted(list(results.category_count.items()), key=lambda x: x[1], reverse=True):
      print("%-60s %5s" % (category.full_name(), count))
      print("  " + " ".join(results.category_words[category]))
      total_count += count

    # Summary for each top-level category
    top_categories = list(self.category_tree.children.values())
    def get_top_category(cat):
      for top_cat in top_categories:
        if cat.isa(top_cat):
          return top_cat
      print("Category %s doesn't exist in %s" % (category, top_categories))
        
    top_category_counts = {}
    for top_category in top_categories:
      top_category_counts[top_category] = 0
    
    for category in results.category_count:
      top_category = get_top_category(category)
      if top_category:
        top_category_counts[top_category] += results.category_count[category]

    print("")

    def percent(x, y):
      if y == 0:
        return 0
      else:
        return (100.0 * x) / y

    for top_category in top_categories:
      count = top_category_counts[top_category]
      print("%-20s: %f %%" % (top_category.full_name(), percent(count, total_count)))
        
    # Word count
    print("\n%d words total" % (results.word_count,))

  def display_results_html(self, results, title):
    # Detailed category breakout 
    total_count = 0
    print("<html><head>")

    print("<meta http-equiv='content-type' content='text/html; charset=UTF-8'>")
    print("""
  <style type="text/css">
    .word-count { vertical-align: super; font-size: 50%; }
    .twisty { color: blue; font-family: monospace; }
    a.twisty { text-decoration: none; }
  </style>
""")
    print("<title>%s</title>" % (title,))
    print("""
<script>

var TWISTY_EXPANDED = ' &#9662; ';
var TWISTY_COLLAPSED = ' &#9656; ';

function allWordNodes() {
  var nodes = document.getElementsByTagName("tr");
  var results = new Array();
  var numResults = 0;

  for (i = 0; i < nodes.length; i++) {
    var node = nodes.item(i);
    if (node.className == 'words') {
      results[numResults] = node;
      numResults++;
    }
  }
  return results;
}

function hideAll() {
  allNodes = allWordNodes();
  for (var i = 0; i < allNodes.length; i++) {
    hide(allNodes[i]);
  }
}

function showAll() {
  allNodes = allWordNodes();
  for (var i = 0; i < allNodes.length; i++) {
    show(allNodes[i]);
  }
}

function get_twisty_node(category) {
  var cell = document.getElementById(category + "-cat");
  return cell.childNodes[0];
}

function hide(element) {
  element.style.display = "none";
  var twisty = get_twisty_node(element.id);
  twisty.innerHTML = TWISTY_COLLAPSED;
}

function show(element) {
  element.style.display = "";
  var twisty = get_twisty_node(element.id);
  twisty.innerHTML = TWISTY_EXPANDED;
}

function toggle(cat) {
  var node = document.getElementById(cat)
  if (node.style.display == "none") {
    show(node);
  } else {
    hide(node);
  }
}

</script>
""")
    print("</head><body>")
    print("<h1>%s</h1>" % (title,))
    print("<p><a href='javascript:hideAll()'>- collapse all</a>  <a href='javascript:showAll()'>+ expand all</a></p>")
    print("<table width='100%'>")
    for (category, count) in sorted(list(results.category_count.items()), key=lambda x: x[1], reverse=True):
      sys.stdout.write("<tr>")
      sys.stdout.write("<td class='%s' id='%s'>" % ("category", category.full_name() + "-cat"))
      sys.stdout.write("""<a class='twisty' href="javascript:toggle('%s')"><span class='twisty'> &#9662; </span></a>""" % (category.full_name(),))
      sys.stdout.write("%s</td><td width='*' align='right'>%s</td></tr>""" % (category.full_name(), count))
      print("<tr class='%s' id='%s'>" % ("words", category.full_name()))
      print("<td style='padding-left: 1cm;' colspan='2'>")
      words = uniq_c(results.category_words[category])
      for word in words:
        sys.stdout.write("%s<span class='word-count'>%s</span> " % (word))
      print("\n</td></tr>")
      total_count += count
    print("</table>")

    # Summary for each top-level category
    top_categories = list(self.category_tree.children.values())
    def get_top_category(cat):
      for top_cat in top_categories:
        if cat.isa(top_cat):
          return top_cat
      print("Category %s doesn't exist in %s" % (category, top_categories))
        
    top_category_counts = {}
    for top_category in top_categories:
      top_category_counts[top_category] = 0
    
    for category in results.category_count:
      top_category = get_top_category(category)
      if top_category:
        top_category_counts[top_category] += results.category_count[category]


    def percent(x, y):
      if y == 0:
        return 0
      else:
        return (100.0 * x) / y

    print("<table>")
    for top_category in top_categories:
      count = top_category_counts[top_category]
      print("<tr><td>%s:</td><td>%f %%</td></tr>" % (top_category.full_name(), percent(count, total_count)))
    print("<table>")
        
    # Word count
    print("<p>%d words total</p>" % (results.word_count,))
    print("</body></html>")


  def ensure_category(self, *args):
    def ensure_cat_aux(category, category_path):
      if len(category_path) == 0 or category_path[0] == None:
        return category
      else:
        cat = category_path.pop(0)
        if not cat in category.children:
          category.children[cat] = Category(cat, category)
        return ensure_cat_aux(category.children[cat], category_path)
    return ensure_cat_aux(self.category_tree, list(args))


class RIDResults:
  def __init__(self):
    self.category_count = {}
    self.category_words = {}
    self.word_count = 0


WORD_REGEX = re.compile(r'[^a-zA-Z]+')
def tokenize(string):
  tokens = WORD_REGEX.split(string.lower())
  tokens = [token for token in tokens if len(token) > 0]
  return tokens


def count_leading_tabs(string):
  for i, char in enumerate(string):
    if char != '\t':
      return i


class DiscriminationTree:
  """
  This is the discrimination tree we use for mapping words to
  categories.  The put method is used to insert category nodes in the
  tree, associated with some word pattern.  The retrieve method finds
  the category for a given word, if one exists.
  """
  def __init__(self, index, parent):
    self.index = index
    self.parent = parent
    self.leaves = []
    self.interiors = []
    self.is_wildcard = False

  def __str__(self):
    return "<DiscriminationTree %s>" % (self.index,)
 
  def child_matching_index(self, index):
    for child in self.interiors:
      if child.index == index:
        return child
    return None

  def retrieve(self, path):
    if len(path) == 0 or self.is_wildcard:
      return self.leaves
    else:
      next_index = path[0]
      next_disc_tree = self.child_matching_index(next_index)
      if next_disc_tree == None:
        return
      else:
        return next_disc_tree.retrieve(path[1:])

  def put(self, path, leaf):
    if len(path) == 0:
      if isinstance(leaf, DiscriminationTree):
        self.interiors.append(leaf)
      else:
        self.leaves.append(leaf)
      return True
    else:
      next_index = path[0]
      if next_index == '*':
        # Got a '*' so this is a wildcard node that will match
        # anything that reaches it.
        self.is_wildcard = True
        self.leaves.append(leaf)
      else:
        next_disc_tree = self.child_matching_index(next_index)
        if next_disc_tree == None:
          next_disc_tree = DiscriminationTree(next_index, self)
          self.interiors.append(next_disc_tree)
        next_disc_tree.put(path[1:], leaf)

  def dump(self, stream=sys.stdout, indent=0):
    stream.write("\n" + " "*indent + str(self))
    for child in self.leaves:
      stream.write("\n" + " "*(indent + 3) + str(child))
    for child in self.interiors:
      child.dump(stream=stream, indent=indent + 3)


class Category:
  def __init__(self, name, parent):
    self.name = name
    self.parent = parent
    self.children = {}
    self.leaves = []

  def __str__(self):
    return "<Category %s>" % (self.full_name(),)

  def add_word_pattern(self, pattern):
    self.leaves.append(pattern)

  def full_name(self):
    if self.parent == None or isinstance(self.parent, CategoryRoot):
      return self.name
    else:
      return self.parent.full_name() + ":" + self.name

  def isa(self, parent):
    return parent == self or (self.parent and self.parent.isa(parent))


class CategoryRoot(Category):
  def __init__(self):
    Category.__init__(self, 'root', None)

  def full_name(self):
    return ""


def uniq_c(words):
  words.sort()
  results = []
  last_word = words[0]
  last_word_count = 1
  for word in words[1:]:
    if word == last_word:
      last_word_count += 1
    else:
      results.append((last_word, last_word_count))
      last_word = word
      last_word_count = 1
  results.append((last_word, last_word_count))
  results = sorted(results, key=lambda x: x[1], reverse=True)
  return results
  

# This dictionary is the one from
# http://www.provalisresearch.com/Download/RID.ZIP with misspellings
# fixed.

DEFAULT_RID_DICTIONARY = """
PRIMARY
	NEED
		ORALITY
			ABSINTH* (1)
			ALE (1)
			ALES (1)
			ALIMENTARY (1)
			AMBROSIA* (1)
			AMBROSIAL* (1)
			APPETIT* (1)
			APPLE* (1)
			ARTICHOK* (1)
			ASPARAGU* (1)
			BACON* (1)
			BANANA* (1)
			BEAN* (1)
			BEEF* (1)
			BEER* (1)
			BELCH* (1)
			BELLIES (1)
			BELLY (1)
			BERRI* (1)
			BERRY* (1)
			BEVERAG* (1)
			BISCUIT* (1)
			BITE* (1)
			BITE (1)
			BITES (1)
			BITING (1)
			BITTEN* (1)
			BONBON* (1)
			BRANDY* (1)
			BREAD* (1)
			BREAKFAST* (1)
			BREAST* (1)
			BREW* (1)
			BROTH (1)
			BURP* (1)
			BUTTER* (1)
			BUTTERMILK* (1)
			CAFE (1)
			CAFES (1)
			CAKE (1)
			CAKES (1)
			CAFETARIA (1)
			CANDY* (1)
			CANNIBAL* (1)
			CAVIAR* (1)
			CHAMPAGN* (1)
			CHEES* (1)
			CHERRI* (1)
			CHERRY* (1)
			CHESTNUT* (1)
			CHEW* (1)
			CHOK* (1)
			CIDER* (1)
			CLARET* (1)
			COB (1)
			COBS (1)
			COCOA* (1)
			COCOANUT* (1)
			COCONUT* (1)
			COFFE* (1)
			CONSUM* (1)
			COOK* (1)
			CORN* (1)
			COUGH* (1)
			CRANBERRY* (1)
			CREAM* (1)
			DELICACI* (1)
			DELICACY* (1)
			DESSERT* (1)
			DEVOUR* (1)
			DIET* (1)
			DIGEST* (1)
			DINE (1)
			DINES (1)
			DINING (1)
			DINNER* (1)
			DISH (1)
			DISHES (1)
			DRANK* (1)
			DRINK* (1)
			DRUNK* (1)
			DRUNKEN* (1)
			EAT* (1)
			EATEN* (1)
			EGG* (1)
			ENTRAIL* (1)
			FAMIN* (1)
			FAMISH* (1)
			FAST (1)
			FASTS (1)
			FAT (1)
			FATTEN* (1)
			FEAST* (1)
			FED (1)
			FEED (1)
			FEEDS (1)
			FIG (1)
			FIGS (1)
			FLOUR* (1)
			FOOD* (1)
			FOODSTUFF* (1)
			FORK* (1)
			FRUIT* (1)
			GARLIC* (1)
			GIN (1)
			GINGER* (1)
			GINS (1)
			GLUTTON* (1)
			GLUTTONOU* (1)
			GNAW* (1)
			GOBBL* (1)
			GRAIN* (1)
			GRAP* (1)
			GROG* (1)
			GRUEL* (1)
			GULP* (1)
			GUM (1)
			GUMS (1)
			GUT (1)
			GUTS (1)
			HAM (1)
			HAMS (1)
			HERB* (1)
			HONEY* (1)
			HUNGER* (1)
			HUNGRY* (1)
			IMBIB* (1)
			INEDIBL* (1)
			INTESTIN* (1)
			JAW* (1)
			JUIC* (1)
			LAP (1)
			LAPS (1)
			LEMON* (1)
			LICK* (1)
			LIME (1)
			LIMES (1)
			LIP (1)
			LIPS (1)
			LIQUEUR* (1)
			LIQUOR* (1)
			LUNCH* (1)
			MAIZ* (1)
			MEAL* (1)
			MEAT* (1)
			MELON* (1)
			MENU* (1)
			MILK* (1)
			MINT* (1)
			MORSEL* (1)
			MOUTH* (1)
			MOUTHFUL* (1)
			MUSHROOM* (1)
			MUTTON* (1)
			NAUS* (1)
			NECTAR* (1)
			NIBBL* (1)
			NOURISH* (1)
			NOURISHMENT* (1)
			NURTUR* (1)
			NUT (1)
			NUTS (1)
			OLIV* (1)
			ORAL* (1)
			PALAT* (1)
			PARTAK* (1)
			PASTRI* (1)
			PASTRY* (1)
			PEA (1)
			PEANUT* (1)
			PEAR* (1)
			PEAS (1)
			PEPPER* (1)
			PHILTR* (1)
			PINEAPPL* (1)
			POISON* (1)
			PORK* (1)
			PORRIDG* (1)
			POT (1)
			POTATO* (1)
			POTBEL* (1)
			POTS (1)
			PUCKER* (1)
			PUMPKIN* (1)
			QUENCH* (1)
			RASPBERRY* (1)
			RAW (1)
			RAWLY (1)
			REPAST* (1)
			RESTAURANT* (1)
			RESTAURENT* (1)
			RICE (1)
			RICES (1)
			RIPENES* (1)
			ROAST* (1)
			RUM (1)
			RUMS (1)
			SALAD* (1)
			SALIVA* (1)
			SALIVAT* (1)
			SALT* (1)
			SAUC* (1)
			SAUERKRAUT* (1)
			SESAM* (1)
			SHERBERT* (1)
			SHERRY* (1)
			SOUP* (1)
			SPAT* (1)
			SPIT* (1)
			SPITTL* (1)
			SPOON* (1)
			STARV* (1)
			STARVAT* (1)
			STOMACH* (1)
			STRAWBERRI* (1)
			STRAWBERRY* (1)
			SUCK* (1)
			SUCKL* (1)
			SUGAR* (1)
			SUPPER* (1)
			SWALLOW* (1)
			TEA (1)
			TEAS (1)
			TEAT* (1)
			TEETH* (1)
			THIRST* (1)
			THIRSTY* (1)
			THROAT* (1)
			TIT (1)
			TITS (1)
			TOMATO* (1)
			TONGU* (1)
			TOOTH* (1)
			UNCOOK* (1)
			VEAL* (1)
			VEGETABL* (1)
			VENISON* (1)
			VODKA* (1)
			VOMIT* (1)
			WHEAT* (1)
			WHISKEY* (1)
			WHISKY* (1)
			YAM (1)
			YAMS* (1)
			YEAST* (1)
		ANALITY
			ANAL (1)
			ANUS (1)
			ANUSES (1)
			ARSE (1)
			ARSEHOL* (1)
			ASSES (1)
			ASS-HOL* (1)
			ASSHOL* (1)
			BESHAT* (1)
			BESHIT* (1)
			BESMEAR* (1)
			BILE* (1)
			BOWEL* (1)
			BUTTOCK* (1)
			CACK* (1)
			CESSPOOL* (1)
			CLOACA* (1)
			CLOT (1)
			CLOTS* (1)
			CONSTIPAT* (1)
			DANK* (1)
			DAUB* (1)
			DEFECAT* (1)
			DEFIL* (1)
			DELOUS* (1)
			DIARRHOEA* (1)
			DIRT* (1)
			DIRTY* (1)
			DISGUST* (1)
			DUNG* (1)
			DUNGHILL* (1)
			EFFLUVIA* (1)
			EFFLUVIUM* (1)
			ENEMA* (1)
			EXCRET* (1)
			FART (1)
			FARTS (1)
			FECAL* (1)
			FECES (1)
			FETID* (1)
			FETOR* (1)
			FILTH* (1)
			FILTHY* (1)
			IMPUR* (1)
			LATRIN* (1)
			LICE (1)
			LOATHSOM* (1)
			LOUS* (1)
			MAGGOT* (1)
			MAGGOTY* (1)
			MALODOROU* (1)
			MALODOUROU* (1)
			MANUR* (1)
			MESS (1)
			MESSES (1)
			MESSING (1)
			MIASMA* (1)
			MUD (1)
			MUDDY* (1)
			MUDS (1)
			OFFAL* (1)
			OOZ* (1)
			OOZY* (1)
			OUTHOUS* (1)
			PISS* (1)
			POLLUT* (1)
			PUTRESCENC* (1)
			PUTRESCENT* (1)
			PUTRID* (1)
			RANCID* (1)
			RECTUM* (1)
			REEK* (1)
			ROT (1)
			ROTS (1)
			ROTTEN* (1)
			ROTTING (1)
			RUMP* (1)
			SCUM* (1)
			SEWER* (1)
			SHAT* (1)
			SHIT* (1)
			SLIMY* (1)
			SMEAR* (1)
			SODOMIST* (1)
			SODOMY* (1)
			SOIL* (1)
			STAL* (1)
			STENCH* (1)
			STINK* (1)
			SWEAT* (1)
			UNCLEAN* (1)
			UNWASH* (1)
			URIN* (1)
		SEX
			VENEREAL* (1)
			ADULTERER* (1)
			ADULTERY* (1)
			ALLUR* (1)
			BAWD* (1)
			BAWDY* (1)
			BITCH* (1)
			BROTHEL* (1)
			CARESS* (1)
			CARNAL* (1)
			CIRCUMCIS* (1)
			CLITORI* (1)
			COHABIT* (1)
			COITU* (1)
			CONCUBIN* (1)
			COPULAT* (1)
			COQUETT* (1)
			COQUETTISH* (1)
			COURTESAN* (1)
			CUCKOLD* (1)
			CUNT* (1)
			CUPID* (1)
			DEBAUCH* (1)
			DEFLOWER* (1)
			EJACULAT* (1)
			EROTIC* (1)
			FONDL* (1)
			FORNICAT* (1)
			FUCK* (1)
			GENITAL* (1)
			GENITALIA* (1)
			GIRDL* (1)
			GROIN* (1)
			HAREM* (1)
			HARLOT* (1)
			HOMOSEXUAL* (1)
			HOMOSEXUALITY* (1)
			IMMODEST* (1)
			INCEST* (1)
			INCESTUOU* (1)
			INDECENT* (1)
			INDISCRET* (1)
			INFATUAT* (1)
			KISS* (1)
			LASCIVIOU* (1)
			LECHER* (1)
			LECHEROU* (1)
			LECHERY* (1)
			LEER (1)
			LEERS (1)
			LEWD* (1)
			LIBERTIN* (1)
			LICENTIOU* (1)
			LOVER* (1)
			LUST* (1)
			LUSTFUL* (1)
			LUSTY* (1)
			MASTURBAT* (1)
			MENSTRUAL* (1)
			MENSTRUAT* (1)
			MISTRES* (1)
			NAKED (1)
			NUDE (1)
			NUDES (1)
			OBSCEN* (1)
			OBSCENITY* (1)
			ORGASM* (1)
			ORGI* (1)
			ORGY* (1)
			PANDER* (1)
			PARAMOUR* (1)
			PENI* (1)
			PERVERS* (1)
			PERVERT* (1)
			PHALLIC* (1)
			PHALLU* (1)
			PREGNANCY* (1)
			PREGNANT* (1)
			PROCREAT* (1)
			PROSTITUT* (1)
			PRURIENT* (1)
			PUBERTY* (1)
			PUBI* (1)
			PUBIC* (1)
			RAPE* (1)
			RAPING* (1)
			RIBALD* (1)
			SATYR* (1)
			SEDUC* (1)
			SENSUAL* (1)
			SENSUOU* (1)
			SEX (1)
			SEXED (1)
			SEXES (1)
			SEX-LINKED (1)
			SEXUAL* (1)
			SEXY* (1)
			SHAMELES* (1)
			SLATTERN* (1)
			SLUT* (1)
			SLUTTY* (1)
			TESTI* (1)
			TESTICL* (1)
			THIGH* (1)
			TROLLOP* (1)
			UNBLUSH* (1)
			UNDRES* (1)
			VAGINA* (1)
			VENU* (1)
			VOLUPTUOU* (1)
			VULVA* (1)
			WAIST* (1)
			WANTON* (1)
			WHOR* (1)
			WOMB* (1)
			SENSATION (1)
	SENSATION
		TOUCH
			BRUSH* (1)
			COARS* (1)
			CONTACT* (1)
			CUDD* (1)
			CUDDL* (1)
			HANDL* (1)
			ITCH* (1)
			ITCHY* (1)
			MASSAG* (1)
			PRICKL* (1)
			ROUGH* (1)
			RUB (1)
			RUBB* (1)
			RUBS (1)
			SCALY (1)
			SCRATCH* (1)
			SHARP* (1)
			SLICK* (1)
			SLIPPERY* (1)
			SMOOTH* (1)
			SNUGGL* (1)
			STING (1)
			STINGS (1)
			STROK* (1)
			TEXTUR* (1)
			THICK* (1)
			TICKL* (1)
			TINGL* (1)
			TOUCH* (1)
			WAXY* (1)
		TASTE
			AFTERTAST* (1)
			BITTER* (1)
			DELECTABL* (1)
			DELICIOU* (1)
			FLAVOR* (1)
			GALL (1)
			HONI* (1)
			LUSCIOU* (1)
			PIQUANT* (1)
			SAVOR* (1)
			SAVORY* (1)
			SAVOUR* (1)
			SAVOURY* (1)
			SOUR* (1)
			SPIC* (1)
			SPICY* (1)
			SUGARY* (1)
			SWEET* (1)
			SWEETNES* (1)
			TANG* (1)
			TANGY* (1)
			TART* (1)
			TAST* (1)
			TASTY* (1)
			TOOTHSOM* (1)
			UNPALATABL* (1)
			UNSAVORY* (1)
			VINEGAR* (1)
			VINEGARY* (1)
		ODOR
			AROMA* (1)
			AROMATIC* (1)
			BREATH* (1)
			COLOGN* (1)
			FRAGRANC* (1)
			FRAGRANT* (1)
			FUME* (1)
			FUMING* (1)
			INCENS* (1)
			INHAL* (1)
			MUSK* (1)
			MUSKY* (1)
			MUSTY* (1)
			NOSE* (1)
			NOSTRIL* (1)
			ODOR* (1)
			ODOUR* (1)
			PERFUM* (1)
			PUNGENC* (1)
			PUNGENT* (1)
			SCENT* (1)
			SMEL* (1)
			SMELL* (1)
			SNIF* (1)
			SNIFF* (1)
		GENERAL-SENSATION
			APPERCEIVE (1)
			APPERCEPTIVE (1)
			ATTENT* (1)
			AWAR* (1)
			AWARENES* (1)
			BALMY* (1)
			BASK* (1)
			BEAUTIFUL* (1)
			BEAUTY* (1)
			CHARM* (1)
			COMFORT* (1)
			COMFORTABL* (1)
			CREAMY* (1)
			FAIR* (1)
			IMPRESS* (1)
			LOVELINES* (1)
			LUSH* (1)
			LUXURIOU* (1)
			LUXURY* (1)
			MILKY* (1)
			OVERSENSITIV* (1)
			PERCEIV* (1)
			PERCEPT* (1)
			PERCEPTUAL (1)
			PHYSICAL* (1)
			PLEASANT* (1)
			PRETTY* (1)
			REFRESH* (1)
			RELISH* (1)
			REVEL* (1)
			SENSAT* (1)
			SENSITIV* (1)
			STIMULAT* (1)
			SUMPTUOU* (1)
		SOUND
			AUDITORILLY (1)
			ALOUD* (1)
			AUDIBL* (1)
			AUDITION (1)
			AUDITORY* (1)
			AURAL (1)
			BANG* (1)
			BELL* (1)
			BINAURAL (1)
			BLAR* (1)
			BOOM* (1)
			BUZZ* (1)
			CHORD* (1)
			CHORU* (1)
			CLACK* (1)
			CLAMOR* (1)
			CLAMOUR* (1)
			CLANG* (1)
			CRACKL* (1)
			CROAK* (1)
			DEAF* (1)
			DRON* (1)
			DRUM* (1)
			EAR (1)
			EARS (1)
			ECHO* (1)
			HARK* (1)
			HEAR* (1)
			HEARD* (1)
			HISS* (1)
			HUM (1)
			HUMM* (1)
			HUMS (1)
			LISTEN* (1)
			LOUD* (1)
			LOUDER* (1)
			MELODI* (1)
			MELODIOU* (1)
			MELODY* (1)
			MUFFL* (1)
			MUSIC* (1)
			MUSICAL* (1)
			NOIS* (1)
			NOISY* (1)
			PEAL* (1)
			PURR* (1)
			RACKET* (1)
			RASP* (1)
			RATTL* (1)
			RAUCOU* (1)
			RESONANT* (1)
			RESOUND* (1)
			RHYTHM* (1)
			RING* (1)
			RUMBL* (1)
			RUSTL* (1)
			SERENAD* (1)
			SHRILL* (1)
			SNAP* (1)
			SONOROU* (1)
			SOUND* (1)
			STRIDANT* (1)
			STRIDENT* (1)
			SWISH* (1)
			SYMPHONY* (1)
			TEMPO* (1)
			THUD* (1)
			TIMBR* (1)
			TINKL* (1)
			TONAL (1)
			TONE (1)
			TONED (1)
			TONES (1)
			TRILL* (1)
			TUNE (1)
			TUNED (1)
			TUNES (1)
			TUNING* (1)
			UNHEARD* (1)
			VOCAL* (1)
			VOIC* (1)
			WHIR* (1)
			WHIRR* (1)
			WHISTL* (1)
			AFTER-IMAGE* (1)
		VISION
			BLINK* (1)
			ILLUMINANT (1)
			INVISIBILITY (1)
			MONOCULAR (1)
			AMBER* (1)
			APPEAR* (1)
			APPEARANC* (1)
			AURORA* (1)
			AZUR* (1)
			BEAM* (1)
			BEHOLD* (1)
			BINOCULAR (1)
			BLUE* (1)
			BLUISH* (1)
			BRIGHT* (1)
			BROWN* (1)
			BRUNETT* (1)
			CHROMATIC* (1)
			COLOR* (1)
			COLOUR* (1)
			COMPLEX* (1)
			CRIMSON* (1)
			DISCERN* (1)
			DYE* (1)
			EMERALD* (1)
			FILM* (1)
			FLASH* (1)
			FLICKER* (1)
			FLOURESCENT* (1)
			GAZE* (1)
			GAZING* (1)
			GLANC* (1)
			GLAR* (1)
			GLEAM* (1)
			GLIMPS* (1)
			GLINT* (1)
			GLISTEN* (1)
			GLITTER* (1)
			GLOSSY* (1)
			GLOW* (1)
			GRAY* (1)
			GREEN* (1)
			GREY* (1)
			HALO* (1)
			HUE* (1)
			ILLUMINAT* (1)
			IMAG* (1)
			INVISIBL* (1)
			LAMP* (1)
			LANTERN* (1)
			LAVENDER* (1)
			LIGHT* (1)
			LIGHTEN* (1)
			LIGHTN* (1)
			LIMPID* (1)
			LOOK* (1)
			LUCID* (1)
			LUMINANCE (1)
			LUMINOU* (1)
			LUSTER* (1)
			LUSTROU* (1)
			MOONBEAM* (1)
			MOONLIGHT* (1)
			NOTIC* (1)
			OBSERV* (1)
			OPAQU* (1)
			PAINT* (1)
			PEEK* (1)
			PEER* (1)
			PICTUR* (1)
			PINK* (1)
			RADIANC* (1)
			RADIANT* (1)
			RAY (1)
			RAYS (1)
			REGARD* (1)
			ROSY* (1)
			ROUG* (1)
			RUBY* (1)
			RUDDY* (1)
			SAPPHIR* (1)
			SAW (1)
			SCAN (1)
			SCANN* (1)
			SCANS (1)
			SCARLET* (1)
			SCEN* (1)
			SCENIC* (1)
			SEE (1)
			SEEING* (1)
			SEEN* (1)
			SEES (1)
			SHEEN* (1)
			SHIMMER* (1)
			SHIN* (1)
			SHON* (1)
			SIGHT* (1)
			SPARKL* (1)
			SPIED (1)
			SPIES (1)
			SPY (1)
			SPYING* (1)
			STAR (1)
			STARLIGHT* (1)
			STARS (1)
			SUNLIGHT* (1)
			SUNSHIN* (1)
			SURVEY* (1)
			TAN (1)
			TANNED (1)
			TANNING* (1)
			TANS (1)
			TINT* (1)
			TRANSLUCENT* (1)
			TRANSPARENT* (1)
			TWINKL* (1)
			UNSEEN* (1)
			VIEW* (1)
			VIOLET* (1)
			VISIBL* (1)
			VISION* (1)
			VISUAL* (1)
			WATCH* (1)
			WITNES* (1)
			YELLOW* (1)
		COLD
			ALASKA* (1)
			ARCTIC* (1)
			BENUMB* (1)
			CHIL* (1)
			CHILL* (1)
			COLD* (1)
			COLDER* (1)
			COOL* (1)
			FREEZ* (1)
			FRIGID* (1)
			FROST* (1)
			FROSTBIT* (1)
			FROZ* (1)
			FROZEN* (1)
			GLACIER* (1)
			HOAR* (1)
			ICE* (1)
			ICINES* (1)
			ICING* (1)
			ICY (1)
			NORTH* (1)
			NORTHERN* (1)
			NUMB (1)
			NUMBNESS* (1)
			POLAR* (1)
			SHIVER* (1)
			SIBERIA* (1)
			SLEET* (1)
			SNOW* (1)
			SNOWSTORM* (1)
			SNOWY* (1)
			THUL* (1)
			WINTER* (1)
			WINTRY* (1)
		HARD
			ALABASTER* (1)
			BRAS* (1)
			BRASSY* (1)
			BRAZEN* (1)
			BRITTL* (1)
			BRONZ* (1)
			COPPER* (1)
			CRISP* (1)
			CRISPY* (1)
			GLAS* (1)
			GLASSY* (1)
			GRANIT* (1)
			GRAVEL* (1)
			HARD* (1)
			IRON* (1)
			MARBL* (1)
			METAL* (1)
			METALLIC* (1)
			NAIL* (1)
			PEBB* (1)
			PORCELAIN* (1)
			RIGID* (1)
			ROCK* (1)
			SOLID* (1)
			SPLINTER* (1)
			STEEL* (1)
			STIFF* (1)
			STON* (1)
			STONY* (1)
			ZINC* (1)
		SOFT
			DAMASK* (1)
			DELICAT* (1)
			DOWNY* (1)
			FEATHER* (1)
			FLEEC* (1)
			FLEECY* (1)
			FLUFFY* (1)
			GENTL* (1)
			GENTLENES* (1)
			GOSSAMER* (1)
			LACE (1)
			LACES (1)
			LACING* (1)
			LACY* (1)
			MELLOW* (1)
			MILD* (1)
			MURMUR* (1)
			PLIANT* (1)
			POWDERY* (1)
			SATIN* (1)
			SATINY* (1)
			SILK* (1)
			SOFT* (1)
			TENDER* (1)
			TING* (1)
			VELVET* (1)
			VELVETY* (1)
			WHISPER* (1)
	DEFENSIVE SYMBOLIZATION
		PASSIVITY
			STAGNANT (1)
			APATHETIC* (1)
			APATHY* (1)
			BED (1)
			BEDD* (1)
			BEDS (1)
			BOREDOM* (1)
			CALM* (1)
			CONTENTED* (1)
			CONTENTMENT* (1)
			COUCH* (1)
			COZY* (1)
			DEAD* (1)
			DEATH* (1)
			DECAY* (1)
			DIE (1)
			DIED* (1)
			DIES (1)
			DORMANT* (1)
			DRIFT* (1)
			DYING* (1)
			EASE* (1)
			EASED (1)
			EASES (1)
			HUSH* (1)
			IDL* (1)
			IMMOBIL* (1)
			INACTIV* (1)
			INACTIVITY* (1)
			INDIFFERENC* (1)
			INDIFFERENT* (1)
			INDOLENT* (1)
			INERT* (1)
			INERTIA* (1)
			INNERT* (1)
			LAID* (1)
			LAIN* (1)
			LANGOROU* (1)
			LANGUID* (1)
			LANGUISH* (1)
			LANGUOR* (1)
			LASSITUD* (1)
			LAY (1)
			LAYING* (1)
			LAYS (1)
			LAZY* (1)
			LEADEN* (1)
			LEISUR* (1)
			LETHARGIC* (1)
			LETHARGY* (1)
			LIE (1)
			LIES (1)
			LINGER* (1)
			LISTLES* (1)
			LUL* (1)
			LULL* (1)
			MOTIONLES* (1)
			NESTL* (1)
			NONCHALANC* (1)
			NONCHALANT* (1)
			PASSIV* (1)
			PASSIVITY* (1)
			PEACEFUL* (1)
			PERISH* (1)
			PHLEGMATIC* (1)
			PLACID* (1)
			PROCRASTINAT* (1)
			QUIET* (1)
			RELAX* (1)
			RELAXAT* (1)
			REPOS* (1)
			REST* (1)
			RESTFUL* (1)
			RETIR* (1)
			SAFE (1)
			SAFELY (1)
			SAFETY* (1)
			SECUR* (1)
			SECURITY* (1)
			SEDENTARY* (1)
			SEREN* (1)
			SERENITY* (1)
			SILENC* (1)
			SILENT* (1)
			SLACK* (1)
			SLOTHFUL* (1)
			SLOW* (1)
			SLUGGISH* (1)
			SOLAC* (1)
			SOOTH* (1)
			STAGNAT* (1)
			STATIC* (1)
			STILLNES* (1)
			SUBMISS* (1)
			SUBMISSIV* (1)
			SUBMIT* (1)
			SUCCUMB* (1)
			TRANQ* (1)
			UNHURRI* (1)
			VAGRANT* (1)
			VELLEITY* (1)
			WEARISOM* (1)
			WEARY* (1)
			YIELD* (1)
		VOYAGE
			CARAVAN* (1)
			CHAS* (1)
			CRUIS* (1)
			DESERT* (1)
			DRIV* (1)
			EMBARK* (1)
			EMIGRAT* (1)
			EXPLOR* (1)
			IMMIGRAT* (1)
			IMMIGRANT* (1)
			JOURNEY* (1)
			MIGRAT* (1)
			NAVIGAT* (1)
			NOMAD* (1)
			NOMADIC* (1)
			OSCILLAT* (1)
			PILGRIM* (1)
			PILGRIMAG* (1)
			RIDE (1)
			RIDES (1)
			RIDING* (1)
			ROAM* (1)
			RODE (1)
			ROV* (1)
			SAIL* (1)
			SAILOR* (1)
			SEAFAR* (1)
			SEARCH* (1)
			SHIP* (1)
			STRAY* (1)
			TOUR* (1)
			TOURIST* (1)
			TRAVEL* (1)
			TREK* (1)
			TRIP* (1)
			VAGABOND* (1)
			VOYAG* (1)
			WANDER* (1)
			WANDERLUST* (1)
			WAYFARER* (1)
			WILDERNES* (1)
			YONDER* (1)
		RANDOM MOVEMENT
			ACTIVITI* (1)
			ACTIVITY* (1)
			AGITAT* (1)
			CHURN* (1)
			COMMOT* (1)
			CONVULS* (1)
			EXPAND* (1)
			EXPANS* (1)
			FIDGET* (1)
			FLOUNDER* (1)
			FLURRI* (1)
			FLURRY* (1)
			JERK* (1)
			LURCH* (1)
			ORBIT* (1)
			PITCH* (1)
			PIVOT* (1)
			PULS* (1)
			PULSAT* (1)
			QUAK* (1)
			QUIVER* (1)
			REEL* (1)
			REVOLV* (1)
			ROL* (1)
			ROLL* (1)
			ROTAT* (1)
			SEETH* (1)
			SHAK* (1)
			SHOOK* (1)
			SPASM* (1)
			SPIN* (1)
			SPREAD* (1)
			STAGGER* (1)
			STIR* (1)
			SWAY* (1)
			SWEL* (1)
			SWELL* (1)
			SWIVEL* (1)
			SWOLLEN* (1)
			THROB* (1)
			TOTTER* (1)
			TWICH* (1)
			TWIST* (1)
			TWITCH* (1)
			UNDULAT* (1)
			VIBRAT* (1)
			WAVE (1)
			WAVED (1)
			WAVES (1)
			WAVING* (1)
			WHIRL* (1)
			WOBBL* (1)
		DIFFUSION
			BLUR* (1)
			CLOUD* (1)
			CLOUDY* (1)
			CURTAIN* (1)
			DARKEN* (1)
			DIFFUS* (1)
			DIM (1)
			DIMM* (1)
			DIMS (1)
			EQUIVOCAL* (1)
			FADE (1)
			FADED (1)
			FADES* (1)
			FADING* (1)
			FOG (1)
			FOGG* (1)
			FOGS (1)
			HAZE* (1)
			HAZING* (1)
			HAZY* (1)
			INDEFINIT* (1)
			INDISTINCT* (1)
			MIST* (1)
			MISTY* (1)
			MURKINES* (1)
			MURKY* (1)
			NEBULA* (1)
			NEBULOU* (1)
			OBSCUR* (1)
			OVERCAST* (1)
			SCREEN* (1)
			SHAD* (1)
			SHADOW* (1)
			SHADOWY* (1)
			SHADY* (1)
			TWILIGHT* (1)
			UNCERTAIN* (1)
			UNCERTAINT* (1)
			UNCLEAR* (1)
			VAGU* (1)
			VAPOR* (1)
			VAPOUR* (1)
			VEIL* (1)
		CHAOS
			AIMLES* (1)
			AMBIGUIT* (1)
			AMBIGUOU* (1)
			ANARCHY* (1)
			CHANC* (1)
			CHAO* (1)
			CHAR (1)
			CHARS (1)
			CATASTROPHE (1)
			CONFUS* (1)
			CROWD* (1)
			DISCORD* (1)
			DISCORDANT* (1)
			DISHEVEL* (1)
			DISORDER* (1)
			ENTANGL* (1)
			GORDIAN* (1)
			HAPHAZARD* (1)
			IRREGULAR* (1)
			JUMBL* (1)
			JUNGL* (1)
			LABYRINTH* (1)
			LAWLES* (1)
			LITTER* (1)
			MOB (1)
			MOBB* (1)
			MOBS (1)
			OVERGROWN* (1)
			OVERRUN* (1)
			PERPLEX* (1)
			RANDOM* (1)
			RUIN* (1)
			UNRU* (1)
			WILD* (1)
	REGRESSIVE COGNITION
		UNKNOWN
			BIZZAR* (1)
			BODILES* (1)
			BOUNDLES* (1)
			CRYPTIC* (1)
			ENIGMA* (1)
			ESOTERIC* (1)
			EXOTIC* (1)
			FANTASTIC* (1)
			FORMLES* (1)
			IMMEASURABL* (1)
			INCONCEIVABL* (1)
			INCREDIBL* (1)
			INDESCRIBABL* (1)
			INEFFABL* (1)
			INFINITY* (1)
			INSCRUTABL* (1)
			LIMITLES* (1)
			MAGI* (1)
			MAGIC* (1)
			MAGU* (1)
			MARVEL* (1)
			MYST* (1)
			NAMELES* (1)
			NOTHINGNES* (1)
			NUMBERLES* (1)
			OCCULT* (1)
			ODD* (1)
			SECRECY* (1)
			SECRET* (1)
			SHAPELES* (1)
			SORCERER* (1)
			SORCERES* (1)
			STRANG* (1)
			TRANSCEND* (1)
			UNBELIEVABL* (1)
			UNBOUND* (1)
			UNIMAGINABL* (1)
			UNKNOWN* (1)
			UNLIMIT* (1)
			UNSPEAKABL* (1)
			UNTOLD* (1)
			VOID* (1)
		TIMELESSNESS
			AEON* (1)
			CEASELES* (1)
			CENTURI* (1)
			CENTURY* (1)
			CONTINUAL* (1)
			CONTINUOU* (1)
			ENDLES* (1)
			ENDUR* (1)
			EON* (1)
			ETERNAL* (1)
			ETERNITY* (1)
			EVERLAST* (1)
			FOREVER* (1)
			IMMORTAL* (1)
			INCESSANT* (1)
			LIFETIM* (1)
			OUTLIV* (1)
			PERMANENC* (1)
			PERMANENT* (1)
			PERPETUAL* (1)
			TIMELESSNES* (1)
			UNCEAS* (1)
			UNDY* (1)
			UNEND* (1)
			TEST5
		CONSCIOUSNESS ALTERATION
			AMUCK* (1)
			ASLEEP* (1)
			AWAK* (1)
			AWAKEN* (1)
			BEDLAM* (1)
			COMA* (1)
			CRAZ* (1)
			CRAZY* (1)
			DELIRIOU* (1)
			DELIRIUM* (1)
			DELPHIC* (1)
			DEMENT* (1)
			DOZE (1)
			DOZED (1)
			DOZES (1)
			DOZING (1)
			DREAM* (1)
			DREAMY* (1)
			DROWSY* (1)
			ECSTACY* (1)
			ECSTASY* (1)
			ECSTATIC* (1)
			ENCHANT* (1)
			EPILEPSY* (1)
			EPILEPTIC* (1)
			EXSTASY* (1)
			FAINT* (1)
			FANTASI* (1)
			FANTASY* (1)
			FEBRIL* (1)
			FEVER* (1)
			FEVERISH* (1)
			FRENZY* (1)
			HALLUCINAT* (1)
			HASHISH* (1)
			HIBERNAT* (1)
			HYPNO* (1)
			HYSTERIA* (1)
			HYSTERIC* (1)
			IMAGIN* (1)
			IMAGINAT* (1)
			INSAN* (1)
			INSANITY* (1)
			INTUIT* (1)
			IRRATIONAL* (1)
			LAUDANUM* (1)
			LUNACY* (1)
			LUNATIC* (1)
			MAD (1)
			MADLY (1)
			MADMAN* (1)
			MADMEN* (1)
			MADNES* (1)
			MADWOMAN* (1)
			MADWOMEN* (1)
			MANIA* (1)
			MANIAC* (1)
			MEDITAT* (1)
			MESMERIZ* (1)
			MONOMANIA* (1)
			NAP (1)
			NAPP* (1)
			NAPS (1)
			NEUROSI* (1)
			NEUROTIC* (1)
			NIGHTMAR* (1)
			NIGHTMARISH* (1)
			OPIUM* (1)
			OPIATES (1)
			ORACL* (1)
			PARANO* (1)
			PREMONIT* (1)
			PSYCHIC* (1)
			PSYCHOSI* (1)
			PSYCHOTIC* (1)
			RAPTUR* (1)
			RAPTUROU* (1)
			REVERI* (1)
			REVERY* (1)
			REVIV* (1)
			SEER* (1)
			SLEEP* (1)
			SLEEPY* (1)
			SLUMBER* (1)
			STUPOR* (1)
			SWOON* (1)
			TELEPATHY* (1)
			TRANC* (1)
			UNREASON* (1)
			VERTIGO* (1)
			VISIONARY* (1)
			WAK* (1)
			WOKE (1)
		BRINK-PASSAGE
			ACCES* (1)
			AISL* (1)
			AQUEDUCT* (1)
			ARTERI* (1)
			ARTERY* (1)
			AVENU* (1)
			BARRIER* (1)
			BORDER* (1)
			BOUNDARI* (1)
			BOUNDARY* (1)
			BRIDG* (1)
			BRIM* (1)
			BRINK* (1)
			CANAL* (1)
			CHANNEL* (1)
			COAST* (1)
			CONDUIT* (1)
			CORRIDOR* (1)
			CURB* (1)
			DOOR* (1)
			DOORSTEP* (1)
			DOORWAY* (1)
			EDG* (1)
			ENTRANC* (1)
			ENTRY* (1)
			FENC* (1)
			FERRI* (1)
			FERRY* (1)
			FLOOR* (1)
			FOOTPATH* (1)
			FOYER* (1)
			FRAM* (1)
			FRING* (1)
			FRONTIER* (1)
			GATE* (1)
			GATING* (1)
			HALL* (1)
			HALLWAY* (1)
			HIGHWAY* (1)
			HORIZON* (1)
			LANE (1)
			LANES (1)
			LEDG* (1)
			LINE (1)
			LINED (1)
			LINES (1)
			LINING* (1)
			MARGIN* (1)
			PASSAG* (1)
			PASSAGEWAY* (1)
			PATH* (1)
			PERIMET* (1)
			PERIPHER* (1)
			PORT* (1)
			RAILROAD* (1)
			RAILWAY* (1)
			RIM (1)
			RIMM* (1)
			RIMS (1)
			ROAD* (1)
			ROUT* (1)
			SIDEWALK* (1)
			SKYLIN* (1)
			STAIR* (1)
			STEP* (1)
			STREET* (1)
			THRESHOLD* (1)
			TRAIL* (1)
			VERG* (1)
			VIADUCT* (1)
			VISTA* (1)
			WALL* (1)
			WINDOW* (1)
		NARCISSISM
			ARM (1)
			ARMS (1)
			BEARD* (1)
			BLOOD* (1)
			BODI* (1)
			BODY* (1)
			BONE (1)
			BONES (1)
			BRAIN* (1)
			BROW (1)
			BROWS (1)
			CHEEK* (1)
			CHEST* (1)
			CHIN* (1)
			CORPS* (1)
			EYE* (1)
			FACE (1)
			FACES (1)
			FACIES (1)
			FEET* (1)
			FLESH* (1)
			FOOT* (1)
			FOREHEAD* (1)
			HAIR* (1)
			HAND* (1)
			HEAD* (1)
			HEART* (1)
			HEEL* (1)
			HIP (1)
			HIPS (1)
			KIDNEY* (1)
			KNEE (1)
			KNEES (1)
			LEG (1)
			LEGS (1)
			LIMB* (1)
			LIVER* (1)
			MUSCL* (1)
			NAVEL* (1)
			NECK* (1)
			ORGAN* (1)
			PALM* (1)
			RIB (1)
			RIBS (1)
			SHOULDER* (1)
			SKIN* (1)
			SKULL* (1)
			THUMB* (1)
			TOE (1)
			TOES (1)
			VEIN* (1)
			WRIST* (1)
		CONCRETENESS
			ACROS* (1)
			AFAR* (1)
			AFIELD* (1)
			AHEAD* (1)
			ALONG* (1)
			AMONG* (1)
			APART* (1)
			ASID* (1)
			AT (1)
			AWAY* (1)
			BACK* (1)
			BEHIND* (1)
			BESID* (1)
			BETWEEN* (1)
			CENTER* (1)
			CENTR* (1)
			CIRCL* (1)
			CLOS* (1)
			CLOSER* (1)
			CORNER* (1)
			CURV* (1)
			DISTANC* (1)
			DISTANT* (1)
			EAST* (1)
			EASTERN* (1)
			EVERYWHER* (1)
			EXTEND* (1)
			EXTENSIV* (1)
			EXTENT* (1)
			FAR (1)
			FARTHER* (1)
			FLAT* (1)
			FORWARD* (1)
			FRONT* (1)
			FURTHER* (1)
			HERE (1)
			HITHER* (1)
			INSID* (1)
			INTERIOR* (1)
			LAYER* (1)
			LENGTH* (1)
			LEVEL* (1)
			LONG* (1)
			MIDDL* (1)
			MIDST* (1)
			NARROW* (1)
			NEAR* (1)
			NEARBY* (1)
			NEARER* (1)
			NEAREST* (1)
			OFF (1)
			OPEN* (1)
			OUT (1)
			OUTING* (1)
			OUTS (1)
			OUTSID* (1)
			OUTWARD* (1)
			OVER* (1)
			PLAC* (1)
			POINT* (1)
			POSIT* (1)
			REAR* (1)
			REGION* (1)
			ROUND* (1)
			SEPARAT* (1)
			SIDE (1)
			SIDED (1)
			SIDES (1)
			SIDING* (1)
			SITUAT* (1)
			SOMEWHER* (1)
			SOUTH* (1)
			SPAC* (1)
			SPACIOU* (1)
			SPATIAL (1)
			SQUAR* (1)
			STRAIGHT* (1)
			SURFAC* (1)
			SURROUND* (1)
			THENC* (1)
			THITHER* (1)
			TIP (1)
			TIPP* (1)
			TIPS (1)
			TOWARD* (1)
			WEST* (1)
			WESTERN* (1)
			WHER* (1)
			WHEREVER* (1)
			WIDE* (1)
			WIDTH* (1)
			WITHIN* (1)
	ICARIAN IMAGERY
		ASCENT
			ALOFT* (1)
			ARIS* (1)
			ARISEN* (1)
			AROS* (1)
			ASCEND* (1)
			ASCENS* (1)
			BOUNC* (1)
			CLIMB* (1)
			DANGL* (1)
			DAWN* (1)
			FLAP* (1)
			FLED (1)
			FLEW* (1)
			FLIER* (1)
			FLIGHT* (1)
			FLING* (1)
			FLOAT* (1)
			FLOWN* (1)
			FLUNG* (1)
			FLUTTER* (1)
			FLY* (1)
			HANG* (1)
			HOVER* (1)
			HURL* (1)
			ICARIAN* (1)
			ICARU* (1)
			JUMP* (1)
			LEAP* (1)
			LEPT* (1)
			LIFT* (1)
			MOUNT* (1)
			MOUNTAINSID* (1)
			RISE (1)
			RISEN* (1)
			RISES (1)
			RISING* (1)
			SOAR* (1)
			SPRANG* (1)
			SPRING* (1)
			SPRUNG* (1)
			SUNRIS* (1)
			SWING* (1)
			THREW* (1)
			THROW* (1)
			THROWN* (1)
			TOSS* (1)
			UPHILL* (1)
			UPWARD* (1)
			WING* (1)
		HEIGHT
			ABOV* (1)
			AERIAL* (1)
			AIRPLAN* (1)
			ARCH (1)
			ATMOSPHER* (1)
			BALCONY* (1)
			BATTLEMENT* (1)
			BIRD* (1)
			BRANCH* (1)
			CEIL* (1)
			CLIFF* (1)
			CRAG* (1)
			CRAGGY* (1)
			DOME (1)
			DOMES (1)
			DOMING (1)
			ELEVAT* (1)
			ERECT* (1)
			GREW* (1)
			GROW* (1)
			GROWN* (1)
			HEAP* (1)
			HEAVEN* (1)
			HEIGHT* (1)
			HIGH* (1)
			HIGHER* (1)
			HILL* (1)
			HILLSID* (1)
			HILLTOP* (1)
			HUNG* (1)
			LADDER* (1)
			LOFT* (1)
			LOFTY* (1)
			MOUND* (1)
			MOUNTAIN* (1)
			OBELISK* (1)
			OVERHEAD* (1)
			PEAK* (1)
			PILE* (1)
			PILING* (1)
			PLANET* (1)
			PRECIPIC* (1)
			PYRAMID* (1)
			RAFTER* (1)
			RAINBOW* (1)
			RAMPART* (1)
			RIDG* (1)
			ROOF* (1)
			SKY (1)
			SLOP* (1)
			SPIR* (1)
			STEEP* (1)
			SUMMIT* (1)
			TALL* (1)
			TALLER* (1)
			TALLEST* (1)
			TOP (1)
			TOPP* (1)
			TOPS (1)
			TOWER* (1)
			TREE* (1)
			TRELLI* (1)
			UPPER* (1)
			UPPERMOST* (1)
			ZENITH* (1)
		DESCENT
			BASE (1)
			BASES (1)
			BURI* (1)
			BURROW* (1)
			BURY* (1)
			DESCEND* (1)
			DESCENT* (1)
			DIG (1)
			DIGG* (1)
			DIGS (1)
			DIP (1)
			DIPP* (1)
			DIPS (1)
			DIVE* (1)
			DOWNHILL* (1)
			DOWNSTREAM* (1)
			DROOP* (1)
			DROP (1)
			DROPS (1)
			DUG (1)
			FALL* (1)
			FALLEN* (1)
			FELL* (1)
			HEADLONG* (1)
			LEAN* (1)
			PLUNG* (1)
			RECED* (1)
			RECLIN* (1)
			SANK* (1)
			SINK* (1)
			SLID* (1)
			SLIP* (1)
			STOOP* (1)
			SUNDOWN* (1)
			SUNK* (1)
			SUNKEN* (1)
			SUNSET* (1)
			SWOOP* (1)
			TOPPL* (1)
			TUMBL* (1)
		DEPTH
			BELOW* (1)
			BENEATH* (1)
			BOTTOM* (1)
			CANYON* (1)
			CAVE* (1)
			CAVING* (1)
			CELLAR* (1)
			CHASM* (1)
			CREVAS* (1)
			DEEP* (1)
			DEEPER* (1)
			DEPTH* (1)
			DITCH* (1)
			DOWNWARD* (1)
			GUTTER* (1)
			HOLE (1)
			HOLES (1)
			LOW* (1)
			PIT (1)
			PITS (1)
			PITT* (1)
			PRECIPITOU* (1)
			RAVIN* (1)
			ROOT* (1)
			SUBMARIN* (1)
			TRENCH* (1)
			TUNNEL* (1)
			UNDER (1)
			UNDERGROUND* (1)
			UNDERNEATH* (1)
			UNDERWORLD* (1)
			VALLEY* (1)
		FIRE
			SOLAR (1)
			ABLAZ* (1)
			AFIR* (1)
			ASH (1)
			ASHES (1)
			BLAST* (1)
			BLAZ* (1)
			BOIL* (1)
			BROIL* (1)
			BURN* (1)
			BURNT* (1)
			CANDL* (1)
			CHARCOAL* (1)
			COAL* (1)
			COMBUST* (1)
			EMBER* (1)
			FIERY* (1)
			FIRE* (1)
			FLAM* (1)
			HEARTH* (1)
			HEAT* (1)
			HOT (1)
			IGNIT* (1)
			INFERNO* (1)
			INFLAM* (1)
			KINDL* (1)
			LIT (1)
			MELT* (1)
			SCORCH* (1)
			SEAR* (1)
			SIZZL* (1)
			SMOK* (1)
			SMOLDER* (1)
			SMOULDER* (1)
			SPARK* (1)
			SULTRY* (1)
			SUN (1)
			SUNN* (1)
			SUNS (1)
			SUNSTROK* (1)
			TROPIC* (1)
			TROPICAL* (1)
			WARM* (1)
			WARMTH* (1)
		WATER
			BATH* (1)
			BEACH* (1)
			BROOK* (1)
			BUBBL* (1)
			BUCKET* (1)
			CREEK* (1)
			DAM (1)
			DAMM* (1)
			DAMP* (1)
			DAMS (1)
			DEW (1)
			DEWS (1)
			DEWY (1)
			DIKE* (1)
			DOWNPOUR* (1)
			DRENCH* (1)
			SHORING (1)
			SURF (1)
			SURFING (1)
			DRIP* (1)
			FEN (1)
			FLOOD* (1)
			FLUID* (1)
			FOAM* (1)
			FOUNTAIN* (1)
			GURGL* (1)
			HUMID* (1)
			LAKE (1)
			LAKES (1)
			LIQUID* (1)
			MOAT* (1)
			MOIST* (1)
			MOISTUR* (1)
			MOSS (1)
			MOSSES (1)
			OCEAN* (1)
			OVERFLOW* (1)
			PERSPIR* (1)
			PERSPIRAT* (1)
			POND* (1)
			POOL* (1)
			POUR* (1)
			RAIN* (1)
			RAINFALL* (1)
			RIVER* (1)
			SATURAT* (1)
			SEA (1)
			SEAS (1)
			SHORE (1)
			SHORES (1)
			SHOWER* (1)
			SOAK* (1)
			SPLASH* (1)
			SPRINKL* (1)
			STEAM* (1)
			STEAMY* (1)
			STREAM* (1)
			SWAM* (1)
			SWAMP* (1)
			SWAMPY* (1)
			SWIM* (1)
			SWUM* (1)
			TIDE (1)
			TIDES (1)
			TIDING (1)
			TRICKL* (1)
			WADE* (1)
			WADING (1)
			WASH* (1)
			WATER* (1)
			WATERFALL* (1)
			WET* (1)
SECONDARY
	ABSTRACTION
		DIVERSE (1)
		DIVERSIFICATION (1)
		DIVERSIFIED (1)
		DIVERSITY (1)
		EVIDENT (1)
		EVIDENTIAL (1)
		GUESS* (1)
		LOGISTIC (1)
		ABSTRACT* (1)
		ALMOST* (1)
		ALTERNATIV* (1)
		ANALY* (1)
		ATTRIBUT* (1)
		AXIOM* (1)
		BASIC* (1)
		BELIEF* (1)
		BELIEV* (1)
		CALCULAT* (1)
		CAUS* (1)
		CERTAIN* (1)
		CHARACTERIZ* (1)
		CHOIC* (1)
		CHOOS* (1)
		CHOS* (1)
		CIRCUMSTANC* (1)
		COMPREHEND* (1)
		COMPAR* (1)
		COMPREHENS* (1)
		CONDITIONAL* (1)
		CONCENTRAT* (1)
		CONCEPT* (1)
		CONCLUD* (1)
		CONJECTUR* (1)
		CONSEQUENC* (1)
		CONSEQUENT* (1)
		CONSIDER* (1)
		CONTRIV* (1)
		CRITER* (1)
		CRITERIA* (1)
		DECID* (1)
		DEEM* (1)
		DEFIN* (1)
		DELIBERAT* (1)
		DETERMIN* (1)
		DIFFERENC* (1)
		DIFFERENT* (1)
		DISTINCT* (1)
		DISTINGUISH* (1)
		DOCTRIN* (1)
		EFFECT* (1)
		ESTABLISH* (1)
		ESTIMAT* (1)
		EVALUAT* (1)
		EVIDENC* (1)
		EXAMIN* (1)
		EXAMPL* (1)
		EXCEPT* (1)
		FACT (1)
		FACTS (1)
		FEATUR* (1)
		FIGUR* (1)
		FORETHOUGHT* (1)
		FORMULAT* (1)
		GUES* (1)
		HISTORY* (1)
		IDEA* (1)
		IMPORTANC* (1)
		IMPORTANT* (1)
		INFORMAT* (1)
		INTERPRET* (1)
		INTERPRETAT* (1)
		JUDG* (1)
		JUDGMENT* (1)
		KNEW* (1)
		KNOW* (1)
		LEARN* (1)
		LOGIC* (1)
		MAY (1)
		MEANT* (1)
		MISTAK* (1)
		MISTAKEN* (1)
		MISTOOK* (1)
		MODEL* (1)
		OPIN* (1)
		OTHERWIS* (1)
		PERHAP* (1)
		PLAN* (1)
		POSSI* (1)
		PREDICAT* (1)
		PREDICT* (1)
		PROBAB* (1)
		PROBABL* (1)
		PROBLEM* (1)
		PROOF* (1)
		PROV* (1)
		PURPOS* (1)
		QUALI* (1)
		QUANT* (1)
		RE-ANALY* (1)
		RE-EXAMIN* (1)
		RATIONAL* (1)
		REAL (1)
		REALITY* (1)
		REASON* (1)
		REASONABL* (1)
		RECONSIDER* (1)
		REEXAMIN* (1)
		REFORMULAT* (1)
		REINTERPRETAT* (1)
		RELEARN* (1)
		RELEVANC* (1)
		RELEVANT* (1)
		RESEARCH* (1)
		RESOLV* (1)
		SCHEM* (1)
		SCIENC* (1)
		SCIENTIFIC* (1)
		SELECT* (1)
		SIGNIFICANC* (1)
		SOLUT* (1)
		SOMETH* (1)
		SOMEWHAT* (1)
		SOURC* (1)
		SUBJECT* (1)
		SUPPOS* (1)
		SURE (1)
		SURELY (1)
		TEND* (1)
		THEM* (1)
		THEOR* (1)
		THINK* (1)
		THINKER* (1)
		THOUGHT* (1)
		TOPIC* (1)
		TRUE (1)
		TRULY (1)
		TRUTH* (1)
		TTT1 (1)
		UNDERSTAND* (1)
		UNDERSTOOD* (1)
		WEIGH (1)
		WEIGHED* (1)
		WEIGHING* (1)
		WEIGHS (1)
		WHY (1)
	SOCIAL BEHAVIOR
		GUEST* (1)
		QUOTA (1)
		QUOTA-* (1)
		QUOTAS (1)
		ACQUIESCENCE (1)
		APPROBATION (1)
		CONSENSUS* (1)
		CONSULT (1)
		PROSOCIAL (1)
		SOCIABLE (1)
		ABLE* (1)
		ACCEPT* (1)
		ACCEPTANC* (1)
		ADDRES* (1)
		ADMIT* (1)
		ADVIC* (1)
		ADVIS* (1)
		AGRE* (1)
		AID* (1)
		ALLOW* (1)
		ANNOUNC* (1)
		ANSWER* (1)
		APOLOGIS* (1)
		APOLOGIZ* (1)
		APPEAL* (1)
		APPROV* (1)
		APPROVAL* (1)
		ASK (1)
		ASKED (1)
		ASKING (1)
		ASKS (1)
		ASSIST* (1)
		ASSUR* (1)
		BARGAIN* (1)
		BECKON* (1)
		BESEECH* (1)
		BORROW* (1)
		CALL* (1)
		COMMENT* (1)
		COMMIT* (1)
		COMMUNICAT* (1)
		CONDUCT* (1)
		CONFER* (1)
		CONFES* (1)
		CONFID* (1)
		CONFIRM* (1)
		CONGRATULAT* (1)
		CONSENT* (1)
		CONSOL* (1)
		CONSOLAT* (1)
		CONVERS* (1)
		CONVERSAT* (1)
		CONVINC* (1)
		COOPERAT* (1)
		COUNSEL* (1)
		DECLAR* (1)
		DEPEND* (1)
		DEPENDENT* (1)
		DESCRIB* (1)
		DIALOGU* (1)
		DISCOURS* (1)
		DISCUS* (1)
		DISCUSS* (1)
		DONAT* (1)
		EDUCAT* (1)
		ELECT* (1)
		ENCOURAG* (1)
		ENCOURAGEMENT* (1)
		ENGAG* (1)
		ESCORT* (1)
		EXCUS* (1)
		EXPLAIN* (1)
		FOLLOW* (1)
		FORGAV* (1)
		FORGIV* (1)
		FORGIVEN* (1)
		GENEROSITY* (1)
		GENEROU* (1)
		GIFT* (1)
		GRANT* (1)
		GREET* (1)
		GUID* (1)
		GUIDANC* (1)
		HELP* (1)
		IMITAT* (1)
		IMPLOR* (1)
		INFLUENC* (1)
		INFORM* (1)
		INQUIR* (1)
		INSTRUCT* (1)
		INTERVIEW* (1)
		INTRODUC* (1)
		INVIT* (1)
		KNEEL* (1)
		LEND* (1)
		LENT* (1)
		MEET* (1)
		MENT* (1)
		MESSAG* (1)
		MET* (1)
		MUTUAL* (1)
		OFFER* (1)
		PARDON* (1)
		PARTICIPAT* (1)
		PERSUAD* (1)
		PERSUA* (1)
		PLEAD* (1)
		PLEAS* (1)
		PREACH* (1)
		PROCLAIM* (1)
		PROMIS* (1)
		PROPOS* (1)
		PROTECT* (1)
		PROVID* (1)
		QUOT* (1)
		RECIT* (1)
		REEDUCATION (1)
		REMARK* (1)
		REMIND* (1)
		REPLI* (1)
		REPLY (1)
		REPRESENT* (1)
		REQUEST* (1)
		RESCU* (1)
		RESPOND* (1)
		RESPONS* (1)
		SAID* (1)
		SALE (1)
		SALES (1)
		SAY* (1)
		SERVIC* (1)
		SHAR* (1)
		SHELTER* (1)
		SIGNAL* (1)
		SOCIAL* (1)
		SOLICIT* (1)
		SPEAK* (1)
		SPEAKER* (1)
		SPEECH* (1)
		SPOK* (1)
		SPOKEN* (1)
		SUGGEST* (1)
		SWORN* (1)
		TALK* (1)
		TAUGHT* (1)
		TEACH* (1)
		TELL* (1)
		THANK* (1)
		TOLD* (1)
		TREAT* (1)
		UTTER* (1)
		VISIT* (1)
	INSTRUMENTAL BEHAVIOR
		AVAIL (1)
		CAVEAT* (1)
		DIVESTMENT* (1)
		DIVIDEND* (1)
		FOUNDR* (1)
		LABORATOR* (1)
		SPIN-OFF* (1)
		AVAILABILITY (1)
		COMPONENT* (1)
		INGREDIENT (1)
		LOGISTICS (1)
		MERCHANDISE (1)
		PROVISION* (1)
		ACHIEV* (1)
		ACHIEVEMENT* (1)
		ACQUIR* (1)
		ACQUISIT* (1)
		AFFORD* (1)
		AIM* (1)
		APPLIC* (1)
		APPLIE* (1)
		APPLY (1)
		ARCHITECT* (1)
		ASSEMBL* (1)
		ATTAIN* (1)
		ATTEMPT* (1)
		AVAILABL* (1)
		BELONG* (1)
		BID* (1)
		BOUGHT* (1)
		BUILD* (1)
		BUILT* (1)
		BURDEN* (1)
		BUSINES* (1)
		BUY* (1)
		CAPABL* (1)
		CARRI* (1)
		CARRY* (1)
		CLAIM* (1)
		COLLECT* (1)
		CONSTRUCT* (1)
		COPI* (1)
		COPY* (1)
		COST* (1)
		COUNT* (1)
		CRAFT* (1)
		CRAFTSMAN* (1)
		CULTIVAT* (1)
		CURE* (1)
		CURING* (1)
		DELIVER* (1)
		EARN* (1)
		EFFORT* (1)
		EMPLOY* (1)
		ENDEAVOR* (1)
		FACTORI* (1)
		FACTORY* (1)
		FEAT (1)
		FEATS (1)
		FIND* (1)
		FINISH* (1)
		FORGE (1)
		FORGES (1)
		FOUND* (1)
		GAIN* (1)
		GOAL* (1)
		GRASP* (1)
		HARVEST* (1)
		HIRE (1)
		HIRED (1)
		HIRES (1)
		HIRING* (1)
		IMPROV* (1)
		INDUSTRI* (1)
		INDUSTRY* (1)
		JOB (1)
		JOBS (1)
		LABOR* (1)
		LABORIOU* (1)
		LABOUR* (1)
		LABOURIOU* (1)
		LESSON* (1)
		MACHIN* (1)
		MACHINERY* (1)
		MAK* (1)
		MANIPULAT* (1)
		MANUFACTUR* (1)
		MARKET* (1)
		MEND* (1)
		MERCHANT* (1)
		MONEY* (1)
		OBTAIN* (1)
		OCCUPAT* (1)
		OCCUPY* (1)
		OWNERSHIP* (1)
		PAID* (1)
		PAY (1)
		PAYING* (1)
		PAYS (1)
		PERFORM* (1)
		PICK* (1)
		PLOUGH* (1)
		PLOW* (1)
		POSSES* (1)
		POSSESS* (1)
		PRACTIC* (1)
		PREPAR* (1)
		PRIC* (1)
		PRIVATION* (1)
		PRODUC* (1)
		PROFIT* (1)
		PROFITABL* (1)
		PROPERTY* (1)
		PURCHAS* (1)
		PURSU* (1)
		REACH* (1)
		RECONSTRUCT (1)
		RECORD* (1)
		RECOVER* (1)
		REPAIR* (1)
		REPRODUCE (1)
		RESTOR* (1)
		RESULT* (1)
		RISK* (1)
		SEL* (1)
		SELL* (1)
		SKIL* (1)
		SKILL* (1)
		SKILLFUL* (1)
		SOLD* (1)
		SOW* (1)
		SPEND* (1)
		SPENT* (1)
		STUDENT* (1)
		STUDI* (1)
		STUDIOU* (1)
		STUDY* (1)
		SUCCE* (1)
		SWEEP* (1)
		SWEPT* (1)
		TASK* (1)
		TEST* (1)
		TOIL (1)
		TOILED (1)
		TOILS* (1)
		TRAD* (1)
		TRIED (1)
		TRY (1)
		TRYING* (1)
		TRYS (1)
		USE (1)
		USED (1)
		USES (1)
		USING (1)
		WIN (1)
		WINNING* (1)
		WINS (1)
		WON (1)
		WORK* (1)
	RESTRAINT
		COMPTROLLER* (1)
		DISCIPLINE (1)
		MAGIST* (1)
		PENALIZ* (1)
		PENITENTIARY (1)
		ARREST* (1)
		ASSIGN* (1)
		AUTHORIZ* (1)
		BAR (1)
		BARRED (1)
		BARRING (1)
		BARS (1)
		BIND* (1)
		BLOCK* (1)
		BLOCKAD* (1)
		BOUND* (1)
		CAG* (1)
		CAPTIV* (1)
		CAPTIVITY* (1)
		CAPTUR* (1)
		CATCH* (1)
		CAUGHT* (1)
		CENSUR* (1)
		CHASTIS* (1)
		CHASTIZ* (1)
		COERC* (1)
		COMPEL* (1)
		CONFIN* (1)
		CONFORM* (1)
		CONFORMITY* (1)
		CONSTRAIN* (1)
		CONSTRAINT* (1)
		CONSTRICT* (1)
		CONTROL* (1)
		DECREE* (1)
		DETAIN* (1)
		DETER* (1)
		DUNGEON* (1)
		ENCLOS* (1)
		FORBAD* (1)
		FORBID* (1)
		FORBIDDEN* (1)
		GUARD* (1)
		GUARDIAN* (1)
		HALT* (1)
		HAMPER* (1)
		HINDER* (1)
		HINDRANC* (1)
		IMPERATIV* (1)
		IMPRISON* (1)
		INHIBIT* (1)
		INSIST* (1)
		INTERFER* (1)
		INTERRUPT* (1)
		JAIL* (1)
		LEASH* (1)
		LIMIT* (1)
		LOCK* (1)
		MANAG* (1)
		MUST* (1)
		NECESSARY* (1)
		NECESSITY* (1)
		OBEDIENC* (1)
		OBEY* (1)
		OBLIG* (1)
		OBLIGAT* (1)
		OBSTACL* (1)
		OBSTRUCT* (1)
		PENALTI* (1)
		PENALTY* (1)
		PERMISS* (1)
		PERMIT* (1)
		POLIC* (1)
		POLICEMAN* (1)
		POLICEMEN* (1)
		PRESCRIB* (1)
		PREVAIL* (1)
		PREVENT* (1)
		PRISON* (1)
		PROHIBIT* (1)
		PUNISH* (1)
		PUNISHMENT* (1)
		REFUS* (1)
		REGULAT* (1)
		REIGN* (1)
		REQUIR* (1)
		REQUIREMENT* (1)
		RESIST* (1)
		RESTRAIN* (1)
		RESTRAINT* (1)
		RESTRICT* (1)
		SCOLD* (1)
		SHUT* (1)
		STOP* (1)
		STRICT* (1)
		SUMMON* (1)
		SUPPRES* (1)
		TABOO* (1)
		TAX* (1)
		THWART* (1)
	ORDER
		ORDINAL (1)
		ACCURAT* (1)
		ARRANG* (1)
		ARRAY* (1)
		BALANC* (1)
		CATALOG* (1)
		CLASS* (1)
		CONSISTENC* (1)
		CONSISTENT* (1)
		CONSTANC* (1)
		CONSTANT* (1)
		DIVID* (1)
		FORM* (1)
		FORMULA* (1)
		GRAD* (1)
		INDEX* (1)
		LIST* (1)
		MEASUR* (1)
		METHOD* (1)
		MODERAT* (1)
		NEAT* (1)
		NORM* (1)
		NORMAL* (1)
		ORGANI* (1)
		ORDER (1)
		PATTERN* (1)
		PRECIS* (1)
		RANK* (1)
		REGULAR* (1)
		REORGANIZ* (1)
		ROUTIN* (1)
		SERIAL (1)
		SERIES* (1)
		SIMPL* (1)
		SIMPLICITY* (1)
		STABILITY* (1)
		STANDARD* (1)
		SYMMETR* (1)
		SYSTEM* (1)
		UNIFORM* (1)
		UNIVERSAL* (1)
	TEMPORAL REFERENCES
		FULL-TIME (1)
		LONG-TERM (1)
		LONGEVIT* (1)
		PART-TIME (1)
		SHORT-TERM (1)
		ABRUPT* (1)
		AGAIN (1)
		AGO (1)
		ALREADY* (1)
		ANCIENT (1)
		BREVITY* (1)
		BRIEF* (1)
		CLOCK* (1)
		DAILY* (1)
		DATE (1)
		DATED (1)
		DATES (1)
		DATING (1)
		DECAD* (1)
		DUR* (1)
		DURAT* (1)
		EARLIER* (1)
		EARLY* (1)
		EPHEMERAL* (1)
		EVER* (1)
		FORMER* (1)
		FREQUENT* (1)
		HAST* (1)
		HENCEFORTH* (1)
		HOUR* (1)
		IMMEDIAT* (1)
		IMMEDIATE* (1)
		INSTANT* (1)
		INTERLUD* (1)
		MEANTIM* (1)
		MEANWHIL* (1)
		MINUT* (1)
		MOMENT* (1)
		MOMENTARY* (1)
		MONTH* (1)
		NOW (1)
		OCCAS* (1)
		OCCASIONAL* (1)
		OFTEN* (1)
		OLD (1)
		OLDER* (1)
		ONCE (1)
		PAST* (1)
		PREMATUR* (1)
		PRESENT* (1)
		PREVIOU* (1)
		PRIOR* (1)
		QUICK* (1)
		SEASON* (1)
		SELDOM* (1)
		SOMETIM* (1)
		SOON* (1)
		SOONER* (1)
		SUDDEN* (1)
		TEMPORARY* (1)
		THEN* (1)
		TILL* (1)
		TIME* (1)
		TIMING* (1)
		TODAY* (1)
		TONIGHT* (1)
		WEEK* (1)
		WHEN* (1)
		WHENEVER* (1)
		WHIL* (1)
		YEAR* (1)
		YESTERDAY* (1)
	MORAL IMPERATIVE
		LEGITIMACY (1)
		RESPECT (1)
		BIRTHRIGHT* (1)
		COMMANDMENT* (1)
		CONSCIENC* (1)
		CONSCIENTIOU* (1)
		CORRECT* (1)
		CUSTOM (1)
		CUSTOMER* (1)
		CUSTOMIZ* (1)
		DUTI* (1)
		DUTY* (1)
		ETHIC* (1)
		HONEST* (1)
		HONESTY* (1)
		HONOR* (1)
		HONORABL* (1)
		HONOUR* (1)
		HONOURABL* (1)
		JUSTIC* (1)
		LAW (1)
		LAWFUL* (1)
		LAWS (1)
		LEGAL* (1)
		LEGITIMAT* (1)
		MORAL* (1)
		MORALITY* (1)
		OUGHT* (1)
		PREROGATIV* (1)
		PRINCIPL* (1)
		PRIVILEG* (1)
		PROPER* (1)
		RECTITUD* (1)
		RESPECTFUL* (1)
		RESPONSIBILITY* (1)
		RESPONSIBL* (1)
		RIGHT* (1)
		RIGHTEOU* (1)
		RIGHTFUL* (1)
		SANCT* (1)
		SHOULD* (1)
		TRUSTWORTHY* (1)
		UNJUST* (1)
		UPRIGHT* (1)
		VIRTU* (1)
EMOTIONS
	POSITIVE AFFECT
		AMUS* (1)
		AMUSEMENT* (1)
		BLITH* (1)
		CAREFRE* (1)
		CELEBRAT* (1)
		CHEER* (1)
		CHEERFUL* (1)
		CHEERY* (1)
		CHUCKL* (1)
		DELIGHT* (1)
		DELIGHTFUL* (1)
		ELAT* (1)
		ENJOY* (1)
		ENJOYABL* (1)
		ENJOYMENT* (1)
		ENTERTAIN* (1)
		ENTERTAINMENT* (1)
		ENTHUSIASM* (1)
		ENTHUSIASTIC* (1)
		EXCIT* (1)
		EXHILERAT* (1)
		EXULT* (1)
		EXULTANT* (1)
		FUN (1)
		FUNNY* (1)
		GAIETY* (1)
		GAY* (1)
		GLAD* (1)
		GLADNES* (1)
		GLEE (1)
		GLEEFUL* (1)
		GLEELY (1)
		GRATIFI* (1)
		GRATIFY* (1)
		GRIN* (1)
		HAPPINES* (1)
		HAPPY* (1)
		HILARIOU* (1)
		HUMOR* (1)
		HUMOROU* (1)
		HUMOUR* (1)
		HUMOUROU* (1)
		JOCUND* (1)
		JOK* (1)
		JOLLY (1)
		JOVIAL* (1)
		JOY* (1)
		JOYFUL* (1)
		JOYOU* (1)
		LAUGH* (1)
		LAUGHTER* (1)
		MERRIMENT* (1)
		MERRY* (1)
		MIRTH* (1)
		MIRTHFUL* (1)
		OVERJOY* (1)
		PLAYFUL* (1)
		PLEASANTRY* (1)
		PLEASUR* (1)
		PLEASURABL* (1)
		REJOIC* (1)
		RELIEF* (1)
		RELIEV* (1)
		ROLLICK* (1)
		SATISF* (1)
		SMIL* (1)
		THRIL* (1)
		THRILL* (1)
		VIVACIOU* (1)
		VIVACITY* (1)
	ANXIETY
		TREMOR (1)
		AFRAID* (1)
		AGHAST* (1)
		ALARM* (1)
		ANGUISH* (1)
		ANXI* (1)
		AVOID* (1)
		BLUSH* (1)
		CARES (1)
		COWARD* (1)
		COWER* (1)
		CRISI* (1)
		DANGEROU* (1)
		DESPERAT* (1)
		DISTRES* (1)
		DREAD* (1)
		DREADFUL* (1)
		FEAR* (1)
		FEARFUL* (1)
		FRANTIC* (1)
		FRET* (1)
		FRIGHT* (1)
		HORRIFI* (1)
		HORRIFY* (1)
		HORROR* (1)
		NERVOU* (1)
		NERVOUSNES* (1)
		PANIC* (1)
		PHOBIA* (1)
		PHOBIC* (1)
		SCARE (1)
		SCARED (1)
		SCARES (1)
		SCARY (1)
		SHRIEK* (1)
		SHUDDER* (1)
		SHY* (1)
		TERRIFI* (1)
		TERRIFY* (1)
		TERROR* (1)
		TIMID* (1)
		TRAUMA* (1)
		TREMBL* (1)
		TREMULOU* (1)
		TROUBL* (1)
		UNEASINES* (1)
		UNEASY* (1)
		WORRI* (1)
		WORRY* (1)
	SADNESS
		AGGRIEVED (1)
		ALAS (1)
		DEJECT* (1)
		DEPRES* (1)
		DEPRESS* (1)
		DESPAIR* (1)
		DESPONDANT* (1)
		DESPONDENT* (1)
		DIRG* (1)
		DISAPPOINT* (1)
		DISAPPOINTMENT* (1)
		DISCONSOLAT* (1)
		DISCOURAG* (1)
		DISHEARTEN* (1)
		DISMAL* (1)
		DISSATISFI* (1)
		DISSATISFY* (1)
		DISTRAUGHT* (1)
		DOLDRUM* (1)
		DOWNCAST* (1)
		DREARY* (1)
		ELEGY* (1)
		FORLORN* (1)
		FROWN* (1)
		FUNEREAL* (1)
		GRIE* (1)
		GROAN* (1)
		HOPELES* (1)
		HUMILIAT* (1)
		LAMENT* (1)
		LAMENTAT* (1)
		LONE* (1)
		LONELINES* (1)
		MELANC* (1)
		MISERABL* (1)
		MISERI* (1)
		MISERY* (1)
		MOAN* (1)
		MOURN* (1)
		MOURNFUL* (1)
		ORPHAN* (1)
		PAIN* (1)
		PITIFUL* (1)
		PLAINT* (1)
		REGRET* (1)
		REGRETFUL* (1)
		REMORS* (1)
		REPENT* (1)
		REPENTANC* (1)
		REPENTENC* (1)
		RUE (1)
		SAD (1)
		SADDEN* (1)
		SADLY (1)
		SADNES* (1)
		SOB (1)
		SOBB* (1)
		SOBS (1)
		SOMBER* (1)
		SOMBR* (1)
		SORROW* (1)
		SORROWFUL* (1)
		SORRY* (1)
		SUFFER* (1)
		TEARFUL* (1)
		TRAGEDY* (1)
		TRAGIC* (1)
		UNHAPPINES* (1)
		UNHAPPY* (1)
		WAIL* (1)
		WEEP* (1)
		WEPT* (1)
		WHIN* (1)
		WOE (1)
		WOES (1)
	AFFECTION
		AFFECT* (1)
		AFFECTIONAT* (1)
		AMOROU* (1)
		AMOUROU* (1)
		APPRECIAT* (1)
		ATTRACTIV* (1)
		BEFRIEND* (1)
		BELOV* (1)
		BOSOM* (1)
		BRIDAL* (1)
		BRIDE* (1)
		CHERISH* (1)
		CONGENIAL* (1)
		CORDIAL* (1)
		COURTSHIP* (1)
		DARL* (1)
		DEAR* (1)
		DEVOT* (1)
		EMBRAC* (1)
		ENAMOR* (1)
		ENAMOUR* (1)
		ENDEAR* (1)
		FAMILIAR* (1)
		FONDER (1)
		FAREWELL* (1)
		FAVOR* (1)
		FAVOUR* (1)
		FIANC* (1)
		FLIRT* (1)
		FOND (1)
		FONDNES* (1)
		FRATERNITY* (1)
		FRIEND* (1)
		FRIENDSHIP* (1)
		GOODBY* (1)
		GRATEFUL* (1)
		INTIMACY* (1)
		INTIMAT* (1)
		KIND* (1)
		KINDNES* (1)
		LIKE* (1)
		LIKING* (1)
		LOV* (1)
		MARRI* (1)
		MARRIAG* (1)
		MARRY* (1)
		MATE (1)
		MATED (1)
		MATES (1)
		MATING* (1)
		MERCY* (1)
		PAT (1)
		PATS (1)
		PATT* (1)
		PITI* (1)
		PITY* (1)
		ROMANC* (1)
		SWEETHEART* (1)
		SYMPAT* (1)
		UNSELFISH* (1)
		WARMHEART* (1)
		WELCOM* (1)
		WOOED* (1)
		WOOING* (1)
		WOOS (1)
	AGGRESSION
		ABHOR* (1)
		ABUS* (1)
		ABUSIV* (1)
		ACCUS* (1)
		AFFLICT* (1)
		AGGRESS* (1)
		AGGRESSIV* (1)
		AMBUSH* (1)
		ANGER* (1)
		ANGRI* (1)
		ANGRIER* (1)
		ANGRY* (1)
		ANNIHILAT* (1)
		ANNOY* (1)
		ANNOYANC* (1)
		ANTAGONIZ* (1)
		ARGU* (1)
		ARGUMENT* (1)
		ARMY* (1)
		ARROW* (1)
		ASSAULT* (1)
		ATTACK* (1)
		AVENG* (1)
		AX (1)
		AXE (1)
		AXES (1)
		BATTL* (1)
		BEAK* (1)
		BEAT* (1)
		BEATEN* (1)
		BETRAY* (1)
		BLADE* (1)
		BLAM* (1)
		BLOODY* (1)
		BOTHER* (1)
		BRAWL* (1)
		BREAK* (1)
		BROK* (1)
		BROKEN* (1)
		BRUTAL* (1)
		CANNON* (1)
		CHID* (1)
		COMBAT* (1)
		COMPLAIN* (1)
		CONFLICT* (1)
		CONDEMN* (1)
		CONTROVERSY* (1)
		CRITIC* (1)
		CRUEL* (1)
		CRUSH* (1)
		CUT (1)
		CUTS (1)
		CUTT* (1)
		DAMAG* (1)
		DECEI* (1)
		DEFEAT* (1)
		DEGRAD* (1)
		DEMOLISH* (1)
		DEPRIV* (1)
		DERID* (1)
		DESPIS* (1)
		DESTROY* (1)
		DESTRUCT* (1)
		DESTRUCTIV* (1)
		DETEST* (1)
		DISAGRE* (1)
		DISAGREEMENT* (1)
		DISAPPROV* (1)
		DISCONTENT* (1)
		DISLIK* (1)
		DISPUT* (1)
		DISTURB* (1)
		DOUBT* (1)
		ENEMI* (1)
		ENEMY* (1)
		ENRAG* (1)
		EXASPERAT* (1)
		CONTROVERSIAL* (1)
		CRITIQUE (1)
		DISPARAG* (1)
		IRRITABLE (1)
		EXPLOIT* (1)
		EXTERMINAT* (1)
		FEUD* (1)
		FIERC* (1)
		FIGHT* (1)
		FOUGHT* (1)
		FURIOU* (1)
		FURY* (1)
		GASH* (1)
		GRAPPL* (1)
		GROWL* (1)
		GRUDG* (1)
		GUN (1)
		GUNN* (1)
		GUNS (1)
		HARM* (1)
		HARSH* (1)
		HATE* (1)
		HATR* (1)
		HIT (1)
		HITS (1)
		HITT* (1)
		HOMICID* (1)
		HOSTIL* (1)
		HURT* (1)
		INGRAT* (1)
		INJUR* (1)
		INJURY* (1)
		INSULT* (1)
		INVAD* (1)
		INVAS* (1)
		IRAT* (1)
		IRK* (1)
		IRRITAT* (1)
		JEALOU* (1)
		JEALOUSY* (1)
		JEER* (1)
		KICK* (1)
		KIL* (1)
		KILL* (1)
		KNIF* (1)
		KNIV* (1)
		LOATH* (1)
		MAIM* (1)
		MISTREAT* (1)
		MOCK* (1)
		MURDER* (1)
		OBLITERAT* (1)
		OFFEND* (1)
		OPPOS* (1)
		PREDATORY* (1)
		PROTEST* (1)
		QUARREL* (1)
		RAGE (1)
		RAGES (1)
		RAGING (1)
		RAPIN* (1)
		REBEL* (1)
		REBELL* (1)
		REBUK* (1)
		RELENTLES* (1)
		REPROACH* (1)
		RESENT* (1)
		RESENTMENT* (1)
		RETRIBUT* (1)
		REVENG* (1)
		REVOLT* (1)
		RIDICUL* (1)
		RIP (1)
		RIPP* (1)
		RIPS (1)
		ROB (1)
		ROBB* (1)
		ROBS (1)
		SARCASM* (1)
		SARCASTIC* (1)
		SCALP* (1)
		SCOF* (1)
		SCOFF* (1)
		SCOURG* (1)
		SEIZ* (1)
		SEVER* (1)
		SEVERITY* (1)
		SHATTER* (1)
		SHOOT* (1)
		SHOT* (1)
		SHOV* (1)
		SLAIN* (1)
		SLANDER* (1)
		SLAP* (1)
		SLAUGHTER* (1)
		SLAY* (1)
		SLEW* (1)
		SMASH* (1)
		SNARL* (1)
		SNEER* (1)
		SPEAR* (1)
		SPITEFUL* (1)
		SPURN* (1)
		STAB* (1)
		STEAL* (1)
		STOL* (1)
		STOLEN* (1)
		STRANGL* (1)
		STRIF* (1)
		STRIK* (1)
		STRUCK* (1)
		STRUGGL* (1)
		STUBBORN* (1)
		SWORD* (1)
		TAUNT* (1)
		TEMPER* (1)
		THREAT* (1)
		THREATEN* (1)
		TORE (1)
		TORMENT* (1)
		TORN* (1)
		TORTUR* (1)
		TRAITOR* (1)
		TRAMPL* (1)
		TREACHEROU* (1)
		TREACHERY* (1)
		TYRANT* (1)
		UNKIND* (1)
		VENGEANC* (1)
		VENGEFUL* (1)
		VEX (1)
		VEXING (1)
		VIOLAT* (1)
		VIOLENC* (1)
		VIOLENT* (1)
		WAR (1)
		WARRING (1)
		WARRIOR* (1)
		WARS (1)
		WEAPON* (1)
		WHIP* (1)
		WOUND* (1)
		WRATH* (1)
		FOOTBALL* (1)
		WRECK* (1)
	EXPRESSIVE BEHAVIOR
		ART (1)
		ARTS* (1)
		BARD* (1)
		BARK* (1)
		BAWL* (1)
		BELLOW* (1)
		BLEAT* (1)
		CAROL* (1)
		CHANT* (1)
		CLOWN* (1)
		CRIE* (1)
		CRIING (1)
		CRY (1)
		DANC* (1)
		EXCLAIM* (1)
		EXPRESSIV* (1)
		FRISK* (1)
		FROLIC* (1)
		GAME* (1)
		GUITAR* (1)
		HARP* (1)
		HORN* (1)
		HURRAH* (1)
		HURRAY* (1)
		LULLABY* (1)
		LUTE (1)
		LUTES (1)
		LYRE (1)
		MINSTREL* (1)
		NEIGH (1)
		NEIGHS (1)
		PAINTER* (1)
		PLAY* (1)
		POEM* (1)
		POET* (1)
		POETIC* (1)
		POETRY* (1)
		ROAR* (1)
		SANG* (1)
		SCREAM* (1)
		SHOUT* (1)
		SIGH* (1)
		SING (1)
		SINGS* (1)
		SPORT* (1)
		SUNG* (1)
		TROUBADOR* (1)
		TROUBADOUR* (1)
		VIOLIN* (1)
		WARBL* (1)
		YEL* (1)
		YELL* (1)
	GLORY
		ADMIR* (1)
		ADMIRABL* (1)
		ADVENTUR* (1)
		APPLAUD* (1)
		APPLAUS* (1)
		ARROGANC* (1)
		ARROGANT* (1)
		AUDACITY* (1)
		AWE* (1)
		BOAST* (1)
		BOASTFUL* (1)
		BRILLIANC* (1)
		BRILLIANT* (1)
		CAESAR* (1)
		CASTL* (1)
		CONQUE* (1)
		CROWN* (1)
		DAZZL* (1)
		EAGL* (1)
		ELIT* (1)
		EMPEROR* (1)
		EMPIR* (1)
		EXALT* (1)
		EXHIBIT* (1)
		EXQUISIT* (1)
		EXTRAORDINARY* (1)
		EXTREM* (1)
		FAME (1)
		FAMED (1)
		FAMOU* (1)
		FOREMOST* (1)
		GENIU* (1)
		GLOR* (1)
		GOLD* (1)
		GOLDEN* (1)
		GRANDEUR* (1)
		GREAT* (1)
		HAUGHTY* (1)
		HERO* (1)
		HOMAG* (1)
		ILLUSTRIOU* (1)
		KINGDOM* (1)
		MAGESTIC* (1)
		MAGNIFICENT* (1)
		MAJESTIC* (1)
		MAJESTY* (1)
		NOBL* (1)
		OUTSTAND* (1)
		PALAC* (1)
		POMP* (1)
		PRESTIG* (1)
		PRID* (1)
		PRINC* (1)
		PROUD* (1)
		RENOWN* (1)
		RESPLENDENT* (1)
		RICH* (1)
		ROYAL* (1)
		ROYALTY* (1)
		SCEPTR* (1)
		SCORN* (1)
		SPLENDID* (1)
		SPLENDOR* (1)
		STRUT* (1)
		SUBLIM* (1)
		SUPERIOR* (1)
		SUPERIORITY* (1)
		SUPREM* (1)
		THRON* (1)
		TRIUMP* (1)
		VICTOR* (1)
		VICTORIOU* (1)
		VICTORY* (1)
		WEALTH* (1)
		WONDER* (1)
		WONDERFUL* (1)
"""

DEFAULT_RID_EXCLUSION_LIST = """
PROVINC*
MIDDLE-*
DIVERSION*
DIETHYL*
COUNTY*
SHARK*
PRICK*
PASTE*
HANDICAP*
HANDBOOK*
GRAPH*
FACTORIAL*
BUTTERFL*
BLANKET*
FASTI*
ENERGUMEN*
RELIGHT
REVERSE
DISPOSSESS*
NEEDL*
EXTREMITY
EXTREMENESS
EMPIRI*
TEMPERAT*
TEMPERAN*
TEMPERAMENT
SEVERAL
HARMO*
PATTERN
DECADENT
TAXO*
TAXI*
DETERS*
DETERR*
DETERIO*
DETERG*
TRADU*
TRADI*
TESTAM*
SOWBUG*
SELF*
FACTORIAL
COUNTE*
COUNTR*
TREATMENT*
TELLU*
QUOTI*
QUOTH*
PROVIDE*
PROMISC*
METTL*
METR*
METO*
METI*
METH*
METE*
META*
MENTO*
MENTH*
MENTA*
INFORMAL
ELECTR*
CONSOLIDAT*
SOLUTE
PROVER*
MAY-1
POOLED-1
POOL-1
HEATH*
COALESC*
COALI*
UNDERGRADUAT*
UNDERC*
FALLAC*
DIVERGEN*
ARIST*
REGU*
REGR*
REGIS*
REGE*
POSITIV*
PLACEN*
PLACEB*
OVERV*
OVERL*
LIMBIC*
CHINE*
PORTU*
PORTR*
PORTM*
PORTL*
PORTI*
PORTF*
PORTE*
PORTA*
PATHO*
PATHE*
SECRETI*
SECRETO*
SECRETA*
ROLE
QUAKER
TRIPT*
TRIPLE
TRIPE
RESTR*
RESTO*
RESTI*
RESTA*
REPOSSESS*
CONTENTS*
CONTENT-*
HOARY
HOARS
HOARD*
BASKET
AWARD*
TESTIN*
TESTIF*
TESTIMON*
STALK
SPATI*
GRAPHIC*
BREADTH
"""

class RIDApp:
  def usage(self, args):
    print("usage: %s [-h [-t TITLE] | -d FILE | -e FILE | --add-dict=FILE | --add-exc=FILE]" % (args[0],))
    print("%s reads from standard input and writes to standard output." % (args[0],))
    print("options:")
    print("    -h                Generate HTML output.")
    print("    -t TITLE          Use TITLE as the report heading.")
    print("    -d FILE           Replaces the built-in dictionary with FILE.")
    print("    -e FILE           Replaces the built-in exclusion list with FILE.")
    print("    --add-dict=FILE   Processes FILE as a category dictionary.")
    print("    --add-exc=FILE    Processes FILE as an exlusion list.")
    
  def run(self, args):
    rid = RegressiveImageryDictionary()
    load_default_dict = True
    load_default_exc = True
    html_output = False
    title = "RID Analysis"

    try:
      optlist, args = getopt.getopt(sys.argv[1:], 'd:e:ht:',
                                    ['add-dict=', 'add-exc='])
      for (o, v) in optlist:
        if o == '-d':
          rid.load_dictionary_from_file(v)
          load_default_dict = False
        elif o == '-e':
          rid.load_exclusion_list_from_file(v)
          load_default_exc = False
        elif o == '--add-dict':
          rid.load_dictionary_from_file(v)
        elif o == '--add-exc':
          rid.load_exclusion_list_from_file(v)
        elif o == '-h':
          html_output = True
        elif o == '-t':
          title = v
        else:
          sys.stderr.write("%s: illegal option '%s'\n" % (args[0], o))
          self.usage(args)
    except getopt.GetoptError as e:
      sys.stderr.write("%s: %s\n" % (args[0], e.msg))
      self.usage(args)
      sys.exit(1)
                       
    if load_default_dict:
      rid.load_dictionary_from_string(DEFAULT_RID_DICTIONARY)
    if load_default_exc:
      rid.load_exclusion_list_from_string(DEFAULT_RID_EXCLUSION_LIST)
      
    results = rid.analyze(sys.stdin.read())
    if html_output:
      rid.display_results_html(results, title)
    else:
      rid.display_results(results)
      
if __name__ == '__main__':
  app = RIDApp()
  app.run(sys.argv)

#######################################################################################################

# From trac.util.compat.py
# Implementation for sorted() for Python versions prior to 2.4

try:
	reversed = reversed
except NameError:
	def reversed(x):
		if hasattr(x, 'keys'):
			raise ValueError('mappings do not support reverse iteration')
		i = len(x)
		while i > 0:
			i -= 1
			yield x[i]

try:
	sorted = sorted
except NameError:
	def sorted(iterable, cmp=None, key=None, reverse=False):
		"""Partial implementation of the "sorted" function from Python 2.4"""
		if key is None:
			lst = list(iterable)
		else:
			lst = [(key(val), idx, val) for idx, val in enumerate(iterable)]
			lst.sort()
			if key is None:
				if reverse:
					return lst[::-1]
				return lst
			if reverse:
				lst = reversed(lst)
			return [i[-1] for i in lst]

#######################################################################################################

rid = RegressiveImageryDictionary()
rid.load_dictionary_from_string(DEFAULT_RID_DICTIONARY)
rid.load_exclusion_list_from_string(DEFAULT_RID_EXCLUSION_LIST)

# A list of subcategories for each top category, e.g. emotions ->
# ['anxiety', 'glory', 'positive affect', 'sadness', 'expressive behavior', 'affection', 'aggression']
primary   = [key.lower() for key in list(rid.category_tree.children["PRIMARY"].children.keys())]
secondary = [key.lower() for key in list(rid.category_tree.children["SECONDARY"].children.keys())]
emotions  = [key.lower() for key in list(rid.category_tree.children["EMOTIONS"].children.keys())]

class RIDScoreItem:
	
	def __init__(self, name, count, words, type):
		
		self.name  = name
		self.count = count
		self.words = words
		self.type  = type
		
	def __str__(self):
		
		return self.name

class RIDScore(list):
	
	def __init__(self, rid, results):
	
		self.primary = 0
		self.secondary = 0
		self.emotions = 0

		self.count(rid, results)
		self.populate(results)

	def count(self, rid, results):

		# Keep a count per top category
		# (primary, secondary, emotional)
		score = {}
		roots = rid.category_tree.children
		for key in roots:
			score[key] = 0

		# Calculate the total count.
		# Increase the count for the top category each category belongs to.
		total = 0
		for category in results.category_count:
			count = results.category_count[category]
			total += count
			for key in roots:
				if category.isa(roots[key]):
					score[key] += count

		# Relativise the score for each top category.
		if total > 0:
			for key in score:
				score[key] = float(score[key]) / total

		self.primary = score["PRIMARY"]
		self.secondary = score["SECONDARY"]
		self.emotions = score["EMOTIONS"]

	def populate(self, results):
		
		# A RIDScore is a sorted list of category items,
		# with relevant words found in the text assigned to each category.
		for (category, count) in sorted(list(results.category_count.items()), key=lambda x: x[1], reverse=True):
			c = RIDScoreItem(
				name=category.name.lower(),
				count=count,
				words=results.category_words[category],
				type=category.parent.name.lower()
			)
			self.append(c)
			
	def __str__(self):
		return str([str(item) for item in self])

def categorise(txt):

	global rid
	results = rid.analyze(txt)
	return RIDScore(rid, results)