openstax_kitchen 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -3
- data/Gemfile.lock +1 -1
- data/README.md +7 -0
- data/lib/kitchen/directions/bake_book_answer_key/eob_solutions_container.xhtml.erb +9 -0
- data/lib/kitchen/directions/bake_book_answer_key/main.rb +11 -0
- data/lib/kitchen/directions/bake_book_answer_key/v1.rb +13 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/main.rb +14 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/strategies/calculus.rb +41 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/strategies/uphysics.rb +61 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/v1.rb +32 -0
- data/lib/kitchen/directions/bake_chapter_glossary.rb +4 -2
- data/lib/kitchen/directions/bake_chapter_key_concepts/key_concepts.xhtml.erb +16 -0
- data/lib/kitchen/directions/bake_chapter_key_concepts/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_key_concepts/v1.rb +30 -0
- data/lib/kitchen/directions/bake_chapter_key_equations.rb +4 -2
- data/lib/kitchen/directions/bake_chapter_review/chapter_review.xhtml.erb +9 -0
- data/lib/kitchen/directions/bake_chapter_review/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_review/v1.rb +13 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/main.rb +15 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/review_exercises.xhtml.erb +10 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/v1.rb +38 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/v2.rb +50 -0
- data/lib/kitchen/directions/bake_chapter_section_exercises/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_section_exercises/v1.rb +28 -0
- data/lib/kitchen/directions/bake_chapter_summary.rb +1 -1
- data/lib/kitchen/directions/bake_checkpoint.rb +44 -0
- data/lib/kitchen/directions/bake_composite_chapters.rb +14 -0
- data/lib/kitchen/directions/bake_equations.rb +27 -0
- data/lib/kitchen/directions/bake_example.rb +29 -7
- data/lib/kitchen/directions/bake_exercises/main.rb +1 -0
- data/lib/kitchen/directions/bake_exercises/v1.rb +34 -31
- data/lib/kitchen/directions/bake_non_introduction_pages.rb +26 -0
- data/lib/kitchen/directions/bake_notes/bake_autotitled_notes.rb +29 -0
- data/lib/kitchen/directions/bake_notes/bake_note_subtitle.rb +18 -0
- data/lib/kitchen/directions/{bake_notes.rb → bake_notes/bake_notes.rb} +6 -16
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes.rb +63 -0
- data/lib/kitchen/directions/bake_notes/bake_unclassified_notes.rb +30 -0
- data/lib/kitchen/directions/bake_numbered_exercise/main.rb +11 -0
- data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +34 -0
- data/lib/kitchen/directions/bake_numbered_table/main.rb +2 -2
- data/lib/kitchen/directions/bake_numbered_table/v1.rb +17 -3
- data/lib/kitchen/directions/bake_page_abstracts.rb +16 -0
- data/lib/kitchen/directions/bake_problem_first_elements.rb +16 -0
- data/lib/kitchen/directions/bake_stepwise.rb +1 -5
- data/lib/kitchen/directions/bake_theorem/main.rb +11 -0
- data/lib/kitchen/directions/bake_theorem/v1.rb +28 -0
- data/lib/kitchen/directions/bake_toc.rb +6 -0
- data/lib/kitchen/directions/eoc_section_title_link_snippet.rb +20 -0
- data/lib/kitchen/element_base.rb +40 -1
- data/lib/kitchen/element_enumerator_base.rb +87 -8
- data/lib/kitchen/exercise_element.rb +45 -0
- data/lib/kitchen/exercise_element_enumerator.rb +21 -0
- data/lib/kitchen/note_element.rb +17 -16
- data/lib/kitchen/page_element.rb +8 -0
- data/lib/kitchen/recipe.rb +35 -2
- data/lib/kitchen/version.rb +1 -1
- data/lib/locales/en.yml +9 -7
- data/lib/locales/pl.yml +24 -0
- data/lib/openstax_kitchen.rb +1 -1
- metadata +39 -3
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeNoteSubtitle
|
6
|
+
def self.v1(note:)
|
7
|
+
title = note.title&.cut
|
8
|
+
|
9
|
+
return unless title
|
10
|
+
|
11
|
+
title.name = 'h4'
|
12
|
+
title.add_class('os-subtitle')
|
13
|
+
title.wrap_children('span', class: 'os-subtitle-label')
|
14
|
+
note.first!('.os-note-body').prepend(child: title.to_s)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,14 +4,12 @@ module Kitchen
|
|
4
4
|
module Directions
|
5
5
|
module BakeNotes
|
6
6
|
def self.v1(book:)
|
7
|
-
|
7
|
+
warn 'WARNING! deprecated direction used: BakeNotes'
|
8
|
+
|
9
|
+
book.notes('$:not(.checkpoint):not(.theorem)').each do |note|
|
8
10
|
title = note.title&.cut
|
9
11
|
|
10
|
-
note.
|
11
|
-
<<~HTML
|
12
|
-
<div class="os-note-body">#{note.children}</div>
|
13
|
-
HTML
|
14
|
-
)
|
12
|
+
note.wrap_children(class: 'os-note-body')
|
15
13
|
|
16
14
|
if title
|
17
15
|
if note.indicates_autogenerated_title?
|
@@ -25,20 +23,12 @@ module Kitchen
|
|
25
23
|
|
26
24
|
title.name = 'h4'
|
27
25
|
title.add_class('os-subtitle')
|
28
|
-
title.
|
29
|
-
<<~HTML
|
30
|
-
<span class="os-subtitle-label">#{title.children}</span>
|
31
|
-
HTML
|
32
|
-
)
|
26
|
+
title.wrap_children('span', class: 'os-subtitle-label')
|
33
27
|
note.first!('.os-note-body').prepend(child: title.raw)
|
34
28
|
else
|
35
29
|
title.name = 'h3'
|
36
30
|
title.add_class('os-title')
|
37
|
-
title.
|
38
|
-
<<~HTML
|
39
|
-
<span data-type="" id="#{title.id}" class="os-title-label">#{title.children}</span>
|
40
|
-
HTML
|
41
|
-
)
|
31
|
+
title.wrap_children('span', data_type: '', id: title.id, class: 'os-title-label')
|
42
32
|
title.remove_attribute('id')
|
43
33
|
note.prepend(child: title.raw)
|
44
34
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeNumberedNotes
|
6
|
+
def self.v1(book:, classes:)
|
7
|
+
classes.each do |klass|
|
8
|
+
book.chapters.notes("$.#{klass}").each do |note|
|
9
|
+
bake_note(note: note)
|
10
|
+
bake_note_exercise(note: note)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.bake_note(note:)
|
16
|
+
note.wrap_children(class: 'os-note-body')
|
17
|
+
|
18
|
+
chapter_count = note.ancestor(:chapter).count_in(:book)
|
19
|
+
note_count = note.count_in(:chapter)
|
20
|
+
note.prepend(child:
|
21
|
+
<<~HTML
|
22
|
+
<div class="os-title">
|
23
|
+
<span class="os-title-label">#{note.autogenerated_title}</span>
|
24
|
+
<span class="os-number">#{chapter_count}.#{note_count}</span>
|
25
|
+
<span class="os-divider"> </span>
|
26
|
+
</div>
|
27
|
+
HTML
|
28
|
+
)
|
29
|
+
|
30
|
+
return unless note['use-subtitle']
|
31
|
+
|
32
|
+
BakeNoteSubtitle.v1(note: note)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.bake_note_exercise(note:)
|
36
|
+
exercise = note.exercises.first
|
37
|
+
return unless exercise
|
38
|
+
|
39
|
+
exercise.add_class('unnumbered')
|
40
|
+
# bake problem
|
41
|
+
exercise.problem.wrap_children('div', class: 'os-problem-container')
|
42
|
+
exercise.problem.first('strong')&.trash
|
43
|
+
exercise.search('[data-type="commentary"]').each(&:trash)
|
44
|
+
solution = exercise.solution
|
45
|
+
return unless solution
|
46
|
+
|
47
|
+
# bake solution in place
|
48
|
+
exercise.add_class('os-hasSolution')
|
49
|
+
solution[:id] = "#{exercise[:id]}-solution"
|
50
|
+
solution_number = note.first('.os-number').text
|
51
|
+
solution.replace_children(with:
|
52
|
+
<<~HTML
|
53
|
+
<a class="os-number" href="##{exercise[:id]}">#{solution_number}</a>
|
54
|
+
<span class="os-divider"> </span>
|
55
|
+
<div class="os-solution-container">
|
56
|
+
#{solution.children}
|
57
|
+
</div>
|
58
|
+
HTML
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeUnclassifiedNotes
|
6
|
+
def self.v1(book:)
|
7
|
+
book.notes.each do |note|
|
8
|
+
next unless note.classes.empty?
|
9
|
+
|
10
|
+
bake_note(note: note)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.bake_note(note:)
|
15
|
+
note.wrap_children(class: 'os-note-body')
|
16
|
+
|
17
|
+
title = note.title&.cut
|
18
|
+
return unless title
|
19
|
+
|
20
|
+
note.prepend(child:
|
21
|
+
<<~HTML
|
22
|
+
<h3 class="os-title" data-type="title">
|
23
|
+
<span class="os-title-label" data-type="" id="#{title[:id]}">#{title.children}</span>
|
24
|
+
</h3>
|
25
|
+
HTML
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::BakeNumberedExercise
|
4
|
+
class V1
|
5
|
+
def bake(exercise:, number:)
|
6
|
+
problem = exercise.problem
|
7
|
+
solution = exercise.solution
|
8
|
+
|
9
|
+
problem_number = "<span class='os-number'>#{number}</span>"
|
10
|
+
|
11
|
+
if solution.present?
|
12
|
+
solution.id = "#{exercise.id}-solution"
|
13
|
+
exercise.add_class('os-hasSolution')
|
14
|
+
problem_number = "<a class='os-number' href='##{exercise.id}-solution'>#{number}</a>"
|
15
|
+
|
16
|
+
solution.replace_children(with:
|
17
|
+
<<~HTML
|
18
|
+
<a class='os-number' href='##{exercise.id}'>#{number}</a>
|
19
|
+
<span class='os-divider'>. </span>
|
20
|
+
<div class="os-solution-container">#{solution.children}</div>
|
21
|
+
HTML
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
problem.replace_children(with:
|
26
|
+
<<~HTML
|
27
|
+
#{problem_number}
|
28
|
+
<span class='os-divider'>. </span>
|
29
|
+
<div class="os-problem-container">#{problem.children}</div>
|
30
|
+
HTML
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module Kitchen
|
4
4
|
module Directions
|
5
5
|
module BakeNumberedTable
|
6
|
-
def self.v1(table:, number:)
|
7
|
-
V1.new.bake(table: table, number: number)
|
6
|
+
def self.v1(table:, number:, always_caption: false)
|
7
|
+
V1.new.bake(table: table, number: number, always_caption: always_caption)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Kitchen::Directions::BakeNumberedTable
|
4
4
|
class V1
|
5
5
|
|
6
|
-
def bake(table:, number:)
|
6
|
+
def bake(table:, number:, always_caption: false)
|
7
7
|
table.wrap(%(<div class="os-table">))
|
8
8
|
|
9
9
|
table_label = "#{I18n.t(:table_label)} #{number}"
|
@@ -22,14 +22,28 @@ module Kitchen::Directions::BakeNumberedTable
|
|
22
22
|
table.parent.add_class('os-column-header-container') if table.column_header?
|
23
23
|
|
24
24
|
# TODO: extra spaces added here to match legacy implementation, but probably not meaningful?
|
25
|
-
new_summary = "#{table_label}
|
25
|
+
new_summary = "#{table_label} "
|
26
26
|
new_caption = ''
|
27
|
+
caption_title = ''
|
28
|
+
|
29
|
+
if (title = table.first("span[data-type='title']")&.cut)
|
30
|
+
new_summary += title.text
|
31
|
+
caption_title = <<~HTML
|
32
|
+
\n<span class="os-title" data-type="title">#{title.children}</span>
|
33
|
+
HTML
|
34
|
+
end
|
35
|
+
|
36
|
+
new_summary += ' '
|
27
37
|
|
28
38
|
if (caption = table.caption&.cut)
|
29
39
|
new_summary += caption.text
|
30
40
|
new_caption = <<~HTML
|
31
41
|
\n<span class="os-caption">#{caption.children}</span>
|
32
42
|
HTML
|
43
|
+
elsif always_caption
|
44
|
+
new_caption = <<~HTML
|
45
|
+
\n<span class="os-caption"></span>
|
46
|
+
HTML
|
33
47
|
end
|
34
48
|
|
35
49
|
table[:summary] = new_summary
|
@@ -41,7 +55,7 @@ module Kitchen::Directions::BakeNumberedTable
|
|
41
55
|
<div class="os-caption-container">
|
42
56
|
<span class="os-title-label">#{I18n.t(:table_label)} </span>
|
43
57
|
<span class="os-number">#{number}</span>
|
44
|
-
<span class="os-divider"> </span
|
58
|
+
<span class="os-divider"> </span>#{caption_title}
|
45
59
|
<span class="os-divider"> </span>#{new_caption}
|
46
60
|
</div>
|
47
61
|
HTML
|
@@ -9,6 +9,22 @@ module Kitchen
|
|
9
9
|
abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def self.v2(chapter:)
|
14
|
+
chapter.abstracts.each do |abstract|
|
15
|
+
abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
|
16
|
+
ul = abstract.first!('ul')
|
17
|
+
ul.add_class('os-abstract')
|
18
|
+
ul.search('li').each_with_index do |li, index|
|
19
|
+
li.replace_children(with:
|
20
|
+
<<~HTML
|
21
|
+
<span class="os-abstract-token">#{chapter.count_in(:book)}.#{abstract.count_in(:chapter)}.#{index + 1}</span>
|
22
|
+
<span class="os-abstract-content">#{li.text}</span>
|
23
|
+
HTML
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
12
28
|
end
|
13
29
|
end
|
14
30
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeProblemFirstElements
|
6
|
+
def self.v1(within:, selectors:)
|
7
|
+
selectors.each do |selector|
|
8
|
+
within.search(".os-problem-container > #{selector}:first-child").each do |problem|
|
9
|
+
problem.add_class('first-element')
|
10
|
+
problem.parent.add_class('has-first-element')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -9,11 +9,7 @@ module Kitchen
|
|
9
9
|
ol.add_class('os-stepwise')
|
10
10
|
|
11
11
|
ol.search('li').each_with_index do |li, ii|
|
12
|
-
li.
|
13
|
-
<<~HTML
|
14
|
-
<span class="os-stepwise-content">#{li.children}</span>
|
15
|
-
HTML
|
16
|
-
)
|
12
|
+
li.wrap_children('span', class: 'os-stepwise-content')
|
17
13
|
li.prepend(child:
|
18
14
|
<<~HTML
|
19
15
|
<span class="os-stepwise-token">#{I18n.t(:stepwise_step_label)} #{ii + 1}. </span>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::BakeTheorem
|
4
|
+
class V1
|
5
|
+
def bake(theorem:, number:)
|
6
|
+
theorem['use-subtitle'] = true
|
7
|
+
new_subtitle = theorem.title.cut
|
8
|
+
|
9
|
+
theorem.wrap_children(class: 'os-note-body')
|
10
|
+
note_body = theorem.first('.os-note-body')
|
11
|
+
|
12
|
+
note_body.prepend(sibling:
|
13
|
+
<<~HTML
|
14
|
+
<div class="os-title">
|
15
|
+
<span class="os-title-label">#{I18n.t(:theorem)} </span>
|
16
|
+
<span class="os-number">#{number}</span>
|
17
|
+
<span class="os-divider"> </span>
|
18
|
+
</div>
|
19
|
+
HTML
|
20
|
+
)
|
21
|
+
|
22
|
+
new_subtitle.name = 'h4'
|
23
|
+
new_subtitle.add_class('os-subtitle')
|
24
|
+
new_subtitle.children.wrap('<span class="os-subtitle-label">')
|
25
|
+
note_body.prepend(child: new_subtitle.paste)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -59,6 +59,7 @@ module Kitchen
|
|
59
59
|
|
60
60
|
def self.li_for_chapter(chapter)
|
61
61
|
pages = chapter.element_children.only(PageElement, CompositePageElement)
|
62
|
+
inner_composite_chapters = chapter.element_children.only(CompositeChapterElement)
|
62
63
|
|
63
64
|
<<~HTML
|
64
65
|
<li class="os-toc-chapter" cnx-archive-shortid="" cnx-archive-uri="">
|
@@ -69,6 +70,11 @@ module Kitchen
|
|
69
70
|
</a>
|
70
71
|
<ol class="os-chapter">
|
71
72
|
#{pages.map { |page| li_for_page(page) }.join("\n")}
|
73
|
+
#{
|
74
|
+
inner_composite_chapters.map do |composite_chapter|
|
75
|
+
li_for_composite_chapter(composite_chapter)
|
76
|
+
end.join("\n")
|
77
|
+
}
|
72
78
|
</ol>
|
73
79
|
</li>
|
74
80
|
HTML
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module EocSectionTitleLinkSnippet
|
6
|
+
def self.v1(page:)
|
7
|
+
chapter = page.ancestor(:chapter)
|
8
|
+
<<~HTML
|
9
|
+
<a href="##{page.title.id}">
|
10
|
+
<h3 data-type="document-title" id="#{page.title.copied_id}">
|
11
|
+
<span class="os-number">#{chapter.count_in(:book)}.#{page.count_in(:chapter)}</span>
|
12
|
+
<span class="os-divider"> </span>
|
13
|
+
<span class="os-text" data-type="" itemprop="">#{page.title.text}</span>
|
14
|
+
</h3>
|
15
|
+
</a>
|
16
|
+
HTML
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/kitchen/element_base.rb
CHANGED
@@ -423,6 +423,12 @@ module Kitchen
|
|
423
423
|
temp_copy.to_s
|
424
424
|
end
|
425
425
|
|
426
|
+
# Copy the element's id
|
427
|
+
def copied_id
|
428
|
+
document.record_id_copied(id)
|
429
|
+
document.modified_id_to_paste(id)
|
430
|
+
end
|
431
|
+
|
426
432
|
# Delete the element
|
427
433
|
#
|
428
434
|
def trash
|
@@ -491,6 +497,35 @@ module Kitchen
|
|
491
497
|
self
|
492
498
|
end
|
493
499
|
|
500
|
+
# Wraps the element's children in a new element. Yields the new wrapper element
|
501
|
+
# to a block, if provided.
|
502
|
+
#
|
503
|
+
# @param name [String] the wrapper's tag name, defaults to 'div'.
|
504
|
+
# @param attributes [Hash] the wrapper's attributes. XML attributes often use hyphens
|
505
|
+
# (e.g. 'data-type') which are hard to put into symbols. Therefore underscores in
|
506
|
+
# keys passed to this method will be converted to hyphens. If you really want an
|
507
|
+
# underscore you can use a double underscore.
|
508
|
+
# @yieldparam [Element] the wrapper Element
|
509
|
+
# @return [Element] self
|
510
|
+
#
|
511
|
+
def wrap_children(name='div', attributes={})
|
512
|
+
if name.is_a?(Hash)
|
513
|
+
attributes = name
|
514
|
+
name = 'div'
|
515
|
+
end
|
516
|
+
|
517
|
+
node.children = node.document.create_element(name) do |new_node|
|
518
|
+
# For some reason passing attributes to create_element doesn't work, so doing here
|
519
|
+
attributes.each do |k, v|
|
520
|
+
new_node[k.to_s.gsub(/([^_])_([^_])/, '\1-\2').gsub('__', '_')] = v
|
521
|
+
end
|
522
|
+
new_node.children = children.to_s
|
523
|
+
yield Element.new(node: new_node, document: document, short_type: nil) if block_given?
|
524
|
+
end.to_s
|
525
|
+
|
526
|
+
self
|
527
|
+
end
|
528
|
+
|
494
529
|
# TODO: methods like replace_children that take string, either forbid or handle Element/Node args
|
495
530
|
|
496
531
|
# Get the content of children matching the provided selector. Mostly
|
@@ -604,10 +639,14 @@ module Kitchen
|
|
604
639
|
end
|
605
640
|
end
|
606
641
|
|
642
|
+
def last_element
|
643
|
+
node.last_element_child
|
644
|
+
end
|
645
|
+
|
607
646
|
# @!method pages
|
608
647
|
# Returns a pages enumerator
|
609
648
|
def_delegators :as_enumerator, :pages, :chapters, :terms, :figures, :notes, :tables, :examples,
|
610
|
-
:metadatas, :units
|
649
|
+
:metadatas, :non_introduction_pages, :units, :titles, :exercises, :composite_pages
|
611
650
|
|
612
651
|
# Returns this element as an enumerator (over only one element, itself)
|
613
652
|
#
|