public static Configuration loadConfiguration( InputStream input ) throws Exception
   {
      Configuration config = new Configuration();
      config.delays = Tries.forInsensitiveStrings( 0 );
      config.inclusion = Tries.forInsensitiveStrings( Boolean.FALSE );
      config.mode = AgentMode.CSV;

      Element root = XmlUtility.read( input );

      validateTagName( root, TAG_ROOT );

      /* INCLUSIONS */
      Element inclusionGroup = findElement( root, TAG_INCLUSION_GROUP );
      XmlFilter<Element> inclusions = createFilter( inclusionGroup, TAG_INCLUSION, true );

      for (Element e : inclusions)
      {
         String pattern = getAttribute( e, ATTR_PATTERN, null );
         Integer delay = Integer.parseInt( getAttribute( e, ATTR_DELAY, 0 ) );

         config.inclusion.put( pattern, Boolean.TRUE );
         config.delays.put( pattern, delay );
      }

      /* EXCLUSIONS */
      Element exclusionGroup = findElement( root, TAG_EXCLUSION_GROUP );
      XmlFilter<Element> exclusions = createFilter( exclusionGroup, TAG_EXCLUSION, false );

      for (Element e : exclusions)
      {
         String pattern = getAttribute( e, ATTR_PATTERN, null );

         config.inclusion.put( pattern, Boolean.FALSE );
      }

      /* PROPERTIES */
      Element propertyGroup = findElement( root, TAG_PROPERTY_GROUP );
      XmlFilter<Element> properties = createFilter( propertyGroup, TAG_PROPERTY, false );

      for (Element e : properties)
      {
         String name = getAttribute( e, ATTR_NAME, null );
         String value = getAttribute( e, ATTR_VALUE, null );

         if (name.equalsIgnoreCase( CONFIG_MODE ))
         {
            config.mode = AgentMode.valueOf( value );
         }
         else
         {
            throw new IOException( "'" + name + "' is an unknown property" );
         }
      }

      return config;
   }