private DistributionEnvelope splitExtract(String s)
        {
            DistributionEnvelope d = new DistributionEnvelope();
            int ee = s.IndexOf(EXTRACT_END_DELIMITER);
            if (ee == -1)
            {
                throw new Exception("Failed DistributionEnvelope extract - envelope not found");
            }
            int ds = ee + EXTRACT_END_DELIMITER.Length;
            String env = s.Substring(ds);
            if ((env == null) || (env.Trim().Length == 0))
            {
                throw new Exception("Failed DistributionEnvelope extract - zero-length envelope");
            }
            d.setDistributionEnvelope(env);
            int es = s.IndexOf(EXTRACT_START_DELIMITER);
            if (es == -1)
            {
                throw new Exception("Failed DistributionEnvelope extract - extract not found");
            }
            es += EXTRACT_START_DELIMITER.Length;
            String extract = s.Substring(es, ee);

            Regex lineDelimiter = new Regex("\\!");
            Regex fieldDelimiter = new Regex("#");

            String[] lines = lineDelimiter.Split(extract);
            List<Address> addresses = new List<Address>();
            List<Identity> audit = new List<Identity>();

            foreach (String l in lines)
            {
                String[] fields = fieldDelimiter.Split(l);
                if (fields[0].Equals("R"))
                {
                    Address a = null;
                    if (fields.Length > 1)
                    {
                        a = (Address)makeEntity(true, fields);
                        d.setSender(a);
                    }
                    continue;
                }
                if (fields[0].Equals("S"))
                {
                    if (fields.Length == 2)
                    {
                        d.setService(fields[1]);
                    }
                    continue;
                }
                if (fields[0].Equals("T"))
                {
                    if (fields.Length == 2)
                    {
                        d.setTrackingId(fields[1]);
                    }
                    continue;
                }
                if (fields[0].Equals("A"))
                {
                    Address a = (Address)makeEntity(true, fields);
                    addresses.Add(a);
                    continue;
                }
                if (fields[0].Equals("I"))
                {
                    Identity i = (Identity)makeEntity(false, fields);
                    audit.Add(i);
                    continue;
                }
                if (fields[0].Equals("H"))
                {
                    if (fields.Length == 3)
                    {
                        d.addHandlingSpecification(fields[1], fields[2]);
                    }
                    else
                    {
                        d.addHandlingSpecification(fields[1], "");
                    }
                }
            }
            d.setTo(addresses.ToArray());
            d.setAudit(audit.ToArray());
            // Add any checkers we have for "all" and for this DE, also the adders and members
            // Dictionary<string,string[]> where key is service name, and array is list of class names
            if (checkClasses != null)
            {
                if (checkClasses.ContainsKey("all"))
                    makeCheckers(d, checkClasses["all"]);
                if (checkClasses.ContainsKey(d.getService()))
                    makeCheckers(d, checkClasses[d.getService()]);
            }
            return d;
        }
 /**
  * Convenience method for creating and doing basic initialisation on a
  * DistributionEnvelope instance, for use by senders.
  */
 public static DistributionEnvelope newInstance()
 {
     DistributionEnvelope d = new DistributionEnvelope();
     d.setTrackingId("uuid_" + System.Guid.NewGuid().ToString().ToLower());
     return d;
 }