wovnrb 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +1 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +1 -0
  5. data/.rubocop_todo.yml +308 -0
  6. data/Rakefile +13 -14
  7. data/lib/wovnrb.rb +43 -98
  8. data/lib/wovnrb/api_translator.rb +143 -0
  9. data/lib/wovnrb/headers.rb +78 -92
  10. data/lib/wovnrb/helpers/nokogumbo_helper.rb +1 -1
  11. data/lib/wovnrb/lang.rb +93 -125
  12. data/lib/wovnrb/railtie.rb +5 -7
  13. data/lib/wovnrb/services/glob.rb +3 -3
  14. data/lib/wovnrb/services/html_converter.rb +192 -0
  15. data/lib/wovnrb/services/html_replace_marker.rb +38 -0
  16. data/lib/wovnrb/services/wovn_logger.rb +8 -4
  17. data/lib/wovnrb/settings.rb +5 -3
  18. data/lib/wovnrb/store.rb +35 -26
  19. data/lib/wovnrb/text_caches/cache_base.rb +3 -2
  20. data/lib/wovnrb/text_caches/memory_cache.rb +2 -2
  21. data/lib/wovnrb/version.rb +1 -1
  22. data/test/fixtures/html/test.html +8 -0
  23. data/test/fixtures/html/test_translated.html +8 -0
  24. data/test/lib/api_translator_test.rb +109 -0
  25. data/test/lib/headers_test.rb +84 -55
  26. data/test/lib/lang_test.rb +157 -357
  27. data/test/lib/services/glob_test.rb +1 -1
  28. data/test/lib/services/html_converter_test.rb +166 -0
  29. data/test/lib/services/html_replace_marker_test.rb +75 -0
  30. data/test/lib/services/wovn_logger_test.rb +6 -6
  31. data/test/lib/store_test.rb +25 -69
  32. data/test/lib/text_caches/cache_base_test.rb +1 -1
  33. data/test/lib/text_caches/memory_cache_test.rb +10 -11
  34. data/test/lib/wovnrb_test.rb +77 -310
  35. data/test/test_helper.rb +22 -32
  36. data/wovnrb.gemspec +35 -44
  37. metadata +86 -205
  38. data/ext/dom/Makefile +0 -239
  39. data/lib/wovnrb/api_data.rb +0 -59
  40. data/lib/wovnrb/html_replacers/image_replacer.rb +0 -69
  41. data/lib/wovnrb/html_replacers/input_replacer.rb +0 -38
  42. data/lib/wovnrb/html_replacers/link_replacer.rb +0 -78
  43. data/lib/wovnrb/html_replacers/meta_replacer.rb +0 -28
  44. data/lib/wovnrb/html_replacers/replacer_base.rb +0 -49
  45. data/lib/wovnrb/html_replacers/script_replacer.rb +0 -39
  46. data/lib/wovnrb/html_replacers/text_replacer.rb +0 -21
  47. data/lib/wovnrb/html_replacers/unified_values/dst_swapping_targets_creator.rb +0 -76
  48. data/lib/wovnrb/html_replacers/unified_values/element_category.rb +0 -242
  49. data/lib/wovnrb/html_replacers/unified_values/node_swapping_targets_creator.rb +0 -134
  50. data/lib/wovnrb/html_replacers/unified_values/text_replacer.rb +0 -35
  51. data/lib/wovnrb/html_replacers/unified_values/text_scraper.rb +0 -152
  52. data/lib/wovnrb/html_replacers/unified_values/values_stack.rb +0 -65
  53. data/lib/wovnrb/services/url.rb +0 -12
  54. data/lib/wovnrb/services/value_agent.rb +0 -9
  55. data/test/fixtures/unified_values/site_html/simple_actual.html +0 -96
  56. data/test/fixtures/unified_values/site_html/simple_expected.json +0 -251
  57. data/test/fixtures/unified_values/site_html/wovn.io_actual.html +0 -686
  58. data/test/fixtures/unified_values/site_html/wovn.io_expected.json +0 -543
  59. data/test/fixtures/unified_values/site_html/www.yahoo.co.jp_actual.html +0 -1024
  60. data/test/fixtures/unified_values/site_html/www.yahoo.co.jp_expected.json +0 -3345
  61. data/test/fixtures/unified_values/small_html/block_inside_inline_actual.html +0 -12
  62. data/test/fixtures/unified_values/small_html/block_inside_inline_expected.json +0 -22
  63. data/test/fixtures/unified_values/small_html/br_tag_actual.html +0 -10
  64. data/test/fixtures/unified_values/small_html/br_tag_expected.json +0 -12
  65. data/test/fixtures/unified_values/small_html/comment_tag_actual.html +0 -12
  66. data/test/fixtures/unified_values/small_html/comment_tag_expected.json +0 -10
  67. data/test/fixtures/unified_values/small_html/complex_text_with_html_entity_actual.html +0 -7
  68. data/test/fixtures/unified_values/small_html/complex_text_with_html_entity_expected.json +0 -11
  69. data/test/fixtures/unified_values/small_html/deep_nested_block_actual.html +0 -14
  70. data/test/fixtures/unified_values/small_html/deep_nested_block_expected.json +0 -8
  71. data/test/fixtures/unified_values/small_html/deep_nested_inline_actual.html +0 -20
  72. data/test/fixtures/unified_values/small_html/deep_nested_inline_expected.json +0 -20
  73. data/test/fixtures/unified_values/small_html/empty_tag_actual.html +0 -10
  74. data/test/fixtures/unified_values/small_html/empty_tag_expected.json +0 -12
  75. data/test/fixtures/unified_values/small_html/empty_text_actual.html +0 -12
  76. data/test/fixtures/unified_values/small_html/empty_text_expected.json +0 -1
  77. data/test/fixtures/unified_values/small_html/ignore_tag_actual.html +0 -12
  78. data/test/fixtures/unified_values/small_html/ignore_tag_expected.json +0 -16
  79. data/test/fixtures/unified_values/small_html/ignored_class_actual.html +0 -10
  80. data/test/fixtures/unified_values/small_html/ignored_class_expected.json +0 -13
  81. data/test/fixtures/unified_values/small_html/img_actual.html +0 -12
  82. data/test/fixtures/unified_values/small_html/img_expected.json +0 -23
  83. data/test/fixtures/unified_values/small_html/nested_and_complex_wovn_ignore_actual.html +0 -10
  84. data/test/fixtures/unified_values/small_html/nested_and_complex_wovn_ignore_expected.json +0 -16
  85. data/test/fixtures/unified_values/small_html/nested_text_value_actual.html +0 -10
  86. data/test/fixtures/unified_values/small_html/nested_text_value_expected.json +0 -12
  87. data/test/fixtures/unified_values/small_html/nested_text_value_mixed_plan_text_actual.html +0 -10
  88. data/test/fixtures/unified_values/small_html/nested_text_value_mixed_plan_text_expected.json +0 -14
  89. data/test/fixtures/unified_values/small_html/option_tag_actual.html +0 -9
  90. data/test/fixtures/unified_values/small_html/option_tag_expected.json +0 -13
  91. data/test/fixtures/unified_values/small_html/text_different_inline_each_other_actual.html +0 -10
  92. data/test/fixtures/unified_values/small_html/text_different_inline_each_other_expected.json +0 -22
  93. data/test/fixtures/unified_values/small_html/text_in_svg_actual.html +0 -9
  94. data/test/fixtures/unified_values/small_html/text_in_svg_expected.json +0 -8
  95. data/test/fixtures/unified_values/small_html/text_with_html_entity_actual.html +0 -6
  96. data/test/fixtures/unified_values/small_html/text_with_html_entity_expected.json +0 -8
  97. data/test/fixtures/unified_values/small_html/unknown_or_custom_tag_actual.html +0 -12
  98. data/test/fixtures/unified_values/small_html/unknown_or_custom_tag_expected.json +0 -24
  99. data/test/fixtures/unified_values/small_html/unnecessay_top_end_tag_actual.html +0 -12
  100. data/test/fixtures/unified_values/small_html/unnecessay_top_end_tag_expected.json +0 -14
  101. data/test/fixtures/unified_values/small_html/wovn_ignore_actual.html +0 -10
  102. data/test/fixtures/unified_values/small_html/wovn_ignore_expected.json +0 -13
  103. data/test/lib/api_data_test.rb +0 -83
  104. data/test/lib/html_replacers/image_replacer_test.rb +0 -165
  105. data/test/lib/html_replacers/input_replacer_test.rb +0 -140
  106. data/test/lib/html_replacers/link_replacer_test.rb +0 -328
  107. data/test/lib/html_replacers/meta_replacer_test.rb +0 -157
  108. data/test/lib/html_replacers/replacer_base_test.rb +0 -128
  109. data/test/lib/html_replacers/script_replacer_test.rb +0 -139
  110. data/test/lib/html_replacers/text_replacer_test.rb +0 -99
  111. data/test/lib/html_replacers/unified_values/dst_swapping_targets_creator_test.rb +0 -137
  112. data/test/lib/html_replacers/unified_values/element_category_test.rb +0 -49
  113. data/test/lib/html_replacers/unified_values/node_swapping_targets_creator_test.rb +0 -137
  114. data/test/lib/html_replacers/unified_values/text_replacer_test.rb +0 -270
  115. data/test/lib/html_replacers/unified_values/text_scraper_test.rb +0 -121
  116. data/test/lib/html_replacers/unified_values/values_stack_test.rb +0 -122
  117. data/test/lib/services/url_test.rb +0 -9
  118. data/test/lib/services/value_agent_test.rb +0 -32
  119. data/test/services/url_test.rb +0 -163
  120. data/values/values +0 -1
