# File lib/asciidoctor/reader.rb, line 812
  def preprocess_include raw_target, raw_attributes
    if (target = @document.sub_attributes raw_target, :attribute_missing => 'drop-line').empty?
      advance
      if @document.attributes.fetch('attribute-missing', Compliance.attribute_missing) == 'skip'
        unshift %(Unresolved directive in #{@path} - include::#{raw_target}[#{raw_attributes}])
      end
      true
    # assume that if an include processor is given, the developer wants
    # to handle when and how to process the include
    elsif include_processors? &&
        (extension = @include_processor_extensions.find {|candidate| candidate.instance.handles? target })
      advance
      # FIXME parse attributes if requested by extension
      extension.process_method[@document, self, target, AttributeList.new(raw_attributes).parse]
      true
    # if running in SafeMode::SECURE or greater, don't process this directive
    # however, be friendly and at least make it a link to the source document
    elsif @document.safe >= SafeMode::SECURE
      # FIXME we don't want to use a link macro if we are in a verbatim context
      replace_next_line %(link:#{target}[])
      true
    elsif (abs_maxdepth = @maxdepth[:abs]) > 0 && @include_stack.size >= abs_maxdepth
      warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded)
      false
    elsif abs_maxdepth > 0
      if ::RUBY_ENGINE_OPAL
        # NOTE resolves uri relative to currently loaded document
        # NOTE we defer checking if file exists and catch the 404 error if it does not
        # TODO only use this logic if env-browser is set
        target_type = :file
        include_file = path = if @include_stack.empty?
          ::Dir.pwd == @document.base_dir ? target : (::File.join @dir, target)
        else
          ::File.join @dir, target
        end
      elsif Helpers.uriish? target
        unless @document.attributes.has_key? 'allow-uri-read'
          replace_next_line %(link:#{target}[])
          return true
        end

        target_type = :uri
        include_file = path = target
        if @document.attributes.has_key? 'cache-uri'
          # caching requires the open-uri-cached gem to be installed
          # processing will be automatically aborted if these libraries can't be opened
          Helpers.require_library 'open-uri/cached', 'open-uri-cached' unless defined? ::OpenURI::Cache
        elsif !::RUBY_ENGINE_OPAL
          # autoload open-uri
          ::OpenURI
        end
      else
        target_type = :file
        # include file is resolved relative to dir of current include, or base_dir if within original docfile
        include_file = @document.normalize_system_path(target, @dir, nil, :target_name => 'include file')
        unless ::File.file? include_file
          warn %(asciidoctor: WARNING: #{line_info}: include file not found: #{include_file})
          replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
          return true
        end
        #path = @document.relative_path include_file
        path = PathResolver.new.relative_path include_file, @document.base_dir
      end

      inc_lines = nil
      tags = nil
      attributes = {}
      if !raw_attributes.empty?
        # QUESTION should we use @document.parse_attribues?
        attributes = AttributeList.new(raw_attributes).parse
        if attributes.has_key? 'lines'
          inc_lines = []
          attributes['lines'].split(DataDelimiterRx).each do |linedef|
            if linedef.include?('..')
              from, to = linedef.split('..').map(&:to_i)
              if to == -1
                inc_lines << from
                inc_lines << 1.0/0.0
              else
                inc_lines.concat ::Range.new(from, to).to_a
              end
            else
              inc_lines << linedef.to_i
            end
          end
          inc_lines = inc_lines.sort.uniq
        elsif attributes.has_key? 'tag'
          tags = [attributes['tag']].to_set
        elsif attributes.has_key? 'tags'
          tags = attributes['tags'].split(DataDelimiterRx).to_set
        end
      end
      if inc_lines
        unless inc_lines.empty?
          selected = []
          inc_line_offset = 0
          inc_lineno = 0
          begin
            open(include_file, 'r') do |f|
              f.each_line do |l|
                inc_lineno += 1
                take = inc_lines[0]
                if take.is_a?(::Float) && take.infinite?
                  selected.push l
                  inc_line_offset = inc_lineno if inc_line_offset == 0
                else
                  if f.lineno == take
                    selected.push l
                    inc_line_offset = inc_lineno if inc_line_offset == 0
                    inc_lines.shift
                  end
                  break if inc_lines.empty?
                end
              end
            end
          rescue
            warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
            replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
            return true
          end
          advance
          # FIXME not accounting for skipped lines in reader line numbering
          push_include selected, include_file, path, inc_line_offset, attributes
        end
      elsif tags
        unless tags.empty?
          selected = []
          inc_line_offset = 0
          inc_lineno = 0
          active_tag = nil
          tags_found = ::Set.new
          begin
            open(include_file, 'r') do |f|
              f.each_line do |l|
                inc_lineno += 1
                # must force encoding here since we're performing String operations on line
                l.force_encoding(::Encoding::UTF_8) if FORCE_ENCODING
                l = l.rstrip
                # tagged lines in XML may end with '-->'
                tl = l.chomp('-->').rstrip
                if active_tag
                  if tl.end_with?(%(end::#{active_tag}[]))
                    active_tag = nil
                  else
                    selected.push l unless tl.end_with?('[]') && TagDirectiveRx =~ tl
                    inc_line_offset = inc_lineno if inc_line_offset == 0
                  end
                else
                  tags.each do |tag|
                    if tl.end_with?(%(tag::#{tag}[]))
                      active_tag = tag
                      tags_found << tag
                      break
                    end
                  end if tl.end_with?('[]') && TagDirectiveRx =~ tl
                end
              end
            end
          rescue
            warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
            replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
            return true
          end
          unless (missing_tags = tags.to_a - tags_found.to_a).empty?
            warn %(asciidoctor: WARNING: #{line_info}: tag#{missing_tags.size > 1 ? 's' : nil} '#{missing_tags * ','}' not found in include #{target_type}: #{include_file})
          end
          advance
          # FIXME not accounting for skipped lines in reader line numbering
          push_include selected, include_file, path, inc_line_offset, attributes
        end
      else
        begin
          # NOTE read content first so that we only advance cursor if IO operation succeeds
          include_content = open(include_file, 'r') {|f| f.read }
          advance
          push_include include_content, include_file, path, 1, attributes
        rescue
          warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
          replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
          return true
        end
      end
      true
    else
      false
    end
  end