summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown.rb10
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb68
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb257
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb38
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb545
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb458
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb626
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb300
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb32
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb58
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb56
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb35
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb85
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb69
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb139
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb551
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb17
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb645
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb26
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb137
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb621
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb377
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb80
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb31
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb30
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb34
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb38
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb57
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb58
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb66
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb26
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb25
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb214
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb64
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb70
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb27
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb165
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb34
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb25
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb149
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb286
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb53
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb62
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb174
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb171
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb44
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb57
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb45
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb45
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb1000
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb84
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb41
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb81
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb46
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb15
55 files changed, 8547 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown.rb
new file mode 100644
index 0000000..3700b9d
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown.rb
@@ -0,0 +1,10 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/document'
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb
new file mode 100644
index 0000000..0055a14
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb
@@ -0,0 +1,68 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/utils'
+
+module Kramdown
+
+ # This module contains all available converters, i.e. classes that take a root Element and convert
+ # it to a specific output format. The result is normally a string. For example, the
+ # Converter::Html module converts an element tree into valid HTML.
+ #
+ # Converters use the Base class for common functionality (like applying a template to the output)
+ # \- see its API documentation for how to create a custom converter class.
+ module Converter
+
+ autoload :Base, 'kramdown/converter/base'
+ autoload :Html, 'kramdown/converter/html'
+ autoload :Latex, 'kramdown/converter/latex'
+ autoload :Kramdown, 'kramdown/converter/kramdown'
+ autoload :Toc, 'kramdown/converter/toc'
+ autoload :RemoveHtmlTags, 'kramdown/converter/remove_html_tags'
+ autoload :HashAST, 'kramdown/converter/hash_ast'
+ autoload :HashAst, 'kramdown/converter/hash_ast'
+ autoload :Man, 'kramdown/converter/man'
+
+ extend ::Kramdown::Utils::Configurable
+
+ configurable(:syntax_highlighter)
+
+ ['Minted', "Rouge"].each do |klass_name|
+ kn_down = klass_name.downcase.intern
+ add_syntax_highlighter(kn_down) do |converter, text, lang, type, opts|
+ require "kramdown/converter/syntax_highlighter/#{kn_down}"
+ klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::SyntaxHighlighter::#{klass_name}")
+ if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE
+ add_syntax_highlighter(kn_down, klass)
+ else
+ add_syntax_highlighter(kn_down) { nil }
+ end
+ syntax_highlighter(kn_down).call(converter, text, lang, type, opts)
+ end
+ end
+
+ configurable(:math_engine)
+
+ ["Mathjax"].each do |klass_name|
+ kn_down = klass_name.downcase.intern
+ add_math_engine(kn_down) do |converter, el, opts|
+ require "kramdown/converter/math_engine/#{kn_down}"
+ klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::MathEngine::#{klass_name}")
+ if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE
+ add_math_engine(kn_down, klass)
+ else
+ add_math_engine(kn_down) { nil }
+ end
+ math_engine(kn_down).call(converter, el, opts)
+ end
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb
new file mode 100644
index 0000000..86cd2b4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb
@@ -0,0 +1,257 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'erb'
+require 'kramdown/utils'
+require 'kramdown/document'
+
+module Kramdown
+
+ module Converter
+
+ # == \Base class for converters
+ #
+ # This class serves as base class for all converters. It provides methods that can/should be
+ # used by all converters (like #generate_id) as well as common functionality that is
+ # automatically applied to the result (for example, embedding the output into a template).
+ #
+ # A converter object is used as a throw-away object, i.e. it is only used for storing the needed
+ # state information during conversion. Therefore one can't instantiate a converter object
+ # directly but only use the Base::convert method.
+ #
+ # == Implementing a converter
+ #
+ # Implementing a new converter is rather easy: just derive a new class from this class and put
+ # it in the Kramdown::Converter module (the latter is only needed if auto-detection should work
+ # properly). Then you need to implement the #convert method which has to contain the conversion
+ # code for converting an element and has to return the conversion result.
+ #
+ # The actual transformation of the document tree can be done in any way. However, writing one
+ # method per element type is a straight forward way to do it - this is how the Html and Latex
+ # converters do the transformation.
+ #
+ # Have a look at the Base::convert method for additional information!
+ class Base
+
+ # Can be used by a converter for storing arbitrary information during the conversion process.
+ attr_reader :data
+
+ # The hash with the conversion options.
+ attr_reader :options
+
+ # The root element that is converted.
+ attr_reader :root
+
+ # The warnings array.
+ attr_reader :warnings
+
+ # Initialize the converter with the given +root+ element and +options+ hash.
+ def initialize(root, options)
+ @options = options
+ @root = root
+ @data = {}
+ @warnings = []
+ end
+ private_class_method(:new, :allocate)
+
+ # Returns whether the template should be applied before the conversion of the tree.
+ #
+ # Defaults to false.
+ def apply_template_before?
+ false
+ end
+
+ # Returns whether the template should be applied after the conversion of the tree.
+ #
+ # Defaults to true.
+ def apply_template_after?
+ true
+ end
+
+ # Convert the element tree +tree+ and return the resulting conversion object (normally a
+ # string) and an array with warning messages. The parameter +options+ specifies the conversion
+ # options that should be used.
+ #
+ # Initializes a new instance of the calling class and then calls the #convert method with
+ # +tree+ as parameter.
+ #
+ # If the +template+ option is specified and non-empty, the template is evaluate with ERB
+ # before and/or after the tree conversion depending on the result of #apply_template_before?
+ # and #apply_template_after?. If the template is evaluated before, an empty string is used for
+ # the body; if evaluated after, the result is used as body. See ::apply_template.
+ #
+ # The template resolution is done in the following way (for the converter ConverterName):
+ #
+ # 1. Look in the current working directory for the template.
+ #
+ # 2. Append +.converter_name+ (e.g. +.html+) to the template name and look for the resulting
+ # file in the current working directory (the form +.convertername+ is deprecated).
+ #
+ # 3. Append +.converter_name+ to the template name and look for it in the kramdown data
+ # directory (the form +.convertername+ is deprecated).
+ #
+ # 4. Check if the template name starts with 'string://' and if so, strip this prefix away and
+ # use the rest as template.
+ def self.convert(tree, options = {})
+ converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {})))
+
+ if !converter.options[:template].empty? && converter.apply_template_before?
+ apply_template(converter, '')
+ end
+ result = converter.convert(tree)
+ if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY
+ result.encode!(tree.options[:encoding] ||
+ (raise ::Kramdown::Error, "Missing encoding option on root element"))
+ end
+ if !converter.options[:template].empty? && converter.apply_template_after?
+ result = apply_template(converter, result)
+ end
+
+ [result, converter.warnings]
+ end
+
+ # Convert the element +el+ and return the resulting object.
+ #
+ # This is the only method that has to be implemented by sub-classes!
+ def convert(_el)
+ raise NotImplementedError
+ end
+
+ # Apply the +template+ using +body+ as the body string.
+ #
+ # The template is evaluated using ERB and the body is available in the @body instance variable
+ # and the converter object in the @converter instance variable.
+ def self.apply_template(converter, body) # :nodoc:
+ erb = ERB.new(get_template(converter.options[:template]))
+ obj = Object.new
+ obj.instance_variable_set(:@converter, converter)
+ obj.instance_variable_set(:@body, body)
+ erb.result(obj.instance_eval { binding })
+ end
+
+ # Return the template specified by +template+.
+ def self.get_template(template) # :nodoc:
+ format_ext = '.' + ::Kramdown::Utils.snake_case(name.split("::").last)
+ shipped = File.join(::Kramdown.data_dir, template + format_ext)
+ if File.exist?(template)
+ File.read(template)
+ elsif File.exist?(template + format_ext)
+ File.read(template + format_ext)
+ elsif File.exist?(shipped)
+ File.read(shipped)
+ elsif template.start_with?('string://')
+ template.delete_prefix("string://")
+ else
+ raise "The specified template file #{template} does not exist"
+ end
+ end
+
+ # Add the given warning +text+ to the warning array.
+ def warning(text)
+ @warnings << text
+ end
+
+ # Return +true+ if the header element +el+ should be used for the table of contents (as
+ # specified by the +toc_levels+ option).
+ def in_toc?(el)
+ @options[:toc_levels].include?(el.options[:level]) && (el.attr['class'] || '') !~ /\bno_toc\b/
+ end
+
+ # Return the output header level given a level.
+ #
+ # Uses the +header_offset+ option for adjusting the header level.
+ def output_header_level(level)
+ [[level + @options[:header_offset], 6].min, 1].max
+ end
+
+ # Extract the code block/span language from the attributes.
+ def extract_code_language(attr)
+ if attr['class'] && attr['class'] =~ /\blanguage-\S+/
+ attr['class'].scan(/\blanguage-(\S+)/).first.first
+ end
+ end
+
+ # See #extract_code_language
+ #
+ # *Warning*: This version will modify the given attributes if a language is present.
+ def extract_code_language!(attr)
+ lang = extract_code_language(attr)
+ attr['class'] = attr['class'].sub(/\blanguage-\S+/, '').strip if lang
+ attr.delete('class') if lang && attr['class'].empty?
+ lang
+ end
+
+ # Highlight the given +text+ in the language +lang+ with the syntax highlighter configured
+ # through the option 'syntax_highlighter'.
+ def highlight_code(text, lang, type, opts = {})
+ return nil unless @options[:syntax_highlighter]
+
+ highlighter = ::Kramdown::Converter.syntax_highlighter(@options[:syntax_highlighter])
+ if highlighter
+ highlighter.call(self, text, lang, type, opts)
+ else
+ warning("The configured syntax highlighter #{@options[:syntax_highlighter]} is not available.")
+ nil
+ end
+ end
+
+ # Format the given math element with the math engine configured through the option
+ # 'math_engine'.
+ def format_math(el, opts = {})
+ return nil unless @options[:math_engine]
+
+ engine = ::Kramdown::Converter.math_engine(@options[:math_engine])
+ if engine
+ engine.call(self, el, opts)
+ else
+ warning("The configured math engine #{@options[:math_engine]} is not available.")
+ nil
+ end
+ end
+
+ # Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID.
+ #
+ # Uses the option +auto_id_prefix+: the value of this option is prepended to every generated
+ # ID.
+ def generate_id(str)
+ str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids]
+ gen_id = basic_generate_id(str)
+ gen_id = 'section' if gen_id.empty?
+ @used_ids ||= {}
+ if @used_ids.key?(gen_id)
+ gen_id += "-#{@used_ids[gen_id] += 1}"
+ else
+ @used_ids[gen_id] = 0
+ end
+ @options[:auto_id_prefix] + gen_id
+ end
+
+ # The basic version of the ID generator, without any special provisions for empty or unique
+ # IDs.
+ def basic_generate_id(str)
+ gen_id = str.gsub(/^[^a-zA-Z]+/, '')
+ gen_id.tr!('^a-zA-Z0-9 -', '')
+ gen_id.tr!(' ', '-')
+ gen_id.downcase!
+ gen_id
+ end
+
+ SMART_QUOTE_INDICES = {lsquo: 0, rsquo: 1, ldquo: 2, rdquo: 3} # :nodoc:
+
+ # Return the entity that represents the given smart_quote element.
+ def smart_quote_entity(el)
+ res = @options[:smart_quotes][SMART_QUOTE_INDICES[el.value]]
+ ::Kramdown::Utils::Entities.entity(res)
+ end
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb
new file mode 100644
index 0000000..95714d4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb
@@ -0,0 +1,38 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser'
+require 'kramdown/converter'
+require 'kramdown/utils'
+
+module Kramdown
+
+ module Converter
+
+ # Converts a Kramdown::Document to a nested hash for further processing or debug output.
+ class HashAST < Base
+
+ def convert(el)
+ hash = {type: el.type}
+ hash[:attr] = el.attr unless el.attr.empty?
+ hash[:value] = el.value unless el.value.nil?
+ hash[:options] = el.options unless el.options.empty?
+ unless el.children.empty?
+ hash[:children] = []
+ el.children.each {|child| hash[:children] << convert(child) }
+ end
+ hash
+ end
+
+ end
+
+ HashAst = HashAST
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb
new file mode 100644
index 0000000..51ac9eb
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb
@@ -0,0 +1,545 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser'
+require 'kramdown/converter'
+require 'kramdown/utils'
+
+module Kramdown
+
+ module Converter
+
+ # Converts a Kramdown::Document to HTML.
+ #
+ # You can customize the HTML converter by sub-classing it and overriding the +convert_NAME+
+ # methods. Each such method takes the following parameters:
+ #
+ # [+el+] The element of type +NAME+ to be converted.
+ #
+ # [+indent+] A number representing the current amount of spaces for indent (only used for
+ # block-level elements).
+ #
+ # The return value of such a method has to be a string containing the element +el+ formatted as
+ # HTML element.
+ class Html < Base
+
+ include ::Kramdown::Utils::Html
+ include ::Kramdown::Parser::Html::Constants
+
+ # The amount of indentation used when nesting HTML tags.
+ attr_accessor :indent
+
+ # Initialize the HTML converter with the given Kramdown document +doc+.
+ def initialize(root, options)
+ super
+ @footnote_counter = @footnote_start = @options[:footnote_nr]
+ @footnotes = []
+ @footnotes_by_name = {}
+ @footnote_location = nil
+ @toc = []
+ @toc_code = nil
+ @indent = 2
+ @stack = []
+
+ # stash string representation of symbol to avoid allocations from multiple interpolations.
+ @highlighter_class = " highlighter-#{options[:syntax_highlighter]}"
+ @dispatcher = Hash.new {|h, k| h[k] = :"convert_#{k}" }
+ end
+
+ # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
+ # the element.
+ def convert(el, indent = -@indent)
+ send(@dispatcher[el.type], el, indent)
+ end
+
+ # Return the converted content of the children of +el+ as a string. The parameter +indent+ has
+ # to be the amount of indentation used for the element +el+.
+ #
+ # Pushes +el+ onto the @stack before converting the child elements and pops it from the stack
+ # afterwards.
+ def inner(el, indent)
+ result = +''
+ indent += @indent
+ @stack.push(el)
+ el.children.each do |inner_el|
+ result << send(@dispatcher[inner_el.type], inner_el, indent)
+ end
+ @stack.pop
+ result
+ end
+
+ def convert_blank(_el, _indent)
+ "\n"
+ end
+
+ def convert_text(el, _indent)
+ escaped = escape_html(el.value, :text)
+ @options[:remove_line_breaks_for_cjk] ? fix_cjk_line_break(escaped) : escaped
+ end
+
+ def convert_p(el, indent)
+ if el.options[:transparent]
+ inner(el, indent)
+ elsif el.children.size == 1 && el.children.first.type == :img &&
+ el.children.first.options[:ial]&.[](:refs)&.include?('standalone')
+ convert_standalone_image(el, indent)
+ else
+ format_as_block_html("p", el.attr, inner(el, indent), indent)
+ end
+ end
+
+ # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img
+ # element.
+ def convert_standalone_image(el, indent)
+ figure_attr = el.attr.dup
+ image_attr = el.children.first.attr.dup
+
+ if image_attr.key?('class') && !figure_attr.key?('class')
+ figure_attr['class'] = image_attr.delete('class')
+ end
+ if image_attr.key?('id') && !figure_attr.key?('id')
+ figure_attr['id'] = image_attr.delete('id')
+ end
+
+ body = "#{' ' * (indent + @indent)}<img#{html_attributes(image_attr)} />\n" \
+ "#{' ' * (indent + @indent)}<figcaption>#{image_attr['alt']}</figcaption>\n"
+ format_as_indented_block_html("figure", figure_attr, body, indent)
+ end
+
+ def convert_codeblock(el, indent)
+ attr = el.attr.dup
+ lang = extract_code_language!(attr)
+ hl_opts = {}
+ highlighted_code = highlight_code(el.value, el.options[:lang] || lang, :block, hl_opts)
+
+ if highlighted_code
+ add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang])
+ "#{' ' * indent}<div#{html_attributes(attr)}>#{highlighted_code}#{' ' * indent}</div>\n"
+ else
+ result = escape_html(el.value)
+ result.chomp!
+ if el.attr['class'].to_s =~ /\bshow-whitespaces\b/
+ result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m|
+ suffix = ($1 ? '-l' : ($2 ? '-r' : ''))
+ m.scan(/./).map do |c|
+ case c
+ when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>"
+ when " " then "<span class=\"ws-space#{suffix}\">&#8901;</span>"
+ end
+ end.join
+ end
+ end
+ code_attr = {}
+ code_attr['class'] = "language-#{lang}" if lang
+ "#{' ' * indent}<pre#{html_attributes(attr)}>" \
+ "<code#{html_attributes(code_attr)}>#{result}\n</code></pre>\n"
+ end
+ end
+
+ def convert_blockquote(el, indent)
+ format_as_indented_block_html("blockquote", el.attr, inner(el, indent), indent)
+ end
+
+ def convert_header(el, indent)
+ attr = el.attr.dup
+ if @options[:auto_ids] && !attr['id']
+ attr['id'] = generate_id(el.options[:raw_text])
+ end
+
+ if @options[:header_links] && attr['id'].to_s.length > 0
+ link = Element.new(:a, nil, nil)
+ link.attr['href'] = "##{attr['id']}"
+ el.children.unshift(link)
+ end
+
+ @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el)
+ level = output_header_level(el.options[:level])
+ format_as_block_html("h#{level}", attr, inner(el, indent), indent)
+ end
+
+ def convert_hr(el, indent)
+ "#{' ' * indent}<hr#{html_attributes(el.attr)} />\n"
+ end
+
+ ZERO_TO_ONETWENTYEIGHT = (0..128).to_a.freeze
+ private_constant :ZERO_TO_ONETWENTYEIGHT
+
+ def convert_ul(el, indent)
+ if !@toc_code && el.options.dig(:ial, :refs)&.include?('toc')
+ @toc_code = [el.type, el.attr, ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join]
+ @toc_code.last
+ elsif !@footnote_location && el.options.dig(:ial, :refs)&.include?('footnotes')
+ @footnote_location = ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join
+ else
+ format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
+ end
+ end
+ alias convert_ol convert_ul
+
+ def convert_dl(el, indent)
+ format_as_indented_block_html("dl", el.attr, inner(el, indent), indent)
+ end
+
+ def convert_li(el, indent)
+ output = ' ' * indent << "<#{el.type}" << html_attributes(el.attr) << ">"
+ res = inner(el, indent)
+ if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent])
+ output << res << (res.match?(/\n\Z/) ? ' ' * indent : '')
+ else
+ output << "\n" << res << ' ' * indent
+ end
+ output << "</#{el.type}>\n"
+ end
+ alias convert_dd convert_li
+
+ def convert_dt(el, indent)
+ attr = el.attr.dup
+ @stack.last.options[:ial][:refs].each do |ref|
+ if ref =~ /\Aauto_ids(?:-([\w-]+))?/
+ attr['id'] = "#{$1}#{basic_generate_id(el.options[:raw_text])}".lstrip
+ break
+ end
+ end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs]
+ format_as_block_html("dt", attr, inner(el, indent), indent)
+ end
+
+ def convert_html_element(el, indent)
+ res = inner(el, indent)
+ if el.options[:category] == :span
+ "<#{el.value}#{html_attributes(el.attr)}" + \
+ (res.empty? && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) ? " />" : ">#{res}</#{el.value}>")
+ else
+ output = +''
+ if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
+ output << ' ' * indent
+ end
+ output << "<#{el.value}#{html_attributes(el.attr)}"
+ if el.options[:is_closed] && el.options[:content_model] == :raw
+ output << " />"
+ elsif !res.empty? && el.options[:content_model] != :block
+ output << ">#{res}</#{el.value}>"
+ elsif !res.empty?
+ output << ">\n#{res.chomp}\n" << ' ' * indent << "</#{el.value}>"
+ elsif HTML_ELEMENTS_WITHOUT_BODY.include?(el.value)
+ output << " />"
+ else
+ output << "></#{el.value}>"
+ end
+ output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
+ output
+ end
+ end
+
+ def convert_xml_comment(el, indent)
+ if el.options[:category] == :block &&
+ (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw)
+ ' ' * indent << el.value << "\n"
+ else
+ el.value
+ end
+ end
+ alias convert_xml_pi convert_xml_comment
+
+ def convert_table(el, indent)
+ format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
+ end
+ alias convert_thead convert_table
+ alias convert_tbody convert_table
+ alias convert_tfoot convert_table
+ alias convert_tr convert_table
+
+ ENTITY_NBSP = ::Kramdown::Utils::Entities.entity('nbsp') # :nodoc:
+
+ def convert_td(el, indent)
+ res = inner(el, indent)
+ type = (@stack[-2].type == :thead ? :th : :td)
+ attr = el.attr
+ alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)]
+ if alignment != :default
+ attr = el.attr.dup
+ attr['style'] = (attr.key?('style') ? "#{attr['style']}; " : '') + "text-align: #{alignment}"
+ end
+ format_as_block_html(type, attr, res.empty? ? entity_to_str(ENTITY_NBSP) : res, indent)
+ end
+
+ def convert_comment(el, indent)
+ if el.options[:category] == :block
+ "#{' ' * indent}<!-- #{el.value} -->\n"
+ else
+ "<!-- #{el.value} -->"
+ end
+ end
+
+ def convert_br(_el, _indent)
+ "<br />"
+ end
+
+ def convert_a(el, indent)
+ format_as_span_html("a", el.attr, inner(el, indent))
+ end
+
+ def convert_img(el, _indent)
+ "<img#{html_attributes(el.attr)} />"
+ end
+
+ def convert_codespan(el, _indent)
+ attr = el.attr.dup
+ lang = extract_code_language(attr)
+ hl_opts = {}
+ result = highlight_code(el.value, lang, :span, hl_opts)
+ if result
+ add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang])
+ else
+ result = escape_html(el.value)
+ end
+
+ format_as_span_html('code', attr, result)
+ end
+
+ def convert_footnote(el, _indent)
+ repeat = ''
+ name = @options[:footnote_prefix] + el.options[:name]
+ if (footnote = @footnotes_by_name[name])
+ number = footnote[2]
+ repeat = ":#{footnote[3] += 1}"
+ else
+ number = @footnote_counter
+ @footnote_counter += 1
+ @footnotes << [name, el.value, number, 0]
+ @footnotes_by_name[name] = @footnotes.last
+ end
+ formatted_link_text = sprintf(@options[:footnote_link_text], number)
+ "<sup id=\"fnref:#{name}#{repeat}\">" \
+ "<a href=\"#fn:#{name}\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">" \
+ "#{formatted_link_text}</a></sup>"
+ end
+
+ def convert_raw(el, _indent)
+ if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html')
+ el.value + (el.options[:category] == :block ? "\n" : '')
+ else
+ ''
+ end
+ end
+
+ def convert_em(el, indent)
+ format_as_span_html(el.type, el.attr, inner(el, indent))
+ end
+ alias convert_strong convert_em
+
+ def convert_entity(el, _indent)
+ entity_to_str(el.value, el.options[:original])
+ end
+
+ TYPOGRAPHIC_SYMS = {
+ mdash: [::Kramdown::Utils::Entities.entity('mdash')],
+ ndash: [::Kramdown::Utils::Entities.entity('ndash')],
+ hellip: [::Kramdown::Utils::Entities.entity('hellip')],
+ laquo_space: [::Kramdown::Utils::Entities.entity('laquo'),
+ ::Kramdown::Utils::Entities.entity('nbsp')],
+ raquo_space: [::Kramdown::Utils::Entities.entity('nbsp'),
+ ::Kramdown::Utils::Entities.entity('raquo')],
+ laquo: [::Kramdown::Utils::Entities.entity('laquo')],
+ raquo: [::Kramdown::Utils::Entities.entity('raquo')],
+ } # :nodoc:
+ def convert_typographic_sym(el, _indent)
+ if (result = @options[:typographic_symbols][el.value])
+ escape_html(result, :text)
+ else
+ TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join
+ end
+ end
+
+ def convert_smart_quote(el, _indent)
+ entity_to_str(smart_quote_entity(el))
+ end
+
+ def convert_math(el, indent)
+ if (result = format_math(el, indent: indent))
+ result
+ else
+ attr = el.attr.dup
+ attr['class'] = "#{attr['class']} kdmath".lstrip
+ if el.options[:category] == :block
+ format_as_block_html('div', attr, "$$\n#{el.value}\n$$", indent)
+ else
+ format_as_span_html('span', attr, "$#{el.value}$")
+ end
+ end
+ end
+
+ def convert_abbreviation(el, _indent)
+ title = @root.options[:abbrev_defs][el.value]
+ attr = @root.options[:abbrev_attr][el.value].dup
+ attr['title'] = title unless title.empty?
+ format_as_span_html("abbr", attr, el.value)
+ end
+
+ def convert_root(el, indent)
+ result = inner(el, indent)
+ if @footnote_location
+ result.sub!(/#{@footnote_location}/, footnote_content.gsub(/\\/, "\\\\\\\\"))
+ else
+ result << footnote_content
+ end
+ if @toc_code
+ toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {})
+ text = toc_tree.children.empty? ? '' : convert(toc_tree, 0)
+ result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\"))
+ end
+ result
+ end
+
+ # Format the given element as span HTML.
+ def format_as_span_html(name, attr, body)
+ "<#{name}#{html_attributes(attr)}>#{body}</#{name}>"
+ end
+
+ # Format the given element as block HTML.
+ def format_as_block_html(name, attr, body, indent)
+ "#{' ' * indent}<#{name}#{html_attributes(attr)}>#{body}</#{name}>\n"
+ end
+
+ # Format the given element as block HTML with a newline after the start tag and indentation
+ # before the end tag.
+ def format_as_indented_block_html(name, attr, body, indent)
+ "#{' ' * indent}<#{name}#{html_attributes(attr)}>\n#{body}#{' ' * indent}</#{name}>\n"
+ end
+
+ # Add the syntax highlighter name to the 'class' attribute of the given attribute hash. And
+ # overwrites or add a "language-LANG" part using the +lang+ parameter if +lang+ is not nil.
+ def add_syntax_highlighter_to_class_attr(attr, lang = nil)
+ (attr['class'] = (attr['class'] || '') + @highlighter_class).lstrip!
+ attr['class'].sub!(/\blanguage-\S+|(^)/) { "language-#{lang}#{$1 ? ' ' : ''}" } if lang
+ end
+
+ # Generate and return an element tree for the table of contents.
+ def generate_toc_tree(toc, type, attr)
+ sections = Element.new(type, nil, attr.dup)
+ sections.attr['id'] ||= 'markdown-toc'
+ stack = []
+ toc.each do |level, id, children|
+ li = Element.new(:li, nil, nil, level: level)
+ li.children << Element.new(:p, nil, nil, transparent: true)
+ a = Element.new(:a, nil)
+ a.attr['href'] = "##{id}"
+ a.attr['id'] = "#{sections.attr['id']}-#{id}"
+ a.children.concat(fix_for_toc_entry(Marshal.load(Marshal.dump(children))))
+ li.children.last.children << a
+ li.children << Element.new(type)
+
+ success = false
+ until success
+ if stack.empty?
+ sections.children << li
+ stack << li
+ success = true
+ elsif stack.last.options[:level] < li.options[:level]
+ stack.last.children.last.children << li
+ stack << li
+ success = true
+ else
+ item = stack.pop
+ item.children.pop if item.children.last.children.empty?
+ end
+ end
+ end
+ until stack.empty?
+ item = stack.pop
+ item.children.pop if item.children.last.children.empty?
+ end
+ sections
+ end
+
+ # Fixes the elements for use in a TOC entry.
+ def fix_for_toc_entry(elements)
+ remove_footnotes(elements)
+ unwrap_links(elements)
+ elements
+ end
+
+ # Remove all link elements by unwrapping them.
+ def unwrap_links(elements)
+ elements.map! do |c|
+ unwrap_links(c.children)
+ c.type == :a ? c.children : c
+ end.flatten!
+ end
+
+ # Remove all footnotes from the given elements.
+ def remove_footnotes(elements)
+ elements.delete_if do |c|
+ remove_footnotes(c.children)
+ c.type == :footnote
+ end
+ end
+
+ # Obfuscate the +text+ by using HTML entities.
+ def obfuscate(text)
+ result = +''
+ text.each_byte do |b|
+ result << (b > 128 ? b.chr : sprintf("&#%03d;", b))
+ end
+ result.force_encoding(text.encoding)
+ result
+ end
+
+ FOOTNOTE_BACKLINK_FMT = "%s<a href=\"#fnref:%s\" class=\"reversefootnote\" role=\"doc-backlink\">%s</a>"
+
+ # Return an HTML ordered list with the footnote content for the used footnotes.
+ def footnote_content
+ ol = Element.new(:ol)
+ ol.attr['start'] = @footnote_start if @footnote_start != 1
+ i = 0
+ backlink_text = escape_html(@options[:footnote_backlink], :text)
+ while i < @footnotes.length
+ name, data, _, repeat = *@footnotes[i]
+ li = Element.new(:li, nil, 'id' => "fn:#{name}")
+ li.children = Marshal.load(Marshal.dump(data.children))
+
+ para = nil
+ if li.children.last.type == :p || @options[:footnote_backlink_inline]
+ parent = li
+ while !parent.children.empty? && ![:p, :header].include?(parent.children.last.type)
+ parent = parent.children.last
+ end
+ para = parent.children.last
+ insert_space = true
+ end
+
+ unless para
+ li.children << (para = Element.new(:p))
+ insert_space = false
+ end
+
+ unless @options[:footnote_backlink].empty?
+ nbsp = entity_to_str(ENTITY_NBSP)
+ value = sprintf(FOOTNOTE_BACKLINK_FMT, (insert_space ? nbsp : ''), name, backlink_text)
+ para.children << Element.new(:raw, value)
+ (1..repeat).each do |index|
+ value = sprintf(FOOTNOTE_BACKLINK_FMT, nbsp, "#{name}:#{index}",
+ "#{backlink_text}<sup>#{index + 1}</sup>")
+ para.children << Element.new(:raw, value)
+ end
+ end
+
+ ol.children << Element.new(:raw, convert(li, 4))
+ i += 1
+ end
+ if ol.children.empty?
+ ''
+ else
+ format_as_indented_block_html('div', {class: "footnotes", role: "doc-endnotes"}, convert(ol, 2), 0)
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb
new file mode 100644
index 0000000..3be4a8d
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb
@@ -0,0 +1,458 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/converter'
+require 'kramdown/utils'
+
+module Kramdown
+
+ module Converter
+
+ # Converts an element tree to the kramdown format.
+ class Kramdown < Base
+
+ # :stopdoc:
+
+ include ::Kramdown::Utils::Html
+
+ def initialize(root, options)
+ super
+ @linkrefs = []
+ @footnotes = []
+ @abbrevs = []
+ @stack = []
+ @list_indent = @options[:list_indent]
+ @list_spacing = ' ' * (@list_indent - 2)
+ end
+
+ def convert(el, opts = {indent: 0})
+ res = send("convert_#{el.type}", el, opts)
+ res = res.dup if res.frozen?
+ if ![:html_element, :li, :dt, :dd, :td].include?(el.type) && (ial = ial_for_element(el))
+ res << ial
+ res << "\n\n" if el.block?
+ elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
+ ([el.type, :codeblock].include?(opts[:next].type) ||
+ (opts[:next].type == :blank && opts[:nnext] &&
+ [el.type, :codeblock].include?(opts[:nnext].type)))
+ res << "^\n\n"
+ elsif el.block? &&
+ ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
+ (el.type != :html_element || @stack.last.type != :html_element) &&
+ (el.type != :p || !el.options[:transparent]) &&
+ !([:ul, :dl, :ol].include?(el.type) && @stack.last.type == :li)
+ res << "\n"
+ end
+ res
+ end
+
+ def inner(el, opts = {indent: 0})
+ @stack.push(el)
+ result = +''
+ el.children.each_with_index do |inner_el, index|
+ options = opts.dup
+ options[:index] = index
+ options[:prev] = (index == 0 ? nil : el.children[index - 1])
+ options[:pprev] = (index <= 1 ? nil : el.children[index - 2])
+ options[:next] = (index == el.children.length - 1 ? nil : el.children[index + 1])
+ options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index + 2])
+ result << convert(inner_el, options)
+ end
+ @stack.pop
+ result
+ end
+
+ def convert_blank(_el, _opts)
+ ""
+ end
+
+ ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]{"'|])|^ {0,3}(:)/
+
+ def convert_text(el, opts)
+ if opts[:raw_text] || (@stack.last.type == :html_element && @stack.last.options[:content_model] == :raw)
+ el.value
+ else
+ result = el.value.gsub(/\A\n/) do
+ opts[:prev] && opts[:prev].type == :br ? '' : "\n"
+ end
+ result.gsub!(/\s+/, ' ') unless el.options[:cdata]
+ result.gsub!(ESCAPED_CHAR_RE) do
+ $1 || !opts[:prev] || opts[:prev].type == :br ? "\\#{$1 || $2}" : $&
+ end
+ result
+ end
+ end
+
+ def convert_p(el, opts)
+ w = @options[:line_width] - opts[:indent].to_s.to_i
+ first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
+ first&.gsub!(/^(?:(#|>)|(\d+)\.(\s)|([+-]\s))/) { $1 || $4 ? "\\#{$1 || $4}" : "#{$2}\\.#{$3}" }
+ second&.gsub!(/^([=-]+\s*?)$/, "\\\1")
+ res = [first, second, *rest].compact.join("\n") + "\n"
+ res.gsub!(/^ {0,3}:/, "\\:")
+ if el.children.length == 1 && el.children.first.type == :math
+ res = "\\#{res}"
+ elsif res.start_with?('\$$') && res.end_with?("\\$$\n")
+ res.sub!(/^\\\$\$/, '\$\$')
+ end
+ res
+ end
+
+ def convert_codeblock(el, _opts)
+ el.value.split("\n").map {|l| l.empty? ? " " : " #{l}" }.join("\n") + "\n"
+ end
+
+ def convert_blockquote(el, opts)
+ opts[:indent] += 2
+ inner(el, opts).chomp.split("\n").map {|l| "> #{l}" }.join("\n") << "\n"
+ end
+
+ def convert_header(el, opts)
+ opts[:in_header] = true
+ res = +''
+ res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}"
+ res[-1, 1] = "\\#" if res[-1] == '#'
+ res << " {##{el.attr['id']}}" if el.attr['id'] && !el.attr['id'].strip.empty?
+ res << "\n"
+ end
+
+ def convert_hr(_el, _opts)
+ "* * *\n"
+ end
+
+ def convert_ul(el, opts)
+ inner(el, opts).sub(/\n+\Z/, "\n")
+ end
+ alias convert_ol convert_ul
+ alias convert_dl convert_ul
+
+ def convert_li(el, opts)
+ sym, width = if @stack.last.type == :ul
+ ['* ' + @list_spacing, el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent]
+ else
+ ["#{opts[:index] + 1}.".ljust(4), 4]
+ end
+ if (ial = ial_for_element(el))
+ sym << ial << " "
+ end
+
+ opts[:indent] += width
+ text = inner(el, opts)
+ newlines = text.scan(/\n*\Z/).first
+ first, *last = text.split("\n")
+ last = last.map {|l| " " * width + l }.join("\n")
+ text = (first.nil? ? "\n" : first + (last.empty? ? "" : "\n") + last + newlines)
+ if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent]
+ res = +"#{sym}#{text}"
+ res << "^\n" if el.children.size == 1 && @stack.last.children.last == el &&
+ (@stack.last.children.any? {|c| !c.children.first || c.children.first.type != :p } || @stack.last.children.size == 1)
+ res
+ elsif el.children.first && el.children.first.type == :codeblock
+ "#{sym}\n #{text}"
+ else
+ "#{sym}#{text}"
+ end
+ end
+
+ def convert_dd(el, opts)
+ sym, width = ": " + @list_spacing, (el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent)
+ if (ial = ial_for_element(el))
+ sym << ial << " "
+ end
+
+ opts[:indent] += width
+ text = inner(el, opts)
+ newlines = text.scan(/\n*\Z/).first
+ first, *last = text.split("\n")
+ last = last.map {|l| " " * width + l }.join("\n")
+ text = first.to_s + (last.empty? ? "" : "\n") + last + newlines
+ text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
+ text << "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt
+ text << "\n" if el.children.empty?
+ if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent]
+ "\n#{sym}#{text}"
+ elsif el.children.first && el.children.first.type == :codeblock
+ "#{sym}\n #{text}"
+ else
+ "#{sym}#{text}"
+ end
+ end
+
+ def convert_dt(el, opts)
+ result = +''
+ if (ial = ial_for_element(el))
+ result << ial << " "
+ end
+ result << inner(el, opts) << "\n"
+ end
+
+ HTML_TAGS_WITH_BODY = %w[div script iframe textarea th td]
+
+ HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze
+ private_constant :HTML_ELEMENT_TYPES
+
+ def convert_html_element(el, opts)
+ markdown_attr = el.options[:category] == :block && el.children.any? do |c|
+ c.type != :html_element &&
+ (c.type != :p || !c.options[:transparent] ||
+ c.children.any? {|t| !HTML_ELEMENT_TYPES.member?(t.type) }) &&
+ c.block?
+ end
+ opts[:force_raw_text] = true if %w[script pre code].include?(el.value)
+ opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || \
+ (el.options[:category] != :span && !markdown_attr)
+ opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text]
+ res = inner(el, opts)
+ if el.options[:category] == :span
+ "<#{el.value}#{html_attributes(el.attr)}" + \
+ (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
+ else
+ output = +''
+ attr = el.attr.dup
+ attr['markdown'] = '1' if markdown_attr
+ output << "<#{el.value}#{html_attributes(attr)}"
+ if !res.empty? && el.options[:content_model] != :block
+ output << ">#{res}</#{el.value}>"
+ elsif !res.empty?
+ output << ">\n#{res}" << "</#{el.value}>"
+ elsif HTML_TAGS_WITH_BODY.include?(el.value)
+ output << "></#{el.value}>"
+ else
+ output << " />"
+ end
+ output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
+ output
+ end
+ end
+
+ def convert_xml_comment(el, _opts)
+ if el.options[:category] == :block &&
+ (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw)
+ el.value + "\n"
+ else
+ el.value.dup
+ end
+ end
+ alias convert_xml_pi convert_xml_comment
+
+ def convert_table(el, opts)
+ opts[:alignment] = el.options[:alignment]
+ inner(el, opts)
+ end
+
+ def convert_thead(el, opts)
+ rows = inner(el, opts)
+ if opts[:alignment].all?(:default)
+ "#{rows}|#{'-' * 10}\n"
+ else
+ "#{rows}| " + opts[:alignment].map do |a|
+ case a
+ when :left then ":-"
+ when :right then "-:"
+ when :center then ":-:"
+ when :default then "-"
+ end
+ end.join(' ') << "\n"
+ end
+ end
+
+ def convert_tbody(el, opts)
+ res = +''
+ res << inner(el, opts)
+ res << '|' << '-' * 10 << "\n" if opts[:next] && opts[:next].type == :tbody
+ res
+ end
+
+ def convert_tfoot(el, opts)
+ "|#{'=' * 10}\n#{inner(el, opts)}"
+ end
+
+ def convert_tr(el, opts)
+ "| #{el.children.map {|c| convert(c, opts) }.join(' | ')} |\n"
+ end
+
+ def convert_td(el, opts)
+ inner(el, opts)
+ end
+
+ def convert_comment(el, _opts)
+ if el.options[:category] == :block
+ "{::comment}\n#{el.value}\n{:/}\n"
+ else
+ "{::comment}#{el.value}{:/}"
+ end
+ end
+
+ def convert_br(_el, opts)
+ opts[:in_header] ? "<br />" : " \n"
+ end
+
+ def convert_a(el, opts)
+ if el.attr['href'].empty?
+ "[#{inner(el, opts)}]()"
+ elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0
+ index = if (link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href'] })
+ @linkrefs.index(link_el) + 1
+ else
+ @linkrefs << el
+ @linkrefs.size
+ end
+ "[#{inner(el, opts)}][#{index}]"
+ else
+ title = parse_title(el.attr['title'])
+ "[#{inner(el, opts)}](#{el.attr['href']}#{title})"
+ end
+ end
+
+ def convert_img(el, _opts)
+ alt_text = el.attr['alt'].to_s.gsub(ESCAPED_CHAR_RE) { $1 ? "\\#{$1}" : $2 }
+ src = el.attr['src'].to_s
+ if src.empty?
+ "![#{alt_text}]()"
+ else
+ title = parse_title(el.attr['title'])
+ link = if src.count("()") > 0
+ "<#{src}>"
+ else
+ src
+ end
+ "![#{alt_text}](#{link}#{title})"
+ end
+ end
+
+ def convert_codespan(el, _opts)
+ delim = (el.value.scan(/`+/).max || '') + '`'
+ "#{delim}#{' ' if delim.size > 1}#{el.value}#{' ' if delim.size > 1}#{delim}"
+ end
+
+ def convert_footnote(el, _opts)
+ @footnotes << [el.options[:name], el.value]
+ "[^#{el.options[:name]}]"
+ end
+
+ def convert_raw(el, _opts)
+ attr = (el.options[:type] || []).join(' ')
+ attr = " type=\"#{attr}\"" unless attr.empty?
+ if @stack.last.type == :html_element
+ el.value
+ elsif el.options[:category] == :block
+ "{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n"
+ else
+ "{::nomarkdown#{attr}}#{el.value}{:/}"
+ end
+ end
+
+ def convert_em(el, opts)
+ "*#{inner(el, opts)}*" +
+ (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '')
+ end
+
+ def convert_strong(el, opts)
+ "**#{inner(el, opts)}**" +
+ (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '')
+ end
+
+ def convert_entity(el, _opts)
+ entity_to_str(el.value, el.options[:original])
+ end
+
+ TYPOGRAPHIC_SYMS = {
+ mdash: '---', ndash: '--', hellip: '...',
+ laquo_space: '<< ', raquo_space: ' >>',
+ laquo: '<<', raquo: '>>'
+ }
+ def convert_typographic_sym(el, _opts)
+ TYPOGRAPHIC_SYMS[el.value]
+ end
+
+ def convert_smart_quote(el, _opts)
+ el.value.to_s.match?(/[rl]dquo/) ? "\"" : "'"
+ end
+
+ def convert_math(el, _opts)
+ "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '')
+ end
+
+ def convert_abbreviation(el, _opts)
+ el.value
+ end
+
+ def convert_root(el, opts)
+ res = inner(el, opts)
+ res << create_link_defs
+ res << create_footnote_defs
+ res << create_abbrev_defs
+ res
+ end
+
+ def create_link_defs
+ res = +''
+ res << "\n\n" unless @linkrefs.empty?
+ @linkrefs.each_with_index do |el, i|
+ title = parse_title(el.attr['title'])
+ res << "[#{i + 1}]: #{el.attr['href']}#{title}\n"
+ end
+ res
+ end
+
+ def create_footnote_defs
+ res = +''
+ @footnotes.each do |name, data|
+ res << "[^#{name}]:\n"
+ res << inner(data).chomp.split("\n").map {|l| " #{l}" }.join("\n") + "\n\n"
+ end
+ res
+ end
+
+ def create_abbrev_defs
+ return '' unless @root.options[:abbrev_defs]
+ res = +''
+ @root.options[:abbrev_defs].each do |name, text|
+ res << "*[#{name}]: #{text}\n"
+ res << ial_for_element(Element.new(:unused, nil, @root.options[:abbrev_attr][name])).to_s << "\n\n"
+ end
+ res
+ end
+
+ # Return the IAL containing the attributes of the element +el+.
+ def ial_for_element(el)
+ res = el.attr.map do |k, v|
+ next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k)
+ next if el.type == :header && k == 'id' && !v.strip.empty?
+ if v.nil?
+ ''
+ elsif k == 'class' && !v.empty? && !v.index(/[.#]/)
+ " " + v.split(/\s+/).map {|w| ".#{w}" }.join(" ")
+ elsif k == 'id' && !v.strip.empty?
+ " ##{v}"
+ else
+ " #{k}=\"#{v}\""
+ end
+ end.compact.join
+ res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
+ el.options.dig(:ial, :refs)&.include?('toc')
+ res = "footnotes" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
+ el.options.dig(:ial, :refs)&.include?('footnotes')
+ if el.type == :dl && el.options[:ial] && el.options[:ial][:refs]
+ auto_ids = el.options[:ial][:refs].select {|ref| ref.start_with?('auto_ids') }.join(" ")
+ res = auto_ids << (res.strip.empty? ? '' : " #{res}") unless auto_ids.empty?
+ end
+ res.strip.empty? ? nil : "{:#{res}}"
+ end
+
+ def parse_title(attr)
+ attr.to_s.empty? ? '' : ' "' + attr.gsub(/"/, '&quot;') + '"'
+ end
+
+ # :startdoc:
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb
new file mode 100644
index 0000000..25f2bbb
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb
@@ -0,0 +1,626 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'set'
+require 'kramdown/converter'
+
+module Kramdown
+
+ module Converter
+
+ # Converts an element tree to LaTeX.
+ #
+ # This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku.
+ #
+ # You can customize this converter by sub-classing it and overriding the +convert_NAME+ methods.
+ # Each such method takes the following parameters:
+ #
+ # [+el+] The element of type +NAME+ to be converted.
+ #
+ # [+opts+] A hash containing processing options that are passed down from parent elements. The
+ # key :parent is always set and contains the parent element as value.
+ #
+ # The return value of such a method has to be a string containing the element +el+ formatted
+ # correctly as LaTeX markup.
+ class Latex < Base
+
+ # Initialize the LaTeX converter with the +root+ element and the conversion +options+.
+ def initialize(root, options)
+ super
+ @data[:packages] = Set.new
+ end
+
+ # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
+ # the element.
+ def convert(el, opts = {})
+ send("convert_#{el.type}", el, opts)
+ end
+
+ # Return the converted content of the children of +el+ as a string.
+ def inner(el, opts)
+ result = +''
+ options = opts.dup.merge(parent: el)
+ el.children.each_with_index do |inner_el, index|
+ options[:index] = index
+ options[:result] = result
+ result << send("convert_#{inner_el.type}", inner_el, options)
+ end
+ result
+ end
+
+ def convert_root(el, opts)
+ inner(el, opts)
+ end
+
+ def convert_blank(_el, opts)
+ opts[:result].match?(/\n\n\Z|\A\Z/) ? "" : "\n"
+ end
+
+ def convert_text(el, _opts)
+ escape(el.value)
+ end
+
+ def convert_p(el, opts)
+ if el.children.size == 1 && el.children.first.type == :img &&
+ !(img = convert_img(el.children.first, opts)).empty?
+ convert_standalone_image(el, opts, img)
+ else
+ "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
+ end
+ end
+
+ # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img
+ # element.
+ def convert_standalone_image(el, _opts, img)
+ attrs = attribute_list(el)
+ "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n" \
+ "\\caption{#{escape(el.children.first.attr['alt'])}}\n" \
+ "#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n"
+ end
+
+ def convert_codeblock(el, _opts)
+ show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/
+ lang = extract_code_language(el.attr)
+
+ if @options[:syntax_highlighter] == :minted &&
+ (highlighted_code = highlight_code(el.value, lang, :block))
+ @data[:packages] << 'minted'
+ "#{latex_link_target(el)}#{highlighted_code}\n"
+ elsif show_whitespace || lang
+ options = []
+ options << (show_whitespace ? "showspaces=true,showtabs=true" : "showspaces=false,showtabs=false")
+ options << "language=#{lang}" if lang
+ options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr"
+ id = el.attr['id']
+ options << "label=#{id}" if id
+ attrs = attribute_list(el)
+ "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n" \
+ "#{el.value}\n\\end{lstlisting}#{attrs}\n"
+ else
+ "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n"
+ end
+ end
+
+ def convert_blockquote(el, opts)
+ latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts))
+ end
+
+ def convert_header(el, opts)
+ type = @options[:latex_headers][output_header_level(el.options[:level]) - 1]
+ if ((id = el.attr['id']) ||
+ (@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el)
+ "\\#{type}{#{inner(el, opts)}}\\hypertarget{#{id}}{}\\label{#{id}}\n\n"
+ else
+ "\\#{type}*{#{inner(el, opts)}}\n\n"
+ end
+ end
+
+ def convert_hr(el, _opts)
+ attrs = attribute_list(el)
+ "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n"
+ end
+
+ def convert_ul(el, opts)
+ if !@data[:has_toc] && el.options.dig(:ial, :refs)&.include?('toc')
+ @data[:has_toc] = true
+ '\tableofcontents'
+ else
+ latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts))
+ end
+ end
+ alias convert_ol convert_ul
+
+ def convert_dl(el, opts)
+ latex_environment('description', el, inner(el, opts))
+ end
+
+ def convert_li(el, opts)
+ "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n"
+ end
+
+ def convert_dt(el, opts)
+ "\\item[#{inner(el, opts)}] "
+ end
+
+ def convert_dd(el, opts)
+ "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
+ end
+
+ def convert_html_element(el, opts)
+ case el.value
+ when 'i', 'em'
+ "\\emph{#{inner(el, opts)}}"
+ when 'b', 'strong'
+ "\\textbf{#{inner(el, opts)}}"
+ else
+ warning("Can't convert HTML element")
+ ''
+ end
+ end
+
+ def convert_xml_comment(el, _opts)
+ el.value.split("\n").map {|l| "% #{l}" }.join("\n") + "\n"
+ end
+
+ def convert_xml_pi(_el, _opts)
+ warning("Can't convert XML PI")
+ ''
+ end
+
+ TABLE_ALIGNMENT_CHAR = {default: 'l', left: 'l', center: 'c', right: 'r'} # :nodoc:
+
+ def convert_table(el, opts)
+ @data[:packages] << 'longtable'
+ align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a] }.join('|')
+ attrs = attribute_list(el)
+ "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n" \
+ "\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n"
+ end
+
+ def convert_thead(el, opts)
+ "#{inner(el, opts)}\\hline\n"
+ end
+
+ def convert_tbody(el, opts)
+ inner(el, opts)
+ end
+
+ def convert_tfoot(el, opts)
+ "\\hline \\hline \n#{inner(el, opts)}"
+ end
+
+ def convert_tr(el, opts)
+ el.children.map {|c| send("convert_#{c.type}", c, opts) }.join(' & ') << "\\\\\n"
+ end
+
+ def convert_td(el, opts)
+ inner(el, opts)
+ end
+
+ def convert_comment(el, _opts)
+ el.value.split("\n").map {|l| "% #{l}" }.join("\n") << "\n"
+ end
+
+ def convert_br(_el, opts)
+ res = +"\\newline"
+ res << "\n" if (c = opts[:parent].children[opts[:index] + 1]) &&
+ (c.type != :text || c.value !~ /^\s*\n/)
+ res
+ end
+
+ def convert_a(el, opts)
+ url = el.attr['href']
+ if url.start_with?('#')
+ "\\hyperlink{#{url[1..-1].gsub('%', '\\%')}}{#{inner(el, opts)}}"
+ else
+ "\\href{#{url.gsub('%', '\\%')}}{#{inner(el, opts)}}"
+ end
+ end
+
+ def convert_img(el, _opts)
+ line = el.options[:location]
+ if el.attr['src'].match?(/^(https?|ftps?):\/\//)
+ warning("Cannot include non-local image#{line ? " (line #{line})" : ''}")
+ ''
+ elsif !el.attr['src'].empty?
+ @data[:packages] << 'graphicx'
+ "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}"
+ else
+ warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}")
+ ''
+ end
+ end
+
+ def convert_codespan(el, _opts)
+ lang = extract_code_language(el.attr)
+ if @options[:syntax_highlighter] == :minted &&
+ (highlighted_code = highlight_code(el.value, lang, :span))
+ @data[:packages] << 'minted'
+ "#{latex_link_target(el)}#{highlighted_code}"
+ else
+ "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}"
+ end
+ end
+
+ def convert_footnote(el, opts)
+ @data[:packages] << 'fancyvrb'
+ "\\footnote{#{inner(el.value, opts).rstrip}}"
+ end
+
+ def convert_raw(el, _opts)
+ if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex')
+ el.value + (el.options[:category] == :block ? "\n" : '')
+ else
+ ''
+ end
+ end
+
+ def convert_em(el, opts)
+ "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}"
+ end
+
+ def convert_strong(el, opts)
+ "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}"
+ end
+
+ # Inspired by Maruku: entity conversion table based on the one from htmltolatex
+ # (http://sourceforge.net/projects/htmltolatex/), with some small adjustments/additions
+ ENTITY_CONV_TABLE = {
+ 913 => ['$A$'],
+ 914 => ['$B$'],
+ 915 => ['$\Gamma$'],
+ 916 => ['$\Delta$'],
+ 917 => ['$E$'],
+ 918 => ['$Z$'],
+ 919 => ['$H$'],
+ 920 => ['$\Theta$'],
+ 921 => ['$I$'],
+ 922 => ['$K$'],
+ 923 => ['$\Lambda$'],
+ 924 => ['$M$'],
+ 925 => ['$N$'],
+ 926 => ['$\Xi$'],
+ 927 => ['$O$'],
+ 928 => ['$\Pi$'],
+ 929 => ['$P$'],
+ 931 => ['$\Sigma$'],
+ 932 => ['$T$'],
+ 933 => ['$Y$'],
+ 934 => ['$\Phi$'],
+ 935 => ['$X$'],
+ 936 => ['$\Psi$'],
+ 937 => ['$\Omega$'],
+ 945 => ['$\alpha$'],
+ 946 => ['$\beta$'],
+ 947 => ['$\gamma$'],
+ 948 => ['$\delta$'],
+ 949 => ['$\epsilon$'],
+ 950 => ['$\zeta$'],
+ 951 => ['$\eta$'],
+ 952 => ['$\theta$'],
+ 953 => ['$\iota$'],
+ 954 => ['$\kappa$'],
+ 955 => ['$\lambda$'],
+ 956 => ['$\mu$'],
+ 957 => ['$\nu$'],
+ 958 => ['$\xi$'],
+ 959 => ['$o$'],
+ 960 => ['$\pi$'],
+ 961 => ['$\rho$'],
+ 963 => ['$\sigma$'],
+ 964 => ['$\tau$'],
+ 965 => ['$\upsilon$'],
+ 966 => ['$\phi$'],
+ 967 => ['$\chi$'],
+ 968 => ['$\psi$'],
+ 969 => ['$\omega$'],
+ 962 => ['$\varsigma$'],
+ 977 => ['$\vartheta$'],
+ 982 => ['$\varpi$'],
+ 8230 => ['\ldots'],
+ 8242 => ['$\prime$'],
+ 8254 => ['-'],
+ 8260 => ['/'],
+ 8472 => ['$\wp$'],
+ 8465 => ['$\Im$'],
+ 8476 => ['$\Re$'],
+ 8501 => ['$\aleph$'],
+ 8226 => ['$\bullet$'],
+ 8482 => ['$^{\rm TM}$'],
+ 8592 => ['$\leftarrow$'],
+ 8594 => ['$\rightarrow$'],
+ 8593 => ['$\uparrow$'],
+ 8595 => ['$\downarrow$'],
+ 8596 => ['$\leftrightarrow$'],
+ 8629 => ['$\hookleftarrow$'],
+ 8657 => ['$\Uparrow$'],
+ 8659 => ['$\Downarrow$'],
+ 8656 => ['$\Leftarrow$'],
+ 8658 => ['$\Rightarrow$'],
+ 8660 => ['$\Leftrightarrow$'],
+ 8704 => ['$\forall$'],
+ 8706 => ['$\partial$'],
+ 8707 => ['$\exists$'],
+ 8709 => ['$\emptyset$'],
+ 8711 => ['$\nabla$'],
+ 8712 => ['$\in$'],
+ 8715 => ['$\ni$'],
+ 8713 => ['$\notin$'],
+ 8721 => ['$\sum$'],
+ 8719 => ['$\prod$'],
+ 8722 => ['$-$'],
+ 8727 => ['$\ast$'],
+ 8730 => ['$\surd$'],
+ 8733 => ['$\propto$'],
+ 8734 => ['$\infty$'],
+ 8736 => ['$\angle$'],
+ 8743 => ['$\wedge$'],
+ 8744 => ['$\vee$'],
+ 8745 => ['$\cap$'],
+ 8746 => ['$\cup$'],
+ 8747 => ['$\int$'],
+ 8756 => ['$\therefore$', 'amssymb'],
+ 8764 => ['$\sim$'],
+ 8776 => ['$\approx$'],
+ 8773 => ['$\cong$'],
+ 8800 => ['$\neq$'],
+ 8801 => ['$\equiv$'],
+ 8804 => ['$\leq$'],
+ 8805 => ['$\geq$'],
+ 8834 => ['$\subset$'],
+ 8835 => ['$\supset$'],
+ 8838 => ['$\subseteq$'],
+ 8839 => ['$\supseteq$'],
+ 8836 => ['$\nsubset$', 'amssymb'],
+ 8853 => ['$\oplus$'],
+ 8855 => ['$\otimes$'],
+ 8869 => ['$\perp$'],
+ 8901 => ['$\cdot$'],
+ 8968 => ['$\rceil$'],
+ 8969 => ['$\lceil$'],
+ 8970 => ['$\lfloor$'],
+ 8971 => ['$\rfloor$'],
+ 9001 => ['$\rangle$'],
+ 9002 => ['$\langle$'],
+ 9674 => ['$\lozenge$', 'amssymb'],
+ 9824 => ['$\spadesuit$'],
+ 9827 => ['$\clubsuit$'],
+ 9829 => ['$\heartsuit$'],
+ 9830 => ['$\diamondsuit$'],
+ 38 => ['\&'],
+ 34 => ['"'],
+ 39 => ['\''],
+ 169 => ['\copyright'],
+ 60 => ['\textless'],
+ 62 => ['\textgreater'],
+ 338 => ['\OE'],
+ 339 => ['\oe'],
+ 352 => ['\v{S}'],
+ 353 => ['\v{s}'],
+ 376 => ['\"Y'],
+ 710 => ['\textasciicircum'],
+ 732 => ['\textasciitilde'],
+ 8211 => ['--'],
+ 8212 => ['---'],
+ 8216 => ['`'],
+ 8217 => ['\''],
+ 8220 => ['``'],
+ 8221 => ['\'\''],
+ 8224 => ['\dag'],
+ 8225 => ['\ddag'],
+ 8240 => ['\permil', 'wasysym'],
+ 8364 => ['\euro', 'eurosym'],
+ 8249 => ['\guilsinglleft'],
+ 8250 => ['\guilsinglright'],
+ 8218 => ['\quotesinglbase', 'mathcomp'],
+ 8222 => ['\quotedblbase', 'mathcomp'],
+ 402 => ['\textflorin', 'mathcomp'],
+ 381 => ['\v{Z}'],
+ 382 => ['\v{z}'],
+ 160 => ['~'],
+ 161 => ['\textexclamdown'],
+ 163 => ['\pounds'],
+ 164 => ['\currency', 'wasysym'],
+ 165 => ['\textyen', 'textcomp'],
+ 166 => ['\brokenvert', 'wasysym'],
+ 167 => ['\S'],
+ 171 => ['\guillemotleft'],
+ 187 => ['\guillemotright'],
+ 174 => ['\textregistered'],
+ 170 => ['\textordfeminine'],
+ 172 => ['$\neg$'],
+ 173 => ['\-'],
+ 176 => ['$\degree$', 'mathabx'],
+ 177 => ['$\pm$'],
+ 180 => ['\''],
+ 181 => ['$\mu$'],
+ 182 => ['\P'],
+ 183 => ['$\cdot$'],
+ 186 => ['\textordmasculine'],
+ 162 => ['\cent', 'wasysym'],
+ 185 => ['$^1$'],
+ 178 => ['$^2$'],
+ 179 => ['$^3$'],
+ 189 => ['$\frac{1}{2}$'],
+ 188 => ['$\frac{1}{4}$'],
+ 190 => ['$\frac{3}{4}'],
+ 192 => ['\`A'],
+ 193 => ['\\\'A'],
+ 194 => ['\^A'],
+ 195 => ['\~A'],
+ 196 => ['\"A'],
+ 197 => ['\AA'],
+ 198 => ['\AE'],
+ 199 => ['\cC'],
+ 200 => ['\`E'],
+ 201 => ['\\\'E'],
+ 202 => ['\^E'],
+ 203 => ['\"E'],
+ 204 => ['\`I'],
+ 205 => ['\\\'I'],
+ 206 => ['\^I'],
+ 207 => ['\"I'],
+ 208 => ['$\eth$', 'amssymb'],
+ 209 => ['\~N'],
+ 210 => ['\`O'],
+ 211 => ['\\\'O'],
+ 212 => ['\^O'],
+ 213 => ['\~O'],
+ 214 => ['\"O'],
+ 215 => ['$\times$'],
+ 216 => ['\O'],
+ 217 => ['\`U'],
+ 218 => ['\\\'U'],
+ 219 => ['\^U'],
+ 220 => ['\"U'],
+ 221 => ['\\\'Y'],
+ 222 => ['\Thorn', 'wasysym'],
+ 223 => ['\ss'],
+ 224 => ['\`a'],
+ 225 => ['\\\'a'],
+ 226 => ['\^a'],
+ 227 => ['\~a'],
+ 228 => ['\"a'],
+ 229 => ['\aa'],
+ 230 => ['\ae'],
+ 231 => ['\cc'],
+ 232 => ['\`e'],
+ 233 => ['\\\'e'],
+ 234 => ['\^e'],
+ 235 => ['\"e'],
+ 236 => ['\`i'],
+ 237 => ['\\\'i'],
+ 238 => ['\^i'],
+ 239 => ['\"i'],
+ 240 => ['$\eth$'],
+ 241 => ['\~n'],
+ 242 => ['\`o'],
+ 243 => ['\\\'o'],
+ 244 => ['\^o'],
+ 245 => ['\~o'],
+ 246 => ['\"o'],
+ 247 => ['$\divide$'],
+ 248 => ['\o'],
+ 249 => ['\`u'],
+ 250 => ['\\\'u'],
+ 251 => ['\^u'],
+ 252 => ['\"u'],
+ 253 => ['\\\'y'],
+ 254 => ['\thorn', 'wasysym'],
+ 255 => ['\"y'],
+ 8201 => ['\thinspace'],
+ 8194 => ['\hskip .5em\relax'],
+ 8195 => ['\quad'],
+ } # :nodoc:
+ ENTITY_CONV_TABLE.each_value {|v| v[0] = "#{v[0]}{}" }
+
+ def entity_to_latex(entity)
+ text, package = ENTITY_CONV_TABLE[entity.code_point]
+ if text
+ @data[:packages] << package if package
+ text
+ else
+ warning("Couldn't find entity with code #{entity.code_point} in substitution table!")
+ ''
+ end
+ end
+
+ def convert_entity(el, _opts)
+ entity_to_latex(el.value)
+ end
+
+ TYPOGRAPHIC_SYMS = {
+ mdash: '---', ndash: '--', hellip: '\ldots{}',
+ laquo_space: '\guillemotleft{}~', raquo_space: '~\guillemotright{}',
+ laquo: '\guillemotleft{}', raquo: '\guillemotright{}'
+ } # :nodoc:
+ def convert_typographic_sym(el, _opts)
+ if (result = @options[:typographic_symbols][el.value])
+ escape(result)
+ else
+ TYPOGRAPHIC_SYMS[el.value]
+ end
+ end
+
+ def convert_smart_quote(el, opts)
+ res = entity_to_latex(smart_quote_entity(el)).chomp('{}')
+ res << "{}" if ((nel = opts[:parent].children[opts[:index] + 1]) && nel.type == :smart_quote) || res =~ /\w$/
+ res
+ end
+
+ def convert_math(el, _opts)
+ @data[:packages] += %w[amssymb amsmath amsthm amsfonts]
+ if el.options[:category] == :block
+ if el.value.match?(/\A\s*\\begin\{/)
+ el.value
+ else
+ latex_environment('displaymath', el, el.value)
+ end
+ else
+ "$#{el.value}$"
+ end
+ end
+
+ def convert_abbreviation(el, _opts)
+ @data[:packages] += %w[acronym]
+ "\\ac{#{normalize_abbreviation_key(el.value)}}"
+ end
+
+ # Normalize the abbreviation key so that it only contains allowed ASCII character
+ def normalize_abbreviation_key(key)
+ key.gsub(/\W/) {|m| m.unpack1('H*') }
+ end
+
+ # Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to
+ # the method #attribute_list -- the resulting string is appended to both the \\begin and the
+ # \\end lines of the LaTeX environment for easier post-processing of LaTeX environments.
+ def latex_environment(type, el, text)
+ attrs = attribute_list(el)
+ "\\begin{#{type}}#{latex_link_target(el)}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n"
+ end
+
+ # Return a string containing a valid \hypertarget command if the element has an ID defined, or
+ # +nil+ otherwise. If the parameter +add_label+ is +true+, a \label command will also be used
+ # additionally to the \hypertarget command.
+ def latex_link_target(el, add_label = false)
+ if (id = el.attr['id'])
+ "\\hypertarget{#{id}}{}#{add_label ? "\\label{#{id}}" : ''}"
+ else
+ nil
+ end
+ end
+
+ # Return a LaTeX comment containing all attributes as 'key="value"' pairs.
+ def attribute_list(el)
+ attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join
+ attrs = " % #{attrs}" unless attrs.empty?
+ attrs
+ end
+
+ ESCAPE_MAP = {
+ "^" => "\\^{}",
+ "\\" => "\\textbackslash{}",
+ "~" => "\\ensuremath{\\sim}",
+ "|" => "\\textbar{}",
+ "<" => "\\textless{}",
+ ">" => "\\textgreater{}",
+ "[" => "{[}",
+ "]" => "{]}",
+ }.merge(Hash[*"{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten]) # :nodoc:
+ ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k, _v| k }) # :nodoc:
+
+ # Escape the special LaTeX characters in the string +str+.
+ def escape(str)
+ str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m] }
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb
new file mode 100644
index 0000000..50da45a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb
@@ -0,0 +1,300 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/converter'
+
+module Kramdown
+
+ module Converter
+
+ # Converts a Kramdown::Document to a manpage in groff format. See man(7), groff_man(7) and
+ # man-pages(7) for information regarding the output.
+ class Man < Base
+
+ def convert(el, opts = {indent: 0, result: +''}) # :nodoc:
+ send("convert_#{el.type}", el, opts)
+ end
+
+ private
+
+ def inner(el, opts, use = :all)
+ arr = el.children.reject {|e| e.type == :blank }
+ arr.each_with_index do |inner_el, index|
+ next if use == :rest && index == 0
+ break if use == :first && index > 0
+ options = opts.dup
+ options[:parent] = el
+ options[:index] = index
+ options[:prev] = (index == 0 ? nil : arr[index - 1])
+ options[:next] = (index == arr.length - 1 ? nil : arr[index + 1])
+ convert(inner_el, options)
+ end
+ end
+
+ def convert_root(el, opts)
+ @title_done = false
+ opts[:result] = +".\\\" generated by kramdown\n"
+ inner(el, opts)
+ opts[:result]
+ end
+
+ def convert_blank(*)
+ end
+ alias convert_hr convert_blank
+ alias convert_xml_pi convert_blank
+
+ def convert_p(el, opts)
+ if (opts[:index] != 0 && opts[:prev].type != :header) ||
+ (opts[:parent].type == :blockquote && opts[:index] == 0)
+ opts[:result] << macro("P")
+ end
+ inner(el, opts)
+ newline(opts[:result])
+ end
+
+ def convert_header(el, opts)
+ return unless opts[:parent].type == :root
+ case el.options[:level]
+ when 1
+ unless @title_done
+ @title_done = true
+ data = el.options[:raw_text].scan(/([^(]+)\s*\((\d\w*)\)(?:\s*-+\s*(.*))?/).first ||
+ el.options[:raw_text].scan(/([^\s]+)\s*(?:-*\s+)?()(.*)/).first
+ return unless data && data[0]
+ name = data[0]
+ section = (data[1].to_s.empty? ? el.attr['data-section'] || '7' : data[1])
+ description = (data[2].to_s.empty? ? nil : " - #{data[2]}")
+ date = el.attr['data-date'] ? quote(el.attr['data-date']) : nil
+ extra = (el.attr['data-extra'] ? quote(escape(el.attr['data-extra'].to_s)) : nil)
+ opts[:result] << macro("TH", quote(escape(name.upcase)), quote(section), date, extra)
+ if description
+ opts[:result] << macro("SH", "NAME") << escape("#{name}#{description}") << "\n"
+ end
+ end
+ when 2
+ opts[:result] << macro("SH", quote(escape(el.options[:raw_text])))
+ when 3
+ opts[:result] << macro("SS", quote(escape(el.options[:raw_text])))
+ else
+ warning("Header levels greater than three are not supported")
+ end
+ end
+
+ def convert_codeblock(el, opts)
+ opts[:result] << macro("sp") << macro("RS", 4) << macro("EX")
+ opts[:result] << newline(escape(el.value, true))
+ opts[:result] << macro("EE") << macro("RE")
+ end
+
+ def convert_blockquote(el, opts)
+ opts[:result] << macro("RS")
+ inner(el, opts)
+ opts[:result] << macro("RE")
+ end
+
+ def convert_ul(el, opts)
+ compact = (el.attr['class'] =~ /\bcompact\b/)
+ opts[:result] << macro("sp") << macro("PD", 0) if compact
+ inner(el, opts)
+ opts[:result] << macro("PD") if compact
+ end
+ alias convert_dl convert_ul
+ alias convert_ol convert_ul
+
+ def convert_li(el, opts)
+ sym = (opts[:parent].type == :ul ? '\(bu' : "#{opts[:index] + 1}.")
+ opts[:result] << macro("IP", sym, 4)
+ inner(el, opts, :first)
+ if el.children.size > 1
+ opts[:result] << macro("RS")
+ inner(el, opts, :rest)
+ opts[:result] << macro("RE")
+ end
+ end
+
+ def convert_dt(el, opts)
+ opts[:result] << macro(opts[:prev] && opts[:prev].type == :dt ? "TQ" : "TP")
+ inner(el, opts)
+ opts[:result] << "\n"
+ end
+
+ def convert_dd(el, opts)
+ inner(el, opts, :first)
+ if el.children.size > 1
+ opts[:result] << macro("RS")
+ inner(el, opts, :rest)
+ opts[:result] << macro("RE")
+ end
+ opts[:result] << macro("sp") if opts[:next] && opts[:next].type == :dd
+ end
+
+ TABLE_CELL_ALIGNMENT = {left: 'l', center: 'c', right: 'r', default: 'l'}
+
+ def convert_table(el, opts)
+ opts[:alignment] = el.options[:alignment].map {|a| TABLE_CELL_ALIGNMENT[a] }
+ table_options = ["box"]
+ table_options << "center" if el.attr['class']&.match?(/\bcenter\b/)
+ opts[:result] << macro("TS") << "#{table_options.join(' ')} ;\n"
+ inner(el, opts)
+ opts[:result] << macro("TE") << macro("sp")
+ end
+
+ def convert_thead(el, opts)
+ opts[:result] << opts[:alignment].map {|a| "#{a}b" }.join(' ') << " .\n"
+ inner(el, opts)
+ opts[:result] << "=\n"
+ end
+
+ def convert_tbody(el, opts)
+ opts[:result] << ".T&\n" if opts[:index] != 0
+ opts[:result] << opts[:alignment].join(' ') << " .\n"
+ inner(el, opts)
+ opts[:result] << (opts[:next].type == :tfoot ? "=\n" : "_\n") if opts[:next]
+ end
+
+ def convert_tfoot(el, opts)
+ inner(el, opts)
+ end
+
+ def convert_tr(el, opts)
+ inner(el, opts)
+ opts[:result] << "\n"
+ end
+
+ def convert_td(el, opts)
+ result = opts[:result]
+ opts[:result] = +''
+ inner(el, opts)
+ if opts[:result].include?("\n")
+ warning("Table cells using links are not supported")
+ result << "\t"
+ else
+ result << opts[:result] << "\t"
+ end
+ end
+
+ def convert_html_element(*)
+ warning("HTML elements are not supported")
+ end
+
+ def convert_xml_comment(el, opts)
+ newline(opts[:result]) << ".\"#{escape(el.value, true).rstrip.gsub(/\n/, "\n.\"")}\n"
+ end
+ alias convert_comment convert_xml_comment
+
+ def convert_a(el, opts)
+ if el.children.size == 1 && el.children[0].type == :text &&
+ el.attr['href'] == el.children[0].value
+ newline(opts[:result]) << macro("UR", escape(el.attr['href'])) << macro("UE")
+ elsif el.attr['href'].start_with?('mailto:')
+ newline(opts[:result]) << macro("MT", escape(el.attr['href'].sub(/^mailto:/, ''))) <<
+ macro("UE")
+ else
+ newline(opts[:result]) << macro("UR", escape(el.attr['href']))
+ inner(el, opts)
+ newline(opts[:result]) << macro("UE")
+ end
+ end
+
+ def convert_img(_el, _opts)
+ warning("Images are not supported")
+ end
+
+ def convert_em(el, opts)
+ opts[:result] << '\fI'
+ inner(el, opts)
+ opts[:result] << '\fP'
+ end
+
+ def convert_strong(el, opts)
+ opts[:result] << '\fB'
+ inner(el, opts)
+ opts[:result] << '\fP'
+ end
+
+ def convert_codespan(el, opts)
+ opts[:result] << "\\fB#{escape(el.value)}\\fP"
+ end
+
+ def convert_br(_el, opts)
+ newline(opts[:result]) << macro("br")
+ end
+
+ def convert_abbreviation(el, opts)
+ opts[:result] << escape(el.value)
+ end
+
+ def convert_math(el, opts)
+ if el.options[:category] == :block
+ convert_codeblock(el, opts)
+ else
+ convert_codespan(el, opts)
+ end
+ end
+
+ def convert_footnote(*)
+ warning("Footnotes are not supported")
+ end
+
+ def convert_raw(*)
+ warning("Raw content is not supported")
+ end
+
+ def convert_text(el, opts)
+ text = escape(el.value)
+ text.lstrip! if opts[:result][-1] == "\n"
+ opts[:result] << text
+ end
+
+ def convert_entity(el, opts)
+ opts[:result] << unicode_char(el.value.code_point)
+ end
+
+ def convert_smart_quote(el, opts)
+ opts[:result] << unicode_char(::Kramdown::Utils::Entities.entity(el.value.to_s).code_point)
+ end
+
+ TYPOGRAPHIC_SYMS_MAP = {
+ mdash: '\(em', ndash: '\(em', hellip: '\.\.\.',
+ laquo_space: '\[Fo]', raquo_space: '\[Fc]', laquo: '\[Fo]', raquo: '\[Fc]'
+ }
+
+ def convert_typographic_sym(el, opts)
+ opts[:result] << TYPOGRAPHIC_SYMS_MAP[el.value]
+ end
+
+ def macro(name, *args)
+ ".#{[name, *args].compact.join(' ')}\n"
+ end
+
+ def newline(text)
+ text << "\n" unless text[-1] == "\n"
+ text
+ end
+
+ def quote(text)
+ "\"#{text.gsub(/"/, '\\"')}\""
+ end
+
+ def escape(text, preserve_whitespace = false)
+ text = (preserve_whitespace ? text.dup : text.gsub(/\s+/, ' '))
+ text.gsub!('\\', "\\e")
+ text.gsub!(/^\./, '\\\\&.')
+ text.gsub!(/[.'-]/) {|m| "\\#{m}" }
+ text
+ end
+
+ def unicode_char(codepoint)
+ "\\[u#{codepoint.to_s(16).rjust(4, '0')}]"
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb
new file mode 100644
index 0000000..84e2144
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb
@@ -0,0 +1,32 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown::Converter::MathEngine
+
+ # Uses the MathJax javascript library for displaying math.
+ #
+ # Note that the javascript library itself is not include or linked, this has to be done
+ # separately. Only the math content is marked up correctly.
+ module Mathjax
+
+ def self.call(converter, el, opts)
+ value = converter.escape_html(el.value)
+ result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)"
+ if el.attr.empty?
+ result
+ elsif el.options[:category] == :block
+ converter.format_as_block_html('div', el.attr, result, opts[:indent])
+ else
+ converter.format_as_span_html('span', el.attr, "$#{el.value}$")
+ end
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb
new file mode 100644
index 0000000..af81ad5
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb
@@ -0,0 +1,58 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/converter'
+
+module Kramdown
+
+ module Converter
+
+ # Removes all block (and optionally span) level HTML tags from the element tree.
+ #
+ # This converter can be used on parsed HTML documents to get an element tree that will only
+ # contain native kramdown elements.
+ #
+ # *Note* that the returned element tree may not be fully conformant (i.e. the content models of
+ # *some elements may be violated)!
+ #
+ # This converter modifies the given tree in-place and returns it.
+ class RemoveHtmlTags < Base
+
+ def initialize(root, options)
+ super
+ @options[:template] = ''
+ end
+
+ def convert(el)
+ real_el, el = el, el.value if el.type == :footnote
+
+ children = el.children.dup
+ index = 0
+ while index < children.length
+ if children[index].type == :xml_pi ||
+ (children[index].type == :html_element && (children[index].value == 'style' ||
+ children[index].value == 'script'))
+ children[index..index] = []
+ elsif children[index].type == :html_element &&
+ ((@options[:remove_block_html_tags] && children[index].options[:category] == :block) ||
+ (@options[:remove_span_html_tags] && children[index].options[:category] == :span))
+ children[index..index] = children[index].children
+ else
+ convert(children[index])
+ index += 1
+ end
+ end
+ el.children = children
+ real_el || el
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb
new file mode 100644
index 0000000..683acbf
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb
@@ -0,0 +1,56 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Converter
+
+ # == Container for Syntax Highlighters
+ #
+ # This module serves as container for the syntax highlighters that can be used together with
+ # kramdown.
+ #
+ # A syntax highlighter should not store any data itself but should use the provided converter
+ # object to do so (See Kramdown::Converter::Base#data).
+ #
+ # == Implementing a Syntax Highlighter
+ #
+ # Implementing a new syntax highlighter is easy because it is just an object that needs to
+ # respond to #call.
+ #
+ # The method #call needs to take the following arguments:
+ #
+ # converter:: This argument contains the converter object that calls the syntax highlighter. It
+ # can be used, for example, to store data in Kramdown::Converter::Base#data for one
+ # conversion run.
+ #
+ # text:: The raw text that should be highlighted.
+ #
+ # lang:: The language that the text should be highlighted for (e.g. ruby, python, ...).
+ #
+ # type:: The type of text, either :span for span-level code or :block for a codeblock.
+ #
+ # opts:: A Hash with options that may be passed from the converter.
+ #
+ # The return value of the method should be the highlighted text, suitable for the given
+ # converter (e.g. HTML for the HTML converter).
+ #
+ # == Special Implementation Details
+ #
+ # HTML converter:: If the syntax highlighter is used with an HTML converter, it should return
+ # :block type text correctly wrapped (i.e. normally inside a pre-tag, but may
+ # also be a table-tag or just a div-tag) but :span type text *without* a
+ # code-tag!
+ #
+ # Also, a syntax highlighter should store the default highlighting language for
+ # the invocation in the +opts+ hash under the key :default_lang.
+ module SyntaxHighlighter
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb
new file mode 100644
index 0000000..2119f00
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb
@@ -0,0 +1,35 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown::Converter::SyntaxHighlighter
+
+ # Uses Minted to highlight code blocks and code spans.
+ module Minted
+
+ def self.call(converter, text, lang, type, _opts)
+ opts = converter.options[:syntax_highlighter_opts]
+
+ # Fallback to default language
+ lang ||= opts[:default_lang]
+
+ options = []
+ options << "breaklines" if opts[:wrap]
+ options << "linenos" if opts[:line_numbers]
+ options << "frame=#{opts[:frame]}" if opts[:frame]
+
+ if lang && type == :block
+ "\\begin{minted}[#{options.join(',')}]{#{lang}}\n#{text}\n\\end{minted}"
+ elsif lang && type == :span
+ "\\mintinline{#{lang}}{#{text}}"
+ else
+ nil
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb
new file mode 100644
index 0000000..ed6a4f8
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb
@@ -0,0 +1,85 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown::Converter::SyntaxHighlighter
+
+ # Uses Rouge which is CSS-compatible to Pygments to highlight code blocks and code spans.
+ module Rouge
+
+ begin
+ require 'rouge'
+
+ # Highlighting via Rouge is available if this constant is +true+.
+ AVAILABLE = true
+ rescue LoadError, SyntaxError
+ AVAILABLE = false # :nodoc:
+ end
+
+ def self.call(converter, text, lang, type, call_opts)
+ opts = options(converter, type)
+ call_opts[:default_lang] = opts[:default_lang]
+ return nil unless lang || opts[:default_lang] || opts[:guess_lang]
+
+ lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text)
+ return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang])
+
+ opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0
+ formatter = formatter_class(opts).new(opts)
+ formatter.format(lexer.lex(text))
+ end
+
+ def self.options(converter, type)
+ prepare_options(converter)
+ converter.data[:syntax_highlighter_rouge][type]
+ end
+
+ def self.prepare_options(converter)
+ return if converter.data.key?(:syntax_highlighter_rouge)
+
+ cache = converter.data[:syntax_highlighter_rouge] = {}
+
+ opts = converter.options[:syntax_highlighter_opts].dup
+
+ span_opts = opts.delete(:span)&.dup || {}
+ block_opts = opts.delete(:block)&.dup || {}
+ normalize_keys(span_opts)
+ normalize_keys(block_opts)
+
+ cache[:span] = opts.merge(span_opts)
+ cache[:span][:wrap] = false
+
+ cache[:block] = opts.merge(block_opts)
+ end
+
+ def self.normalize_keys(hash)
+ return if hash.empty?
+
+ hash.keys.each do |k|
+ hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k)
+ end
+ end
+
+ def self.formatter_class(opts = {})
+ case formatter = opts[:formatter]
+ when Class
+ formatter
+ when /\A[[:upper:]][[:alnum:]_]*\z/
+ ::Rouge::Formatters.const_get(formatter, false)
+ else
+ # Available in Rouge 2.0 or later
+ ::Rouge::Formatters::HTMLLegacy
+ end
+ rescue NameError
+ # Fallback to Rouge 1.x
+ ::Rouge::Formatters::HTML
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb
new file mode 100644
index 0000000..7ffbc5d
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb
@@ -0,0 +1,69 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/converter'
+
+module Kramdown
+
+ module Converter
+
+ # Converts a Kramdown::Document to an element tree that represents the table of contents.
+ #
+ # The returned tree consists of Element objects of type :toc where the root element is just used
+ # as container object. Each :toc element contains as value the wrapped :header element and under
+ # the attribute key :id the header ID that should be used (note that this ID may not exist in
+ # the wrapped element).
+ #
+ # Since the TOC tree consists of special :toc elements, one cannot directly feed this tree to
+ # other converters!
+ class Toc < Base
+
+ def initialize(root, options)
+ super
+ @toc = Element.new(:toc)
+ @stack = []
+ @options[:template] = ''
+ end
+
+ def convert(el)
+ if el.type == :header && in_toc?(el)
+ attr = el.attr.dup
+ attr['id'] = generate_id(el.options[:raw_text]) if @options[:auto_ids] && !attr['id']
+ add_to_toc(el, attr['id']) if attr['id']
+ else
+ el.children.each {|child| convert(child) }
+ end
+ @toc
+ end
+
+ private
+
+ def add_to_toc(el, id)
+ toc_element = Element.new(:toc, el, id: id)
+
+ success = false
+ until success
+ if @stack.empty?
+ @toc.children << toc_element
+ @stack << toc_element
+ success = true
+ elsif @stack.last.value.options[:level] < el.options[:level]
+ @stack.last.children << toc_element
+ @stack << toc_element
+ success = true
+ else
+ @stack.pop
+ end
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb
new file mode 100644
index 0000000..7a10e76
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb
@@ -0,0 +1,139 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+# = kramdown
+#
+# kramdown is fast, pure Ruby Markdown superset converter, using a strict syntax definition and
+# supporting several common extensions.
+#
+# The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However,
+# due to its flexibility it supports other input and output formats as well. Here is a list of the
+# supported formats:
+#
+# * input formats: kramdown (a Markdown superset), Markdown, GFM, HTML
+# * output formats: HTML, kramdown, LaTeX (and therefore PDF), PDF via Prawn
+#
+# All the documentation on the available input and output formats is available at
+# http://kramdown.gettalong.org.
+#
+# == Usage
+#
+# kramdown has a simple API, so using kramdown is as easy as
+#
+# require 'kramdown'
+#
+# Kramdown::Document.new(text).to_html
+#
+# For detailed information have a look at the *\Kramdown::Document* class.
+#
+# == License
+#
+# MIT - see the COPYING file.
+
+require 'kramdown/version'
+require 'kramdown/element'
+require 'kramdown/error'
+require 'kramdown/parser'
+require 'kramdown/converter'
+require 'kramdown/options'
+require 'kramdown/utils'
+
+module Kramdown
+
+ # Return the data directory for kramdown.
+ def self.data_dir
+ unless defined?(@data_dir)
+ require 'rbconfig'
+ @data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'kramdown'))
+ @data_dir = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "kramdown")) unless File.exist?(@data_dir)
+ raise "kramdown data directory not found! This is a bug, please report it!" unless File.directory?(@data_dir)
+ end
+ @data_dir
+ end
+
+ # The main interface to kramdown.
+ #
+ # This class provides a one-stop-shop for using kramdown to convert text into various output
+ # formats. Use it like this:
+ #
+ # require 'kramdown'
+ # doc = Kramdown::Document.new('This *is* some kramdown text')
+ # puts doc.to_html
+ #
+ # The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for
+ # more information.
+ #
+ # The second argument to the ::new method is an options hash for customizing the behaviour of the
+ # used parser and the converter. See ::new for more information!
+ class Document
+
+ # The root Element of the element tree. It is immediately available after the ::new method has
+ # been called.
+ attr_accessor :root
+
+ # The options hash which holds the options for parsing/converting the Kramdown document.
+ attr_reader :options
+
+ # An array of warning messages. It is filled with warnings during the parsing phase (i.e. in
+ # ::new) and the conversion phase.
+ attr_reader :warnings
+
+ # Create a new Kramdown document from the string +source+ and use the provided +options+. The
+ # options that can be used are defined in the Options module.
+ #
+ # The special options key :input can be used to select the parser that should parse the
+ # +source+. It has to be the name of a class in the Kramdown::Parser module. For example, to
+ # select the kramdown parser, one would set the :input key to +Kramdown+. If this key is not
+ # set, it defaults to +Kramdown+.
+ #
+ # The +source+ is immediately parsed by the selected parser so that the root element is
+ # immediately available and the output can be generated.
+ def initialize(source, options = {})
+ @options = Options.merge(options).freeze
+ parser = (@options[:input] || 'kramdown').to_s
+ parser = parser[0..0].upcase + parser[1..-1]
+ try_require('parser', parser)
+ if Parser.const_defined?(parser)
+ @root, @warnings = Parser.const_get(parser).parse(source, @options)
+ else
+ raise Kramdown::Error, "kramdown has no parser to handle the specified " \
+ "input format: #{@options[:input]}"
+ end
+ end
+
+ # Check if a method is invoked that begins with +to_+ and if so, try to instantiate a converter
+ # class (i.e. a class in the Kramdown::Converter module) and use it for converting the document.
+ #
+ # For example, +to_html+ would instantiate the Kramdown::Converter::Html class.
+ def method_missing(id, *attr, &block)
+ if id.to_s =~ /^to_(\w+)$/ && (name = Utils.camelize($1)) &&
+ try_require('converter', name) && Converter.const_defined?(name)
+ output, warnings = Converter.const_get(name).convert(@root, @options)
+ @warnings.concat(warnings)
+ output
+ else
+ super
+ end
+ end
+
+ def inspect # :nodoc:
+ "<KD:Document: options=#{@options.inspect} root=#{@root.inspect} warnings=#{@warnings.inspect}>"
+ end
+
+ # Try requiring a parser or converter class and don't raise an error if the file is not found.
+ def try_require(type, name)
+ require("kramdown/#{type}/#{Utils.snake_case(name)}")
+ true
+ rescue LoadError
+ true
+ end
+ protected :try_require
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb
new file mode 100644
index 0000000..031c7dd
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb
@@ -0,0 +1,551 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+
+ # Represents all elements in the element tree.
+ #
+ # kramdown only uses this one class for representing all available elements in an element tree
+ # (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor.
+ #
+ # The root of a kramdown element tree has to be an element of type :root. It needs to have certain
+ # option keys set so that conversions work correctly. If only a part of a tree should be
+ # converted, duplicate the root node and assign the #children appropriately, e.g:
+ #
+ # root = doc.root
+ # new_root = root.dup
+ # new_root.children = [root.children[0]] # assign new array with elements to convert
+ #
+ # Following is a description of all supported element types.
+ #
+ # Note that the option :location may contain the start line number of an element in the source
+ # document.
+ #
+ # == Structural Elements
+ #
+ # === :root
+ #
+ # [Category] None
+ # [Usage context] As the root element of a document
+ # [Content model] Block-level elements
+ #
+ # Represents the root of a kramdown document.
+ #
+ # The root element contains the following option keys:
+ #
+ # :encoding:: When running on Ruby 1.9 this key has to be set to the encoding used for the text
+ # parts of the kramdown document.
+ #
+ # :abbrev_defs:: This key may be used to store the mapping of abbreviation to abbreviation
+ # definition.
+ #
+ # :abbrev_attr:: This key may be used to store the mapping of abbreviation to abbreviation
+ # attributes.
+ #
+ # :options:: This key may be used to store options that were set during parsing of the document.
+ #
+ # :footnote_count:: This key stores the number of actually referenced footnotes of the document.
+ #
+ # === :blank
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] Empty
+ #
+ # Represents one or more blank lines. It is not allowed to have two or more consecutive blank
+ # elements.
+ #
+ # The +value+ field may contain the original content of the blank lines.
+ #
+ #
+ # === :p
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] Span-level elements
+ #
+ # Represents a paragraph.
+ #
+ # If the option :transparent is +true+, this element just represents a block of text. I.e. this
+ # element just functions as a container for span-level elements.
+ #
+ #
+ # === :header
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] Span-level elements
+ #
+ # Represents a header.
+ #
+ # The option :level specifies the header level and has to contain a number between 1 and \6. The
+ # option :raw_text has to contain the raw header text.
+ #
+ #
+ # === :blockquote
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] Block-level elements
+ #
+ # Represents a blockquote.
+ #
+ #
+ # === :codeblock
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] Empty
+ #
+ # Represents a code block, i.e. a block of text that should be used as-is.
+ #
+ # The +value+ field has to contain the content of the code block.
+ #
+ # The option :lang specifies a highlighting language with possible HTML style options (e.g.
+ # php?start_inline=1) and should be used instead of a possibly also available language embedded in
+ # a class name of the form 'language-LANG'.
+ #
+ #
+ # === :ul
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] One or more :li elements
+ #
+ # Represents an unordered list.
+ #
+ #
+ # === :ol
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] One or more :li elements
+ #
+ # Represents an ordered list.
+ #
+ #
+ # === :li
+ #
+ # [Category] Block-level element
+ # [Usage context] Inside :ol and :ul elements
+ # [Content model] Block-level elements
+ #
+ # Represents a list item of an ordered or unordered list.
+ #
+ # Note that the first child of a list item must not be a :blank element!
+ #
+ #
+ # === :dl
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] One or more groups each consisting of one or more :dt elements followed by one
+ # or more :dd elements.
+ #
+ # Represents a definition list which contains groups consisting of terms and definitions for them.
+ #
+ #
+ # === :dt
+ #
+ # [Category] Block-level element
+ # [Usage context] Before :dt or :dd elements inside a :dl elment
+ # [Content model] Span-level elements
+ #
+ # Represents the term part of a term-definition group in a definition list.
+ #
+ #
+ # === :dd
+ #
+ # [Category] Block-level element
+ # [Usage context] After :dt or :dd elements inside a :dl elment
+ # [Content model] Block-level elements
+ #
+ # Represents the definition part of a term-definition group in a definition list.
+ #
+ #
+ # === :hr
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] None
+ #
+ # Represents a horizontal line.
+ #
+ #
+ # === :table
+ #
+ # [Category] Block-level element
+ # [Usage context] Where block-level elements are expected
+ # [Content model] Zero or one :thead elements, one or more :tbody elements, zero or one :tfoot
+ # elements
+ #
+ # Represents a table. Each table row (i.e. :tr element) of the table has to contain the same
+ # number of :td elements.
+ #
+ # The option :alignment has to be an array containing the alignment values, exactly one for each
+ # column of the table. The possible alignment values are :left, :center, :right and :default.
+ #
+ #
+ # === :thead
+ #
+ # [Category] None
+ # [Usage context] As first element inside a :table element
+ # [Content model] One or more :tr elements
+ #
+ # Represents the table header.
+ #
+ #
+ # === :tbody
+ #
+ # [Category] None
+ # [Usage context] After a :thead element but before a :tfoot element inside a :table element
+ # [Content model] One or more :tr elements
+ #
+ # Represents a table body.
+ #
+ #
+ # === :tfoot
+ #
+ # [Category] None
+ # [Usage context] As last element inside a :table element
+ # [Content model] One or more :tr elements
+ #
+ # Represents the table footer.
+ #
+ #
+ # === :tr
+ #
+ # [Category] None
+ # [Usage context] Inside :thead, :tbody and :tfoot elements
+ # [Content model] One or more :td elements
+ #
+ # Represents a table row.
+ #
+ #
+ # === :td
+ #
+ # [Category] Block-level element
+ # [Usage context] Inside :tr elements
+ # [Content model] As child of :thead/:tr span-level elements, as child of :tbody/:tr and
+ # :tfoot/:tr block-level elements
+ #
+ # Represents a table cell.
+ #
+ #
+ # === :math
+ #
+ # [Category] Block/span-level element
+ # [Usage context] Where block/span-level elements are expected
+ # [Content model] None
+ #
+ # Represents mathematical text that is written in LaTeX.
+ #
+ # The +value+ field has to contain the actual mathematical text.
+ #
+ # The option :category has to be set to either :span or :block depending on the context where the
+ # element is used.
+ #
+ #
+ # == Text Markup Elements
+ #
+ # === :text
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents text.
+ #
+ # The +value+ field has to contain the text itself.
+ #
+ #
+ # === :br
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a hard line break.
+ #
+ #
+ # === :a
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] Span-level elements
+ #
+ # Represents a link to an URL.
+ #
+ # The attribute +href+ has to be set to the URL to which the link points. The attribute +title+
+ # optionally contains the title of the link.
+ #
+ #
+ # === :img
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents an image.
+ #
+ # The attribute +src+ has to be set to the URL of the image. The attribute +alt+ has to contain a
+ # text description of the image. The attribute +title+ optionally contains the title of the image.
+ #
+ #
+ # === :codespan
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents verbatim text.
+ #
+ # The +value+ field has to contain the content of the code span.
+ #
+ #
+ # === :footnote
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a footnote marker.
+ #
+ # The +value+ field has to contain an element whose children are the content of the footnote. The
+ # option :name has to contain a valid and unique footnote name. A valid footnote name consists of
+ # a word character or a digit and then optionally followed by other word characters, digits or
+ # dashes.
+ #
+ #
+ # === :em
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] Span-level elements
+ #
+ # Represents emphasis of its contents.
+ #
+ #
+ # === :strong
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] Span-level elements
+ #
+ # Represents strong importance for its contents.
+ #
+ #
+ # === :entity
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents an HTML entity.
+ #
+ # The +value+ field has to contain an instance of Kramdown::Utils::Entities::Entity. The option
+ # :original can be used to store the original representation of the entity.
+ #
+ #
+ # === :typographic_sym
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a typographic symbol.
+ #
+ # The +value+ field needs to contain a Symbol representing the specific typographic symbol from
+ # the following list:
+ #
+ # :mdash:: An mdash character (---)
+ # :ndash:: An ndash character (--)
+ # :hellip:: An ellipsis (...)
+ # :laquo:: A left guillemet (<<)
+ # :raquo:: A right guillemet (>>)
+ # :laquo_space:: A left guillemet with a space (<< )
+ # :raquo_space:: A right guillemet with a space ( >>)
+ #
+ #
+ # === :smart_quote
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a quotation character.
+ #
+ # The +value+ field needs to contain a Symbol representing the specific quotation character:
+ #
+ # :lsquo:: Left single quote
+ # :rsquo:: Right single quote
+ # :ldquo:: Left double quote
+ # :rdquo:: Right double quote
+ #
+ #
+ # === :abbreviation
+ #
+ # [Category] Span-level element
+ # [Usage context] Where span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a text part that is an abbreviation.
+ #
+ # The +value+ field has to contain the text part that is the abbreviation. The definition of the
+ # abbreviation is stored in the :root element of the document.
+ #
+ #
+ # == Other Elements
+ #
+ # === :html_element
+ #
+ # [Category] Block/span-level element
+ # [Usage context] Where block/span-level elements or raw HTML elements are expected
+ # [Content model] Depends on the element
+ #
+ # Represents an HTML element.
+ #
+ # The +value+ field has to contain the name of the HTML element the element is representing.
+ #
+ # The option :category has to be set to either :span or :block depending on the whether the
+ # element is a block-level or a span-level element. The option :content_model has to be set to the
+ # content model for the element (either :block if it contains block-level elements, :span if it
+ # contains span-level elements or :raw if it contains raw content).
+ #
+ #
+ # === :xml_comment
+ #
+ # [Category] Block/span-level element
+ # [Usage context] Where block/span-level elements are expected or in raw HTML elements
+ # [Content model] None
+ #
+ # Represents an XML/HTML comment.
+ #
+ # The +value+ field has to contain the whole XML/HTML comment including the delimiters.
+ #
+ # The option :category has to be set to either :span or :block depending on the context where the
+ # element is used.
+ #
+ #
+ # === :xml_pi
+ #
+ # [Category] Block/span-level element
+ # [Usage context] Where block/span-level elements are expected or in raw HTML elements
+ # [Content model] None
+ #
+ # Represents an XML/HTML processing instruction.
+ #
+ # The +value+ field has to contain the whole XML/HTML processing instruction including the
+ # delimiters.
+ #
+ # The option :category has to be set to either :span or :block depending on the context where the
+ # element is used.
+ #
+ #
+ # === :comment
+ #
+ # [Category] Block/span-level element
+ # [Usage context] Where block/span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a comment.
+ #
+ # The +value+ field has to contain the comment.
+ #
+ # The option :category has to be set to either :span or :block depending on the context where the
+ # element is used. If it is set to :span, then no blank lines are allowed in the comment.
+ #
+ #
+ # === :raw
+ #
+ # [Category] Block/span-level element
+ # [Usage context] Where block/span-level elements are expected
+ # [Content model] None
+ #
+ # Represents a raw string that should not be modified. For example, the element could contain some
+ # HTML code that should be output as-is without modification and escaping.
+ #
+ # The +value+ field has to contain the actual raw text.
+ #
+ # The option :category has to be set to either :span or :block depending on the context where the
+ # element is used. If it is set to :span, then no blank lines are allowed in the raw text.
+ #
+ # The option :type can be set to an array of strings to define for which converters the raw string
+ # is valid.
+ #
+ class Element
+
+ # A symbol representing the element type. For example, :p or :blockquote.
+ attr_accessor :type
+
+ # The value of the element. The interpretation of this field depends on the type of the element.
+ # Many elements don't use this field.
+ attr_accessor :value
+
+ # The child elements of this element.
+ attr_accessor :children
+
+ # Create a new Element object of type +type+. The optional parameters +value+, +attr+ and
+ # +options+ can also be set in this constructor for convenience.
+ def initialize(type, value = nil, attr = nil, options = nil)
+ @type, @value, @attr, @options = type, value, attr, options
+ @children = []
+ end
+
+ # The attributes of the element.
+ def attr
+ @attr ||= {}
+ end
+
+ # The options hash for the element. It is used for storing arbitray options.
+ def options
+ @options ||= {}
+ end
+
+ def inspect # :nodoc:
+ "<kd:#{@type}" \
+ "#{value.nil? ? '' : ' value=' + value.inspect}" \
+ "#{attr.empty? ? '' : ' attr=' + attr.inspect}" \
+ "#{options.empty? ? '' : ' options=' + options.inspect}" \
+ "#{children.empty? ? '' : ' children=' + children.inspect}>"
+ end
+
+ CATEGORY = {} # :nodoc:
+ [:blank, :p, :header, :blockquote, :codeblock, :ul, :ol, :li, :dl, :dt, :dd,
+ :table, :td, :hr].each {|b| CATEGORY[b] = :block }
+ [:text, :a, :br, :img, :codespan, :footnote, :em, :strong, :entity, :typographic_sym,
+ :smart_quote, :abbreviation].each {|b| CATEGORY[b] = :span }
+
+ # Return the category of +el+ which can be :block, :span or +nil+.
+ #
+ # Most elements have a fixed category, however, some elements can either appear in a block-level
+ # or a span-level context. These elements need to have the option :category correctly set.
+ def self.category(el)
+ CATEGORY[el.type] || el.options[:category]
+ end
+
+ # syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :block+ with
+ # +el.block?+.
+ #
+ # Returns boolean true or false.
+ def block?
+ (CATEGORY[type] || options[:category]) == :block
+ end
+
+ # syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :span+ with
+ # +el.span?+.
+ #
+ # Returns boolean true or false.
+ def span?
+ (CATEGORY[type] || options[:category]) == :span
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb
new file mode 100644
index 0000000..81ffbc9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb
@@ -0,0 +1,17 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+
+ # This error is raised when an error condition is encountered.
+ #
+ # *Note* that this error is only raised by the support framework for the parsers and converters.
+ class Error < RuntimeError; end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb
new file mode 100644
index 0000000..18d04e4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb
@@ -0,0 +1,645 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'yaml'
+
+module Kramdown
+
+ # This module defines all options that are used by parsers and/or converters as well as providing
+ # methods to deal with the options.
+ module Options
+
+ # Helper class introducing a boolean type for specifying boolean values (+true+ and +false+) as
+ # option types.
+ class Boolean
+
+ # Return +true+ if +other+ is either +true+ or +false+
+ def self.===(other)
+ FalseClass === other || TrueClass === other
+ end
+
+ end
+
+ # ----------------------------
+ # :section: Option definitions
+ #
+ # This sections describes the methods that can be used on the Options module.
+ # ----------------------------
+
+ # Struct class for storing the definition of an option.
+ Definition = Struct.new(:name, :type, :default, :desc, :validator)
+
+ # Allowed option types.
+ ALLOWED_TYPES = [String, Integer, Float, Symbol, Boolean, Object]
+
+ @options = {}
+ @defaults = nil
+
+ # Define a new option called +name+ (a Symbol) with the given +type+ (String, Integer, Float,
+ # Symbol, Boolean, Object), default value +default+ and the description +desc+. If a block is
+ # specified, it should validate the value and either raise an error or return a valid value.
+ #
+ # The type 'Object' should only be used for complex types for which none of the other types
+ # suffices. A block needs to be specified when using type 'Object' and it has to cope with
+ # a value given as string and as the opaque type.
+ def self.define(name, type, default, desc, &block)
+ name = name.to_sym
+ raise ArgumentError, "Option name #{name} is already used" if @options.key?(name)
+ raise ArgumentError, "Invalid option type #{type} specified" unless ALLOWED_TYPES.include?(type)
+ raise ArgumentError, "Invalid type for default value" if !(type === default) && !default.nil?
+ raise ArgumentError, "Missing validator block" if type == Object && block.nil?
+ @options[name] = Definition.new(name, type, default, desc, block)
+ @defaults = nil
+ end
+
+ # Return all option definitions.
+ def self.definitions
+ @options
+ end
+
+ # Return +true+ if an option called +name+ is defined.
+ def self.defined?(name)
+ @options.key?(name.to_sym)
+ end
+
+ # Return a Hash with the default values for all options.
+ def self.defaults
+ @defaults ||=
+ begin
+ temp = {}
+ @options.each {|_n, o| temp[o.name] = o.default }
+ temp.freeze
+ end
+ end
+
+ # Merge the #defaults Hash with the *parsed* options from the given Hash, i.e. only valid option
+ # names are considered and their value is run through the #parse method.
+ def self.merge(hash)
+ temp = defaults.dup
+ hash.each do |k, v|
+ k = k.to_sym
+ temp[k] = @options.key?(k) ? parse(k, v) : v
+ end
+ temp
+ end
+
+ # Parse the given value +data+ as if it was a value for the option +name+ and return the parsed
+ # value with the correct type.
+ #
+ # If +data+ already has the correct type, it is just returned. Otherwise it is converted to a
+ # String and then to the correct type.
+ def self.parse(name, data)
+ name = name.to_sym
+ raise ArgumentError, "No option named #{name} defined" unless @options.key?(name)
+ unless @options[name].type === data
+ data = data.to_s
+ data = if @options[name].type == String
+ data
+ elsif @options[name].type == Integer
+ Integer(data) rescue raise Kramdown::Error, "Invalid integer value for option '#{name}': '#{data}'"
+ elsif @options[name].type == Float
+ Float(data) rescue raise Kramdown::Error, "Invalid float value for option '#{name}': '#{data}'"
+ elsif @options[name].type == Symbol
+ str_to_sym(data)
+ elsif @options[name].type == Boolean
+ data.downcase.strip != 'false' && !data.empty?
+ end
+ end
+ data = @options[name].validator[data] if @options[name].validator
+ data
+ end
+
+ # Converts the given String +data+ into a Symbol or +nil+ with the
+ # following provisions:
+ #
+ # - A leading colon is stripped from the string.
+ # - An empty value or a value equal to "nil" results in +nil+.
+ def self.str_to_sym(data)
+ data = data.strip
+ data = data[1..-1] if data[0] == ':'
+ (data.empty? || data == 'nil' ? nil : data.to_sym)
+ end
+
+ # ----------------------------
+ # :section: Option Validators
+ #
+ # This sections contains all pre-defined option validators.
+ # ----------------------------
+
+ # Ensures that the option value +val+ for the option called +name+ is a valid array. The
+ # parameter +val+ can be
+ #
+ # - a comma separated string which is split into an array of values
+ # - or an array.
+ #
+ # Optionally, the array is checked for the correct size.
+ def self.simple_array_validator(val, name, size = nil)
+ if String === val
+ val = val.split(",")
+ elsif !(Array === val)
+ raise Kramdown::Error, "Invalid type #{val.class} for option #{name}"
+ end
+ if size && val.size != size
+ raise Kramdown::Error, "Option #{name} needs exactly #{size} values"
+ end
+ val
+ end
+
+ # Ensures that the option value +val+ for the option called +name+ is a valid hash. The
+ # parameter +val+ can be
+ #
+ # - a hash in YAML format
+ # - or a Ruby Hash object.
+ def self.simple_hash_validator(val, name)
+ if String === val
+ begin
+ val = YAML.safe_load(val)
+ rescue RuntimeError, ArgumentError, SyntaxError
+ raise Kramdown::Error, "Invalid YAML value for option #{name}"
+ end
+ end
+ raise Kramdown::Error, "Invalid type #{val.class} for option #{name}" unless Hash === val
+ val
+ end
+
+ # ----------------------------
+ # :section: Option Definitions
+ #
+ # This sections contains all option definitions that are used by the included
+ # parsers/converters.
+ # ----------------------------
+
+ define(:template, String, '', <<~EOF)
+ The name of an ERB template file that should be used to wrap the output
+ or the ERB template itself.
+
+ This is used to wrap the output in an environment so that the output can
+ be used as a stand-alone document. For example, an HTML template would
+ provide the needed header and body tags so that the whole output is a
+ valid HTML file. If no template is specified, the output will be just
+ the converted text.
+
+ When resolving the template file, the given template name is used first.
+ If such a file is not found, the converter extension (the same as the
+ converter name) is appended. If the file still cannot be found, the
+ templates name is interpreted as a template name that is provided by
+ kramdown (without the converter extension). If the file is still not
+ found, the template name is checked if it starts with 'string://' and if
+ it does, this prefix is removed and the rest is used as template
+ content.
+
+ kramdown provides a default template named 'document' for each converter.
+
+ Default: ''
+ Used by: all converters
+ EOF
+
+ define(:auto_ids, Boolean, true, <<~EOF)
+ Use automatic header ID generation
+
+ If this option is `true`, ID values for all headers are automatically
+ generated if no ID is explicitly specified.
+
+ Default: true
+ Used by: HTML/Latex converter
+ EOF
+
+ define(:auto_id_stripping, Boolean, false, <<~EOF)
+ Strip all formatting from header text for automatic ID generation
+
+ If this option is `true`, only the text elements of a header are used
+ for generating the ID later (in contrast to just using the raw header
+ text line).
+
+ This option will be removed in version 2.0 because this will be the
+ default then.
+
+ Default: false
+ Used by: kramdown parser
+ EOF
+
+ define(:auto_id_prefix, String, '', <<~EOF)
+ Prefix used for automatically generated header IDs
+
+ This option can be used to set a prefix for the automatically generated
+ header IDs so that there is no conflict when rendering multiple kramdown
+ documents into one output file separately. The prefix should only
+ contain characters that are valid in an ID!
+
+ Default: ''
+ Used by: HTML/Latex converter
+ EOF
+
+ define(:header_links, Boolean, false, <<~EOF)
+ Adds anchor tags within headers that can be used to generate permalinks
+ when not using a table of contents.
+
+ The anchor tags are empty, but can be styled to your liking.
+
+ Default: false
+ EOF
+
+ define(:transliterated_header_ids, Boolean, false, <<~EOF)
+ Transliterate the header text before generating the ID
+
+ Only ASCII characters are used in headers IDs. This is not good for
+ languages with many non-ASCII characters. By enabling this option
+ the header text is transliterated to ASCII as good as possible so that
+ the resulting header ID is more useful.
+
+ The stringex library needs to be installed for this feature to work!
+
+ Default: false
+ Used by: HTML/Latex converter
+ EOF
+
+ define(:parse_block_html, Boolean, false, <<~EOF)
+ Process kramdown syntax in block HTML tags
+
+ If this option is `true`, the kramdown parser processes the content of
+ block HTML tags as text containing block-level elements. Since this is
+ not wanted normally, the default is `false`. It is normally better to
+ selectively enable kramdown processing via the markdown attribute.
+
+ Default: false
+ Used by: kramdown parser
+ EOF
+
+ define(:parse_span_html, Boolean, true, <<~EOF)
+ Process kramdown syntax in span HTML tags
+
+ If this option is `true`, the kramdown parser processes the content of
+ span HTML tags as text containing span-level elements.
+
+ Default: true
+ Used by: kramdown parser
+ EOF
+
+ define(:html_to_native, Boolean, false, <<~EOF)
+ Convert HTML elements to native elements
+
+ If this option is `true`, the parser converts HTML elements to native
+ elements. For example, when parsing `<em>hallo</em>` the emphasis tag
+ would normally be converted to an `:html` element with tag type `:em`.
+ If `html_to_native` is `true`, then the emphasis would be converted to a
+ native `:em` element.
+
+ This is useful for converters that cannot deal with HTML elements.
+
+ Default: false
+ Used by: kramdown parser
+ EOF
+
+ define(:link_defs, Object, {}, <<~EOF) do |val|
+ Pre-defines link definitions
+
+ This option can be used to pre-define link definitions. The value needs
+ to be a Hash where the keys are the link identifiers and the values are
+ two element Arrays with the link URL and the link title.
+
+ If the value is a String, it has to contain a valid YAML hash and the
+ hash has to follow the above guidelines.
+
+ Default: {}
+ Used by: kramdown parser
+ EOF
+ val = simple_hash_validator(val, :link_defs)
+ val.each do |_k, v|
+ if !(Array === v) || v.size > 2 || v.empty?
+ raise Kramdown::Error, "Invalid structure for hash value of option #{name}"
+ end
+ v << nil if v.size == 1
+ end
+ val
+ end
+
+ define(:footnote_nr, Integer, 1, <<~EOF)
+ The number of the first footnote
+
+ This option can be used to specify the number that is used for the first
+ footnote.
+
+ Default: 1
+ Used by: HTML converter
+ EOF
+
+ define(:entity_output, Symbol, :as_char, <<~EOF)
+ Defines how entities are output
+
+ The possible values are :as_input (entities are output in the same
+ form as found in the input), :numeric (entities are output in numeric
+ form), :symbolic (entities are output in symbolic form if possible) or
+ :as_char (entities are output as characters if possible, only available
+ on Ruby 1.9).
+
+ Default: :as_char
+ Used by: HTML converter, kramdown converter
+ EOF
+
+ TOC_LEVELS_RANGE = (1..6).freeze
+ TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze
+ private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY
+
+ define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val|
+ Defines the levels that are used for the table of contents
+
+ The individual levels can be specified by separating them with commas
+ (e.g. 1,2,3) or by using the range syntax (e.g. 1..3). Only the
+ specified levels are used for the table of contents.
+
+ Default: 1..6
+ Used by: HTML/Latex converter
+ EOF
+ case val
+ when String
+ if val =~ /^(\d)\.\.(\d)$/
+ val = Range.new($1.to_i, $2.to_i).to_a
+ elsif val.match?(/^\d(?:,\d)*$/)
+ val = val.split(",").map(&:to_i).uniq
+ else
+ raise Kramdown::Error, "Invalid syntax for option toc_levels"
+ end
+ when Array
+ unless val.eql?(TOC_LEVELS_ARRAY)
+ val = val.map(&:to_i).uniq
+ end
+ when Range
+ val = if val.eql?(TOC_LEVELS_RANGE)
+ TOC_LEVELS_ARRAY
+ else
+ val.map(&:to_i).uniq
+ end
+ else
+ raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels"
+ end
+ if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) }
+ raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6"
+ end
+ val
+ end
+
+ define(:line_width, Integer, 72, <<~EOF)
+ Defines the line width to be used when outputting a document
+
+ Default: 72
+ Used by: kramdown converter
+ EOF
+
+ define(:latex_headers, Object, %w[section subsection subsubsection paragraph subparagraph subparagraph], <<~EOF) do |val|
+ Defines the LaTeX commands for different header levels
+
+ The commands for the header levels one to six can be specified by
+ separating them with commas.
+
+ Default: section,subsection,subsubsection,paragraph,subparagraph,subparagraph
+ Used by: Latex converter
+ EOF
+ simple_array_validator(val, :latex_headers, 6)
+ end
+
+ SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze
+ SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze
+ private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR
+
+ define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val|
+ Defines the HTML entity names or code points for smart quote output
+
+ The entities identified by entity name or code point that should be
+ used for, in order, a left single quote, a right single quote, a left
+ double and a right double quote are specified by separating them with
+ commas.
+
+ Default: lsquo,rsquo,ldquo,rdquo
+ Used by: HTML/Latex converter
+ EOF
+ if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES
+ SMART_QUOTES_ENTITIES
+ else
+ val = simple_array_validator(val, :smart_quotes, 4)
+ val.map! {|v| Integer(v) rescue v }
+ val
+ end
+ end
+
+ define(:typographic_symbols, Object, {}, <<~EOF) do |val|
+ Defines a mapping from typographical symbol to output characters
+
+ Typographical symbols are normally output using their equivalent Unicode
+ codepoint. However, sometimes one wants to change the output, mostly to
+ fallback to a sequence of ASCII characters.
+
+ This option allows this by specifying a mapping from typographical
+ symbol to its output string. For example, the mapping {hellip: ...} would
+ output the standard ASCII representation of an ellipsis.
+
+ The available typographical symbol names are:
+
+ * hellip: ellipsis
+ * mdash: em-dash
+ * ndash: en-dash
+ * laquo: left guillemet
+ * raquo: right guillemet
+ * laquo_space: left guillemet followed by a space
+ * raquo_space: right guillemet preceeded by a space
+
+ Default: {}
+ Used by: HTML/Latex converter
+ EOF
+ val = simple_hash_validator(val, :typographic_symbols)
+ val.keys.each do |k|
+ val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k).to_s
+ end
+ val
+ end
+
+ define(:remove_block_html_tags, Boolean, true, <<~EOF)
+ Remove block HTML tags
+
+ If this option is `true`, the RemoveHtmlTags converter removes
+ block HTML tags.
+
+ Default: true
+ Used by: RemoveHtmlTags converter
+ EOF
+
+ define(:remove_span_html_tags, Boolean, false, <<~EOF)
+ Remove span HTML tags
+
+ If this option is `true`, the RemoveHtmlTags converter removes
+ span HTML tags.
+
+ Default: false
+ Used by: RemoveHtmlTags converter
+ EOF
+
+ define(:header_offset, Integer, 0, <<~EOF)
+ Sets the output offset for headers
+
+ If this option is c (may also be negative) then a header with level n
+ will be output as a header with level c+n. If c+n is lower than 1,
+ level 1 will be used. If c+n is greater than 6, level 6 will be used.
+
+ Default: 0
+ Used by: HTML converter, Kramdown converter, Latex converter
+ EOF
+
+ define(:syntax_highlighter, Symbol, :rouge, <<~EOF)
+ Set the syntax highlighter
+
+ Specifies the syntax highlighter that should be used for highlighting
+ code blocks and spans. If this option is set to +nil+, no syntax
+ highlighting is done.
+
+ Options for the syntax highlighter can be set with the
+ syntax_highlighter_opts configuration option.
+
+ Default: rouge
+ Used by: HTML/Latex converter
+ EOF
+
+ define(:syntax_highlighter_opts, Object, {}, <<~EOF) do |val|
+ Set the syntax highlighter options
+
+ Specifies options for the syntax highlighter set via the
+ syntax_highlighter configuration option.
+
+ The value needs to be a hash with key-value pairs that are understood by
+ the used syntax highlighter.
+
+ Default: {}
+ Used by: HTML/Latex converter
+ EOF
+ val = simple_hash_validator(val, :syntax_highlighter_opts)
+ val.keys.each do |k|
+ val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k)
+ end
+ val
+ end
+
+ define(:math_engine, Symbol, :mathjax, <<~EOF)
+ Set the math engine
+
+ Specifies the math engine that should be used for converting math
+ blocks/spans. If this option is set to +nil+, no math engine is used and
+ the math blocks/spans are output as is.
+
+ Options for the selected math engine can be set with the
+ math_engine_opts configuration option.
+
+ Default: mathjax
+ Used by: HTML converter
+ EOF
+
+ define(:math_engine_opts, Object, {}, <<~EOF) do |val|
+ Set the math engine options
+
+ Specifies options for the math engine set via the math_engine
+ configuration option.
+
+ The value needs to be a hash with key-value pairs that are understood by
+ the used math engine.
+
+ Default: {}
+ Used by: HTML converter
+ EOF
+ val = simple_hash_validator(val, :math_engine_opts)
+ val.keys.each do |k|
+ val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k)
+ end
+ val
+ end
+
+ define(:footnote_backlink, String, '&#8617;', <<~EOF)
+ Defines the text that should be used for the footnote backlinks
+
+ The footnote backlink is just text, so any special HTML characters will
+ be escaped.
+
+ If the footnote backlint text is an empty string, no footnote backlinks
+ will be generated.
+
+ Default: '&8617;'
+ Used by: HTML converter
+ EOF
+
+ define(:footnote_backlink_inline, Boolean, false, <<~EOF)
+ Specifies whether the footnote backlink should always be inline
+
+ With the default of false the footnote backlink is placed at the end of
+ the last paragraph if there is one, or an extra paragraph with only the
+ footnote backlink is created.
+
+ Setting this option to true tries to place the footnote backlink in the
+ last, possibly nested paragraph or header. If this fails (e.g. in the
+ case of a table), an extra paragraph with only the footnote backlink is
+ created.
+
+ Default: false
+ Used by: HTML converter
+ EOF
+
+ define(:footnote_prefix, String, '', <<~EOF)
+ Prefix used for footnote IDs
+
+ This option can be used to set a prefix for footnote IDs. This is useful
+ when rendering multiple documents into the same output file to avoid
+ duplicate IDs. The prefix should only contain characters that are valid
+ in an ID!
+
+ Default: ''
+ Used by: HTML
+ EOF
+
+ define(:footnote_link_text, String, '%s', <<~EOF) do |val|
+ The text used for the footnote number in a footnote link
+
+ This option can be used to add additional text to the footnote
+ link. It should be a format string, and is passed the footnote
+ number as the only argument to the format string.
+ e.g. "[footnote %s]" would display as "[footnote 1]".
+
+ Default: '%s'
+ Used by: HTML
+ EOF
+ if !val.include?('%s')
+ raise Kramdown::Error, "option footnote_link_text needs to contain a '%s'"
+ end
+ val
+ end
+
+
+ define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF)
+ Specifies whether line breaks should be removed between CJK characters
+
+ Default: false
+ Used by: HTML converter
+ EOF
+
+ define(:forbidden_inline_options, Object, %w[template], <<~EOF) do |val|
+ Defines the options that may not be set using the {::options} extension
+
+ The value needs to be an array of option names.
+
+ Default: [template]
+ Used by: HTML converter
+ EOF
+ val.map! {|item| item.kind_of?(String) ? str_to_sym(item) : item }
+ simple_array_validator(val, :forbidden_inline_options)
+ end
+
+ define(:list_indent, Integer, 2, <<~EOF)
+ Sets the number of spaces to use for list indentation
+
+ Default: 2
+ Used by: Kramdown converter
+ EOF
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb
new file mode 100644
index 0000000..f77dcf6
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb
@@ -0,0 +1,26 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+
+ # This module contains all available parsers. A parser takes an input string and converts the
+ # string to an element tree.
+ #
+ # New parsers should be derived from the Base class which provides common functionality - see its
+ # API documentation for how to create a custom converter class.
+ module Parser
+
+ autoload :Base, 'kramdown/parser/base'
+ autoload :Kramdown, 'kramdown/parser/kramdown'
+ autoload :Html, 'kramdown/parser/html'
+ autoload :Markdown, 'kramdown/parser/markdown'
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb
new file mode 100644
index 0000000..298c974
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb
@@ -0,0 +1,137 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/utils'
+require 'kramdown/parser'
+
+module Kramdown
+
+ module Parser
+
+ # == \Base class for parsers
+ #
+ # This class serves as base class for parsers. It provides common methods that can/should be
+ # used by all parsers, especially by those using StringScanner(Kramdown) for parsing.
+ #
+ # A parser object is used as a throw-away object, i.e. it is only used for storing the needed
+ # state information during parsing. Therefore one can't instantiate a parser object directly but
+ # only use the Base::parse method.
+ #
+ # == Implementing a parser
+ #
+ # Implementing a new parser is rather easy: just derive a new class from this class and put it
+ # in the Kramdown::Parser module -- the latter is needed so that the auto-detection of the new
+ # parser works correctly. Then you need to implement the +#parse+ method which has to contain
+ # the parsing code.
+ #
+ # Have a look at the Base::parse, Base::new and Base#parse methods for additional information!
+ class Base
+
+ # The hash with the parsing options.
+ attr_reader :options
+
+ # The array with the parser warnings.
+ attr_reader :warnings
+
+ # The original source string.
+ attr_reader :source
+
+ # The root element of element tree that is created from the source string.
+ attr_reader :root
+
+ # Initialize the parser object with the +source+ string and the parsing +options+.
+ #
+ # The @root element, the @warnings array and @text_type (specifies the default type for newly
+ # created text nodes) are automatically initialized.
+ def initialize(source, options)
+ @source = source
+ @options = Kramdown::Options.merge(options)
+ @root = Element.new(:root, nil, nil, encoding: (source.encoding rescue nil), location: 1,
+ options: {}, abbrev_defs: {}, abbrev_attr: {})
+
+ @root.options[:abbrev_defs].default_proc = @root.options[:abbrev_attr].default_proc =
+ lambda do |h, k|
+ k_mod = k.gsub(/[\s\p{Z}]+/, " ")
+ k != k_mod ? h[k_mod] : nil
+ end
+ @warnings = []
+ @text_type = :text
+ end
+ private_class_method(:new, :allocate)
+
+ # Parse the +source+ string into an element tree, possibly using the parsing +options+, and
+ # return the root element of the element tree and an array with warning messages.
+ #
+ # Initializes a new instance of the calling class and then calls the +#parse+ method that must
+ # be implemented by each subclass.
+ def self.parse(source, options = {})
+ parser = new(source, options)
+ parser.parse
+ [parser.root, parser.warnings]
+ end
+
+ # Parse the source string into an element tree.
+ #
+ # The parsing code should parse the source provided in @source and build an element tree the
+ # root of which should be @root.
+ #
+ # This is the only method that has to be implemented by sub-classes!
+ def parse
+ raise NotImplementedError
+ end
+
+ # Add the given warning +text+ to the warning array.
+ def warning(text)
+ @warnings << text
+ # TODO: add position information
+ end
+
+ # Modify the string +source+ to be usable by the parser (unifies line ending characters to
+ # +\n+ and makes sure +source+ ends with a new line character).
+ def adapt_source(source)
+ unless source.valid_encoding?
+ raise "The source text contains invalid characters for the used encoding #{source.encoding}"
+ end
+ source = source.encode('UTF-8')
+ source.gsub!(/\r\n?/, "\n")
+ source.chomp!
+ source << "\n"
+ end
+
+ # This helper method adds the given +text+ either to the last element in the +tree+ if it is a
+ # +type+ element or creates a new text element with the given +type+.
+ def add_text(text, tree = @tree, type = @text_type)
+ last = tree.children.last
+ if last && last.type == type
+ last.value << text
+ elsif !text.empty?
+ location = (last && last.options[:location] || tree.options[:location])
+ tree.children << Element.new(type, text, nil, location: location)
+ end
+ end
+
+ # Extract the part of the StringScanner +strscan+ backed string specified by the +range+. This
+ # method works correctly under Ruby 1.8 and Ruby 1.9.
+ def extract_string(range, strscan)
+ result = nil
+ begin
+ enc = strscan.string.encoding
+ strscan.string.force_encoding('ASCII-8BIT')
+ result = strscan.string[range].force_encoding(enc)
+ ensure
+ strscan.string.force_encoding(enc)
+ end
+ result
+ end
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb
new file mode 100644
index 0000000..2c99fdc
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb
@@ -0,0 +1,621 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'rexml/parsers/baseparser'
+require 'strscan'
+require 'kramdown/utils'
+require 'kramdown/parser'
+
+module Kramdown
+
+ module Parser
+
+ # Used for parsing an HTML document.
+ #
+ # The parsing code is in the Parser module that can also be used by other parsers.
+ class Html < Base
+
+ # Contains all constants that are used when parsing.
+ module Constants
+
+ # :stopdoc:
+ # The following regexps are based on the ones used by REXML, with some slight modifications.
+ HTML_DOCTYPE_RE = /<!DOCTYPE.*?>/im
+ HTML_COMMENT_RE = /<!--(.*?)-->/m
+ HTML_INSTRUCTION_RE = /<\?(.*?)\?>/m
+ HTML_CDATA_RE = /<!\[CDATA\[(.*?)\]\]>/m
+ HTML_ATTRIBUTE_RE = /\s*(#{REXML::Parsers::BaseParser::UNAME_STR})(?:\s*=\s*(?:(\p{Word}+)|("|')(.*?)\3))?/m
+ HTML_TAG_RE = /<((?>#{REXML::Parsers::BaseParser::UNAME_STR}))\s*((?>\s+#{REXML::Parsers::BaseParser::UNAME_STR}(?:\s*=\s*(?:\p{Word}+|("|').*?\3))?)*)\s*(\/)?>/m
+ HTML_TAG_CLOSE_RE = /<\/(#{REXML::Parsers::BaseParser::UNAME_STR})\s*>/m
+ HTML_ENTITY_RE = /&([\w:][\w.:-]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/
+
+ HTML_CONTENT_MODEL_BLOCK = %w[address applet article aside blockquote body
+ dd details div dl fieldset figure figcaption
+ footer form header hgroup iframe li main
+ map menu nav noscript object section summary td]
+ HTML_CONTENT_MODEL_SPAN = %w[a abbr acronym b bdo big button cite caption del dfn dt em
+ h1 h2 h3 h4 h5 h6 i ins label legend optgroup p q rb rbc
+ rp rt rtc ruby select small span strong sub sup th tt]
+ HTML_CONTENT_MODEL_RAW = %w[script style math option textarea pre code kbd samp var]
+ # The following elements are also parsed as raw since they need child elements that cannot
+ # be expressed using kramdown syntax: colgroup table tbody thead tfoot tr ul ol
+
+ HTML_CONTENT_MODEL = Hash.new {|h, k| h[k] = :raw }
+ HTML_CONTENT_MODEL_BLOCK.each {|i| HTML_CONTENT_MODEL[i] = :block }
+ HTML_CONTENT_MODEL_SPAN.each {|i| HTML_CONTENT_MODEL[i] = :span }
+ HTML_CONTENT_MODEL_RAW.each {|i| HTML_CONTENT_MODEL[i] = :raw }
+
+ # Some HTML elements like script belong to both categories (i.e. are valid in block and
+ # span HTML) and don't appear therefore!
+ # script, textarea
+ HTML_SPAN_ELEMENTS = %w[a abbr acronym b big bdo br button cite code del dfn em i img input
+ ins kbd label mark option q rb rbc rp rt rtc ruby samp select small
+ span strong sub sup time tt u var]
+ HTML_BLOCK_ELEMENTS = %w[address article aside applet body blockquote caption col colgroup
+ dd div dl dt fieldset figcaption footer form h1 h2 h3 h4 h5 h6
+ header hgroup hr html head iframe legend menu li main map nav ol
+ optgroup p pre section summary table tbody td th thead tfoot tr ul]
+ HTML_ELEMENTS_WITHOUT_BODY = %w[area base br col command embed hr img input keygen link
+ meta param source track wbr]
+
+ HTML_ELEMENT = Hash.new(false)
+ (HTML_SPAN_ELEMENTS + HTML_BLOCK_ELEMENTS + HTML_ELEMENTS_WITHOUT_BODY +
+ HTML_CONTENT_MODEL.keys).each do |a|
+ HTML_ELEMENT[a] = true
+ end
+ end
+
+ # Contains the parsing methods. This module can be mixed into any parser to get HTML parsing
+ # functionality. The only thing that must be provided by the class are instance variable
+ # @stack for storing the needed state and @src (instance of StringScanner) for the actual
+ # parsing.
+ module Parser
+
+ include Constants
+
+ # Process the HTML start tag that has already be scanned/checked via @src.
+ #
+ # Does the common processing steps and then yields to the caller for further processing
+ # (first parameter is the created element; the second parameter is +true+ if the HTML
+ # element is already closed, ie. contains no body; the third parameter specifies whether the
+ # body - and the end tag - need to be handled in case closed=false).
+ def handle_html_start_tag(line = nil) # :yields: el, closed, handle_body
+ name = @src[1]
+ name.downcase! if HTML_ELEMENT[name.downcase]
+ closed = !@src[4].nil?
+ attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[name])
+
+ el = Element.new(:html_element, name, attrs, category: :block)
+ el.options[:location] = line if line
+ @tree.children << el
+
+ if !closed && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value)
+ closed = true
+ end
+ if name == 'script' || name == 'style'
+ handle_raw_html_tag(name)
+ yield(el, false, false)
+ else
+ yield(el, closed, true)
+ end
+ end
+
+ # Parses the given string for HTML attributes and returns the resulting hash.
+ #
+ # If the optional +line+ parameter is supplied, it is used in warning messages.
+ #
+ # If the optional +in_html_tag+ parameter is set to +false+, attributes are not modified to
+ # contain only lowercase letters.
+ def parse_html_attributes(str, line = nil, in_html_tag = true)
+ attrs = {}
+ str.scan(HTML_ATTRIBUTE_RE).each do |attr, val, _sep, quoted_val|
+ attr.downcase! if in_html_tag
+ if attrs.key?(attr)
+ warning("Duplicate HTML attribute '#{attr}' on line #{line || '?'} - overwriting previous one")
+ end
+ attrs[attr] = val || quoted_val || ""
+ end
+ attrs
+ end
+
+ # Handle the raw HTML tag at the current position.
+ def handle_raw_html_tag(name)
+ curpos = @src.pos
+ if @src.scan_until(/(?=<\/#{name}\s*>)/mi)
+ add_text(extract_string(curpos...@src.pos, @src), @tree.children.last, :raw)
+ @src.scan(HTML_TAG_CLOSE_RE)
+ else
+ add_text(@src.rest, @tree.children.last, :raw)
+ @src.terminate
+ warning("Found no end tag for '#{name}' - auto-closing it")
+ end
+ end
+
+ HTML_RAW_START = /(?=<(#{REXML::Parsers::BaseParser::UNAME_STR}|\/|!--|\?|!\[CDATA\[))/ # :nodoc:
+
+ # Parse raw HTML from the current source position, storing the found elements in +el+.
+ # Parsing continues until one of the following criteria are fulfilled:
+ #
+ # - The end of the document is reached.
+ # - The matching end tag for the element +el+ is found (only used if +el+ is an HTML
+ # element).
+ #
+ # When an HTML start tag is found, processing is deferred to #handle_html_start_tag,
+ # providing the block given to this method.
+ def parse_raw_html(el, &block)
+ @stack.push(@tree)
+ @tree = el
+
+ done = false
+ while !@src.eos? && !done
+ if (result = @src.scan_until(HTML_RAW_START))
+ add_text(result, @tree, :text)
+ line = @src.current_line_number
+ if (result = @src.scan(HTML_COMMENT_RE))
+ @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line)
+ elsif (result = @src.scan(HTML_INSTRUCTION_RE))
+ @tree.children << Element.new(:xml_pi, result, nil, category: :block, location: line)
+ elsif @src.scan(HTML_CDATA_RE)
+ @tree.children << Element.new(:text, @src[1], nil, cdata: true, location: line)
+ elsif @src.scan(HTML_TAG_RE)
+ if method(:handle_html_start_tag).arity.abs >= 1
+ handle_html_start_tag(line, &block)
+ else
+ handle_html_start_tag(&block) # DEPRECATED: method needs to accept line number in 2.0
+ end
+ elsif @src.scan(HTML_TAG_CLOSE_RE)
+ if @tree.value == (HTML_ELEMENT[@tree.value] ? @src[1].downcase : @src[1])
+ done = true
+ else
+ add_text(@src.matched, @tree, :text)
+ warning("Found invalidly used HTML closing tag for '#{@src[1]}' on " \
+ "line #{line} - ignoring it")
+ end
+ else
+ add_text(@src.getch, @tree, :text)
+ end
+ else
+ add_text(@src.rest, @tree, :text)
+ @src.terminate
+ if @tree.type == :html_element
+ warning("Found no end tag for '#{@tree.value}' on line " \
+ "#{@tree.options[:location]} - auto-closing it")
+ end
+ done = true
+ end
+ end
+
+ @tree = @stack.pop
+ end
+
+ end
+
+ # Converts HTML elements to native elements if possible.
+ class ElementConverter
+
+ # :stopdoc:
+
+ include Constants
+ include ::Kramdown::Utils::Entities
+
+ REMOVE_TEXT_CHILDREN = %w[html head hgroup ol ul dl table colgroup tbody thead tfoot tr
+ select optgroup]
+ WRAP_TEXT_CHILDREN = %w[body section nav article aside header footer address div li dd
+ blockquote figure figcaption fieldset form]
+ REMOVE_WHITESPACE_CHILDREN = %w[body section nav article aside header footer address
+ div li dd blockquote figure figcaption td th fieldset form]
+ STRIP_WHITESPACE = %w[address article aside blockquote body caption dd div dl dt fieldset
+ figcaption form footer header h1 h2 h3 h4 h5 h6 legend li nav p
+ section td th]
+ SIMPLE_ELEMENTS = %w[em strong blockquote hr br img p thead tbody tfoot tr td th ul ol dl
+ li dl dt dd]
+
+ def initialize(root)
+ @root = root
+ end
+
+ def self.convert(root, el = root)
+ new(root).process(el)
+ end
+
+ # Convert the element +el+ and its children.
+ def process(el, do_conversion = true, preserve_text = false, parent = nil)
+ case el.type
+ when :xml_comment, :xml_pi
+ ptype = if parent.nil?
+ 'div'
+ else
+ case parent.type
+ when :html_element then parent.value
+ when :code_span then 'code'
+ when :code_block then 'pre'
+ when :header then 'h1'
+ else parent.type.to_s
+ end
+ end
+ el.options.replace(category: (HTML_CONTENT_MODEL[ptype] == :span ? :span : :block))
+ return
+ when :html_element
+ # do nothing
+ when :root
+ el.children.map! do |c|
+ if c.type == :text
+ process_text(c.value, !do_conversion)
+ else
+ process(c)
+ c
+ end
+ end.flatten!
+ remove_whitespace_children(el)
+ return
+ else return
+ end
+
+ mname = "convert_#{el.value}"
+ if do_conversion && self.class.method_defined?(mname)
+ send(mname, el)
+ else
+ type = el.value
+ remove_text_children(el) if do_conversion && REMOVE_TEXT_CHILDREN.include?(type)
+
+ if do_conversion && SIMPLE_ELEMENTS.include?(type)
+ set_basics(el, type.intern)
+ process_children(el, do_conversion, preserve_text)
+ else
+ process_html_element(el, do_conversion, preserve_text)
+ end
+
+ if do_conversion
+ strip_whitespace(el) if STRIP_WHITESPACE.include?(type)
+ remove_whitespace_children(el) if REMOVE_WHITESPACE_CHILDREN.include?(type)
+ wrap_text_children(el) if WRAP_TEXT_CHILDREN.include?(type)
+ end
+ end
+ end
+
+ def process_children(el, do_conversion = true, preserve_text = false)
+ el.children.map! do |c|
+ if c.type == :text
+ process_text(c.value, preserve_text || !do_conversion)
+ else
+ process(c, do_conversion, preserve_text, el)
+ c
+ end
+ end.flatten!
+ end
+
+ # Process the HTML text +raw+: compress whitespace (if +preserve+ is +false+) and convert
+ # entities in entity elements.
+ def process_text(raw, preserve = false)
+ raw.gsub!(/\s+/, ' ') unless preserve
+ src = Kramdown::Utils::StringScanner.new(raw)
+ result = []
+ until src.eos?
+ if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/o))
+ result << Element.new(:text, tmp)
+ src.scan(HTML_ENTITY_RE)
+ val = src[1] || src[2]&.to_i || src[3].hex
+ result << if %w[lsquo rsquo ldquo rdquo].include?(val)
+ Element.new(:smart_quote, val.intern)
+ elsif %w[mdash ndash hellip laquo raquo].include?(val)
+ Element.new(:typographic_sym, val.intern)
+ else
+ begin
+ Element.new(:entity, entity(val), nil, original: src.matched)
+ rescue ::Kramdown::Error
+ src.pos -= src.matched_size - 1
+ Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp'))
+ end
+ end
+ else
+ result << Element.new(:text, src.rest)
+ src.terminate
+ end
+ end
+ result
+ end
+
+ def process_html_element(el, do_conversion = true, preserve_text = false)
+ el.options.replace(category: HTML_SPAN_ELEMENTS.include?(el.value) ? :span : :block,
+ content_model: (do_conversion ? HTML_CONTENT_MODEL[el.value] : :raw))
+ process_children(el, do_conversion, preserve_text)
+ end
+
+ def remove_text_children(el)
+ el.children.delete_if {|c| c.type == :text }
+ end
+
+ def wrap_text_children(el)
+ tmp = []
+ last_is_p = false
+ el.children.each do |c|
+ if !c.block? || c.type == :text
+ unless last_is_p
+ tmp << Element.new(:p, nil, nil, transparent: true)
+ last_is_p = true
+ end
+ tmp.last.children << c
+ tmp
+ else
+ tmp << c
+ last_is_p = false
+ end
+ end
+ el.children = tmp
+ end
+
+ def strip_whitespace(el)
+ return if el.children.empty?
+ if el.children.first.type == :text
+ el.children.first.value.lstrip!
+ end
+ if el.children.last.type == :text
+ el.children.last.value.rstrip!
+ end
+ end
+
+ def remove_whitespace_children(el)
+ i = -1
+ el.children = el.children.reject do |c|
+ i += 1
+ c.type == :text && c.value.strip.empty? &&
+ (i == 0 || i == el.children.length - 1 || (el.children[i - 1].block? &&
+ el.children[i + 1].block?))
+ end
+ end
+
+ def set_basics(el, type, opts = {})
+ el.type = type
+ el.options.replace(opts)
+ el.value = nil
+ end
+
+ def extract_text(el, raw)
+ raw << el.value.to_s if el.type == :text
+ el.children.each {|c| extract_text(c, raw) }
+ end
+
+ def convert_textarea(el)
+ process_html_element(el, true, true)
+ end
+
+ def convert_a(el)
+ if el.attr['href']
+ set_basics(el, :a)
+ process_children(el)
+ else
+ process_html_element(el, false)
+ end
+ end
+
+ EMPHASIS_TYPE_MAP = {'em' => :em, 'i' => :em, 'strong' => :strong, 'b' => :strong}
+ def convert_em(el)
+ text = +''
+ extract_text(el, text)
+ if text =~ /\A\s/ || text =~ /\s\z/
+ process_html_element(el, false)
+ else
+ set_basics(el, EMPHASIS_TYPE_MAP[el.value])
+ process_children(el)
+ end
+ end
+ %w[b strong i].each do |i|
+ alias_method("convert_#{i}".to_sym, :convert_em)
+ end
+
+ def convert_h1(el)
+ set_basics(el, :header, level: el.value[1..1].to_i)
+ extract_text(el, el.options[:raw_text] = +'')
+ process_children(el)
+ end
+ %w[h2 h3 h4 h5 h6].each do |i|
+ alias_method("convert_#{i}".to_sym, :convert_h1)
+ end
+
+ def convert_code(el)
+ raw = +''
+ extract_text(el, raw)
+ result = process_text(raw, true)
+ begin
+ str = result.inject(+'') do |mem, c|
+ case c.type
+ when :text
+ mem << c.value
+ when :entity
+ mem << if [60, 62, 34, 38].include?(c.value.code_point)
+ c.value.code_point.chr
+ else
+ c.value.char
+ end
+ when :smart_quote, :typographic_sym
+ mem << entity(c.value.to_s).char
+ else
+ raise "Bug - please report"
+ end
+ end
+ result.clear
+ result << Element.new(:text, str)
+ rescue StandardError
+ end
+ if result.length > 1 || result.first.type != :text
+ process_html_element(el, false, true)
+ else
+ if el.value == 'code'
+ set_basics(el, :codespan)
+ el.attr['class']&.gsub!(/\s+\bhighlighter-\w+\b|\bhighlighter-\w+\b\s*/, '')
+ else
+ set_basics(el, :codeblock)
+ if el.children.size == 1 && el.children.first.value == 'code'
+ value = (el.children.first.attr['class'] || '').scan(/\blanguage-\S+/).first
+ el.attr['class'] = "#{value} #{el.attr['class']}".rstrip if value
+ end
+ end
+ el.value = result.first.value
+ el.children.clear
+ end
+ end
+ alias convert_pre convert_code
+
+ def convert_table(el)
+ unless is_simple_table?(el)
+ process_html_element(el, false)
+ return
+ end
+ remove_text_children(el)
+ process_children(el)
+ set_basics(el, :table)
+
+ calc_alignment = lambda do |c|
+ if c.type == :tr
+ el.options[:alignment] = c.children.map do |td|
+ if td.attr['style']
+ td.attr['style'].slice!(/(?:;\s*)?text-align:\s+(center|left|right)/)
+ td.attr.delete('style') if td.attr['style'].strip.empty?
+ $1 ? $1.to_sym : :default
+ else
+ :default
+ end
+ end
+ else
+ c.children.each {|cc| calc_alignment.call(cc) }
+ end
+ end
+ calc_alignment.call(el)
+ el.children.delete_if {|c| c.type == :html_element }
+
+ change_th_type = lambda do |c|
+ if c.type == :th
+ c.type = :td
+ else
+ c.children.each {|cc| change_th_type.call(cc) }
+ end
+ end
+ change_th_type.call(el)
+
+ if el.children.first.type == :tr
+ tbody = Element.new(:tbody)
+ tbody.children = el.children
+ el.children = [tbody]
+ end
+ end
+
+ def is_simple_table?(el)
+ only_phrasing_content = lambda do |c|
+ c.children.all? do |cc|
+ (cc.type == :text || !HTML_BLOCK_ELEMENTS.include?(cc.value)) && only_phrasing_content.call(cc)
+ end
+ end
+ check_cells = proc do |c|
+ if c.value == 'th' || c.value == 'td'
+ return false unless only_phrasing_content.call(c)
+ else
+ c.children.each {|cc| check_cells.call(cc) }
+ end
+ end
+ check_cells.call(el)
+
+ nr_cells = 0
+ check_nr_cells = lambda do |t|
+ if t.value == 'tr'
+ count = t.children.count {|cc| cc.value == 'th' || cc.value == 'td' }
+ if count != nr_cells
+ if nr_cells == 0
+ nr_cells = count
+ else
+ nr_cells = -1
+ break
+ end
+ end
+ else
+ t.children.each {|cc| check_nr_cells.call(cc) }
+ end
+ end
+ check_nr_cells.call(el)
+ return false if nr_cells == -1 || nr_cells == 0
+
+ alignment = nil
+ check_alignment = proc do |t|
+ if t.value == 'tr'
+ cur_alignment = t.children.select {|cc| cc.value == 'th' || cc.value == 'td' }.map do |cell|
+ md = /text-align:\s+(center|left|right|justify|inherit)/.match(cell.attr['style'].to_s)
+ return false if md && (md[1] == 'justify' || md[1] == 'inherit')
+ md.nil? ? :default : md[1]
+ end
+ alignment = cur_alignment if alignment.nil?
+ return false if alignment != cur_alignment
+ else
+ t.children.each {|cc| check_alignment.call(cc) }
+ end
+ end
+ check_alignment.call(el)
+
+ check_rows = lambda do |t, type|
+ t.children.all? do |r|
+ (r.value == 'tr' || r.type == :text) && r.children.all? {|c| c.value == type || c.type == :text }
+ end
+ end
+ check_rows.call(el, 'td') ||
+ (el.children.all? do |t|
+ t.type == :text || (t.value == 'thead' && check_rows.call(t, 'th')) ||
+ ((t.value == 'tfoot' || t.value == 'tbody') && check_rows.call(t, 'td'))
+ end && el.children.any? {|t| t.value == 'tbody' })
+ end
+
+ def convert_script(el)
+ if is_math_tag?(el)
+ handle_math_tag(el)
+ else
+ process_html_element(el)
+ end
+ end
+
+ def is_math_tag?(el)
+ el.attr['type'].to_s =~ /\bmath\/tex\b/
+ end
+
+ def handle_math_tag(el)
+ set_basics(el, :math, category: (el.attr['type'].include?("mode=display") ? :block : :span))
+ el.value = el.children.shift.value.sub(/\A(?:%\s*)?<!\[CDATA\[\n?(.*?)(?:\s%)?\]\]>\z/m, '\1')
+ el.attr.delete('type')
+ end
+
+ end
+
+ include Parser
+
+ # Parse the source string provided on initialization as HTML document.
+ def parse
+ @stack, @tree = [], @root
+ @src = Kramdown::Utils::StringScanner.new(adapt_source(source))
+
+ while true
+ if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/o))
+ @tree.children << Element.new(:xml_pi, result.strip, nil, category: :block)
+ elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/o))
+ # ignore the doctype
+ elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/o))
+ @tree.children << Element.new(:xml_comment, result.strip, nil, category: :block)
+ else
+ break
+ end
+ end
+
+ tag_handler = lambda do |c, closed, handle_body|
+ parse_raw_html(c, &tag_handler) if !closed && handle_body
+ end
+ parse_raw_html(@tree, &tag_handler)
+
+ ElementConverter.convert(@tree)
+ end
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb
new file mode 100644
index 0000000..a8f480b
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb
@@ -0,0 +1,377 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'strscan'
+require 'stringio'
+require 'kramdown/parser'
+
+# TODO: use [[:alpha:]] in all regexp to allow parsing of international values in 1.9.1
+# NOTE: use @src.pre_match only before other check/match?/... operations, otherwise the content is changed
+
+module Kramdown
+
+ module Parser
+
+ # Used for parsing a document in kramdown format.
+ #
+ # If you want to extend the functionality of the parser, you need to do the following:
+ #
+ # * Create a new subclass
+ # * add the needed parser methods
+ # * modify the @block_parsers and @span_parsers variables and add the names of your parser
+ # methods
+ #
+ # Here is a small example for an extended parser class that parses ERB style tags as raw text if
+ # they are used as span-level elements (an equivalent block-level parser should probably also be
+ # made to handle the block case):
+ #
+ # require 'kramdown/parser/kramdown'
+ #
+ # class Kramdown::Parser::ERBKramdown < Kramdown::Parser::Kramdown
+ #
+ # def initialize(source, options)
+ # super
+ # @span_parsers.unshift(:erb_tags)
+ # end
+ #
+ # ERB_TAGS_START = /<%.*?%>/
+ #
+ # def parse_erb_tags
+ # @src.pos += @src.matched_size
+ # @tree.children << Element.new(:raw, @src.matched)
+ # end
+ # define_parser(:erb_tags, ERB_TAGS_START, '<%')
+ #
+ # end
+ #
+ # The new parser can be used like this:
+ #
+ # require 'kramdown/document'
+ # # require the file with the above parser class
+ #
+ # Kramdown::Document.new(input_text, :input => 'ERBKramdown').to_html
+ #
+ class Kramdown < Base
+
+ include ::Kramdown
+
+ # Create a new Kramdown parser object with the given +options+.
+ def initialize(source, options)
+ super
+
+ reset_env
+
+ @alds = {}
+ @footnotes = {}
+ @link_defs = {}
+ update_link_definitions(@options[:link_defs])
+
+ @block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header,
+ :horizontal_rule, :list, :definition_list, :block_html, :setext_header,
+ :block_math, :table, :footnote_definition, :link_definition,
+ :abbrev_definition, :block_extensions, :eob_marker, :paragraph]
+ @span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link,
+ :smart_quotes, :inline_math, :span_extensions, :html_entity,
+ :typographic_syms, :line_break, :escaped_chars]
+
+ @span_pattern_cache ||= Hash.new {|h, k| h[k] = {} }
+ end
+ private_class_method(:new, :allocate)
+
+ # The source string provided on initialization is parsed into the @root element.
+ def parse
+ configure_parser
+ parse_blocks(@root, adapt_source(source))
+ update_tree(@root)
+ correct_abbreviations_attributes
+ replace_abbreviations(@root)
+ @footnotes.each do |_name, data|
+ update_tree(data[:content])
+ replace_abbreviations(data[:content])
+ end
+ footnote_count = 0
+ @footnotes.each do |name, data|
+ (footnote_count += 1; next) if data.key?(:marker)
+ line = data[:content].options[:location]
+ warning("Footnote definition for '#{name}' on line #{line} is unreferenced - ignoring")
+ end
+ @root.options[:footnote_count] = footnote_count
+ end
+
+ protected
+
+ # :doc:
+ #
+ # Update the parser specific link definitions with the data from +link_defs+ (the value of the
+ # :link_defs option).
+ #
+ # The parameter +link_defs+ is a hash where the keys are possibly unnormalized link IDs and
+ # the values are two element arrays consisting of the link target and a title (can be +nil+).
+ def update_link_definitions(link_defs)
+ link_defs.each {|k, v| @link_defs[normalize_link_id(k)] = v }
+ end
+
+ # Adapt the object to allow parsing like specified in the options.
+ def configure_parser
+ @parsers = {}
+ (@block_parsers + @span_parsers).each do |name|
+ if self.class.has_parser?(name)
+ @parsers[name] = self.class.parser(name)
+ else
+ raise Kramdown::Error, "Unknown parser: #{name}"
+ end
+ end
+ @span_start, @span_start_re = span_parser_regexps
+ end
+
+ # Create the needed span parser regexps.
+ def span_parser_regexps(parsers = @span_parsers)
+ span_start = /#{parsers.map {|name| @parsers[name].span_start }.join('|')}/
+ [span_start, /(?=#{span_start})/]
+ end
+
+ # Parse all block-level elements in +text+ into the element +el+.
+ def parse_blocks(el, text = nil)
+ @stack.push([@tree, @src, @block_ial])
+ @tree, @block_ial = el, nil
+ @src = (text.nil? ? @src : ::Kramdown::Utils::StringScanner.new(text, el.options[:location]))
+
+ status = catch(:stop_block_parsing) do
+ until @src.eos?
+ @block_parsers.any? do |name|
+ if @src.check(@parsers[name].start_re)
+ send(@parsers[name].method)
+ else
+ false
+ end
+ end || begin
+ warning('Warning: this should not occur - no block parser handled the line')
+ add_text(@src.scan(/.*\n/))
+ end
+ end
+ end
+
+ @tree, @src, @block_ial = *@stack.pop
+ status
+ end
+
+ # Update the tree by parsing all :+raw_text+ elements with the span-level parser (resets the
+ # environment) and by updating the attributes from the IALs.
+ def update_tree(element)
+ last_blank = nil
+ element.children.map! do |child|
+ case child.type
+ when :raw_text
+ last_blank = nil
+ reset_env(src: ::Kramdown::Utils::StringScanner.new(child.value, element.options[:location]),
+ text_type: :text)
+ parse_spans(child)
+ child.children
+ when :eob
+ update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial]
+ []
+ when :blank
+ if last_blank
+ last_blank.value << child.value
+ []
+ else
+ last_blank = child
+ child
+ end
+ else
+ last_blank = nil
+ update_tree(child)
+ update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial]
+ # DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be
+ # the default behaviour
+ if child.type == :dt || (child.type == :header && @options[:auto_id_stripping])
+ update_raw_text(child)
+ end
+ child
+ end
+ end.flatten!
+ end
+
+ def span_pattern_cache(stop_re, span_start)
+ @span_pattern_cache[stop_re][span_start] ||= /(?=#{Regexp.union(stop_re, span_start)})/
+ end
+ private :span_pattern_cache
+
+ # Parse all span-level elements in the source string of @src into +el+.
+ #
+ # If the parameter +stop_re+ (a regexp) is used, parsing is immediately stopped if the regexp
+ # matches and if no block is given or if a block is given and it returns +true+.
+ #
+ # The parameter +parsers+ can be used to specify the (span-level) parsing methods that should
+ # be used for parsing.
+ #
+ # The parameter +text_type+ specifies the type which should be used for created text nodes.
+ def parse_spans(el, stop_re = nil, parsers = nil, text_type = @text_type)
+ @stack.push([@tree, @text_type]) unless @tree.nil?
+ @tree, @text_type = el, text_type
+
+ span_start = @span_start
+ span_start_re = @span_start_re
+ span_start, span_start_re = span_parser_regexps(parsers) if parsers
+ parsers ||= @span_parsers
+
+ used_re = (stop_re.nil? ? span_start_re : span_pattern_cache(stop_re, span_start))
+ stop_re_found = false
+ while !@src.eos? && !stop_re_found
+ if (result = @src.scan_until(used_re))
+ add_text(result)
+ if stop_re && @src.check(stop_re)
+ stop_re_found = (block_given? ? yield : true)
+ end
+ processed = parsers.any? do |name|
+ if @src.check(@parsers[name].start_re)
+ send(@parsers[name].method)
+ true
+ else
+ false
+ end
+ end unless stop_re_found
+ add_text(@src.getch) if !processed && !stop_re_found
+ else
+ (add_text(@src.rest); @src.terminate) unless stop_re
+ break
+ end
+ end
+
+ @tree, @text_type = @stack.pop
+
+ stop_re_found
+ end
+
+ # Reset the current parsing environment. The parameter +env+ can be used to set initial
+ # values for one or more environment variables.
+ def reset_env(opts = {})
+ opts = {text_type: :raw_text, stack: []}.merge(opts)
+ @src = opts[:src]
+ @tree = opts[:tree]
+ @block_ial = opts[:block_ial]
+ @stack = opts[:stack]
+ @text_type = opts[:text_type]
+ end
+
+ # Return the current parsing environment.
+ def save_env
+ [@src, @tree, @block_ial, @stack, @text_type]
+ end
+
+ # Restore the current parsing environment.
+ def restore_env(env)
+ @src, @tree, @block_ial, @stack, @text_type = *env
+ end
+
+ # Update the given attributes hash +attr+ with the information from the inline attribute list
+ # +ial+ and all referenced ALDs.
+ def update_attr_with_ial(attr, ial)
+ ial[:refs]&.each do |ref|
+ update_attr_with_ial(attr, ref) if (ref = @alds[ref])
+ end
+ ial.each do |k, v|
+ if k == IAL_CLASS_ATTR
+ attr[k] = "#{attr[k]} #{v}".lstrip
+ elsif k.kind_of?(String)
+ attr[k] = v
+ end
+ end
+ end
+
+ # Update the raw text for automatic ID generation.
+ def update_raw_text(item)
+ raw_text = +''
+
+ append_text = lambda do |child|
+ if child.type == :text
+ raw_text << child.value
+ else
+ child.children.each {|c| append_text.call(c) }
+ end
+ end
+
+ append_text.call(item)
+ item.options[:raw_text] = raw_text
+ end
+
+ # Create a new block-level element, taking care of applying a preceding block IAL if it
+ # exists. This method should always be used for creating a block-level element!
+ def new_block_el(*args)
+ el = Element.new(*args)
+ if @block_ial
+ el.options[:ial] = @block_ial
+ @block_ial = nil
+ end
+ el
+ end
+
+ @@parsers = {}
+
+ # Struct class holding all the needed data for one block/span-level parser method.
+ Data = Struct.new(:name, :start_re, :span_start, :method)
+
+ # Add a parser method
+ #
+ # * with the given +name+,
+ # * using +start_re+ as start regexp
+ # * and, for span parsers, +span_start+ as a String that can be used in a regexp and
+ # which identifies the starting character(s)
+ #
+ # to the registry. The method name is automatically derived from the +name+ or can explicitly
+ # be set by using the +meth_name+ parameter.
+ def self.define_parser(name, start_re, span_start = nil, meth_name = "parse_#{name}")
+ raise "A parser with the name #{name} already exists!" if @@parsers.key?(name)
+ @@parsers[name] = Data.new(name, start_re, span_start, meth_name)
+ end
+
+ # Return the Data structure for the parser +name+.
+ def self.parser(name = nil)
+ @@parsers[name]
+ end
+
+ # Return +true+ if there is a parser called +name+.
+ def self.has_parser?(name)
+ @@parsers.key?(name)
+ end
+
+ # Regexp for matching indentation (one tab or four spaces)
+ INDENT = /^(?:\t| {4})/
+ # Regexp for matching the optional space (zero or up to three spaces)
+ OPT_SPACE = / {0,3}/
+
+ require 'kramdown/parser/kramdown/blank_line'
+ require 'kramdown/parser/kramdown/eob'
+ require 'kramdown/parser/kramdown/paragraph'
+ require 'kramdown/parser/kramdown/header'
+ require 'kramdown/parser/kramdown/blockquote'
+ require 'kramdown/parser/kramdown/table'
+ require 'kramdown/parser/kramdown/codeblock'
+ require 'kramdown/parser/kramdown/horizontal_rule'
+ require 'kramdown/parser/kramdown/list'
+ require 'kramdown/parser/kramdown/link'
+ require 'kramdown/parser/kramdown/extensions'
+ require 'kramdown/parser/kramdown/footnote'
+ require 'kramdown/parser/kramdown/html'
+ require 'kramdown/parser/kramdown/escaped_chars'
+ require 'kramdown/parser/kramdown/html_entity'
+ require 'kramdown/parser/kramdown/line_break'
+ require 'kramdown/parser/kramdown/typographic_symbol'
+ require 'kramdown/parser/kramdown/autolink'
+ require 'kramdown/parser/kramdown/codespan'
+ require 'kramdown/parser/kramdown/emphasis'
+ require 'kramdown/parser/kramdown/smart_quotes'
+ require 'kramdown/parser/kramdown/math'
+ require 'kramdown/parser/kramdown/abbreviation'
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb
new file mode 100644
index 0000000..dbde8d2
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb
@@ -0,0 +1,80 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ ABBREV_DEFINITION_START = /^#{OPT_SPACE}\*\[(.+?)\]:(.*?)\n/
+
+ # Parse the link definition at the current location.
+ def parse_abbrev_definition
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ abbrev_id, abbrev_text = @src[1], @src[2]
+ abbrev_text.strip!
+ if @root.options[:abbrev_defs][abbrev_id]
+ warning("Duplicate abbreviation ID '#{abbrev_id}' on line #{start_line_number} " \
+ "- overwriting")
+ end
+ @tree.children << new_block_el(:eob, :abbrev_def)
+ @root.options[:abbrev_defs][abbrev_id] = abbrev_text
+ @root.options[:abbrev_attr][abbrev_id] = @tree.children.last
+ true
+ end
+ define_parser(:abbrev_definition, ABBREV_DEFINITION_START)
+
+ # Correct abbreviation attributes.
+ def correct_abbreviations_attributes
+ @root.options[:abbrev_attr].keys.each do |k|
+ @root.options[:abbrev_attr][k] = @root.options[:abbrev_attr][k].attr
+ end
+ end
+
+ # Replace the abbreviation text with elements.
+ def replace_abbreviations(el, regexps = nil)
+ return if @root.options[:abbrev_defs].empty?
+ unless regexps
+ sorted_abbrevs = @root.options[:abbrev_defs].keys.sort {|a, b| b.length <=> a.length }
+ regexps = [Regexp.union(*sorted_abbrevs.map do |k|
+ /#{Regexp.escape(k).gsub(/\\\s/, "[\\s\\p{Z}]+").force_encoding(Encoding::UTF_8)}/
+ end)]
+ regexps << /(?=(?:\W|^)#{regexps.first}(?!\w))/ # regexp should only match on word boundaries
+ end
+ el.children.map! do |child|
+ if child.type == :text && el.options[:content_model] != :raw
+ if child.value.match?(regexps.first)
+ result = []
+ strscan = Kramdown::Utils::StringScanner.new(child.value, child.options[:location])
+ text_lineno = strscan.current_line_number
+ while (temp = strscan.scan_until(regexps.last))
+ abbr_lineno = strscan.current_line_number
+ abbr = strscan.scan(regexps.first) # begin of line case of abbr with \W char as first one
+ if abbr.nil?
+ temp << strscan.scan(/\W|^/)
+ abbr = strscan.scan(regexps.first)
+ end
+ result << Element.new(:text, temp, nil, location: text_lineno)
+ result << Element.new(:abbreviation, abbr, nil, location: abbr_lineno)
+ text_lineno = strscan.current_line_number
+ end
+ result << Element.new(:text, strscan.rest, nil, location: text_lineno)
+ else
+ child
+ end
+ else
+ replace_abbreviations(child, regexps)
+ child
+ end
+ end.flatten!
+ end
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb
new file mode 100644
index 0000000..8fa974e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb
@@ -0,0 +1,31 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ ACHARS = '[[:alnum:]]-_.'
+ AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[#{ACHARS}]+?@[#{ACHARS}]+?)>"
+ AUTOLINK_START = /#{AUTOLINK_START_STR}/u
+
+ # Parse the autolink at the current location.
+ def parse_autolink
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1])
+ el = Element.new(:a, nil, {'href' => href}, location: start_line_number)
+ add_text(@src[1].sub(/^mailto:/, ''), el)
+ @tree.children << el
+ end
+ define_parser(:autolink, AUTOLINK_START, '<')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb
new file mode 100644
index 0000000..bb8989a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb
@@ -0,0 +1,30 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ BLANK_LINE = /(?>^\s*\n)+/
+
+ # Parse the blank line at the current postition.
+ def parse_blank_line
+ @src.pos += @src.matched_size
+ if (last_child = @tree.children.last) && last_child.type == :blank
+ last_child.value << @src.matched
+ else
+ @tree.children << new_block_el(:blank, @src.matched)
+ end
+ true
+ end
+ define_parser(:blank_line, BLANK_LINE)
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb
new file mode 100644
index 0000000..daa0884
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb
@@ -0,0 +1,34 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/extensions'
+require 'kramdown/parser/kramdown/blank_line'
+require 'kramdown/parser/kramdown/eob'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|#{IAL_BLOCK_START}|\Z/
+
+ # Return +true+ if we are after a block boundary.
+ def after_block_boundary?
+ last_child = @tree.children.last
+ !last_child || last_child.type == :blank ||
+ (last_child.type == :eob && last_child.value.nil?) || @block_ial
+ end
+
+ # Return +true+ if we are before a block boundary.
+ def before_block_boundary?
+ @src.check(self.class::BLOCK_BOUNDARY)
+ end
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb
new file mode 100644
index 0000000..8934c5a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb
@@ -0,0 +1,38 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/blank_line'
+require 'kramdown/parser/kramdown/extensions'
+require 'kramdown/parser/kramdown/eob'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/
+
+ # Parse the blockquote at the current location.
+ def parse_blockquote
+ start_line_number = @src.current_line_number
+ result = @src.scan(PARAGRAPH_MATCH)
+ until @src.match?(self.class::LAZY_END)
+ result << @src.scan(PARAGRAPH_MATCH)
+ end
+ result.gsub!(BLOCKQUOTE_START, '')
+
+ el = new_block_el(:blockquote, nil, nil, location: start_line_number)
+ @tree.children << el
+ parse_blocks(el, result)
+ true
+ end
+ define_parser(:blockquote, BLOCKQUOTE_START)
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb
new file mode 100644
index 0000000..b2b76d9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb
@@ -0,0 +1,57 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/blank_line'
+require 'kramdown/parser/kramdown/extensions'
+require 'kramdown/parser/kramdown/eob'
+require 'kramdown/parser/kramdown/paragraph'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ CODEBLOCK_START = INDENT
+ CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+(?:(?!#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START})^[ \t]*\S.*\n)*)*/
+
+ # Parse the indented codeblock at the current location.
+ def parse_codeblock
+ start_line_number = @src.current_line_number
+ data = @src.scan(self.class::CODEBLOCK_MATCH)
+ data.gsub!(/\n( {0,3}\S)/, ' \\1')
+ data.gsub!(INDENT, '')
+ @tree.children << new_block_el(:codeblock, data, nil, location: start_line_number)
+ true
+ end
+ define_parser(:codeblock, CODEBLOCK_START)
+
+ FENCED_CODEBLOCK_START = /^~{3,}/
+ FENCED_CODEBLOCK_MATCH = /^((~){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^\1\2*\s*?\n/m
+
+ # Parse the fenced codeblock at the current location.
+ def parse_codeblock_fenced
+ if @src.check(self.class::FENCED_CODEBLOCK_MATCH)
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ el = new_block_el(:codeblock, @src[5], nil, location: start_line_number, fenced: true)
+ lang = @src[3].to_s.strip
+ unless lang.empty?
+ el.options[:lang] = lang
+ el.attr['class'] = "language-#{@src[4]}"
+ end
+ @tree.children << el
+ true
+ else
+ false
+ end
+ end
+ define_parser(:codeblock_fenced, FENCED_CODEBLOCK_START)
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb
new file mode 100644
index 0000000..450d1ef
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb
@@ -0,0 +1,58 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ CODESPAN_DELIMITER = /`+/
+
+ # Parse the codespan at the current scanner location.
+ def parse_codespan
+ start_line_number = @src.current_line_number
+ result = @src.scan(CODESPAN_DELIMITER)
+ simple = (result.length == 1)
+ saved_pos = @src.save_pos
+
+ if simple && @src.pre_match =~ /\s\Z|\A\Z/ && @src.match?(/\s/)
+ add_text(result)
+ return
+ end
+
+ # assign static regex to avoid allocating the same on every instance
+ # where +result+ equals a single-backtick. Interpolate otherwise.
+ if result == '`'
+ scan_pattern = /`/
+ str_sub_pattern = /`\Z/
+ else
+ scan_pattern = /#{result}/
+ str_sub_pattern = /#{result}\Z/
+ end
+
+ if (text = @src.scan_until(scan_pattern))
+ text.sub!(str_sub_pattern, '')
+ unless simple
+ text = text[1..-1] if text[0..0] == ' '
+ text = text[0..-2] if text[-1..-1] == ' '
+ end
+ @tree.children << Element.new(:codespan, text, nil, {
+ codespan_delimiter: result,
+ location: start_line_number,
+ })
+
+ else
+ @src.revert_pos(saved_pos)
+ add_text(result)
+ end
+ end
+ define_parser(:codespan, CODESPAN_DELIMITER, '`')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb
new file mode 100644
index 0000000..bedeaa0
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb
@@ -0,0 +1,66 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ EMPHASIS_START = /(?:\*\*?|__?)/
+
+ # Parse the emphasis at the current location.
+ def parse_emphasis
+ start_line_number = @src.current_line_number
+ saved_pos = @src.save_pos
+
+ result = @src.scan(EMPHASIS_START)
+ element = (result.length == 2 ? :strong : :em)
+ type = result[0..0]
+
+ if (type == '_' && @src.pre_match =~ /[[:alpha:]]-?[[:alpha:]]*_*\z/) || @src.check(/\s/) ||
+ @tree.type == element || @stack.any? {|el, _| el.type == element }
+ add_text(result)
+ return
+ end
+
+ warnings_pos = @warnings.size
+ sub_parse = lambda do |delim, elem|
+ el = Element.new(elem, nil, nil, location: start_line_number)
+ stop_re = /#{Regexp.escape(delim)}/
+ found = parse_spans(el, stop_re) do
+ (@src.pre_match[-1, 1] !~ /\s/) &&
+ (elem != :em || !@src.match?(/#{Regexp.escape(delim * 2)}(?!#{Regexp.escape(delim)})/)) &&
+ (type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && !el.children.empty?
+ end
+ [found, el, stop_re]
+ end
+
+ found, el, stop_re = sub_parse.call(result, element)
+ if !found && element == :strong && @tree.type != :em
+ @src.revert_pos(saved_pos)
+ @src.pos += 1
+ found, el, stop_re = sub_parse.call(type, :em)
+ end
+ if found
+ # Useful for implementing underlines.
+ el.options[:char] = type
+
+ @src.scan(stop_re)
+ @tree.children << el
+ else
+ @warnings.slice!(0...warnings_pos)
+ @src.revert_pos(saved_pos)
+ @src.pos += result.length
+ add_text(result)
+ end
+ end
+ define_parser(:emphasis, EMPHASIS_START, '\*|_')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb
new file mode 100644
index 0000000..f151a9a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb
@@ -0,0 +1,26 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ EOB_MARKER = /^\^\s*?\n/
+
+ # Parse the EOB marker at the current location.
+ def parse_eob_marker
+ @src.pos += @src.matched_size
+ @tree.children << new_block_el(:eob)
+ true
+ end
+ define_parser(:eob_marker, EOB_MARKER)
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb
new file mode 100644
index 0000000..d63ada9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb
@@ -0,0 +1,25 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ ESCAPED_CHARS = /\\([\\.*_+`<>()\[\]{}#!:|"'$=-])/
+
+ # Parse the backslash-escaped character at the current location.
+ def parse_escaped_chars
+ @src.pos += @src.matched_size
+ add_text(@src[1])
+ end
+ define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb
new file mode 100644
index 0000000..3d29115
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb
@@ -0,0 +1,214 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ IAL_CLASS_ATTR = 'class'
+
+ # Parse the string +str+ and extract all attributes and add all found attributes to the hash
+ # +opts+.
+ def parse_attribute_list(str, opts)
+ return if str.strip.empty? || str.strip == ':'
+ attrs = str.scan(ALD_TYPE_ANY)
+ attrs.each do |key, sep, val, ref, id_and_or_class, _, _|
+ if ref
+ (opts[:refs] ||= []) << ref
+ elsif id_and_or_class
+ id_and_or_class.scan(ALD_TYPE_ID_OR_CLASS).each do |id_attr, class_attr|
+ if class_attr
+ opts[IAL_CLASS_ATTR] = "#{opts[IAL_CLASS_ATTR]} #{class_attr}".lstrip
+ else
+ opts['id'] = id_attr
+ end
+ end
+ else
+ val.gsub!(/\\(\}|#{sep})/, "\\1")
+ opts[key] = val
+ end
+ end
+ warning("No or invalid attributes found in IAL/ALD content: #{str}") if attrs.empty?
+ end
+
+ # Update the +ial+ with the information from the inline attribute list +opts+.
+ def update_ial_with_ial(ial, opts)
+ (ial[:refs] ||= []).concat(opts[:refs]) if opts.key?(:refs)
+ opts.each do |k, v|
+ if k == IAL_CLASS_ATTR
+ ial[k] = "#{ial[k]} #{v}".lstrip
+ elsif k.kind_of?(String)
+ ial[k] = v
+ end
+ end
+ end
+
+ # Parse the generic extension at the current point. The parameter +type+ can either be :block
+ # or :span depending whether we parse a block or span extension tag.
+ def parse_extension_start_tag(type)
+ saved_pos = @src.save_pos
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+
+ error_block = lambda do |msg|
+ warning(msg)
+ @src.revert_pos(saved_pos)
+ add_text(@src.getch) if type == :span
+ false
+ end
+
+ if @src[4] || @src.matched == '{:/}'
+ name = (@src[4] ? "for '#{@src[4]}' " : '')
+ return error_block.call("Invalid extension stop tag #{name} found on line " \
+ "#{start_line_number} - ignoring it")
+ end
+
+ ext = @src[1]
+ opts = {}
+ body = nil
+ parse_attribute_list(@src[2] || '', opts)
+
+ unless @src[3]
+ stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/)
+ if (result = @src.scan_until(stop_re))
+ body = result.sub!(stop_re, '')
+ body.chomp! if type == :block
+ else
+ return error_block.call("No stop tag for extension '#{ext}' found on line " \
+ "#{start_line_number} - ignoring it")
+ end
+ end
+
+ if handle_extension(ext, opts, body, type, start_line_number)
+ true
+ else
+ error_block.call("Invalid extension with name '#{ext}' specified on line " \
+ "#{start_line_number} - ignoring it")
+ end
+ end
+
+ def handle_extension(name, opts, body, type, line_no = nil)
+ case name
+ when 'comment'
+ if body.kind_of?(String)
+ @tree.children << Element.new(:comment, body, nil, category: type, location: line_no)
+ end
+ true
+ when 'nomarkdown'
+ if body.kind_of?(String)
+ @tree.children << Element.new(:raw, body, nil, category: type,
+ location: line_no, type: opts['type'].to_s.split(/\s+/))
+ end
+ true
+ when 'options'
+ opts.select do |k, v|
+ k = k.to_sym
+ if Kramdown::Options.defined?(k)
+ if @options[:forbidden_inline_options].include?(k) ||
+ k == :forbidden_inline_options
+ warning("Option #{k} may not be set inline")
+ next false
+ end
+
+ begin
+ val = Kramdown::Options.parse(k, v)
+ @options[k] = val
+ (@root.options[:options] ||= {})[k] = val
+ rescue StandardError
+ end
+ false
+ else
+ true
+ end
+ end.each do |k, _v|
+ warning("Unknown kramdown option '#{k}'")
+ end
+ @tree.children << new_block_el(:eob, :extension) if type == :block
+ true
+ else
+ false
+ end
+ end
+
+ ALD_ID_CHARS = /[\w-]/
+ ALD_ANY_CHARS = /\\\}|[^}]/
+ ALD_ID_NAME = /\w#{ALD_ID_CHARS}*/
+ ALD_CLASS_NAME = /[^\s.#]+/
+ ALD_TYPE_KEY_VALUE_PAIR = /(#{ALD_ID_NAME})=("|')((?:\\\}|\\\2|[^}\2])*?)\2/
+ ALD_TYPE_CLASS_NAME = /\.(#{ALD_CLASS_NAME})/
+ ALD_TYPE_ID_NAME = /#([A-Za-z][\w:-]*)/
+ ALD_TYPE_ID_OR_CLASS = /#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME}/
+ ALD_TYPE_ID_OR_CLASS_MULTI = /((?:#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME})+)/
+ ALD_TYPE_REF = /(#{ALD_ID_NAME})/
+ ALD_TYPE_ANY = /(?:\A|\s)(?:#{ALD_TYPE_KEY_VALUE_PAIR}|#{ALD_TYPE_REF}|#{ALD_TYPE_ID_OR_CLASS_MULTI})(?=\s|\Z)/
+ ALD_START = /^#{OPT_SPACE}\{:(#{ALD_ID_NAME}):(#{ALD_ANY_CHARS}+)\}\s*?\n/
+
+ EXT_STOP_STR = "\\{:/(%s)?\\}"
+ EXT_START_STR = "\\{::(\\w+)(?:\\s(#{ALD_ANY_CHARS}*?)|)(\\/)?\\}"
+ EXT_BLOCK_START = /^#{OPT_SPACE}(?:#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME})\s*?\n/
+ EXT_BLOCK_STOP_STR = "^#{OPT_SPACE}#{EXT_STOP_STR}\s*?\n"
+
+ IAL_BLOCK = /\{:(?!:|\/)(#{ALD_ANY_CHARS}+)\}\s*?\n/
+ IAL_BLOCK_START = /^#{OPT_SPACE}#{IAL_BLOCK}/
+
+ BLOCK_EXTENSIONS_START = /^#{OPT_SPACE}\{:/
+
+ # Parse one of the block extensions (ALD, block IAL or generic extension) at the current
+ # location.
+ def parse_block_extensions
+ if @src.scan(ALD_START)
+ parse_attribute_list(@src[2], @alds[@src[1]] ||= {})
+ @tree.children << new_block_el(:eob, :ald)
+ true
+ elsif @src.check(EXT_BLOCK_START)
+ parse_extension_start_tag(:block)
+ elsif @src.scan(IAL_BLOCK_START)
+ if (last_child = @tree.children.last) && last_child.type != :blank &&
+ (last_child.type != :eob ||
+ [:link_def, :abbrev_def, :footnote_def].include?(last_child.value))
+ parse_attribute_list(@src[1], last_child.options[:ial] ||= {})
+ @tree.children << new_block_el(:eob, :ial) unless @src.check(IAL_BLOCK_START)
+ else
+ parse_attribute_list(@src[1], @block_ial ||= {})
+ end
+ true
+ else
+ false
+ end
+ end
+ define_parser(:block_extensions, BLOCK_EXTENSIONS_START)
+
+ EXT_SPAN_START = /#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME}/
+ IAL_SPAN_START = /\{:(#{ALD_ANY_CHARS}+)\}/
+ SPAN_EXTENSIONS_START = /\{:/
+
+ # Parse the extension span at the current location.
+ def parse_span_extensions
+ if @src.check(EXT_SPAN_START)
+ parse_extension_start_tag(:span)
+ elsif @src.check(IAL_SPAN_START)
+ if (last_child = @tree.children.last) && last_child.type != :text
+ @src.pos += @src.matched_size
+ attr = {}
+ parse_attribute_list(@src[1], attr)
+ update_ial_with_ial(last_child.options[:ial] ||= {}, attr)
+ update_attr_with_ial(last_child.attr, attr)
+ else
+ warning("Found span IAL after text - ignoring it")
+ add_text(@src.getch)
+ end
+ else
+ add_text(@src.getch)
+ end
+ end
+ define_parser(:span_extensions, SPAN_EXTENSIONS_START, '\{:')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb
new file mode 100644
index 0000000..b45fc12
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb
@@ -0,0 +1,64 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/extensions'
+require 'kramdown/parser/kramdown/blank_line'
+require 'kramdown/parser/kramdown/codeblock'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/
+
+ # Parse the foot note definition at the current location.
+ def parse_footnote_definition
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+
+ el = Element.new(:footnote_def, nil, nil, location: start_line_number)
+ parse_blocks(el, @src[2].gsub(INDENT, ''))
+ if @footnotes[@src[1]]
+ warning("Duplicate footnote name '#{@src[1]}' on line #{start_line_number} - overwriting")
+ end
+ @tree.children << new_block_el(:eob, :footnote_def)
+ (@footnotes[@src[1]] = {})[:content] = el
+ @footnotes[@src[1]][:eob] = @tree.children.last
+ true
+ end
+ define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START)
+
+ FOOTNOTE_MARKER_START = /\[\^(#{ALD_ID_NAME})\]/
+
+ # Parse the footnote marker at the current location.
+ def parse_footnote_marker
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ fn_def = @footnotes[@src[1]]
+ if fn_def
+ if fn_def[:eob]
+ update_attr_with_ial(fn_def[:eob].attr, fn_def[:eob].options[:ial] || {})
+ fn_def[:attr] = fn_def[:eob].attr
+ fn_def[:options] = fn_def[:eob].options
+ fn_def.delete(:eob)
+ end
+ fn_def[:marker] ||= []
+ fn_def[:marker].push(Element.new(:footnote, fn_def[:content], fn_def[:attr],
+ fn_def[:options].merge(name: @src[1], location: start_line_number)))
+ @tree.children << fn_def[:marker].last
+ else
+ warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}")
+ add_text(@src.matched)
+ end
+ end
+ define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb
new file mode 100644
index 0000000..d490a46
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb
@@ -0,0 +1,70 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/block_boundary'
+require 'rexml/xmltokens'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ SETEXT_HEADER_START = /^#{OPT_SPACE}(?<contents>[^ \t].*)\n(?<level>[-=])[-=]*[ \t\r\f\v]*\n/
+
+ # Parse the Setext header at the current location.
+ def parse_setext_header
+ return false unless after_block_boundary?
+ text, id = parse_header_contents
+ return false if text.empty?
+ add_header(@src["level"] == '-' ? 2 : 1, text, id)
+ true
+ end
+ define_parser(:setext_header, SETEXT_HEADER_START)
+
+ ATX_HEADER_START = /^(?<level>\#{1,6})[\t ]*(?<contents>[^ \t].*)\n/
+
+ # Parse the Atx header at the current location.
+ def parse_atx_header
+ return false unless after_block_boundary?
+ text, id = parse_header_contents
+ text.sub!(/(?<!\\)#+\z/, '') && text.rstrip!
+ return false if text.empty?
+ add_header(@src["level"].length, text, id)
+ true
+ end
+ define_parser(:atx_header, ATX_HEADER_START)
+
+ protected
+
+ HEADER_ID = /[\t ]{#(?<id>#{REXML::XMLTokens::NAME_START_CHAR}#{REXML::XMLTokens::NAME_CHAR}*)}\z/
+
+ # Returns header text and optional ID.
+ def parse_header_contents
+ text = @src["contents"]
+ text.rstrip!
+ id_match = HEADER_ID.match(text)
+ if id_match
+ id = id_match["id"]
+ text = text[0...-id_match[0].length]
+ text.rstrip!
+ end
+ [text, id]
+ end
+
+ def add_header(level, text, id)
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ el = new_block_el(:header, nil, nil, level: level, raw_text: text, location: start_line_number)
+ add_text(text, el)
+ el.attr['id'] = id if id
+ @tree.children << el
+ end
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb
new file mode 100644
index 0000000..73a936d
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb
@@ -0,0 +1,27 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ HR_START = /^#{OPT_SPACE}(\*|-|_)[ \t]*\1[ \t]*\1(\1|[ \t])*\n/
+
+ # Parse the horizontal rule at the current location.
+ def parse_horizontal_rule
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ @tree.children << new_block_el(:hr, nil, nil, location: start_line_number)
+ true
+ end
+ define_parser(:horizontal_rule, HR_START)
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb
new file mode 100644
index 0000000..c0fcd1a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb
@@ -0,0 +1,165 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/html'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ include Kramdown::Parser::Html::Parser
+ include Kramdown::Utils::Html
+
+ # Mapping of markdown attribute value to content model. I.e. :raw when "0", :default when "1"
+ # (use default content model for the HTML element), :span when "span", :block when block and
+ # for everything else +nil+ is returned.
+ HTML_MARKDOWN_ATTR_MAP = {"0" => :raw, "1" => :default, "span" => :span, "block" => :block}
+
+ TRAILING_WHITESPACE = /[ \t]*\n/
+
+ def handle_kramdown_html_tag(el, closed, handle_body)
+ if @block_ial
+ el.options[:ial] = @block_ial
+ @block_ial = nil
+ end
+
+ content_model = if @tree.type != :html_element || @tree.options[:content_model] != :raw
+ (@options[:parse_block_html] ? HTML_CONTENT_MODEL[el.value] : :raw)
+ else
+ :raw
+ end
+ if (val = HTML_MARKDOWN_ATTR_MAP[el.attr.delete('markdown')])
+ content_model = (val == :default ? HTML_CONTENT_MODEL[el.value] : val)
+ end
+
+ @src.scan(TRAILING_WHITESPACE) if content_model == :block
+ el.options[:content_model] = content_model
+ el.options[:is_closed] = closed
+
+ if !closed && handle_body
+ case content_model
+ when :block
+ unless parse_blocks(el)
+ warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it")
+ end
+ when :span
+ curpos = @src.pos
+ if @src.scan_until(/(?=<\/#{el.value}\s*>)/mi)
+ add_text(extract_string(curpos...@src.pos, @src), el)
+ @src.scan(HTML_TAG_CLOSE_RE)
+ else
+ add_text(@src.rest, el)
+ @src.terminate
+ warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it")
+ end
+ else
+ parse_raw_html(el) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) }
+ end
+ unless @tree.type == :html_element && @tree.options[:content_model] == :raw
+ @src.scan(TRAILING_WHITESPACE)
+ end
+ end
+ end
+
+ HTML_BLOCK_START = /^#{OPT_SPACE}<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/)/
+
+ # Parse the HTML at the current position as block-level HTML.
+ def parse_block_html
+ line = @src.current_line_number
+ if (result = @src.scan(HTML_COMMENT_RE))
+ @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line)
+ @src.scan(TRAILING_WHITESPACE)
+ true
+ elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase)
+ @src.pos += @src.matched_size
+ handle_html_start_tag(line) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) }
+ Kramdown::Parser::Html::ElementConverter.convert(@root, @tree.children.last) if @options[:html_to_native]
+ true
+ elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase)
+ name = @src[1].downcase
+
+ if @tree.type == :html_element && @tree.value == name
+ @src.pos += @src.matched_size
+ throw :stop_block_parsing, :found
+ else
+ false
+ end
+ else
+ false
+ end
+ end
+ define_parser(:block_html, HTML_BLOCK_START)
+
+ HTML_SPAN_START = /<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/|!\[CDATA\[)/
+
+ # Parse the HTML at the current position as span-level HTML.
+ def parse_span_html
+ line = @src.current_line_number
+ if (result = @src.scan(HTML_COMMENT_RE))
+ @tree.children << Element.new(:xml_comment, result, nil, category: :span, location: line)
+ elsif @src.scan(HTML_CDATA_RE)
+ add_text(escape_html(@src[1]))
+ elsif (result = @src.scan(HTML_TAG_CLOSE_RE))
+ warning("Found invalidly used HTML closing tag for '#{@src[1]}' on line #{line}")
+ add_text(result)
+ elsif (result = @src.scan(HTML_TAG_RE))
+ tag_name = @src[1]
+ tag_name.downcase! if HTML_ELEMENT[tag_name.downcase]
+ if HTML_BLOCK_ELEMENTS.include?(tag_name)
+ warning("Found block HTML tag '#{tag_name}' in span-level text on line #{line}")
+ add_text(result)
+ return
+ end
+
+ attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[tag_name])
+ attrs.each_value {|value| value.gsub!(/\n+/, ' ') unless value.empty? }
+
+ do_parsing = if HTML_CONTENT_MODEL[tag_name] == :raw || @tree.options[:content_model] == :raw
+ false
+ else
+ @options[:parse_span_html]
+ end
+ if (val = HTML_MARKDOWN_ATTR_MAP[attrs.delete('markdown')])
+ case val
+ when :block
+ warning("Cannot use block-level parsing in span-level HTML tag (line #{line}) " \
+ "- using default mode")
+ when :span
+ do_parsing = true
+ when :default
+ do_parsing = HTML_CONTENT_MODEL[tag_name] != :raw
+ when :raw
+ do_parsing = false
+ end
+ end
+
+ el = Element.new(:html_element, tag_name, attrs, category: :span, location: line,
+ content_model: (do_parsing ? :span : :raw), is_closed: !@src[4].nil?)
+ @tree.children << el
+ stop_re = /<\/#{Regexp.escape(tag_name)}\s*>/
+ stop_re = Regexp.new(stop_re.source, Regexp::IGNORECASE) if HTML_ELEMENT[tag_name]
+ if !@src[4] && !HTML_ELEMENTS_WITHOUT_BODY.include?(el.value)
+ if parse_spans(el, stop_re, (do_parsing ? nil : [:span_html]))
+ @src.scan(stop_re)
+ else
+ warning("Found no end tag for '#{el.value}' (line #{line}) - auto-closing it")
+ add_text(@src.rest, el)
+ @src.terminate
+ end
+ end
+ Kramdown::Parser::Html::ElementConverter.convert(@root, el) if @options[:html_to_native]
+ else
+ add_text(@src.getch)
+ end
+ end
+ define_parser(:span_html, HTML_SPAN_START, '<')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb
new file mode 100644
index 0000000..9852df7
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb
@@ -0,0 +1,34 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/html'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ # Parse the HTML entity at the current location.
+ def parse_html_entity
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ begin
+ value = ::Kramdown::Utils::Entities.entity(@src[1] || @src[2]&.to_i || @src[3].hex)
+ @tree.children << Element.new(:entity, value,
+ nil, original: @src.matched, location: start_line_number)
+ rescue ::Kramdown::Error
+ @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp'),
+ nil, location: start_line_number)
+ add_text(@src.matched[1..-1])
+ end
+ end
+ define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb
new file mode 100644
index 0000000..5f85427
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb
@@ -0,0 +1,25 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ LINE_BREAK = /( |\\\\)(?=\n)/
+
+ # Parse the line break at the current location.
+ def parse_line_break
+ @tree.children << Element.new(:br, nil, nil, location: @src.current_line_number)
+ @src.pos += @src.matched_size
+ end
+ define_parser(:line_break, LINE_BREAK, '( |\\\\)(?=\n)')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb
new file mode 100644
index 0000000..e4c0935
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb
@@ -0,0 +1,149 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/escaped_chars'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ # Normalize the link identifier.
+ def normalize_link_id(id)
+ id.gsub(/\s+/, ' ').downcase
+ end
+
+ LINK_DEFINITION_START = /^#{OPT_SPACE}\[([^\n\]]+)\]:[ \t]*(?:<(.*?)>|([^\n]*?\S[^\n]*?))(?:(?:[ \t]*?\n|[ \t]+?)[ \t]*?(["'])(.+?)\4)?[ \t]*?\n/
+
+ # Parse the link definition at the current location.
+ def parse_link_definition
+ return false if @src[3].to_s.match?(/[ \t]+["']/)
+ @src.pos += @src.matched_size
+ link_id, link_url, link_title = normalize_link_id(@src[1]), @src[2] || @src[3], @src[5]
+ if @link_defs[link_id]
+ warning("Duplicate link ID '#{link_id}' on line #{@src.current_line_number} - overwriting")
+ end
+ @tree.children << new_block_el(:eob, :link_def)
+ @link_defs[link_id] = [link_url, link_title, @tree.children.last]
+ true
+ end
+ define_parser(:link_definition, LINK_DEFINITION_START)
+
+ # This helper methods adds the approriate attributes to the element +el+ of type +a+ or +img+
+ # and the element itself to the @tree.
+ def add_link(el, href, title, alt_text = nil, ial = nil)
+ el.options[:ial] = ial
+ update_attr_with_ial(el.attr, ial) if ial
+ if el.type == :a
+ el.attr['href'] = href
+ else
+ el.attr['src'] = href
+ el.attr['alt'] = alt_text
+ el.children.clear
+ end
+ el.attr['title'] = title if title
+ @tree.children << el
+ end
+
+ LINK_BRACKET_STOP_RE = /(\])|!?\[/
+ LINK_PAREN_STOP_RE = /(\()|(\))|\s(?=['"])/
+ LINK_INLINE_ID_RE = /\s*?\[([^\]]+)?\]/
+ LINK_INLINE_TITLE_RE = /\s*?(["'])(.+?)\1\s*?\)/m
+ LINK_START = /!?\[(?=[^^])/
+
+ # Parse the link at the current scanner position. This method is used to parse normal links as
+ # well as image links.
+ def parse_link
+ start_line_number = @src.current_line_number
+ result = @src.scan(LINK_START)
+ cur_pos = @src.pos
+ saved_pos = @src.save_pos
+
+ link_type = (result.match?(/^!/) ? :img : :a)
+
+ # no nested links allowed
+ if link_type == :a && (@tree.type == :img || @tree.type == :a ||
+ @stack.any? {|t, _| t && (t.type == :img || t.type == :a) })
+ add_text(result)
+ return
+ end
+ el = Element.new(link_type, nil, nil, location: start_line_number)
+
+ count = 1
+ found = parse_spans(el, LINK_BRACKET_STOP_RE) do
+ count += (@src[1] ? -1 : 1)
+ count - el.children.count {|c| c.type == :img } == 0
+ end
+ unless found
+ @src.revert_pos(saved_pos)
+ add_text(result)
+ return
+ end
+ alt_text = extract_string(cur_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1')
+ @src.scan(LINK_BRACKET_STOP_RE)
+
+ # reference style link or no link url
+ if @src.scan(LINK_INLINE_ID_RE) || !@src.check(/\(/)
+ emit_warning = !@src[1]
+ link_id = normalize_link_id(@src[1] || alt_text)
+ if @link_defs.key?(link_id)
+ link_def = @link_defs[link_id]
+ add_link(el, link_def[0], link_def[1], alt_text,
+ link_def[2] && link_def[2].options[:ial])
+ else
+ if emit_warning
+ warning("No link definition for link ID '#{link_id}' found on line #{start_line_number}")
+ end
+ @src.revert_pos(saved_pos)
+ add_text(result)
+ end
+ return
+ end
+
+ # link url in parentheses
+ if @src.scan(/\(<(.*?)>/)
+ link_url = @src[1]
+ if @src.scan(/\)/)
+ add_link(el, link_url, nil, alt_text)
+ return
+ end
+ else
+ link_url = +''
+ nr_of_brackets = 0
+ while (temp = @src.scan_until(LINK_PAREN_STOP_RE))
+ link_url << temp
+ if @src[2]
+ nr_of_brackets -= 1
+ break if nr_of_brackets == 0
+ elsif @src[1]
+ nr_of_brackets += 1
+ else
+ break
+ end
+ end
+ link_url = link_url[1..-2]
+ link_url.strip!
+
+ if nr_of_brackets == 0
+ add_link(el, link_url, nil, alt_text)
+ return
+ end
+ end
+
+ if @src.scan(LINK_INLINE_TITLE_RE)
+ add_link(el, link_url, @src[2], alt_text)
+ else
+ @src.revert_pos(saved_pos)
+ add_text(result)
+ end
+ end
+ define_parser(:link, LINK_START, '!?\[')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb
new file mode 100644
index 0000000..4cf9d3f
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb
@@ -0,0 +1,286 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/blank_line'
+require 'kramdown/parser/kramdown/eob'
+require 'kramdown/parser/kramdown/horizontal_rule'
+require 'kramdown/parser/kramdown/extensions'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ LIST_ITEM_IAL = /^\s*(?:\{:(?!(?:#{ALD_ID_NAME})?:|\/)(#{ALD_ANY_CHARS}+)\})\s*/
+ LIST_ITEM_IAL_CHECK = /^#{LIST_ITEM_IAL}?\s*\n/
+
+ PARSE_FIRST_LIST_LINE_REGEXP_CACHE = Hash.new do |h, indentation|
+ indent_re = /^ {#{indentation}}/
+ content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*\S.*\n/
+ lazy_re = /(?!^ {0,#{[indentation, 3].min}}(?:#{IAL_BLOCK}|#{LAZY_END_HTML_STOP}|#{LAZY_END_HTML_START})).*\S.*\n/
+
+ h[indentation] = [content_re, lazy_re, indent_re]
+ end
+
+ # Used for parsing the first line of a list item or a definition, i.e. the line with list item
+ # marker or the definition marker.
+ def parse_first_list_line(indentation, content)
+ if content.match?(self.class::LIST_ITEM_IAL_CHECK)
+ indentation = 4
+ else
+ while content.match?(/^ *\t/)
+ temp = content.scan(/^ */).first.length + indentation
+ content.sub!(/^( *)(\t+)/) { $1 << " " * (4 - (temp % 4) + ($2.length - 1) * 4) }
+ end
+ indentation += content[/^ */].length
+ end
+ content.sub!(/^\s*/, '')
+
+ [content, indentation, *PARSE_FIRST_LIST_LINE_REGEXP_CACHE[indentation]]
+ end
+
+ PATTERN_TAIL = /[\t| ].*?\n/
+
+ LIST_START_UL = /^(#{OPT_SPACE}[+*-])(#{PATTERN_TAIL})/
+ LIST_START_OL = /^(#{OPT_SPACE}\d+\.)(#{PATTERN_TAIL})/
+ LIST_START = /#{LIST_START_UL}|#{LIST_START_OL}/
+
+ # Parse the ordered or unordered list at the current location.
+ def parse_list
+ start_line_number = @src.current_line_number
+ type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL])
+ list = new_block_el(type, nil, nil, location: start_line_number)
+
+ item = nil
+ content_re, lazy_re, indent_re = nil
+ eob_found = false
+ nested_list_found = false
+ last_is_blank = false
+ until @src.eos?
+ start_line_number = @src.current_line_number
+ if last_is_blank && @src.check(HR_START)
+ break
+ elsif @src.scan(EOB_MARKER)
+ eob_found = true
+ break
+ elsif @src.scan(list_start_re)
+ list.options[:first_list_marker] ||= @src[1].strip
+ item = Element.new(:li, nil, nil, location: start_line_number)
+ item.value, indentation, content_re, lazy_re, indent_re =
+ parse_first_list_line(@src[1].length, @src[2])
+ list.children << item
+
+ item.value.sub!(self.class::LIST_ITEM_IAL) do
+ parse_attribute_list($1, item.options[:ial] ||= {})
+ ''
+ end
+
+ list_start_re = fetch_pattern(type, indentation)
+ nested_list_found = (item.value =~ LIST_START)
+ last_is_blank = false
+ item.value = [item.value]
+ elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re)))
+ result.sub!(/^(\t+)/) { " " * 4 * $1.length }
+ indentation_found = result.sub!(indent_re, '')
+ if !nested_list_found && indentation_found && result =~ LIST_START
+ item.value << +''
+ nested_list_found = true
+ elsif nested_list_found && !indentation_found && result =~ LIST_START
+ result = " " * (indentation + 4) << result
+ end
+ item.value.last << result
+ last_is_blank = false
+ elsif (result = @src.scan(BLANK_LINE))
+ nested_list_found = true
+ last_is_blank = true
+ item.value.last << result
+ else
+ break
+ end
+ end
+
+ @tree.children << list
+
+ last = nil
+ list.children.each do |it|
+ temp = Element.new(:temp, nil, nil, location: it.options[:location])
+
+ env = save_env
+ location = it.options[:location]
+ it.value.each do |val|
+ @src = ::Kramdown::Utils::StringScanner.new(val, location)
+ parse_blocks(temp)
+ location = @src.current_line_number
+ end
+ restore_env(env)
+
+ it.children = temp.children
+ it.value = nil
+
+ it_children = it.children
+ next if it_children.empty?
+
+ # Handle the case where an EOB marker is inserted by a block IAL for the first paragraph
+ it_children.delete_at(1) if it_children.first.type == :p &&
+ it_children.length >= 2 && it_children[1].type == :eob && it_children.first.options[:ial]
+
+ if it_children.first.type == :p &&
+ (it_children.length < 2 || it_children[1].type != :blank ||
+ (it == list.children.last && it_children.length == 2 && !eob_found)) &&
+ (list.children.last != it || list.children.size == 1 ||
+ list.children[0..-2].any? {|cit| !cit.children.first || cit.children.first.type != :p || cit.children.first.options[:transparent] })
+ it_children.first.children.first.value << "\n" if it_children.size > 1 && it_children[1].type != :blank
+ it_children.first.options[:transparent] = true
+ end
+
+ last = (it_children.last.type == :blank ? it_children.pop : nil)
+ end
+
+ @tree.children << last if !last.nil? && !eob_found
+
+ true
+ end
+ define_parser(:list, LIST_START)
+
+ DEFINITION_LIST_START = /^(#{OPT_SPACE}:)(#{PATTERN_TAIL})/
+
+ # Parse the ordered or unordered list at the current location.
+ def parse_definition_list
+ children = @tree.children
+ if !children.last || (children.length == 1 && children.last.type != :p) ||
+ (children.length >= 2 && children[-1].type != :p &&
+ (children[-1].type != :blank || children[-1].value != "\n" || children[-2].type != :p))
+ return false
+ end
+
+ first_as_para = false
+ deflist = new_block_el(:dl)
+ para = @tree.children.pop
+ if para.type == :blank
+ para = @tree.children.pop
+ first_as_para = true
+ end
+ # take location from preceding para which is the first definition term
+ deflist.options[:location] = para.options[:location]
+ para.children.first.value.split("\n").each do |term|
+ el = Element.new(:dt, nil, nil, location: @src.current_line_number)
+ term.sub!(self.class::LIST_ITEM_IAL) do
+ parse_attribute_list($1, el.options[:ial] ||= {})
+ ''
+ end
+ el.options[:raw_text] = term
+ el.children << Element.new(:raw_text, term)
+ deflist.children << el
+ end
+ deflist.options[:ial] = para.options[:ial]
+
+ item = nil
+ content_re, lazy_re, indent_re = nil
+ def_start_re = DEFINITION_LIST_START
+ last_is_blank = false
+ until @src.eos?
+ start_line_number = @src.current_line_number
+ if @src.scan(def_start_re)
+ item = Element.new(:dd, nil, nil, location: start_line_number)
+ item.options[:first_as_para] = first_as_para
+ item.value, indentation, content_re, lazy_re, indent_re =
+ parse_first_list_line(@src[1].length, @src[2])
+ deflist.children << item
+
+ item.value.sub!(self.class::LIST_ITEM_IAL) do |_match|
+ parse_attribute_list($1, item.options[:ial] ||= {})
+ ''
+ end
+
+ def_start_re = fetch_pattern(:dl, indentation)
+ first_as_para = false
+ last_is_blank = false
+ elsif @src.check(EOB_MARKER)
+ break
+ elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re)))
+ result.sub!(/^(\t+)/) { " " * ($1 ? 4 * $1.length : 0) }
+ result.sub!(indent_re, '')
+ item.value << result
+ first_as_para = false
+ last_is_blank = false
+ elsif (result = @src.scan(BLANK_LINE))
+ first_as_para = true
+ item.value << result
+ last_is_blank = true
+ else
+ break
+ end
+ end
+
+ last = nil
+ deflist.children.each do |it|
+ next if it.type == :dt
+
+ parse_blocks(it, it.value)
+ it.value = nil
+ it_children = it.children
+ next if it_children.empty?
+
+ last = (it_children.last.type == :blank ? it_children.pop : nil)
+
+ if it_children.first && it_children.first.type == :p && !it.options.delete(:first_as_para)
+ it_children.first.children.first.value << "\n" if it_children.size > 1
+ it_children.first.options[:transparent] = true
+ end
+ end
+
+ children = @tree.children
+ if children.length >= 1 && children.last.type == :dl
+ children[-1].children.concat(deflist.children)
+ elsif children.length >= 2 && children[-1].type == :blank &&
+ children[-2].type == :dl
+ children.pop
+ children[-1].children.concat(deflist.children)
+ else
+ children << deflist
+ end
+
+ children << last if last
+
+ true
+ end
+ define_parser(:definition_list, DEFINITION_LIST_START)
+
+ private
+
+ # precomputed patterns for indentations 1..4 and fallback expression
+ # to compute pattern when indentation is outside the 1..4 range.
+ def fetch_pattern(type, indentation)
+ case type
+ when :ul
+ case indentation
+ when 1 then /^( {0}[+*-])(#{PATTERN_TAIL})/o
+ when 2 then /^( {0,1}[+*-])(#{PATTERN_TAIL})/o
+ when 3 then /^( {0,2}[+*-])(#{PATTERN_TAIL})/o
+ else /^( {0,3}[+*-])(#{PATTERN_TAIL})/o
+ end
+ when :ol
+ case indentation
+ when 1 then /^( {0}\d+\.)(#{PATTERN_TAIL})/o
+ when 2 then /^( {0,1}\d+\.)(#{PATTERN_TAIL})/o
+ when 3 then /^( {0,2}\d+\.)(#{PATTERN_TAIL})/o
+ else /^( {0,3}\d+\.)(#{PATTERN_TAIL})/o
+ end
+ when :dl
+ case indentation
+ when 1 then /^( {0}:)(#{PATTERN_TAIL})/o
+ when 2 then /^( {0,1}:)(#{PATTERN_TAIL})/o
+ when 3 then /^( {0,2}:)(#{PATTERN_TAIL})/o
+ else /^( {0,3}:)(#{PATTERN_TAIL})/o
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb
new file mode 100644
index 0000000..32c87bf
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb
@@ -0,0 +1,53 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/block_boundary'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ BLOCK_MATH_START = /^#{OPT_SPACE}(\\)?\$\$(.*?)\$\$(\s*?\n)?/m
+
+ # Parse the math block at the current location.
+ def parse_block_math
+ start_line_number = @src.current_line_number
+ if !after_block_boundary?
+ return false
+ elsif @src[1]
+ @src.scan(/^#{OPT_SPACE}\\/o) if @src[3]
+ return false
+ end
+
+ saved_pos = @src.save_pos
+ @src.pos += @src.matched_size
+ data = @src[2].strip
+ if before_block_boundary?
+ @tree.children << new_block_el(:math, data, nil, category: :block, location: start_line_number)
+ true
+ else
+ @src.revert_pos(saved_pos)
+ false
+ end
+ end
+ define_parser(:block_math, BLOCK_MATH_START)
+
+ INLINE_MATH_START = /\$\$(.*?)\$\$/m
+
+ # Parse the inline math at the current location.
+ def parse_inline_math
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ @tree.children << Element.new(:math, @src[1].strip, nil, category: :span, location: start_line_number)
+ end
+ define_parser(:inline_math, INLINE_MATH_START, '\$')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb
new file mode 100644
index 0000000..d89e6a2
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb
@@ -0,0 +1,62 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/blank_line'
+require 'kramdown/parser/kramdown/extensions'
+require 'kramdown/parser/kramdown/eob'
+require 'kramdown/parser/kramdown/list'
+require 'kramdown/parser/kramdown/html'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ LAZY_END_HTML_SPAN_ELEMENTS = HTML_SPAN_ELEMENTS + %w[script]
+ LAZY_END_HTML_START = /<(?>(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR})/
+ LAZY_END_HTML_STOP = /<\/(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR}\s*>/m
+
+ LAZY_END = /#{BLANK_LINE}|#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/
+
+ PARAGRAPH_START = /^#{OPT_SPACE}[^ \t].*?\n/
+ PARAGRAPH_MATCH = /^.*?\n/
+ PARAGRAPH_END = /#{LAZY_END}|#{DEFINITION_LIST_START}/
+
+ # Parse the paragraph at the current location.
+ def parse_paragraph
+ pos = @src.pos
+ start_line_number = @src.current_line_number
+ result = @src.scan(PARAGRAPH_MATCH)
+ until @src.match?(paragraph_end)
+ result << @src.scan(PARAGRAPH_MATCH)
+ end
+ result.rstrip!
+ if (last_child = @tree.children.last) && last_child.type == :p
+ last_item_in_para = last_child.children.last
+ if last_item_in_para && last_item_in_para.type == @text_type
+ joiner = (extract_string((pos - 3)...pos, @src) == " \n" ? " \n" : "\n")
+ last_item_in_para.value << joiner << result
+ else
+ add_text(result, last_child)
+ end
+ else
+ @tree.children << new_block_el(:p, nil, nil, location: start_line_number)
+ result.lstrip!
+ add_text(result, @tree.children.last)
+ end
+ true
+ end
+ define_parser(:paragraph, PARAGRAPH_START)
+
+ def paragraph_end
+ self.class::PARAGRAPH_END
+ end
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb
new file mode 100644
index 0000000..c0a6aaa
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb
@@ -0,0 +1,174 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+#--
+# Parts of this file are based on code from RubyPants:
+#
+# = RubyPants -- SmartyPants ported to Ruby
+#
+# Ported by Christian Neukirchen <mailto:chneukirchen@gmail.com>
+# Copyright (C) 2004 Christian Neukirchen
+#
+# Incooporates ideas, comments and documentation by Chad Miller
+# Copyright (C) 2004 Chad Miller
+#
+# Original SmartyPants by John Gruber
+# Copyright (C) 2003 John Gruber
+#
+#
+# = RubyPants -- SmartyPants ported to Ruby
+#
+#
+# [snip]
+#
+# == Authors
+#
+# John Gruber did all of the hard work of writing this software in
+# Perl for Movable Type and almost all of this useful documentation.
+# Chad Miller ported it to Python to use with Pyblosxom.
+#
+# Christian Neukirchen provided the Ruby port, as a general-purpose
+# library that follows the *Cloth API.
+#
+#
+# == Copyright and License
+#
+# === SmartyPants license:
+#
+# Copyright (c) 2003 John Gruber
+# (http://daringfireball.net)
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name "SmartyPants" nor the names of its contributors
+# may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# This software is provided by the copyright holders and contributors
+# "as is" and any express or implied warranties, including, but not
+# limited to, the implied warranties of merchantability and fitness
+# for a particular purpose are disclaimed. In no event shall the
+# copyright owner or contributors be liable for any direct, indirect,
+# incidental, special, exemplary, or consequential damages (including,
+# but not limited to, procurement of substitute goods or services;
+# loss of use, data, or profits; or business interruption) however
+# caused and on any theory of liability, whether in contract, strict
+# liability, or tort (including negligence or otherwise) arising in
+# any way out of the use of this software, even if advised of the
+# possibility of such damage.
+#
+# === RubyPants license
+#
+# RubyPants is a derivative work of SmartyPants and smartypants.py.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# This software is provided by the copyright holders and contributors
+# "as is" and any express or implied warranties, including, but not
+# limited to, the implied warranties of merchantability and fitness
+# for a particular purpose are disclaimed. In no event shall the
+# copyright owner or contributors be liable for any direct, indirect,
+# incidental, special, exemplary, or consequential damages (including,
+# but not limited to, procurement of substitute goods or services;
+# loss of use, data, or profits; or business interruption) however
+# caused and on any theory of liability, whether in contract, strict
+# liability, or tort (including negligence or otherwise) arising in
+# any way out of the use of this software, even if advised of the
+# possibility of such damage.
+#
+# == Links
+#
+# John Gruber:: http://daringfireball.net
+# SmartyPants:: http://daringfireball.net/projects/smartypants
+#
+# Chad Miller:: http://web.chad.org
+#
+# Christian Neukirchen:: http://kronavita.de/chris
+#
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ SQ_PUNCT = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
+ SQ_CLOSE = %![^ \\\\\t\r\n\\[{(-]!
+
+ SQ_RULES = [
+ [/("|')(?=[_*]{1,2}\S)/, [:lquote1]],
+ [/("|')(?=#{SQ_PUNCT}(?!\.\.)\B)/, [:rquote1]],
+ # Special case for double sets of quotes, e.g.:
+ # <p>He said, "'Quoted' words in a larger quote."</p>
+ [/(\s?)"'(?=\w)/, [1, :ldquo, :lsquo]],
+ [/(\s?)'"(?=\w)/, [1, :lsquo, :ldquo]],
+ # Special case for decade abbreviations (the '80s):
+ [/(\s?)'(?=\d\ds)/, [1, :rsquo]],
+
+ # Get most opening single/double quotes:
+ [/(\s)('|")(?=\w)/, [1, :lquote2]],
+ # Single/double closing quotes:
+ [/(#{SQ_CLOSE})('|")/, [1, :rquote2]],
+ # Special case for e.g. "<i>Custer</i>'s Last Stand."
+ [/("|')(?=\s|s\b|$)/, [:rquote1]],
+ # Any remaining single quotes should be opening ones:
+ [/(.?)'/m, [1, :lsquo]],
+ [/(.?)"/m, [1, :ldquo]],
+ ] # '"
+
+ SQ_SUBSTS = {
+ [:rquote1, '"'] => :rdquo,
+ [:rquote1, "'"] => :rsquo,
+ [:rquote2, '"'] => :rdquo,
+ [:rquote2, "'"] => :rsquo,
+ [:lquote1, '"'] => :ldquo,
+ [:lquote1, "'"] => :lsquo,
+ [:lquote2, '"'] => :ldquo,
+ [:lquote2, "'"] => :lsquo,
+ }
+ SMART_QUOTES_RE = /[^\\]?["']/
+
+ # Parse the smart quotes at current location.
+ def parse_smart_quotes
+ start_line_number = @src.current_line_number
+ substs = SQ_RULES.find {|reg, _subst| @src.scan(reg) }[1]
+ substs.each do |subst|
+ if subst.kind_of?(Integer)
+ add_text(@src[subst])
+ else
+ val = SQ_SUBSTS[[subst, @src[subst.to_s[-1, 1].to_i]]] || subst
+ @tree.children << Element.new(:smart_quote, val, nil, location: start_line_number)
+ end
+ end
+ end
+ define_parser(:smart_quotes, SMART_QUOTES_RE, '[^\\\\]?["\']')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb
new file mode 100644
index 0000000..68be6b4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb
@@ -0,0 +1,171 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser/kramdown/block_boundary'
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ TABLE_SEP_LINE = /^([+|: \t-]*?-[+|: \t-]*?)[ \t]*\n/
+ TABLE_HSEP_ALIGN = /[ \t]?(:?)-+(:?)[ \t]?/
+ TABLE_FSEP_LINE = /^[+|: \t=]*?=[+|: \t=]*?[ \t]*\n/
+ TABLE_ROW_LINE = /^(.*?)[ \t]*\n/
+ TABLE_PIPE_CHECK = /(?:\||.*?[^\\\n]\|)/
+ TABLE_LINE = /#{TABLE_PIPE_CHECK}.*?\n/
+ TABLE_START = /^#{OPT_SPACE}(?=\S)#{TABLE_LINE}/
+
+ # Parse the table at the current location.
+ def parse_table
+ return false unless after_block_boundary?
+
+ saved_pos = @src.save_pos
+ orig_pos = @src.pos
+ table = new_block_el(:table, nil, nil, alignment: [], location: @src.current_line_number)
+ leading_pipe = (@src.check(TABLE_LINE) =~ /^\s*\|/)
+ @src.scan(TABLE_SEP_LINE)
+
+ rows = []
+ has_footer = false
+ columns = 0
+
+ add_container = lambda do |type, force|
+ if !has_footer || type != :tbody || force
+ cont = Element.new(type)
+ cont.children, rows = rows, []
+ table.children << cont
+ end
+ end
+
+ until @src.eos?
+ break unless @src.check(TABLE_LINE)
+ if @src.scan(TABLE_SEP_LINE)
+ if rows.empty?
+ # nothing to do, ignoring multiple consecutive separator lines
+ elsif table.options[:alignment].empty? && !has_footer
+ add_container.call(:thead, false)
+ table.options[:alignment] = @src[1].scan(TABLE_HSEP_ALIGN).map do |left, right|
+ (left.empty? && right.empty? && :default) || (right.empty? && :left) ||
+ (left.empty? && :right) || :center
+ end
+ else # treat as normal separator line
+ add_container.call(:tbody, false)
+ end
+ elsif @src.scan(TABLE_FSEP_LINE)
+ add_container.call(:tbody, true) unless rows.empty?
+ has_footer = true
+ elsif @src.scan(TABLE_ROW_LINE)
+ trow = Element.new(:tr)
+
+ # parse possible code spans on the line and correctly split the line into cells
+ env = save_env
+ cells = []
+ @src[1].split(/(<code.*?>.*?<\/code>)/).each_with_index do |str, i|
+ if i.odd?
+ (cells.empty? ? cells : cells.last) << str
+ else
+ reset_env(src: Kramdown::Utils::StringScanner.new(str, @src.current_line_number))
+ root = Element.new(:root)
+ parse_spans(root, nil, [:codespan])
+
+ root.children.each do |c|
+ if c.type == :raw_text
+ f, *l = c.value.split(/(?<!\\)\|/, -1).map {|t| t.gsub(/\\\|/, '|') }
+ (cells.empty? ? cells : cells.last) << f
+ cells.concat(l)
+ else
+ delim = (c.value.scan(/`+/).max || '') + '`'
+ tmp = +"#{delim}#{' ' if delim.size > 1}#{c.value}#{' ' if delim.size > 1}#{delim}"
+ (cells.empty? ? cells : cells.last) << tmp
+ end
+ end
+ end
+ end
+ restore_env(env)
+
+ cells.shift if leading_pipe && cells.first.strip.empty?
+ cells.pop if cells.last.strip.empty?
+ cells.each do |cell_text|
+ tcell = Element.new(:td)
+ tcell.children << Element.new(:raw_text, cell_text.strip)
+ trow.children << tcell
+ end
+ columns = [columns, cells.length].max
+ rows << trow
+ else
+ break
+ end
+ end
+
+ unless before_block_boundary?
+ @src.revert_pos(saved_pos)
+ return false
+ end
+
+ # Parse all lines of the table with the code span parser
+ env = save_env
+ l_src = ::Kramdown::Utils::StringScanner.new(extract_string(orig_pos...(@src.pos - 1), @src),
+ @src.current_line_number)
+ reset_env(src: l_src)
+ root = Element.new(:root)
+ parse_spans(root, nil, [:codespan, :span_html])
+ restore_env(env)
+
+ # Check if each line has at least one unescaped pipe that is not inside a code span/code
+ # HTML element
+ # Note: It doesn't matter that we parse *all* span HTML elements because the row splitting
+ # algorithm above only takes <code> elements into account!
+ pipe_on_line = false
+ while (c = root.children.shift)
+ next unless (lines = c.value)
+ lines = lines.split("\n")
+ if c.type == :codespan
+ if lines.size > 2 || (lines.size == 2 && !pipe_on_line)
+ break
+ elsif lines.size == 2 && pipe_on_line
+ pipe_on_line = false
+ end
+ else
+ break if lines.size > 1 && !pipe_on_line && lines.first !~ /^#{TABLE_PIPE_CHECK}/o
+ pipe_on_line = (lines.size > 1 ? false : pipe_on_line) || (lines.last =~ /^#{TABLE_PIPE_CHECK}/o)
+ end
+ end
+ @src.revert_pos(saved_pos) and return false unless pipe_on_line
+
+ add_container.call(has_footer ? :tfoot : :tbody, false) unless rows.empty?
+
+ if table.children.none? {|el| el.type == :tbody }
+ warning("Found table without body on line #{table.options[:location]} - ignoring it")
+ @src.revert_pos(saved_pos)
+ return false
+ end
+
+ # adjust all table rows to have equal number of columns, same for alignment defs
+ table.children.each do |kind|
+ kind.children.each do |row|
+ (columns - row.children.length).times do
+ row.children << Element.new(:td)
+ end
+ end
+ end
+ if table.options[:alignment].length > columns
+ table.options[:alignment] = table.options[:alignment][0...columns]
+ else
+ table.options[:alignment] += [:default] * (columns - table.options[:alignment].length)
+ end
+
+ @tree.children << table
+
+ true
+ end
+ define_parser(:table, TABLE_START)
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb
new file mode 100644
index 0000000..095c8d5
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb
@@ -0,0 +1,44 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Parser
+ class Kramdown
+
+ TYPOGRAPHIC_SYMS = [['---', :mdash], ['--', :ndash], ['...', :hellip],
+ ['\\<<', '&lt;&lt;'], ['\\>>', '&gt;&gt;'],
+ ['<< ', :laquo_space], [' >>', :raquo_space],
+ ['<<', :laquo], ['>>', :raquo]]
+ TYPOGRAPHIC_SYMS_SUBST = Hash[*TYPOGRAPHIC_SYMS.flatten]
+ TYPOGRAPHIC_SYMS_RE = /#{TYPOGRAPHIC_SYMS.map {|k, _v| Regexp.escape(k) }.join('|')}/
+
+ # Parse the typographic symbols at the current location.
+ def parse_typographic_syms
+ start_line_number = @src.current_line_number
+ @src.pos += @src.matched_size
+ val = TYPOGRAPHIC_SYMS_SUBST[@src.matched]
+ if val.kind_of?(Symbol)
+ @tree.children << Element.new(:typographic_sym, val, nil, location: start_line_number)
+ elsif @src.matched == '\\<<'
+ @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'),
+ nil, location: start_line_number)
+ @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'),
+ nil, location: start_line_number)
+ else
+ @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'),
+ nil, location: start_line_number)
+ @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'),
+ nil, location: start_line_number)
+ end
+ end
+ define_parser(:typographic_syms, TYPOGRAPHIC_SYMS_RE, '--|\\.\\.\\.|(?:\\\\| )?(?:<<|>>)')
+
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb
new file mode 100644
index 0000000..9f36758
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb
@@ -0,0 +1,57 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'kramdown/parser'
+
+module Kramdown
+
+ module Parser
+
+ # Used for parsing a document in Markdown format.
+ #
+ # This parser is based on the kramdown parser and removes the parser methods for the additional
+ # non-Markdown features. However, since some things are handled differently by the kramdown
+ # parser methods (like deciding when a list item contains just text), this parser differs from
+ # real Markdown parsers in some respects.
+ #
+ # Note, though, that the parser basically fails just one of the Markdown test cases (some others
+ # also fail but those failures are negligible).
+ class Markdown < Kramdown
+
+ # Array with all the parsing methods that should be removed from the standard kramdown parser.
+ EXTENDED = [:codeblock_fenced, :table, :definition_list, :footnote_definition,
+ :abbrev_definition, :block_math, :block_extensions,
+ :footnote_marker, :smart_quotes, :inline_math, :span_extensions, :typographic_syms]
+
+ def initialize(source, options) # :nodoc:
+ super
+ @block_parsers.delete_if {|i| EXTENDED.include?(i) }
+ @span_parsers.delete_if {|i| EXTENDED.include?(i) }
+ end
+
+ # :stopdoc:
+
+ BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|\Z/
+ LAZY_END = /#{BLANK_LINE}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|
+ ^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/x
+ CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+)*/
+ PARAGRAPH_END = LAZY_END
+
+ IAL_RAND_CHARS = (('a'..'z').to_a + ('0'..'9').to_a)
+ IAL_RAND_STRING = (1..20).collect { IAL_RAND_CHARS[rand(IAL_RAND_CHARS.size)] }.join
+ LIST_ITEM_IAL = /^\s*(#{IAL_RAND_STRING})?\s*\n/
+ IAL_SPAN_START = LIST_ITEM_IAL
+
+ # :startdoc:
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb
new file mode 100644
index 0000000..5928def
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb
@@ -0,0 +1,45 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+
+ # == \Utils Module
+ #
+ # This module contains utility class/modules/methods that can be used by both parsers and
+ # converters.
+ module Utils
+
+ autoload :Entities, 'kramdown/utils/entities'
+ autoload :Html, 'kramdown/utils/html'
+ autoload :Unidecoder, 'kramdown/utils/unidecoder'
+ autoload :StringScanner, 'kramdown/utils/string_scanner'
+ autoload :Configurable, 'kramdown/utils/configurable'
+ autoload :LRUCache, 'kramdown/utils/lru_cache'
+
+ # Treat +name+ as if it were snake cased (e.g. snake_case) and camelize it (e.g. SnakeCase).
+ def self.camelize(name)
+ name.split('_').inject(+'') {|s, x| s << x[0..0].upcase << x[1..-1] }
+ end
+
+ # Treat +name+ as if it were camelized (e.g. CamelizedName) and snake-case it (e.g. camelized_name).
+ def self.snake_case(name)
+ name = name.dup
+ name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
+ name.gsub!(/([a-z])([A-Z])/, '\1_\2')
+ name.downcase!
+ name
+ end
+
+ def self.deep_const_get(str)
+ ::Object.const_get(str)
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb
new file mode 100644
index 0000000..2989493
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb
@@ -0,0 +1,45 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Utils
+
+ # Methods for registering configurable extensions.
+ module Configurable
+
+ # Create a new configurable extension called +name+.
+ #
+ # Three methods will be defined on the calling object which allow to use this configurable
+ # extension:
+ #
+ # configurables:: Returns a hash of hashes that is used to store all configurables of the
+ # object.
+ #
+ # <name>(ext_name):: Return the configured extension +ext_name+.
+ #
+ # add_<name>(ext_name, data=nil, &block):: Define an extension +ext_name+ by specifying either
+ # the data as argument or by using a block.
+ def configurable(name)
+ unless respond_to?(:configurables)
+ singleton_class.send(:define_method, :configurables) do
+ @_configurables ||= Hash.new {|h, k| h[k] = {} }
+ end
+ end
+ singleton_class.send(:define_method, name) do |data|
+ configurables[name][data]
+ end
+ singleton_class.send(:define_method, "add_#{name}".intern) do |data, *args, &block|
+ configurables[name][data] = args.first || block
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb
new file mode 100644
index 0000000..156dd76
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb
@@ -0,0 +1,1000 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+
+ module Utils
+
+ # Provides convenience methods for handling named and numeric entities.
+ module Entities
+
+ # Represents an entity that has a +code_point+ and +name+.
+ Entity = Struct.new(:code_point, :name) do
+ # Return the UTF8 representation of the entity.
+ def char
+ [code_point].pack('U*') rescue nil
+ end
+ end
+
+ # Array of arrays. Each sub-array specifies a code point and the associated name.
+ #
+ # This table is not used directly -- Entity objects are automatically created from it and put
+ # into a Hash map when this file is loaded.
+ ENTITY_TABLE = [
+
+ # html4
+ [913, 'Alpha'],
+ [914, 'Beta'],
+ [915, 'Gamma'],
+ [916, 'Delta'],
+ [917, 'Epsilon'],
+ [918, 'Zeta'],
+ [919, 'Eta'],
+ [920, 'Theta'],
+ [921, 'Iota'],
+ [922, 'Kappa'],
+ [923, 'Lambda'],
+ [924, 'Mu'],
+ [925, 'Nu'],
+ [926, 'Xi'],
+ [927, 'Omicron'],
+ [928, 'Pi'],
+ [929, 'Rho'],
+ [931, 'Sigma'],
+ [932, 'Tau'],
+ [933, 'Upsilon'],
+ [934, 'Phi'],
+ [935, 'Chi'],
+ [936, 'Psi'],
+ [937, 'Omega'],
+ [945, 'alpha'],
+ [946, 'beta'],
+ [947, 'gamma'],
+ [948, 'delta'],
+ [949, 'epsilon'],
+ [950, 'zeta'],
+ [951, 'eta'],
+ [952, 'theta'],
+ [953, 'iota'],
+ [954, 'kappa'],
+ [955, 'lambda'],
+ [956, 'mu'],
+ [957, 'nu'],
+ [958, 'xi'],
+ [959, 'omicron'],
+ [960, 'pi'],
+ [961, 'rho'],
+ [963, 'sigma'],
+ [964, 'tau'],
+ [965, 'upsilon'],
+ [966, 'phi'],
+ [967, 'chi'],
+ [968, 'psi'],
+ [969, 'omega'],
+ [962, 'sigmaf'],
+ [977, 'thetasym'],
+ [978, 'upsih'],
+ [982, 'piv'],
+ [988, 'Gammad'],
+ [989, 'gammad'],
+ [8204, 'zwnj'],
+ [8205, 'zwj'],
+ [8206, 'lrm'],
+ [8207, 'rlm'],
+ [8230, 'hellip'],
+ [8242, 'prime'],
+ [8243, 'Prime'],
+ [8254, 'oline'],
+ [8260, 'frasl'],
+ [8472, 'weierp'],
+ [8465, 'image'],
+ [8476, 'real'],
+ [8501, 'alefsym'],
+ [8226, 'bull'],
+ [8482, 'trade'],
+ [8592, 'larr'],
+ [8594, 'rarr'],
+ [8593, 'uarr'],
+ [8595, 'darr'],
+ [8596, 'harr'],
+ [8629, 'crarr'],
+ [8657, 'uArr'],
+ [8659, 'dArr'],
+ [8656, 'lArr'],
+ [8658, 'rArr'],
+ [8660, 'hArr'],
+ [8704, 'forall'],
+ [8706, 'part'],
+ [8707, 'exist'],
+ [8709, 'empty'],
+ [8711, 'nabla'],
+ [8712, 'isin'],
+ [8715, 'ni'],
+ [8713, 'notin'],
+ [8721, 'sum'],
+ [8719, 'prod'],
+ [8722, 'minus'],
+ [8727, 'lowast'],
+ [8730, 'radic'],
+ [8733, 'prop'],
+ [8734, 'infin'],
+ [8736, 'ang'],
+ [8743, 'and'],
+ [8744, 'or'],
+ [8745, 'cap'],
+ [8746, 'cup'],
+ [8747, 'int'],
+ [8756, 'there4'],
+ [8764, 'sim'],
+ [8776, 'asymp'],
+ [8773, 'cong'],
+ [8800, 'ne'],
+ [8801, 'equiv'],
+ [8804, 'le'],
+ [8805, 'ge'],
+ [8834, 'sub'],
+ [8835, 'sup'],
+ [8838, 'sube'],
+ [8839, 'supe'],
+ [8836, 'nsub'],
+ [8853, 'oplus'],
+ [8855, 'otimes'],
+ [8869, 'perp'],
+ [8901, 'sdot'],
+ [8942, 'vellip'],
+ [8968, 'rceil'],
+ [8969, 'lceil'],
+ [8970, 'lfloor'],
+ [8971, 'rfloor'],
+ [9001, 'rang'],
+ [9002, 'lang'],
+ [9674, 'loz'],
+ [9824, 'spades'],
+ [9827, 'clubs'],
+ [9829, 'hearts'],
+ [9830, 'diams'],
+ [38, 'amp'],
+ [34, 'quot'],
+ [39, 'apos'],
+ [169, 'copy'],
+ [60, 'lt'],
+ [62, 'gt'],
+ [338, 'OElig'],
+ [339, 'oelig'],
+ [352, 'Scaron'],
+ [353, 'scaron'],
+ [376, 'Yuml'],
+ [710, 'circ'],
+ [732, 'tilde'],
+ [8211, 'ndash'],
+ [8212, 'mdash'],
+ [8216, 'lsquo'],
+ [8217, 'rsquo'],
+ [8220, 'ldquo'],
+ [8221, 'rdquo'],
+ [8224, 'dagger'],
+ [8225, 'Dagger'],
+ [8240, 'permil'],
+ [8364, 'euro'],
+ [8249, 'lsaquo'],
+ [8250, 'rsaquo'],
+ [160, 'nbsp'],
+ [161, 'iexcl'],
+ [163, 'pound'],
+ [164, 'curren'],
+ [165, 'yen'],
+ [166, 'brvbar'],
+ [167, 'sect'],
+ [168, 'uml'],
+ [171, 'laquo'],
+ [187, 'raquo'],
+ [174, 'reg'],
+ [170, 'ordf'],
+ [172, 'not'],
+ [173, 'shy'],
+ [175, 'macr'],
+ [176, 'deg'],
+ [177, 'plusmn'],
+ [180, 'acute'],
+ [181, 'micro'],
+ [182, 'para'],
+ [183, 'middot'],
+ [184, 'cedil'],
+ [186, 'ordm'],
+ [162, 'cent'],
+ [185, 'sup1'],
+ [178, 'sup2'],
+ [179, 'sup3'],
+ [189, 'frac12'],
+ [188, 'frac14'],
+ [190, 'frac34'],
+ [8531, 'frac13'],
+ [8532, 'frac23'],
+ [8533, 'frac15'],
+ [8534, 'frac25'],
+ [8535, 'frac35'],
+ [8536, 'frac45'],
+ [8537, 'frac16'],
+ [8538, 'frac56'],
+ [8539, 'frac18'],
+ [8540, 'frac38'],
+ [8541, 'frac58'],
+ [8542, 'frac78'],
+ [191, 'iquest'],
+ [192, 'Agrave'],
+ [193, 'Aacute'],
+ [194, 'Acirc'],
+ [195, 'Atilde'],
+ [196, 'Auml'],
+ [197, 'Aring'],
+ [198, 'AElig'],
+ [199, 'Ccedil'],
+ [200, 'Egrave'],
+ [201, 'Eacute'],
+ [202, 'Ecirc'],
+ [203, 'Euml'],
+ [204, 'Igrave'],
+ [205, 'Iacute'],
+ [206, 'Icirc'],
+ [207, 'Iuml'],
+ [208, 'ETH'],
+ [209, 'Ntilde'],
+ [210, 'Ograve'],
+ [211, 'Oacute'],
+ [212, 'Ocirc'],
+ [213, 'Otilde'],
+ [214, 'Ouml'],
+ [215, 'times'],
+ [216, 'Oslash'],
+ [217, 'Ugrave'],
+ [218, 'Uacute'],
+ [219, 'Ucirc'],
+ [220, 'Uuml'],
+ [221, 'Yacute'],
+ [222, 'THORN'],
+ [223, 'szlig'],
+ [224, 'agrave'],
+ [225, 'aacute'],
+ [226, 'acirc'],
+ [227, 'atilde'],
+ [228, 'auml'],
+ [229, 'aring'],
+ [230, 'aelig'],
+ [231, 'ccedil'],
+ [232, 'egrave'],
+ [233, 'eacute'],
+ [234, 'ecirc'],
+ [235, 'euml'],
+ [236, 'igrave'],
+ [237, 'iacute'],
+ [238, 'icirc'],
+ [239, 'iuml'],
+ [240, 'eth'],
+ [241, 'ntilde'],
+ [242, 'ograve'],
+ [243, 'oacute'],
+ [244, 'ocirc'],
+ [245, 'otilde'],
+ [246, 'ouml'],
+ [247, 'divide'],
+ [248, 'oslash'],
+ [249, 'ugrave'],
+ [250, 'uacute'],
+ [251, 'ucirc'],
+ [252, 'uuml'],
+ [253, 'yacute'],
+ [254, 'thorn'],
+ [255, 'yuml'],
+
+ [8218, 'sbquo'],
+ [402, 'fnof'],
+ [8222, 'bdquo'],
+
+ [128, 8364],
+ [130, 8218],
+ [131, 402],
+ [132, 8222],
+ [133, 8230],
+ [134, 8224],
+ [135, 8225],
+ [136, 710],
+ [137, 8240],
+ [138, 352],
+ [139, 8249],
+ [140, 338],
+ [142, 381],
+ [145, 8216],
+ [146, 8217],
+ [147, 8220],
+ [148, 8221],
+ [149, 8226],
+ [150, 8211],
+ [151, 8212],
+ [152, 732],
+ [153, 8482],
+ [154, 353],
+ [155, 8250],
+ [156, 339],
+ [158, 382],
+ [159, 376],
+
+ [8194, 'ensp'],
+ [8195, 'emsp'],
+ [8201, 'thinsp'],
+
+ # html5
+ [10218, 'Lang'],
+ [10219, 'Rang'],
+ [10220, 'loang'],
+ [10221, 'roang'],
+ [10229, 'xlarr'],
+ [10229, 'longleftarrow'],
+ [10229, 'LongLeftArrow'],
+ [10230, 'xrarr'],
+ [10230, 'longrightarrow'],
+ [10230, 'LongRightArrow'],
+ [10231, 'xharr'],
+ [10231, 'longleftrightarrow'],
+ [10231, 'LongLeftRightArrow'],
+ [10232, 'xlArr'],
+ [10232, 'Longleftarrow'],
+ [10232, 'DoubleLongLeftArrow'],
+ [10233, 'xrArr'],
+ [10233, 'Longrightarrow'],
+ [10233, 'DoubleLongRightArrow'],
+ [10234, 'xhArr'],
+ [10234, 'Longleftrightarrow'],
+ [10234, 'DoubleLongLeftRightArrow'],
+ [10236, 'xmap'],
+ [10236, 'longmapsto'],
+ [10239, 'dzigrarr'],
+ [10498, 'nvlArr'],
+ [10499, 'nvrArr'],
+ [10500, 'nvHarr'],
+ [10501, 'Map'],
+ [10508, 'lbarr'],
+ [10509, 'rbarr'],
+ [10509, 'bkarow'],
+ [10510, 'lBarr'],
+ [10511, 'rBarr'],
+ [10511, 'dbkarow'],
+ [10512, 'RBarr'],
+ [10512, 'drbkarow'],
+ [10513, 'DDotrahd'],
+ [10514, 'UpArrowBar'],
+ [10515, 'DownArrowBar'],
+ [10518, 'Rarrtl'],
+ [10521, 'latail'],
+ [10522, 'ratail'],
+ [10523, 'lAtail'],
+ [10524, 'rAtail'],
+ [10525, 'larrfs'],
+ [10526, 'rarrfs'],
+ [10527, 'larrbfs'],
+ [10528, 'rarrbfs'],
+ [10531, 'nwarhk'],
+ [10532, 'nearhk'],
+ [10533, 'searhk'],
+ [10533, 'hksearow'],
+ [10534, 'swarhk'],
+ [10534, 'hkswarow'],
+ [10535, 'nwnear'],
+ [10536, 'nesear'],
+ [10536, 'toea'],
+ [10537, 'seswar'],
+ [10537, 'tosa'],
+ [10538, 'swnwar'],
+ [10547, 'rarrc'],
+ [10549, 'cudarrr'],
+ [10550, 'ldca'],
+ [10551, 'rdca'],
+ [10552, 'cudarrl'],
+ [10553, 'larrpl'],
+ [10556, 'curarrm'],
+ [10557, 'cularrp'],
+ [10565, 'rarrpl'],
+ [10568, 'harrcir'],
+ [10569, 'Uarrocir'],
+ [10570, 'lurdshar'],
+ [10571, 'ldrushar'],
+ [10574, 'LeftRightVector'],
+ [10575, 'RightUpDownVector'],
+ [10576, 'DownLeftRightVector'],
+ [10577, 'LeftUpDownVector'],
+ [10578, 'LeftVectorBar'],
+ [10579, 'RightVectorBar'],
+ [10580, 'RightUpVectorBar'],
+ [10581, 'RightDownVectorBar'],
+ [10582, 'DownLeftVectorBar'],
+ [10583, 'DownRightVectorBar'],
+ [10584, 'LeftUpVectorBar'],
+ [10585, 'LeftDownVectorBar'],
+ [10586, 'LeftTeeVector'],
+ [10587, 'RightTeeVector'],
+ [10588, 'RightUpTeeVector'],
+ [10589, 'RightDownTeeVector'],
+ [10590, 'DownLeftTeeVector'],
+ [10591, 'DownRightTeeVector'],
+ [10592, 'LeftUpTeeVector'],
+ [10593, 'LeftDownTeeVector'],
+ [10594, 'lHar'],
+ [10595, 'uHar'],
+ [10596, 'rHar'],
+ [10597, 'dHar'],
+ [10598, 'luruhar'],
+ [10599, 'ldrdhar'],
+ [10600, 'ruluhar'],
+ [10601, 'rdldhar'],
+ [10602, 'lharul'],
+ [10603, 'llhard'],
+ [10604, 'rharul'],
+ [10605, 'lrhard'],
+ [10606, 'udhar'],
+ [10606, 'UpEquilibrium'],
+ [10607, 'duhar'],
+ [10607, 'ReverseUpEquilibrium'],
+ [10608, 'RoundImplies'],
+ [10609, 'erarr'],
+ [10610, 'simrarr'],
+ [10611, 'larrsim'],
+ [10612, 'rarrsim'],
+ [10613, 'rarrap'],
+ [10614, 'ltlarr'],
+ [10616, 'gtrarr'],
+ [10617, 'subrarr'],
+ [10619, 'suplarr'],
+ [10620, 'lfisht'],
+ [10621, 'rfisht'],
+ [10622, 'ufisht'],
+ [10623, 'dfisht'],
+ [10629, 'lopar'],
+ [10630, 'ropar'],
+ [10635, 'lbrke'],
+ [10636, 'rbrke'],
+ [10637, 'lbrkslu'],
+ [10638, 'rbrksld'],
+ [10639, 'lbrksld'],
+ [10640, 'rbrkslu'],
+ [10641, 'langd'],
+ [10642, 'rangd'],
+ [10643, 'lparlt'],
+ [10644, 'rpargt'],
+ [10645, 'gtlPar'],
+ [10646, 'ltrPar'],
+ [10650, 'vzigzag'],
+ [10652, 'vangrt'],
+ [10653, 'angrtvbd'],
+ [10660, 'ange'],
+ [10661, 'range'],
+ [10662, 'dwangle'],
+ [10663, 'uwangle'],
+ [10664, 'angmsdaa'],
+ [10665, 'angmsdab'],
+ [10666, 'angmsdac'],
+ [10667, 'angmsdad'],
+ [10668, 'angmsdae'],
+ [10669, 'angmsdaf'],
+ [10670, 'angmsdag'],
+ [10671, 'angmsdah'],
+ [10672, 'bemptyv'],
+ [10673, 'demptyv'],
+ [10674, 'cemptyv'],
+ [10675, 'raemptyv'],
+ [10676, 'laemptyv'],
+ [10677, 'ohbar'],
+ [10678, 'omid'],
+ [10679, 'opar'],
+ [10681, 'operp'],
+ [10683, 'olcross'],
+ [10684, 'odsold'],
+ [10686, 'olcir'],
+ [10687, 'ofcir'],
+ [10688, 'olt'],
+ [10689, 'ogt'],
+ [10690, 'cirscir'],
+ [10691, 'cirE'],
+ [10692, 'solb'],
+ [10693, 'bsolb'],
+ [10697, 'boxbox'],
+ [10701, 'trisb'],
+ [10702, 'rtriltri'],
+ [10703, 'LeftTriangleBar'],
+ [10704, 'RightTriangleBar'],
+ [10716, 'iinfin'],
+ [10717, 'infintie'],
+ [10718, 'nvinfin'],
+ [10723, 'eparsl'],
+ [10724, 'smeparsl'],
+ [10725, 'eqvparsl'],
+ [10731, 'lozf'],
+ [10731, 'blacklozenge'],
+ [10740, 'RuleDelayed'],
+ [10742, 'dsol'],
+ [10752, 'xodot'],
+ [10752, 'bigodot'],
+ [10753, 'xoplus'],
+ [10753, 'bigoplus'],
+ [10754, 'xotime'],
+ [10754, 'bigotimes'],
+ [10756, 'xuplus'],
+ [10756, 'biguplus'],
+ [10758, 'xsqcup'],
+ [10758, 'bigsqcup'],
+ [10764, 'qint'],
+ [10764, 'iiiint'],
+ [10765, 'fpartint'],
+ [10768, 'cirfnint'],
+ [10769, 'awint'],
+ [10770, 'rppolint'],
+ [10771, 'scpolint'],
+ [10772, 'npolint'],
+ [10773, 'pointint'],
+ [10774, 'quatint'],
+ [10775, 'intlarhk'],
+ [10786, 'pluscir'],
+ [10787, 'plusacir'],
+ [10788, 'simplus'],
+ [10789, 'plusdu'],
+ [10790, 'plussim'],
+ [10791, 'plustwo'],
+ [10793, 'mcomma'],
+ [10794, 'minusdu'],
+ [10797, 'loplus'],
+ [10798, 'roplus'],
+ [10799, 'Cross'],
+ [10800, 'timesd'],
+ [10801, 'timesbar'],
+ [10803, 'smashp'],
+ [10804, 'lotimes'],
+ [10805, 'rotimes'],
+ [10806, 'otimesas'],
+ [10807, 'Otimes'],
+ [10808, 'odiv'],
+ [10809, 'triplus'],
+ [10810, 'triminus'],
+ [10811, 'tritime'],
+ [10812, 'iprod'],
+ [10812, 'intprod'],
+ [10815, 'amalg'],
+ [10816, 'capdot'],
+ [10818, 'ncup'],
+ [10819, 'ncap'],
+ [10820, 'capand'],
+ [10821, 'cupor'],
+ [10822, 'cupcap'],
+ [10823, 'capcup'],
+ [10824, 'cupbrcap'],
+ [10825, 'capbrcup'],
+ [10826, 'cupcup'],
+ [10827, 'capcap'],
+ [10828, 'ccups'],
+ [10829, 'ccaps'],
+ [10832, 'ccupssm'],
+ [10835, 'And'],
+ [10836, 'Or'],
+ [10837, 'andand'],
+ [10838, 'oror'],
+ [10839, 'orslope'],
+ [10840, 'andslope'],
+ [10842, 'andv'],
+ [10843, 'orv'],
+ [10844, 'andd'],
+ [10845, 'ord'],
+ [10847, 'wedbar'],
+ [10854, 'sdote'],
+ [10858, 'simdot'],
+ [10861, 'congdot'],
+ [10862, 'easter'],
+ [10863, 'apacir'],
+ [10864, 'apE'],
+ [10865, 'eplus'],
+ [10866, 'pluse'],
+ [10867, 'Esim'],
+ [10868, 'Colone'],
+ [10869, 'Equal'],
+ [10871, 'eDDot'],
+ [10871, 'ddotseq'],
+ [10872, 'equivDD'],
+ [10873, 'ltcir'],
+ [10874, 'gtcir'],
+ [10875, 'ltquest'],
+ [10876, 'gtquest'],
+ [10877, 'les'],
+ [10877, 'LessSlantEqual'],
+ [10877, 'leqslant'],
+ [10878, 'ges'],
+ [10878, 'GreaterSlantEqual'],
+ [10878, 'geqslant'],
+ [10879, 'lesdot'],
+ [10880, 'gesdot'],
+ [10881, 'lesdoto'],
+ [10882, 'gesdoto'],
+ [10883, 'lesdotor'],
+ [10884, 'gesdotol'],
+ [10885, 'lap'],
+ [10885, 'lessapprox'],
+ [10886, 'gap'],
+ [10886, 'gtrapprox'],
+ [10887, 'lne'],
+ [10887, 'lneq'],
+ [10888, 'gne'],
+ [10888, 'gneq'],
+ [10889, 'lnap'],
+ [10889, 'lnapprox'],
+ [10890, 'gnap'],
+ [10890, 'gnapprox'],
+ [10891, 'lEg'],
+ [10891, 'lesseqqgtr'],
+ [10892, 'gEl'],
+ [10892, 'gtreqqless'],
+ [10893, 'lsime'],
+ [10894, 'gsime'],
+ [10895, 'lsimg'],
+ [10896, 'gsiml'],
+ [10897, 'lgE'],
+ [10898, 'glE'],
+ [10899, 'lesges'],
+ [10900, 'gesles'],
+ [10901, 'els'],
+ [10901, 'eqslantless'],
+ [10902, 'egs'],
+ [10902, 'eqslantgtr'],
+ [10903, 'elsdot'],
+ [10904, 'egsdot'],
+ [10905, 'el'],
+ [10906, 'eg'],
+ [10909, 'siml'],
+ [10910, 'simg'],
+ [10911, 'simlE'],
+ [10912, 'simgE'],
+ [10913, 'LessLess'],
+ [10914, 'GreaterGreater'],
+ [10916, 'glj'],
+ [10917, 'gla'],
+ [10918, 'ltcc'],
+ [10919, 'gtcc'],
+ [10920, 'lescc'],
+ [10921, 'gescc'],
+ [10922, 'smt'],
+ [10923, 'lat'],
+ [10924, 'smte'],
+ [10925, 'late'],
+ [10926, 'bumpE'],
+ [10927, 'pre'],
+ [10927, 'preceq'],
+ [10927, 'PrecedesEqual'],
+ [10928, 'sce'],
+ [10928, 'succeq'],
+ [10928, 'SucceedsEqual'],
+ [10931, 'prE'],
+ [10932, 'scE'],
+ [10933, 'prnE'],
+ [10933, 'precneqq'],
+ [10934, 'scnE'],
+ [10934, 'succneqq'],
+ [10935, 'prap'],
+ [10935, 'precapprox'],
+ [10936, 'scap'],
+ [10936, 'succapprox'],
+ [10937, 'prnap'],
+ [10937, 'precnapprox'],
+ [10938, 'scnap'],
+ [10938, 'succnapprox'],
+ [10939, 'Pr'],
+ [10940, 'Sc'],
+ [10941, 'subdot'],
+ [10942, 'supdot'],
+ [10943, 'subplus'],
+ [10944, 'supplus'],
+ [10945, 'submult'],
+ [10946, 'supmult'],
+ [10947, 'subedot'],
+ [10948, 'supedot'],
+ [10949, 'subE'],
+ [10949, 'subseteqq'],
+ [10950, 'supE'],
+ [10950, 'supseteqq'],
+ [10951, 'subsim'],
+ [10952, 'supsim'],
+ [10955, 'subnE'],
+ [10955, 'subsetneqq'],
+ [10956, 'supnE'],
+ [10956, 'supsetneqq'],
+ [10959, 'csub'],
+ [10960, 'csup'],
+ [10961, 'csube'],
+ [10962, 'csupe'],
+ [10963, 'subsup'],
+ [10964, 'supsub'],
+ [10965, 'subsub'],
+ [10966, 'supsup'],
+ [10967, 'suphsub'],
+ [10968, 'supdsub'],
+ [10969, 'forkv'],
+ [10970, 'topfork'],
+ [10971, 'mlcp'],
+ [10980, 'Dashv'],
+ [10980, 'DoubleLeftTee'],
+ [10982, 'Vdashl'],
+ [10983, 'Barv'],
+ [10984, 'vBar'],
+ [10985, 'vBarv'],
+ [10987, 'Vbar'],
+ [10988, 'Not'],
+ [10989, 'bNot'],
+ [10990, 'rnmid'],
+ [10991, 'cirmid'],
+ [10992, 'midcir'],
+ [10993, 'topcir'],
+ [10994, 'nhpar'],
+ [10995, 'parsim'],
+ [11005, 'parsl'],
+ [64256, 'fflig'],
+ [64257, 'filig'],
+ [64258, 'fllig'],
+ [64259, 'ffilig'],
+ [64260, 'ffllig'],
+ [119964, 'Ascr'],
+ [119966, 'Cscr'],
+ [119967, 'Dscr'],
+ [119970, 'Gscr'],
+ [119973, 'Jscr'],
+ [119974, 'Kscr'],
+ [119977, 'Nscr'],
+ [119978, 'Oscr'],
+ [119979, 'Pscr'],
+ [119980, 'Qscr'],
+ [119982, 'Sscr'],
+ [119983, 'Tscr'],
+ [119984, 'Uscr'],
+ [119985, 'Vscr'],
+ [119986, 'Wscr'],
+ [119987, 'Xscr'],
+ [119988, 'Yscr'],
+ [119989, 'Zscr'],
+ [119990, 'ascr'],
+ [119991, 'bscr'],
+ [119992, 'cscr'],
+ [119993, 'dscr'],
+ [119995, 'fscr'],
+ [119997, 'hscr'],
+ [119998, 'iscr'],
+ [119999, 'jscr'],
+ [120000, 'kscr'],
+ [120001, 'lscr'],
+ [120002, 'mscr'],
+ [120003, 'nscr'],
+ [120005, 'pscr'],
+ [120006, 'qscr'],
+ [120007, 'rscr'],
+ [120008, 'sscr'],
+ [120009, 'tscr'],
+ [120010, 'uscr'],
+ [120011, 'vscr'],
+ [120012, 'wscr'],
+ [120013, 'xscr'],
+ [120014, 'yscr'],
+ [120015, 'zscr'],
+ [120068, 'Afr'],
+ [120069, 'Bfr'],
+ [120071, 'Dfr'],
+ [120072, 'Efr'],
+ [120073, 'Ffr'],
+ [120074, 'Gfr'],
+ [120077, 'Jfr'],
+ [120078, 'Kfr'],
+ [120079, 'Lfr'],
+ [120080, 'Mfr'],
+ [120081, 'Nfr'],
+ [120082, 'Ofr'],
+ [120083, 'Pfr'],
+ [120084, 'Qfr'],
+ [120086, 'Sfr'],
+ [120087, 'Tfr'],
+ [120088, 'Ufr'],
+ [120089, 'Vfr'],
+ [120090, 'Wfr'],
+ [120091, 'Xfr'],
+ [120092, 'Yfr'],
+ [120094, 'afr'],
+ [120095, 'bfr'],
+ [120096, 'cfr'],
+ [120097, 'dfr'],
+ [120098, 'efr'],
+ [120099, 'ffr'],
+ [120100, 'gfr'],
+ [120101, 'hfr'],
+ [120102, 'ifr'],
+ [120103, 'jfr'],
+ [120104, 'kfr'],
+ [120105, 'lfr'],
+ [120106, 'mfr'],
+ [120107, 'nfr'],
+ [120108, 'ofr'],
+ [120109, 'pfr'],
+ [120110, 'qfr'],
+ [120111, 'rfr'],
+ [120112, 'sfr'],
+ [120113, 'tfr'],
+ [120114, 'ufr'],
+ [120115, 'vfr'],
+ [120116, 'wfr'],
+ [120117, 'xfr'],
+ [120118, 'yfr'],
+ [120119, 'zfr'],
+ [120120, 'Aopf'],
+ [120121, 'Bopf'],
+ [120123, 'Dopf'],
+ [120124, 'Eopf'],
+ [120125, 'Fopf'],
+ [120126, 'Gopf'],
+ [120128, 'Iopf'],
+ [120129, 'Jopf'],
+ [120130, 'Kopf'],
+ [120131, 'Lopf'],
+ [120132, 'Mopf'],
+ [120134, 'Oopf'],
+ [120138, 'Sopf'],
+ [120139, 'Topf'],
+ [120140, 'Uopf'],
+ [120141, 'Vopf'],
+ [120142, 'Wopf'],
+ [120143, 'Xopf'],
+ [120144, 'Yopf'],
+ [120146, 'aopf'],
+ [120147, 'bopf'],
+ [120148, 'copf'],
+ [120149, 'dopf'],
+ [120150, 'eopf'],
+ [120151, 'fopf'],
+ [120152, 'gopf'],
+ [120153, 'hopf'],
+ [120154, 'iopf'],
+ [120155, 'jopf'],
+ [120156, 'kopf'],
+ [120157, 'lopf'],
+ [120158, 'mopf'],
+ [120159, 'nopf'],
+ [120160, 'oopf'],
+ [120161, 'popf'],
+ [120162, 'qopf'],
+ [120163, 'ropf'],
+ [120164, 'sopf'],
+ [120165, 'topf'],
+ [120166, 'uopf'],
+ [120167, 'vopf'],
+ [120168, 'wopf'],
+ [120169, 'xopf'],
+ [120170, 'yopf'],
+ [120171, 'zopf'],
+ [60, 'nvlt'],
+ [61, 'bne'],
+ [62, 'nvgt'],
+ [102, 'fjlig'],
+ [8287, 'ThickSpace'],
+ [8605, 'nrarrw'],
+ [8706, 'npart'],
+ [8736, 'nang'],
+ [8745, 'caps'],
+ [8746, 'cups'],
+ [8764, 'nvsim'],
+ [8765, 'race'],
+ [8766, 'acE'],
+ [8770, 'nesim'],
+ [8770, 'NotEqualTilde'],
+ [8779, 'napid'],
+ [8781, 'nvap'],
+ [8782, 'nbump'],
+ [8782, 'NotHumpDownHump'],
+ [8783, 'nbumpe'],
+ [8783, 'NotHumpEqual'],
+ [8784, 'nedot'],
+ [8801, 'bnequiv'],
+ [8804, 'nvle'],
+ [8805, 'nvge'],
+ [8806, 'nlE'],
+ [8806, 'nleqq'],
+ [8807, 'ngE'],
+ [8807, 'ngeqq'],
+ [8807, 'NotGreaterFullEqual'],
+ [8808, 'lvertneqq'],
+ [8808, 'lvnE'],
+ [8809, 'gvertneqq'],
+ [8809, 'gvnE'],
+ [8810, 'nLtv'],
+ [8810, 'NotLessLess'],
+ [8810, 'nLt'],
+ [8811, 'nGtv'],
+ [8811, 'NotGreaterGreater'],
+ [8811, 'nGt'],
+ [8831, 'NotSucceedsTilde'],
+ [8834, 'NotSubset'],
+ [8834, 'nsubset'],
+ [8834, 'vnsub'],
+ [8835, 'NotSuperset'],
+ [8835, 'nsupset'],
+ [8835, 'vnsup'],
+ [8842, 'varsubsetneq'],
+ [8842, 'vsubne'],
+ [8843, 'varsupsetneq'],
+ [8843, 'vsupne'],
+ [8847, 'NotSquareSubset'],
+ [8848, 'NotSquareSuperset'],
+ [8851, 'sqcaps'],
+ [8852, 'sqcups'],
+ [8884, 'nvltrie'],
+ [8885, 'nvrtrie'],
+ [8920, 'nLl'],
+ [8921, 'nGg'],
+ [8922, 'lesg'],
+ [8923, 'gesl'],
+ [8949, 'notindot'],
+ [8953, 'notinE'],
+ [10547, 'nrarrc'],
+ [10703, 'NotLeftTriangleBar'],
+ [10704, 'NotRightTriangleBar'],
+ [10861, 'ncongdot'],
+ [10864, 'napE'],
+ [10877, 'nleqslant'],
+ [10877, 'nles'],
+ [10877, 'NotLessSlantEqual'],
+ [10878, 'ngeqslant'],
+ [10878, 'nges'],
+ [10878, 'NotGreaterSlantEqual'],
+ [10913, 'NotNestedLessLess'],
+ [10914, 'NotNestedGreaterGreater'],
+ [10924, 'smtes'],
+ [10925, 'lates'],
+ [10927, 'NotPrecedesEqual'],
+ [10927, 'npre'],
+ [10927, 'npreceq'],
+ [10928, 'NotSucceedsEqual'],
+ [10928, 'nsce'],
+ [10928, 'nsucceq'],
+ [10949, 'nsubE'],
+ [10949, 'nsubseteqq'],
+ [10950, 'nsupE'],
+ [10950, 'nsupseteqq'],
+ [10955, 'varsubsetneqq'],
+ [10955, 'vsubnE'],
+ [10956, 'varsupsetneqq'],
+ [10956, 'vsupnE'],
+ [11005, 'nparsl'],
+
+ ]
+
+ # Contains the mapping of code point (or name) to the actual Entity object.
+ ENTITY_MAP = Hash.new do |h, k|
+ if k.kind_of?(Integer)
+ h[k] = Entity.new(k, nil)
+ else
+ raise Kramdown::Error, "Can't handle generic non-integer character reference '#{k}'"
+ end
+ end
+
+ ENTITY_TABLE.each do |code_point, data|
+ ENTITY_MAP[code_point] = if data.kind_of?(String)
+ ENTITY_MAP[data] = Entity.new(code_point, data)
+ else
+ ENTITY_MAP[data]
+ end
+ end
+
+ # Return the entity for the given code point or name +point_or_name+.
+ def entity(point_or_name)
+ ENTITY_MAP[point_or_name]
+ end
+
+ module_function :entity
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb
new file mode 100644
index 0000000..0fba9d4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb
@@ -0,0 +1,84 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'rexml/parsers/baseparser'
+
+module Kramdown
+
+ module Utils
+
+ # Provides convenience methods for HTML related tasks.
+ #
+ # *Note* that this module has to be mixed into a class that has a @root (containing an element
+ # of type :root) and an @options (containing an options hash) instance variable so that some of
+ # the methods can work correctly.
+ module Html
+
+ # Convert the entity +e+ to a string. The optional parameter +original+ may contain the
+ # original representation of the entity.
+ #
+ # This method uses the option +entity_output+ to determine the output form for the entity.
+ def entity_to_str(e, original = nil)
+ entity_output = @options[:entity_output]
+
+ if entity_output == :as_char &&
+ (c = e.char.encode(@root.options[:encoding]) rescue nil) &&
+ ((c = e.char) == '"' || !ESCAPE_MAP.key?(c))
+ c
+ elsif (entity_output == :as_input || entity_output == :as_char) && original
+ original
+ elsif (entity_output == :symbolic || ESCAPE_MAP.key?(e.char)) && !e.name.nil?
+ "&#{e.name};"
+ else # default to :numeric
+ "&##{e.code_point};"
+ end
+ end
+
+ # Return the HTML representation of the attributes +attr+.
+ def html_attributes(attr)
+ return '' if attr.empty?
+
+ attr.map do |k, v|
+ v.nil? || (k == 'id' && v.strip.empty?) ? '' : " #{k}=\"#{escape_html(v.to_s, :attribute)}\""
+ end.join
+ end
+
+ # :stopdoc:
+ ESCAPE_MAP = {
+ '<' => '&lt;',
+ '>' => '&gt;',
+ '&' => '&amp;',
+ '"' => '&quot;',
+ }
+ ESCAPE_ALL_RE = /<|>|&/
+ ESCAPE_TEXT_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&/)
+ ESCAPE_ATTRIBUTE_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&|"/)
+ ESCAPE_RE_FROM_TYPE = {all: ESCAPE_ALL_RE, text: ESCAPE_TEXT_RE, attribute: ESCAPE_ATTRIBUTE_RE}
+ # :startdoc:
+
+ # Escape the special HTML characters in the string +str+. The parameter +type+ specifies what
+ # is escaped: :all - all special HTML characters except the quotation mark as well as
+ # entities, :text - all special HTML characters except the quotation mark but no entities and
+ # :attribute - all special HTML characters including the quotation mark but no entities.
+ def escape_html(str, type = :all)
+ str.gsub(ESCAPE_RE_FROM_TYPE[type]) {|m| ESCAPE_MAP[m] || m }
+ end
+
+ REDUNDANT_LINE_BREAK_REGEX = /([\p{Han}\p{Hiragana}\p{Katakana}]+)\n([\p{Han}\p{Hiragana}\p{Katakana}]+)/u
+ def fix_cjk_line_break(str)
+ while str.gsub!(REDUNDANT_LINE_BREAK_REGEX, '\1\2')
+ end
+ str
+ end
+
+ end
+
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb
new file mode 100644
index 0000000..32549fb
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb
@@ -0,0 +1,41 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+ module Utils
+
+ # A simple least recently used (LRU) cache.
+ #
+ # The cache relies on the fact that Ruby's Hash class maintains insertion order. So deleting
+ # and re-inserting a key-value pair on access moves the key to the last position. When an
+ # entry is added and the cache is full, the first entry is removed.
+ class LRUCache
+
+ # Creates a new LRUCache that can hold +size+ entries.
+ def initialize(size)
+ @size = size
+ @cache = {}
+ end
+
+ # Returns the stored value for +key+ or +nil+ if no value was stored under the key.
+ def [](key)
+ (val = @cache.delete(key)).nil? ? nil : @cache[key] = val
+ end
+
+ # Stores the +value+ under the +key+.
+ def []=(key, value)
+ @cache.delete(key)
+ @cache[key] = value
+ @cache.shift if @cache.length > @size
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb
new file mode 100644
index 0000000..2ef194e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb
@@ -0,0 +1,81 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+require 'strscan'
+
+module Kramdown
+ module Utils
+
+ # This patched StringScanner adds line number information for current scan position and a
+ # start_line_number override for nested StringScanners.
+ class StringScanner < ::StringScanner
+
+ # The start line number. Used for nested StringScanners that scan a sub-string of the source
+ # document. The kramdown parser uses this, e.g., for span level parsers.
+ attr_reader :start_line_number
+
+ # Takes the start line number as optional second argument.
+ #
+ # Note: The original second argument is no longer used so this should be safe.
+ def initialize(string, start_line_number = 1)
+ super(string)
+ @start_line_number = start_line_number || 1
+ @previous_pos = 0
+ @previous_line_number = @start_line_number
+ end
+
+ # Sets the byte position of the scan pointer.
+ #
+ # Note: This also resets some internal variables, so always use pos= when setting the position
+ # and don't use any other method for that!
+ def pos=(pos)
+ if self.pos > pos
+ @previous_line_number = @start_line_number
+ @previous_pos = 0
+ end
+ super
+ end
+
+ # Return information needed to revert the byte position of the string scanner in a performant
+ # way.
+ #
+ # The returned data can be fed to #revert_pos to revert the position to the saved one.
+ #
+ # Note: Just saving #pos won't be enough.
+ def save_pos
+ [pos, @previous_pos, @previous_line_number]
+ end
+
+ # Revert the position to one saved by #save_pos.
+ def revert_pos(data)
+ self.pos = data[0]
+ @previous_pos, @previous_line_number = data[1], data[2]
+ end
+
+ # Returns the line number for current charpos.
+ #
+ # NOTE: Requires that all line endings are normalized to '\n'
+ #
+ # NOTE: Normally we'd have to add one to the count of newlines to get the correct line number.
+ # However we add the one indirectly by using a one-based start_line_number.
+ def current_line_number
+ # Not using string[@previous_pos..best_pos].count('\n') because it is slower
+ strscan = ::StringScanner.new(string)
+ strscan.pos = @previous_pos
+ old_pos = pos + 1
+ @previous_line_number += 1 while strscan.skip_until(/\n/) && strscan.pos <= old_pos
+
+ @previous_pos = (eos? ? pos : pos + 1)
+ @previous_line_number
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb
new file mode 100644
index 0000000..b4bbe28
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb
@@ -0,0 +1,46 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+# This file is based on code originally from the Stringex library and needs the data files from
+# Stringex to work correctly.
+
+module Kramdown
+ module Utils
+
+ # Provides the ability to tranliterate Unicode strings into plain ASCII ones.
+ module Unidecoder
+
+ gem 'stringex'
+ path = $:.find do |dir|
+ File.directory?(File.join(File.expand_path(dir), "stringex", "unidecoder_data"))
+ end
+
+ if path
+ CODEPOINTS = Hash.new do |h, k|
+ h[k] = YAML.load_file(File.join(path, "stringex", "unidecoder_data", "#{k}.yml"))
+ end
+
+ # Transliterate string from Unicode into ASCII.
+ def self.decode(string)
+ string.gsub(/[^\x00-\x7f]/u) do |codepoint|
+ unpacked = codepoint.unpack1("U")
+ CODEPOINTS[sprintf("x%02x", unpacked >> 8)][unpacked & 255]
+ rescue StandardError
+ "?"
+ end
+ end
+ else
+ def self.decode(string)
+ string
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb
new file mode 100644
index 0000000..0bc4130
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb
@@ -0,0 +1,15 @@
+# -*- coding: utf-8; frozen_string_literal: true -*-
+#
+#--
+# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
+#
+# This file is part of kramdown which is licensed under the MIT.
+#++
+#
+
+module Kramdown
+
+ # The kramdown version.
+ VERSION = '2.5.1'
+
+end