qiita-markdown 0.44.0 → 0.44.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,9 +21,9 @@ module Qiita
21
21
  GROUP_IDENTIFIER_PATTERN = %r{
22
22
  (?:^|\W)
23
23
  @((?>[a-z\d][a-z\d-]{2,31}))
24
- \/
24
+ /
25
25
  ([A-Za-z\d][A-Za-z\d-]{0,62}[A-Za-z\d])
26
- (?!\/)
26
+ (?!/)
27
27
  (?=
28
28
  \.+[ \t\W]|
29
29
  \.+$|
@@ -4,12 +4,12 @@ module Qiita
4
4
  class ImageLink < HTML::Pipeline::Filter
5
5
  def call
6
6
  doc.search("img").each do |img|
7
- unless img.ancestors.any? { |ancestor| ancestor.name == "a" }
8
- outer = Nokogiri::HTML.fragment(%(<a href="#{img['src']}" target="_blank"></a>))
9
- inner = img.clone
10
- outer.at("a").add_child(inner)
11
- img.replace(outer)
12
- end
7
+ next if img.ancestors.any? { |ancestor| ancestor.name == "a" }
8
+
9
+ outer = Nokogiri::HTML.fragment(%(<a href="#{img['src']}" target="_blank"></a>))
10
+ inner = img.clone
11
+ outer.at("a").add_child(inner)
12
+ img.replace(outer)
13
13
  end
14
14
  doc
15
15
  end
@@ -6,15 +6,15 @@ module Qiita
6
6
 
7
7
  REGEXPS = Regexp.union(
8
8
  /\#(?:\h{3}|\h{6})/,
9
- /rgba?\(\s*(?:\d+(?:\,|\s)\s*){2}\d+\s*\)/,
10
- /rgba?\(\s*(?:\d+%(?:\,|\s)\s*){2}\d+%\s*\)/,
11
- /rgba?\(\s*(?:\d+\,\s*){3}\d*\.?\d+%?\s*\)/,
12
- /rgba?\(\s*(?:\d+\s*){2}\d+\s*\/\s*\d?\.?\d+%?\s*\)/,
13
- /rgba?\(\s*(?:\d+%\s*){2}\d+%\s*\/\s*\d?\.?\d+%?\s*\)/,
14
- /hsla?\(\s*\d+(?:deg|rad|grad|turn)?\,\s*\d+%\,\s*\d+%\s*\)/,
9
+ /rgba?\(\s*(?:\d+(?:,|\s)\s*){2}\d+\s*\)/,
10
+ /rgba?\(\s*(?:\d+%(?:,|\s)\s*){2}\d+%\s*\)/,
11
+ /rgba?\(\s*(?:\d+,\s*){3}\d*\.?\d+%?\s*\)/,
12
+ %r{rgba?\(\s*(?:\d+\s*){2}\d+\s*/\s*\d?\.?\d+%?\s*\)},
13
+ %r{rgba?\(\s*(?:\d+%\s*){2}\d+%\s*/\s*\d?\.?\d+%?\s*\)},
14
+ /hsla?\(\s*\d+(?:deg|rad|grad|turn)?,\s*\d+%,\s*\d+%\s*\)/,
15
15
  /hsla?\(\s*\d+(?:deg|rad|grad|turn)?\s+\d+%\s+\d+%\s*\)/,
16
- /hsla?\(\s*\d+(?:deg|rad|grad|turn)?\,\s*(?:\d+%\,\s*){2}\d?\.?\d+%?\s*\)/,
17
- /hsla?\(\s*\d+(?:deg|rad|grad|turn)?\s+\d+%\s+\d+%\s*\/\s*\d?\.?\d+%?\s*\)/,
16
+ /hsla?\(\s*\d+(?:deg|rad|grad|turn)?,\s*(?:\d+%,\s*){2}\d?\.?\d+%?\s*\)/,
17
+ %r{hsla?\(\s*\d+(?:deg|rad|grad|turn)?\s+\d+%\s+\d+%\s*/\s*\d?\.?\d+%?\s*\)},
18
18
  )
19
19
 
20
20
  COLOR_CODE_PATTERN = /\A\s*(#{REGEXPS})\s*\z/
@@ -8,17 +8,17 @@ module Qiita
8
8
  class Mention < HTML::Pipeline::MentionFilter
9
9
  IGNORE_PARENTS = ::HTML::Pipeline::MentionFilter::IGNORE_PARENTS + Set["blockquote"]
10
10
 
11
- MentionPattern = /
11
+ MentionPattern = %r{
12
12
  (?:^|\W)
13
- @((?>[\w][\w-]{0,30}\w(?:@github)?))
14
- (?!\/)
13
+ @((?>\w[\w-]{0,30}\w(?:@github)?))
14
+ (?!/)
15
15
  (?=
16
16
  \.+[ \t\W]|
17
17
  \.+$|
18
18
  [^0-9a-zA-Z_.]|
19
19
  $
20
20
  )
21
- /ix
21
+ }ix
22
22
 
23
23
  # @note Override to use another IGNORE_PARENTS
24
24
  def call
@@ -28,8 +28,10 @@ module Qiita
28
28
  content = node.to_html
29
29
  next unless content.include?("@")
30
30
  next if has_ancestor?(node, IGNORE_PARENTS)
31
+
31
32
  html = mention_link_filter(content, base_url, info_url, username_pattern)
32
33
  next if html == content
34
+
33
35
  node.replace(html)
34
36
  end
35
37
  doc
@@ -38,22 +40,22 @@ module Qiita
38
40
  # @note Override to use customized MentionPattern and allowed_usernames logic.
39
41
  def mention_link_filter(text, _, _, _)
40
42
  text.gsub(MentionPattern) do |match|
41
- name = $1
43
+ name = ::Regexp.last_match(1)
42
44
  case
43
45
  when allowed_usernames && name == "all"
44
46
  result[:mentioned_usernames] |= allowed_usernames
45
47
  match.sub(
46
48
  "@#{name}",
47
- %[<a href="/" class="user-mention" title="#{name}">@#{name}</a>]
49
+ %(<a href="/" class="user-mention" title="#{name}">@#{name}</a>),
48
50
  )
49
- when allowed_usernames && !allowed_usernames.include?(name) || name == "all"
51
+ when (allowed_usernames && !allowed_usernames.include?(name)) || name == "all"
50
52
  match
51
53
  else
52
54
  result[:mentioned_usernames] |= [name]
53
55
  url = File.join(base_url, name)
54
56
  match.sub(
55
57
  "@#{name}",
56
- %[<a href="#{url}" class="user-mention js-hovercard" title="#{name}" data-hovercard-target-type="user" data-hovercard-target-name="#{name}">@#{name}</a>]
58
+ %(<a href="#{url}" class="user-mention js-hovercard" title="#{name}" data-hovercard-target-type="user" data-hovercard-target-name="#{name}">@#{name}</a>),
57
59
  )
58
60
  end
59
61
  end
@@ -66,7 +68,7 @@ module Qiita
66
68
  end
67
69
 
68
70
  def has_ancestor?(node, tags)
69
- super || node.parent.parent && node.parent.parent["class"] == "code-lang"
71
+ super || (node.parent.parent && node.parent.parent["class"] == "code-lang")
70
72
  end
71
73
  end
72
74
  end
@@ -38,6 +38,7 @@ module Qiita
38
38
  doc.traverse do |node|
39
39
  next unless node.element?
40
40
  next if SIMPLE_ELEMENTS.include?(node.name)
41
+
41
42
  node.replace(node.children)
42
43
  end
43
44
  end
@@ -54,7 +54,7 @@ module Qiita
54
54
  end
55
55
 
56
56
  def call
57
- outer = Nokogiri::HTML.fragment(%Q[<div class="code-frame" data-lang="#{language}">])
57
+ outer = Nokogiri::HTML.fragment(%(<div class="code-frame" data-lang="#{language}">))
58
58
  frame = outer.at("div")
59
59
  frame.add_child(filename_node) if filename
60
60
  frame.add_child(highlighted_node)
@@ -72,7 +72,7 @@ module Qiita
72
72
  end
73
73
 
74
74
  def filename_node
75
- %Q[<div class="code-lang"><span class="bold">#{filename}</span></div>]
75
+ %(<div class="code-lang"><span class="bold">#{filename}</span></div>)
76
76
  end
77
77
 
78
78
  def has_inline_php?
@@ -87,7 +87,7 @@ module Qiita
87
87
  if specific_language && Rouge::Lexer.find(specific_language)
88
88
  begin
89
89
  highlight(specific_language).presence or raise
90
- rescue
90
+ rescue StandardError
91
91
  highlight(@default_language)
92
92
  end
93
93
  else
@@ -100,7 +100,7 @@ module Qiita
100
100
  end
101
101
 
102
102
  def language_node
103
- Nokogiri::HTML.fragment(%Q[<div class="code-frame" data-lang="#{language}"></div>])
103
+ Nokogiri::HTML.fragment(%(<div class="code-frame" data-lang="#{language}"></div>))
104
104
  end
105
105
 
106
106
  def specific_language
@@ -51,9 +51,7 @@ module Qiita
51
51
  node.content.each_char.with_index do |char, index|
52
52
  current_char_is_blank = char.strip.empty?
53
53
 
54
- if !@previous_char_was_blank || !current_char_is_blank
55
- @current_length += 1
56
- end
54
+ @current_length += 1 if !@previous_char_was_blank || !current_char_is_blank
57
55
 
58
56
  @previous_char_was_blank = current_char_is_blank
59
57
 
@@ -10,24 +10,24 @@ module Qiita
10
10
  summary sup table tbody td tfoot th thead tr ul var
11
11
  ],
12
12
  attributes: {
13
- "a" => %w[class href rel title],
13
+ "a" => %w[class href rel title],
14
14
  "blockquote" => %w[cite] + Embed::Tweet::ATTRIBUTES,
15
- "code" => %w[data-metadata],
16
- "div" => %w[class data-type data-metadata],
17
- "font" => %w[color],
18
- "h1" => %w[id],
19
- "h2" => %w[id],
20
- "h3" => %w[id],
21
- "h4" => %w[id],
22
- "h5" => %w[id],
23
- "h6" => %w[id],
24
- "img" => %w[alt height src title width],
25
- "ins" => %w[cite datetime],
26
- "li" => %w[id],
27
- "p" => Embed::CodePen::ATTRIBUTES,
28
- "q" => %w[cite],
29
- "script" => %w[async src id].concat(Embed::SpeekerDeck::ATTRIBUTES, Embed::Docswell::ATTRIBUTES),
30
- "iframe" => %w[
15
+ "code" => %w[data-metadata],
16
+ "div" => %w[class data-type data-metadata],
17
+ "font" => %w[color],
18
+ "h1" => %w[id],
19
+ "h2" => %w[id],
20
+ "h3" => %w[id],
21
+ "h4" => %w[id],
22
+ "h5" => %w[id],
23
+ "h6" => %w[id],
24
+ "img" => %w[alt height src title width],
25
+ "ins" => %w[cite datetime],
26
+ "li" => %w[id],
27
+ "p" => Embed::CodePen::ATTRIBUTES,
28
+ "q" => %w[cite],
29
+ "script" => %w[async src id].concat(Embed::SpeekerDeck::ATTRIBUTES, Embed::Docswell::ATTRIBUTES),
30
+ "iframe" => %w[
31
31
  allowfullscreen
32
32
  frameborder
33
33
  height
@@ -38,14 +38,14 @@ module Qiita
38
38
  style
39
39
  width
40
40
  ],
41
- "sup" => %w[id],
42
- "td" => %w[colspan rowspan style],
43
- "th" => %w[colspan rowspan style],
41
+ "sup" => %w[id],
42
+ "td" => %w[colspan rowspan style],
43
+ "th" => %w[colspan rowspan style],
44
44
  },
45
45
  protocols: {
46
- "a" => { "href" => ["http", "https", "mailto", :relative] },
46
+ "a" => { "href" => ["http", "https", "mailto", :relative] },
47
47
  "blockquote" => { "cite" => ["http", "https", :relative] },
48
- "q" => { "cite" => ["http", "https", :relative] },
48
+ "q" => { "cite" => ["http", "https", :relative] },
49
49
  },
50
50
  css: {
51
51
  properties: %w[
@@ -18,11 +18,11 @@ module Qiita
18
18
  end
19
19
 
20
20
  def to_s
21
- fail NotImplementedError
21
+ raise NotImplementedError
22
22
  end
23
23
 
24
24
  def increment
25
- fail NotImplementedError
25
+ raise NotImplementedError
26
26
  end
27
27
 
28
28
  private
@@ -12,7 +12,7 @@ module Qiita
12
12
 
13
13
  # https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L609-L642
14
14
  def header(text, level)
15
- @level_offset = level - 1 unless @level_offset
15
+ @level_offset ||= level - 1
16
16
 
17
17
  level -= @level_offset
18
18
  level = 1 if level < 1
@@ -37,6 +37,7 @@ module Qiita
37
37
 
38
38
  def transform
39
39
  return unless FILTERS.key?(name)
40
+
40
41
  FILTERS[name].each_pair do |attr, pattern|
41
42
  filter_attribute(attr, pattern) if node.attributes.key?(attr)
42
43
  end
@@ -2,8 +2,7 @@ module Qiita
2
2
  module Markdown
3
3
  module Transformers
4
4
  class FilterIframe
5
- URL_WHITE_LIST = [
6
- ].flatten.freeze
5
+ URL_WHITE_LIST = [].flatten.freeze
7
6
 
8
7
  HOST_WHITE_LIST = [
9
8
  Embed::Youtube::SCRIPT_HOSTS,
@@ -45,7 +45,7 @@ module Qiita
45
45
  def host_of(url)
46
46
  if url
47
47
  scheme = URI.parse(url).scheme
48
- Addressable::URI.parse(url).host if ["http", "https"].include? scheme
48
+ Addressable::URI.parse(url).host if %w[http https].include? scheme
49
49
  end
50
50
  rescue Addressable::URI::InvalidURIError, URI::InvalidURIError
51
51
  nil
@@ -12,9 +12,7 @@ module Qiita
12
12
  end
13
13
 
14
14
  def transform
15
- if has_invalid_list_node? || has_invalid_table_node?
16
- node.replace(node.children)
17
- end
15
+ node.replace(node.children) if has_invalid_list_node? || has_invalid_table_node?
18
16
  end
19
17
 
20
18
  private
@@ -1,5 +1,5 @@
1
1
  module Qiita
2
2
  module Markdown
3
- VERSION = "0.44.0"
3
+ VERSION = "0.44.1"
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require "qiita/markdown/version"
4
4
 
@@ -13,26 +13,26 @@ Gem::Specification.new do |spec|
13
13
 
14
14
  spec.files = `git ls-files -z`.split("\x0")
15
15
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
16
  spec.require_paths = ["lib"]
18
17
 
19
18
  spec.required_ruby_version = ">= 2.6.0"
20
19
 
20
+ spec.add_dependency "addressable"
21
21
  spec.add_dependency "gemoji"
22
22
  spec.add_dependency "github-linguist", "~> 4.0"
23
+ spec.add_dependency "greenmat", "3.5.1.4"
23
24
  spec.add_dependency "html-pipeline", "~> 2.0"
24
25
  spec.add_dependency "mem"
25
26
  spec.add_dependency "rouge", "3.26.0"
26
- spec.add_dependency "greenmat", "3.5.1.4"
27
27
  spec.add_dependency "sanitize"
28
- spec.add_dependency "addressable"
29
28
  spec.add_development_dependency "activesupport", "~> 5.2.7"
30
29
  spec.add_development_dependency "benchmark-ips", "~> 1.2"
31
30
  spec.add_development_dependency "bundler"
32
31
  spec.add_development_dependency "codeclimate-test-reporter", "0.4.4"
33
- spec.add_development_dependency "simplecov", "!= 0.18.0", "!= 0.18.1", "!= 0.18.2", "!= 0.18.3", "!= 0.18.4", "!= 0.18.5", "!= 0.19.0", "!= 0.19.1"
34
32
  spec.add_development_dependency "pry"
35
33
  spec.add_development_dependency "rake", "~> 10.0"
36
34
  spec.add_development_dependency "rspec", "~> 3.1"
37
- spec.add_development_dependency "rubocop", "~> 1.27.0"
35
+ spec.add_development_dependency "rubocop", "~> 1.39.0"
36
+ spec.add_development_dependency "simplecov", "!= 0.18.0", "!= 0.18.1", "!= 0.18.2", "!= 0.18.3", "!= 0.18.4", "!= 0.18.5", "!= 0.19.0", "!= 0.19.1"
37
+ spec.metadata["rubygems_mfa_required"] = "true"
38
38
  end
@@ -250,7 +250,7 @@ describe Qiita::Markdown::Processor do
250
250
  foo
251
251
 
252
252
  </code></pre></div></div>
253
- HTML
253
+ HTML
254
254
  end
255
255
  end
256
256
 
@@ -383,7 +383,7 @@ describe Qiita::Markdown::Processor do
383
383
 
384
384
  context "with @all and allowed_usernames context" do
385
385
  before do
386
- context[:allowed_usernames] = ["alice", "bob"]
386
+ context[:allowed_usernames] = %w[alice bob]
387
387
  end
388
388
 
389
389
  let(:markdown) do
@@ -400,7 +400,7 @@ describe Qiita::Markdown::Processor do
400
400
 
401
401
  context "with @all and @alice" do
402
402
  before do
403
- context[:allowed_usernames] = ["alice", "bob"]
403
+ context[:allowed_usernames] = %w[alice bob]
404
404
  end
405
405
 
406
406
  let(:markdown) do
@@ -517,7 +517,7 @@ describe Qiita::Markdown::Processor do
517
517
  it "creates link for that with .autolink class" do
518
518
  should eq(
519
519
  '<p><a href="http://example.com/search?q=%E6%97%A5%E6%9C%AC%E8%AA%9E" class="autolink">' \
520
- "http://example.com/search?q=日本語</a></p>\n"
520
+ "http://example.com/search?q=日本語</a></p>\n",
521
521
  )
522
522
  end
523
523
  end
@@ -613,7 +613,7 @@ describe Qiita::Markdown::Processor do
613
613
 
614
614
  context "with font element with color attribute" do
615
615
  let(:markdown) do
616
- %[<font color="red">test</font>]
616
+ %(<font color="red">test</font>)
617
617
  end
618
618
 
619
619
  it "allows font element with color attribute" do
@@ -844,7 +844,7 @@ describe Qiita::Markdown::Processor do
844
844
 
845
845
  context "with emoji_names and emoji_url_generator context" do
846
846
  before do
847
- context[:emoji_names] = %w(foo o)
847
+ context[:emoji_names] = %w[foo o]
848
848
 
849
849
  context[:emoji_url_generator] = proc do |emoji_name|
850
850
  "https://example.com/foo.png" if emoji_name == "foo"
@@ -860,11 +860,11 @@ describe Qiita::Markdown::Processor do
860
860
  it "replaces only the specified emoji names with img elements with custom URL" do
861
861
  should include(
862
862
  '<img class="emoji" title=":foo:" alt=":foo:" src="https://example.com/foo.png"',
863
- '<img class="emoji" title=":o:" alt=":o:" src="/images/emoji/unicode/2b55.png"'
863
+ '<img class="emoji" title=":o:" alt=":o:" src="/images/emoji/unicode/2b55.png"',
864
864
  )
865
865
 
866
866
  should_not include(
867
- '<img class="emoji" title=":x:" alt=":x:"'
867
+ '<img class="emoji" title=":x:" alt=":x:"',
868
868
  )
869
869
  end
870
870
  end
@@ -881,7 +881,7 @@ describe Qiita::Markdown::Processor do
881
881
  it "creates link which does not have rel='nofollow noopener' and target='_blank'" do
882
882
  should eq(
883
883
  '<p><a href="http://qiita.com/?a=b" class="autolink">' \
884
- "http://qiita.com/?a=b</a></p>\n"
884
+ "http://qiita.com/?a=b</a></p>\n",
885
885
  )
886
886
  end
887
887
  end
@@ -898,7 +898,7 @@ describe Qiita::Markdown::Processor do
898
898
  it "creates link which has rel='nofollow noopener' and target='_blank'" do
899
899
  should eq(
900
900
  '<p><a href="http://external.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
901
- "http://external.com/?a=b</a></p>\n"
901
+ "http://external.com/?a=b</a></p>\n",
902
902
  )
903
903
  end
904
904
  end
@@ -914,7 +914,7 @@ describe Qiita::Markdown::Processor do
914
914
 
915
915
  it "creates link which does not have rel='nofollow noopener' and target='_blank'" do
916
916
  should eq(
917
- "<p><a href=\"http://qiita.com/?a=b\">foobar</a></p>\n"
917
+ "<p><a href=\"http://qiita.com/?a=b\">foobar</a></p>\n",
918
918
  )
919
919
  end
920
920
  end
@@ -930,7 +930,7 @@ describe Qiita::Markdown::Processor do
930
930
 
931
931
  it "creates link which has rel='nofollow noopener' and target='_blank'" do
932
932
  should eq(
933
- "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
933
+ "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n",
934
934
  )
935
935
  end
936
936
  end
@@ -947,7 +947,7 @@ describe Qiita::Markdown::Processor do
947
947
  it "creates link which has rel='nofollow noopener' and target='_blank'" do
948
948
  should eq(
949
949
  '<p><a href="http://qqqqqqiita.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
950
- "http://qqqqqqiita.com/?a=b</a></p>\n"
950
+ "http://qqqqqqiita.com/?a=b</a></p>\n",
951
951
  )
952
952
  end
953
953
  end
@@ -963,7 +963,7 @@ describe Qiita::Markdown::Processor do
963
963
 
964
964
  it "creates link which has rel='nofollow noopener' and target='_blank'" do
965
965
  should eq(
966
- "<p><a href=\"http://qqqqqqiita.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
966
+ "<p><a href=\"http://qqqqqqiita.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n",
967
967
  )
968
968
  end
969
969
  end
@@ -980,7 +980,7 @@ describe Qiita::Markdown::Processor do
980
980
  it "creates link which has rel='nofollow noopener' and target='_blank'" do
981
981
  should eq(
982
982
  '<p><a href="http://sub.qiita.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
983
- "http://sub.qiita.com/?a=b</a></p>\n"
983
+ "http://sub.qiita.com/?a=b</a></p>\n",
984
984
  )
985
985
  end
986
986
  end
@@ -996,7 +996,7 @@ describe Qiita::Markdown::Processor do
996
996
 
997
997
  it "creates link which has rel='nofollow noopener' and target='_blank', and rel value is overwritten" do
998
998
  should eq(
999
- "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
999
+ "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n",
1000
1000
  )
1001
1001
  end
1002
1002
  end
@@ -11,7 +11,7 @@ describe Qiita::Markdown::SummaryProcessor do
11
11
  end
12
12
 
13
13
  let(:markdown) do
14
- fail NotImplementedError
14
+ raise NotImplementedError
15
15
  end
16
16
 
17
17
  let(:result) do
@@ -240,7 +240,7 @@ describe Qiita::Markdown::SummaryProcessor do
240
240
  end
241
241
 
242
242
  it "replaces mention with link" do
243
- should eq %{<a href="/alice" class="user-mention js-hovercard" title="alice" data-hovercard-target-type="user" data-hovercard-target-name="alice">@alice</a>\n}
243
+ should eq %(<a href="/alice" class="user-mention js-hovercard" title="alice" data-hovercard-target-type="user" data-hovercard-target-name="alice">@alice</a>\n)
244
244
  end
245
245
  end
246
246