@@ -1,134 +0,0 @@
1
- module Wovnrb
2
- module UnifiedValues
3
- class NodeSwappingTargetsCreator
4
- # NOTE: `nodes_info` is the format like below
5
- #
6
- # [
7
- # {:dst=>"an<span>apple is a good</span>foods",
8
- # :nodes=>
9
- # [
10
- # (Text "an"),
11
- # (Element:0x13e84e1334 { name = "span", children = [ #(Text "apple is a good")] }),
12
- # (Text "apple is a good"),
13
- # (Element:0x13e84e1334 { name = "span", childrelib/wovnrb/html_replacers/unified_values/node_swapping_targets_creator.rbn = [ #(Text "apple is a good")] }),
14
- # (Text "\n foods\n \n \n")]}
15
- # ]
16
- # }
17
- # ]
18
- def initialize(nodes_info)
19
- @nodes_info = nodes_info
20
- end
21
-
22
- # NOTE: `run` make a swapping_targets like below
23
- #
24
- # [
25
- # {:dst=>"an<span>apple is a good</span>foods",
26
- # :nodes=>
27
- # [
28
- # (Text "an"),
29
- # (Element:0x13e84e1334 { name = "span", children = [ #(Text "apple is a good")] }),
30
- # (Text "apple is a good"),
31
- # (Element:0x13e84e1334 { name = "span", children = [ #(Text "apple is a good")] }),
32
- # (Text "\n foods\n \n \n")]}
33
- # ]
34
- # :swapping_targets=>
35
- # [
36
- # (Text "an"),
37
- # (Text "apple is a good"),
38
- # (Text "\n foods\n \n \n")]}
39
- # ]
40
- # }
41
- # ]
42
-
43
- def run!
44
- @nodes_info.each do |node_info|
45
- mold = []
46
- node_info[:nodes].each do |node|
47
- mold_size = mold.size
48
- mold.push create_dummy_empty_text_node(next_node: node) if mold_size.even? && node.element?
49
- mold.push node
50
- end
51
-
52
- mold.push create_dummy_empty_text_node(previous_node: mold.last) if mold.last.element?
53
- node_info[:swapping_targets] = remove_tag_element(mold)
54
- end
55
- end
56
-
57
- def remove_tag_element(mold)
58
- id_of_tag_with_wovn_ignore = nil
59
- swapping_targets = []
60
- mold.each do |node|
61
- if id_of_tag_with_wovn_ignore.nil? && node.attributes.keys.include?('wovn-ignore')
62
- id_of_tag_with_wovn_ignore = node.object_id
63
- next
64
- end
65
-
66
- if node.object_id == id_of_tag_with_wovn_ignore
67
- id_of_tag_with_wovn_ignore = nil
68
- end
69
-
70
- if id_of_tag_with_wovn_ignore.nil? && node.text?
71
- swapping_targets << node
72
- end
73
- end
74
-
75
- swapping_targets
76
- end
77
-
78
- def create_dummy_empty_text_node(option)
79
- DummyEmpryTextNode.new(option)
80
- end
81
-
82
- class DummyEmpryTextNode
83
- attr_reader :name
84
-
85
- def initialize(next_node: nil, previous_node: nil)
86
- @name = 'text'
87
- @next_node = next_node
88
- @previous_node = previous_node
89
- @added_empty_text = nil
90
- end
91
-
92
- def text?
93
- true
94
- end
95
-
96
- def content
97
- ''
98
- end
99
-
100
- def to_s
101
- content
102
- end
103
-
104
- def attributes
105
- {}
106
- end
107
-
108
- def parent
109
- @next_node.try(:parent) || @previous_node.try(:parent)
110
- end
111
-
112
- def document
113
- @next_node.try(:document) || @previous_node.try(:document)
114
- end
115
-
116
- def add_previous_sibling(comment_node)
117
- @added_empty_text.try(:add_previous_sibling, comment_node)
118
- end
119
-
120
- def content=(text)
121
- return if text == ''
122
-
123
- if @next_node
124
- @next_node.add_previous_sibling(text)
125
- @added_empty_text = @next_node.previous
126
- elsif @previous_node
127
- @previous_node.add_next_sibling(text)
128
- @added_empty_text = @previous_node.next
129
- end
130
- end
131
- end
132
- end
133
- end
134
- end
@@ -1,35 +0,0 @@
1
- module Wovnrb
2
- module UnifiedValues
3
- class TextReplacer < ReplacerBase
4
- def initialize(store, text_index)
5
- super(store)
6
- @text_index = text_index
7
- end
8
-
9
- def replace(dom, lang)
10
- translated_nodes_with_targets = NodeSwappingTargetsCreator.new(TextScraper.new(@ignored_class_set).run(dom)).run!
11
- text_index_with_targets = DstSwappingTargetsCreator.new(@text_index).run!
12
-
13
- translated_nodes_with_targets.each do |translated_nodes_with_target|
14
- dst_swapping_targets =
15
- text_index_with_targets[translated_nodes_with_target[:dst]]
16
- .try(:fetch, lang.lang_code, nil)
17
- .try(:first)
18
- .try(:fetch, 'swapping_targets', nil)
19
- next unless dst_swapping_targets
20
-
21
- translated_nodes_with_target[:swapping_targets].each_with_index do |node_swapping_target, index|
22
- # NOTE: current logic to swap back search text node and find wovn-src base on the text node.
23
- # if `translated_text` is empry string, translated html don't have text node. it means that widget can't find wovn-src and swap back
24
- # so we use `\u200b`(ZERO WIDTH SPACE) instead of empty string
25
- translated_text = dst_swapping_targets[index].blank? ? "\u200b" : dst_swapping_targets[index]
26
- original_text = node_swapping_target.content
27
-
28
- node_swapping_target.content = translated_text
29
- add_comment_node(node_swapping_target, original_text)
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,152 +0,0 @@
1
- module Wovnrb
2
- module UnifiedValues
3
- class TextScraper
4
- def initialize(ignored_class_set)
5
- @ignored_class_set = ignored_class_set
6
- @values = []
7
- @values_stack = nil
8
- end
9
-
10
- def run(dom)
11
- refresh_all!
12
- @values_stack = ValuesStack.new(dom.path, 1)
13
- scrape(dom)
14
- end
15
-
16
- def create_text_value(src, node_stack)
17
- { dst: ValueAgent.normalize_text(src.gsub(/&nbsp;/i, ' ')), nodes: node_stack }
18
- end
19
-
20
- private
21
-
22
- def scrape(dom)
23
- type = stop_recursion_type(dom)
24
- if type
25
- case type
26
- when 'ignore_element', 'skip_element'
27
- next_stack = @values_stack.build_next_stack
28
- build_src
29
- @values_stack = next_stack
30
- when 'text_element'
31
- @values_stack.add_text_element(dom, dom.content)
32
- when 'empty_element'
33
- @values_stack.add(dom, empty_tag(dom))
34
- when 'comment_element'
35
- # do nothing
36
- else
37
- raise 'Unsupported type'
38
- end
39
- elsif inline_element?(dom)
40
- @values_stack.add(dom, start_tag(dom))
41
- scrape_children_of(dom)
42
- @values_stack.add(dom, end_tag(dom)) unless @values_stack.blank?
43
- elsif block_element?(dom)
44
- next_stack = @values_stack.build_next_stack
45
- build_src
46
- @values_stack = ValuesStack.new(dom.path, 1)
47
- scrape_children_of(dom)
48
- build_src
49
- @values_stack = next_stack
50
- else
51
- next_stack = @values_stack.build_next_stack
52
- build_src
53
- @values_stack = ValuesStack.new(dom.path, 1)
54
- scrape_children_of(dom)
55
- build_src
56
- @values_stack = next_stack
57
- end
58
-
59
- @values
60
- end
61
-
62
- def scrape_children_of(dom)
63
- dom.children.each { |c| scrape(c) } unless wovn_ignore_element?(dom)
64
- end
65
-
66
- def build_src
67
- return nil if @values_stack.blank?
68
-
69
- src = @values_stack.src
70
- @values << create_text_value(src, @values_stack.node_stack) if src.present? && !tag_only?(src)
71
- @values_stack = nil
72
- end
73
-
74
- def tag_only?(src)
75
- Nokogiri::HTML5.fragment(src).text.blank?
76
- end
77
-
78
- def start_tag(dom)
79
- if wovn_ignore_element?(dom)
80
- "<#{dom.name} wovn-ignore>"
81
- else
82
- "<#{dom.name}>"
83
- end
84
- end
85
-
86
- def end_tag(dom)
87
- "</#{dom.name}>"
88
- end
89
-
90
- def empty_tag(dom)
91
- start_tag(dom)
92
- end
93
-
94
- def block_element?(element)
95
- ElementCategory::BLOCK_ELEMENTS.include?(element.name)
96
- end
97
-
98
- def inline_element?(element)
99
- ElementCategory::INLINE_ELEMENTS.include?(element.name)
100
- end
101
-
102
- def empty_element?(element)
103
- ElementCategory::EMPTY_ELEMENTS.include?(element.name)
104
- end
105
-
106
- def ignore_element?(element)
107
- ElementCategory::IGNORE_ELEMENTS.include?(element.name)
108
- end
109
-
110
- def skip_element?(element)
111
- ElementCategory::SKIP_ELEMENTS.include?(element.name)
112
- end
113
-
114
- def comment_element?(element)
115
- element.comment?
116
- end
117
-
118
- def text_element?(element)
119
- element.text?
120
- end
121
-
122
- def wovn_ignore_element?(element)
123
- return false unless element
124
-
125
- return true if element.attribute('wovn-ignore')
126
-
127
- class_attribute = element.attribute('class')
128
- return false unless class_attribute
129
- class_attribute.value.split.any? { |c| @ignored_class_set.include?(c) }
130
- end
131
-
132
- def stop_recursion_type(element)
133
- return 'ignore_element' if ignore_element?(element)
134
- return 'skip_element' if skip_element?(element)
135
- return 'text_element' if text_element?(element)
136
- return 'empty_element' if empty_element?(element)
137
- return 'comment_element' if comment_element?(element)
138
-
139
- nil
140
- end
141
-
142
- def refresh_all!
143
- @values_stack = nil
144
- refresh_values!
145
- end
146
-
147
- def refresh_values!
148
- @values = []
149
- end
150
- end
151
- end
152
- end
@@ -1,65 +0,0 @@
1
- require 'wovnrb/services/value_agent'
2
-
3
- module Wovnrb
4
- module UnifiedValues
5
- class ValuesStack
6
- attr_reader :node_stack
7
-
8
- # @param head_path [String]
9
- # @param index [Number]
10
- #
11
- # Be careful xpath's index starts with 1
12
- def initialize(head_path, index)
13
- @head_path = head_path
14
- @index = index
15
- @node_stack = []
16
- @src_stack = []
17
- @src_without_tag_stack = []
18
- end
19
-
20
- # @param node [Nokogiri::XML::Element]
21
- # @param src [String]
22
- def add(node, src)
23
- @node_stack << node if node.name != 'text' || node.content.present?
24
- @src_stack << Wovnrb::ValueAgent.normalize_text(src)
25
- end
26
-
27
- # @param node [Nokogiri::XML::Element]
28
- # @param dom_content [String]
29
- def add_text_element(node, dom_content)
30
- add(node, CGI.escapeHTML(dom_content))
31
- @src_without_tag_stack << Wovnrb::ValueAgent.normalize_text(dom_content)
32
- end
33
-
34
- # @return [Bool]
35
- def blank?
36
- @src_stack.blank?
37
- end
38
-
39
- # @return [String]
40
- def path
41
- return @head_path if @head_path.end_with?('title')
42
-
43
- # Ends with "text()" because some type checking takes path as a normal text when the path ends with "text()"
44
- p = "#{@head_path}/text()"
45
-
46
- @index == 1 ? p : "#{p}[#{@index}]"
47
- end
48
-
49
- # @return [String]
50
- def src
51
- @src_stack.inject(:+)
52
- end
53
-
54
- # @return [String]
55
- def src_without_tag
56
- @src_without_tag_stack.inject(:+)
57
- end
58
-
59
- # @return [ValuesStack]
60
- def build_next_stack
61
- ValuesStack.new(@head_path, @index + 1)
62
- end
63
- end
64
- end
65
- end
@@ -1,12 +0,0 @@
1
- module Wovnrb
2
- class URL
3
- def self.resolve_absolute_url(curr_location, rel_location)
4
- end
5
-
6
- # Set the path lang to
7
- def self.prepend_path(url, dir)
8
- result = url.sub(/(.+\.[^\/]+)(\/|$)/, '\1/' + dir + '\2')
9
- return result
10
- end
11
- end
12
- end
@@ -1,9 +0,0 @@
1
- module Wovnrb
2
- class ValueAgent
3
- def self.normalize_text(src)
4
- src.gsub(/[\ufffd]/, "\b")
5
- .gsub(/[\n \t\u0020\u0009\u000C\u200B\u000D\u000A]+/, ' ')
6
- .gsub(/^[\s\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]+|[\s\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]+$/, '')
7
- end
8
- end
9
- end
@@ -1,96 +0,0 @@
1
- <html>
2
- <script>console.log('hello')</script>
3
- <title>SIMPLE TITLE</title>
4
- <meta name="description" content="meta description">
5
- <body>
6
- <div>
7
- <form role="search">
8
- <div class="search-control">
9
- <input type="search" id="site-search" name="q"
10
- placeholder="Search the site..."
11
- aria-label="Search through site content">
12
- <button>Search</button>
13
- </div>
14
- </form>
15
-
16
- <form role="search" method="get" class="search-form wb-flex" action="https://www.wovn.io/">
17
- <label>
18
- <span>Search for:</span>
19
- <input type="search" placeholder="Search …" value="" name="s" title="Search for:">
20
- </label>
21
- </form>
22
- </div>
23
- <div>
24
- <span>
25
- <p>Well</p>
26
- </span>
27
- </div>
28
- <a class="home">
29
- <span><h1>scrap</h1>only
30
- <img src="/assets/hedgehog.jpg">
31
- this too</span>
32
- </a><br>
33
- <span href="/" class="home">
34
- <a><img src="/assets/hedgehog.jpg"></a>
35
- <a>"Storm hunters" it is to see.</a>
36
- <a>BLABLA5</a>
37
- </span>
38
- <div>
39
- <form class="ftr-locator-form">
40
- <input name="hdr-ftr-locator-term" placeholder="Street, City, State or ZIP" type="text">
41
- <input type="submit">
42
-
43
- </form>
44
- </div>
45
- <h1>
46
- <div style="opacity: 1;">Welcome to my Website!</div>
47
- </h1>
48
- <div>
49
- <div class="content-asset"><div class="heading1">LOST AF?</div>
50
- <div class="error-info">
51
- <p>WE'LL TAKE THE BLAME.</p>
52
- <p>LET US MAKE IT UP TO YOU WITH SOME LINKS.</p>
53
- </div>
54
-
55
- <div class="shopping-link">
56
- <nav class="gender-links">
57
- <ul>
58
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/mens/" class="nav-link">SHOP MENS</a></li>
59
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/womens/" class="nav-link">SHOP WOMENS</a></li>
60
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/kids/boys/" class="nav-link">shop boys</a></li>
61
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/kids/girls/" class="nav-link">shop girls</a></li>
62
- </ul>
63
- </nav>
64
- </div></div>
65
- <div class="error-custom-message noshow">"<div class="heading1">LOST AF?</div>
66
- <div class="error-info">
67
- <p>WE'LL TAKE THE BLAME.</p>
68
- <p>LET US MAKE IT UP TO YOU WITH SOME LINKS.</p>
69
- </div>
70
-
71
- <div class="shopping-link">
72
- <nav class="gender-links">
73
- <ul>
74
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/mens/" class="nav-link">SHOP MENS</a></li>
75
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/womens/" class="nav-link">SHOP WOMENS</a></li>
76
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/kids/boys/" class="nav-link">shop boys</a></li>
77
- <li class="link-text"><a href="https://www.abercrombie.co.jp/en_JP/kids/girls/" class="nav-link">shop girls</a></li>
78
- </ul>
79
- </nav>
80
- </div></div>"
81
- </div>
82
-
83
- <p>This is a paragraph! Here's how you make a link: <a href="https://neocities.org">Neocities</a>.</p>
84
-
85
- <p>Here's how you can make <strong>bold</strong> and <em>italic</em> text.</p>
86
- <p>Here's how you can add an image:</p>
87
- <p>Here's how to make a list:</p>
88
- <ul>
89
- <li href="/">First thing</li>
90
- <li>Second thing</li>
91
- <li>Third thing</li>
92
- </ul>
93
-
94
- <p>To learn more HTML/CSS, check out these <a href="https://neocities.org/tutorials">tutorials</a>!</p>
95
- </body>
96
- </html>