def write_cargo_section(name, value, options = {})
      raise CargoStreamerError.new("Mode must be 'w' to write cargo data") unless @mode == "w"
      raise CargoStreamerError.new("CargoStreamer section names must be strings") unless name.is_a? String
      raise CargoStreamerError.new("Invalid cargo name '" + name + "'") unless name == clean_for_html_comment(name)
      raise CargoStreamerError.new("Cargo name cannot include newlines") if name.include?("\n")
      raise CargoStreamerError.new("Value must be an array") unless value.is_a? Array
      [:to_xml, :attributes=, :valid?].each do |message|
        unless value.all? { |e| e.respond_to? message }
          raise CargoStreamerError.new("All elements must respond to #{message}") 
        end
      end
      unless value.all? { |e| e.class.respond_to?(:safe_to_load_from_cargo_stream?) && e.class.safe_to_load_from_cargo_stream? }
        raise CargoStreamerError.new("All element classes must be models which are safe_to_load_from_cargo_stream")
      end

      unless options[:skip_validation]
        unless value.all?(&:valid?)
          raise CargoStreamerError.new("All elements must be valid")
        end
      end

      if options[:human_readable]
        human_data = value.map{ |rec|
          rec.attributes.map{ |k, v| "#{k.to_s.titleize}: #{v.to_s}" }.join("\n")
        }.join("\n\n")
        @ioh.write "<!--\n"
        @ioh.write name.titleize + "\n"
        @ioh.write "\n"
        @ioh.write clean_for_html_comment(human_data) + "\n"
        @ioh.write "-->\n"
      end
      
      name = name.chomp
      
      assoc_list = options[:include] || []
      
      xml = Builder::XmlMarkup.new
      xml_data = "<records>%s</records>" % value.map {
        |r| r.to_xml(
          :skip_instruct => true,
          :skip_types => true,
          :root => "record",
          :indent => 0,
          :include => assoc_list
        ) do |xml|
          xml.cargo_streamer_type r.class.name
          assoc_info = assoc_list.reject{|a| r.send(a) == nil}.map{|a| "#{a.to_s}=#{r.send(a).class.name}"}.join(",")
          xml.cargo_streamer_includes assoc_info
        end
      }.join()
      deflated_data = Zlib::Deflate::deflate(xml_data)
      b64_data = Base64.encode64(deflated_data).chomp
      digest = Digest::MD5::hexdigest(deflated_data).chomp
      
      @ioh.write CARGO_BEGIN + "\n"
      @ioh.write name + "\n"
      @ioh.write digest + "\n"
      @ioh.write b64_data + "\n"
      @ioh.write CARGO_END + "\n"
    end
def write_cargo_section(name, value, options = {})
      raise CargoStreamerError.new("Mode must be 'w' to write cargo data") unless @mode == "w"
      raise CargoStreamerError.new("CargoStreamer section names must be strings") unless name.is_a? String
      raise CargoStreamerError.new("Invalid cargo name '" + name + "'") unless name == clean_for_html_comment(name)
      raise CargoStreamerError.new("Cargo name cannot include newlines") if name.include?("\n")
      raise CargoStreamerError.new("Value must be an array") unless value.is_a? Array
      [:to_xml, :attributes=, :valid?].each do |message|
        unless value.all? { |e| e.respond_to? message }
          raise CargoStreamerError.new("All elements must respond to #{message}") 
        end
      end
      unless value.all? { |e| e.class.respond_to?(:safe_to_load_from_cargo_stream?) && e.class.safe_to_load_from_cargo_stream? }
        raise CargoStreamerError.new("All element classes must be models which are safe_to_load_from_cargo_stream")
      end

      unless options[:skip_validation]
        unless value.all?(&:valid?)
          raise CargoStreamerError.new("All elements must be valid")
        end
      end

      if options[:human_readable]
        human_data = value.map{ |rec|
          rec.attributes.map{ |k, v| "#{k.to_s.titleize}: #{v.to_s}" }.join("\n")
        }.join("\n\n")
        @ioh.write "<!--\n"
        @ioh.write name.titleize + "\n"
        @ioh.write "\n"
        @ioh.write clean_for_html_comment(human_data) + "\n"
        @ioh.write "-->\n"
      end
      
      name = name.chomp
      
      assoc_list = options[:include] || []
      
      xml = Builder::XmlMarkup.new
      xml_data = "<records>%s</records>" % value.map {
        |r| r.to_xml(
          :skip_instruct => true,
          :skip_types => true,
          :root => "record",
          :indent => 0,
          :include => assoc_list
        ) do |xml|
          xml.cargo_streamer_type r.class.name
          assoc_info = assoc_list.reject{|a| r.send(a) == nil}.map{|a| "#{a.to_s}=#{r.send(a).class.name}"}.join(",")
          xml.cargo_streamer_includes assoc_info
        end
      }.join()
      deflated_data = Zlib::Deflate::deflate(xml_data)
      b64_data = Base64.encode64(deflated_data).chomp
      digest = Digest::MD5::hexdigest(deflated_data).chomp
      
      @ioh.write CARGO_BEGIN + "\n"
      @ioh.write name + "\n"
      @ioh.write digest + "\n"
      @ioh.write b64_data + "\n"
      @ioh.write CARGO_END + "\n"
    end
Models which are to be encoded need to have a method safe_to_load_from_cargo_stream? that returns true.
 Creates a new CargoStreamer on the given stream, which will be used in the given mode (must be "w" or "r").
 If the mode is "r", the file is immediately scanned to determine what cargo it contains.
 Writes a cargo section with the given name and value to the IO stream.
 Options:
 * :human_readable => true - Before writing the cargo section, writes a comment with human-readable data.
 * :include => [:assoc, :other_assoc] - Includes these first-level associations in the encoded data