primer_view_components 0.0.9 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +2 -175
- data/app/components/primer/avatar_component.rb +22 -11
- data/app/components/primer/base_component.rb +56 -11
- data/app/components/primer/blankslate_component.html.erb +1 -1
- data/app/components/primer/blankslate_component.rb +71 -116
- data/app/components/primer/border_box_component.html.erb +5 -5
- data/app/components/primer/border_box_component.rb +45 -33
- data/app/components/primer/box_component.rb +6 -4
- data/app/components/primer/breadcrumb_component.html.erb +2 -2
- data/app/components/primer/breadcrumb_component.rb +23 -30
- data/app/components/primer/button_component.rb +26 -9
- data/app/components/primer/component.rb +1 -0
- data/app/components/primer/counter_component.rb +13 -9
- data/app/components/primer/details_component.html.erb +1 -1
- data/app/components/primer/details_component.rb +18 -18
- data/app/components/primer/dropdown_menu_component.html.erb +1 -1
- data/app/components/primer/dropdown_menu_component.rb +6 -6
- data/app/components/primer/flash_component.html.erb +2 -2
- data/app/components/primer/flash_component.rb +42 -12
- data/app/components/primer/flex_component.rb +5 -5
- data/app/components/primer/flex_item_component.rb +5 -5
- data/app/components/primer/heading_component.rb +4 -4
- data/app/components/primer/label_component.rb +37 -14
- data/app/components/primer/layout_component.html.erb +1 -1
- data/app/components/primer/layout_component.rb +22 -5
- data/app/components/primer/link_component.rb +17 -7
- data/app/components/primer/octicon_component.rb +20 -7
- data/app/components/primer/popover_component.html.erb +1 -1
- data/app/components/primer/popover_component.rb +61 -23
- data/app/components/primer/progress_bar_component.html.erb +2 -2
- data/app/components/primer/progress_bar_component.rb +40 -30
- data/app/components/primer/slot.rb +1 -0
- data/app/components/primer/spinner_component.html.erb +6 -0
- data/app/components/primer/spinner_component.rb +39 -0
- data/app/components/primer/state_component.rb +26 -14
- data/app/components/primer/subhead_component.html.erb +4 -4
- data/app/components/primer/subhead_component.rb +68 -43
- data/app/components/primer/text_component.rb +10 -4
- data/app/components/primer/timeline_item_component.html.erb +4 -4
- data/app/components/primer/timeline_item_component.rb +48 -24
- data/app/components/primer/underline_nav_component.html.erb +1 -1
- data/app/components/primer/underline_nav_component.rb +5 -5
- data/app/components/primer/view_components.rb +1 -0
- data/lib/primer/classify.rb +2 -4
- data/lib/primer/view_components/version.rb +1 -1
- metadata +4 -2
@@ -1,25 +1,25 @@
|
|
1
|
-
<%= render Primer::BaseComponent.new(**@
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
2
|
<% if header %>
|
3
|
-
<%= render Primer::BaseComponent.new(**header.
|
3
|
+
<%= render Primer::BaseComponent.new(**header.system_arguments) do %>
|
4
4
|
<%= header.content %>
|
5
5
|
<% end %>
|
6
6
|
<% end %>
|
7
7
|
<% if body %>
|
8
|
-
<%= render Primer::BaseComponent.new(**body.
|
8
|
+
<%= render Primer::BaseComponent.new(**body.system_arguments) do %>
|
9
9
|
<%= body.content %>
|
10
10
|
<% end %>
|
11
11
|
<% end %>
|
12
12
|
<% if rows.any? %>
|
13
13
|
<ul>
|
14
14
|
<% rows.each do |row| %>
|
15
|
-
<%= render Primer::BaseComponent.new(**row.
|
15
|
+
<%= render Primer::BaseComponent.new(**row.system_arguments) do %>
|
16
16
|
<%= row.content %>
|
17
17
|
<% end %>
|
18
18
|
<% end %>
|
19
19
|
</ul>
|
20
20
|
<% end %>
|
21
21
|
<% if footer %>
|
22
|
-
<%= render Primer::BaseComponent.new(**footer.
|
22
|
+
<%= render Primer::BaseComponent.new(**footer.system_arguments) do %>
|
23
23
|
<%= footer.content %>
|
24
24
|
<% end %>
|
25
25
|
<% end %>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
+
# BorderBox is a Box component with a border.
|
4
5
|
class BorderBoxComponent < Primer::Component
|
5
6
|
include ViewComponent::Slotable
|
6
7
|
|
@@ -9,12 +10,23 @@ module Primer
|
|
9
10
|
with_slot :footer, class_name: "Footer"
|
10
11
|
with_slot :row, collection: true, class_name: "Row"
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
# @example 350|Header, body, rows, and footer
|
14
|
+
# <%= render(Primer::BorderBoxComponent.new) do |component|
|
15
|
+
# component.slot(:header) { "Header" }
|
16
|
+
# component.slot(:body) { "Body" }
|
17
|
+
# component.slot(:row) { "Row one" }
|
18
|
+
# component.slot(:row) { "Row two" }
|
19
|
+
# component.slot(:row) { "Row three" }
|
20
|
+
# component.slot(:footer) { "Footer" }
|
21
|
+
# end %>
|
22
|
+
#
|
23
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
24
|
+
def initialize(**system_arguments)
|
25
|
+
@system_arguments = system_arguments
|
26
|
+
@system_arguments[:tag] = :div
|
27
|
+
@system_arguments[:classes] = class_names(
|
16
28
|
"Box",
|
17
|
-
|
29
|
+
system_arguments[:classes]
|
18
30
|
)
|
19
31
|
end
|
20
32
|
|
@@ -23,53 +35,53 @@ module Primer
|
|
23
35
|
end
|
24
36
|
|
25
37
|
class Header < Primer::Slot
|
26
|
-
|
27
|
-
|
28
|
-
def initialize(**
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
38
|
+
attr_reader :system_arguments
|
39
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
40
|
+
def initialize(**system_arguments)
|
41
|
+
@system_arguments = system_arguments
|
42
|
+
@system_arguments[:tag] = :div
|
43
|
+
@system_arguments[:classes] = class_names(
|
32
44
|
"Box-header",
|
33
|
-
|
45
|
+
system_arguments[:classes]
|
34
46
|
)
|
35
47
|
end
|
36
48
|
end
|
37
49
|
|
38
50
|
class Body < Primer::Slot
|
39
|
-
|
40
|
-
|
41
|
-
def initialize(**
|
42
|
-
@
|
43
|
-
@
|
44
|
-
@
|
51
|
+
attr_reader :system_arguments
|
52
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
53
|
+
def initialize(**system_arguments)
|
54
|
+
@system_arguments = system_arguments
|
55
|
+
@system_arguments[:tag] = :div
|
56
|
+
@system_arguments[:classes] = class_names(
|
45
57
|
"Box-body",
|
46
|
-
|
58
|
+
system_arguments[:classes]
|
47
59
|
)
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
51
63
|
class Footer < Primer::Slot
|
52
|
-
|
53
|
-
|
54
|
-
def initialize(**
|
55
|
-
@
|
56
|
-
@
|
57
|
-
@
|
64
|
+
attr_reader :system_arguments
|
65
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
66
|
+
def initialize(**system_arguments)
|
67
|
+
@system_arguments = system_arguments
|
68
|
+
@system_arguments[:tag] = :div
|
69
|
+
@system_arguments[:classes] = class_names(
|
58
70
|
"Box-footer",
|
59
|
-
|
71
|
+
system_arguments[:classes]
|
60
72
|
)
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
64
76
|
class Row < Primer::Slot
|
65
|
-
|
66
|
-
|
67
|
-
def initialize(**
|
68
|
-
@
|
69
|
-
@
|
70
|
-
@
|
77
|
+
attr_reader :system_arguments
|
78
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
79
|
+
def initialize(**system_arguments)
|
80
|
+
@system_arguments = system_arguments
|
81
|
+
@system_arguments[:tag] = :li
|
82
|
+
@system_arguments[:classes] = class_names(
|
71
83
|
"Box-row",
|
72
|
-
|
84
|
+
system_arguments[:classes]
|
73
85
|
)
|
74
86
|
end
|
75
87
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
+
# A basic wrapper component for most layout related needs.
|
4
5
|
class BoxComponent < Primer::Component
|
5
|
-
|
6
|
-
|
7
|
-
@
|
6
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
7
|
+
def initialize(**system_arguments)
|
8
|
+
@system_arguments = system_arguments
|
9
|
+
@system_arguments[:tag] = :div
|
8
10
|
end
|
9
11
|
|
10
12
|
def call
|
11
|
-
render(Primer::BaseComponent.new(**@
|
13
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
<%= render Primer::BaseComponent.new(**@
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
2
|
<ol>
|
3
3
|
<% items.each do |item| %>
|
4
4
|
<%# The <li> and <a> need to be on the same line to prevent unwanted whitespace %>
|
5
|
-
<%= render Primer::BaseComponent.new(**item.
|
5
|
+
<%= render Primer::BaseComponent.new(**item.system_arguments) do %><%- if item.href.present? %><a href="<%= item.href %>"><%= item.content %></a><%- else %><%= item.content %><%- end %><%- end %>
|
6
6
|
<% end %>
|
7
7
|
</ol>
|
8
8
|
<% end %>
|
@@ -1,51 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
##
|
4
|
-
# Breadcrumbs are used to display page hierarchy within a section of the site. All of the items in the breadcrumb "trail" are links except for the final item which is a plain string indicating the current page.
|
5
|
-
#
|
6
|
-
# ## Example
|
7
|
-
#
|
8
|
-
# The `Primer::BreadcrumbComponent` uses the [Slots API](https://github.com/github/view_component#slots-experimental) and at least one slot is required for the component to render. Each slot can accept the following parameters:
|
9
|
-
#
|
10
|
-
# 1. `href` (string). The URL to link to.
|
11
|
-
# 2. `selected` (boolean, default=false). Flag indicating whether or not the item is selected and not rendered as a link.
|
12
|
-
#
|
13
|
-
# Note that if if both `href` and `selected: true` are passed in, `href` will be ignored and the item will not be rendered as a link.
|
14
|
-
#
|
15
|
-
# ```ruby
|
16
|
-
# <%= render(Primer::BreadcrumbComponent.new) do |component| %>
|
17
|
-
# <% component.slot(:item, href: "/") do %>Home<% end %>
|
18
|
-
# <% component.slot(:item, href: "/about") do %>About<% end %>
|
19
|
-
# <% component.slot(:item, selected: true) do %>Team<% end %>
|
20
|
-
# <% end %>
|
21
|
-
# ```
|
22
|
-
##
|
23
3
|
module Primer
|
4
|
+
# Use breadcrumbs to display page hierarchy within a section of the site. All of the items in the breadcrumb "trail" are links except for the final item, which is a plain string indicating the current page.
|
24
5
|
class BreadcrumbComponent < Primer::Component
|
25
6
|
include ViewComponent::Slotable
|
26
7
|
|
27
8
|
with_slot :item, collection: true, class_name: "BreadcrumbItem"
|
28
9
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
10
|
+
# @example 40|Basic
|
11
|
+
# <%= render(Primer::BreadcrumbComponent.new) do |component| %>
|
12
|
+
# <% component.slot(:item, href: "/") do %>Home<% end %>
|
13
|
+
# <% component.slot(:item, href: "/about") do %>About<% end %>
|
14
|
+
# <% component.slot(:item, selected: true) do %>Team<% end %>
|
15
|
+
# <% end %>
|
16
|
+
#
|
17
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
18
|
+
def initialize(**system_arguments)
|
19
|
+
@system_arguments = system_arguments
|
20
|
+
@system_arguments[:tag] = :nav
|
21
|
+
@system_arguments[:aria] = { label: "Breadcrumb" }
|
33
22
|
end
|
34
23
|
|
35
24
|
def render?
|
36
25
|
items.any?
|
37
26
|
end
|
38
27
|
|
28
|
+
# _Note: if both `href` and `selected: true` are passed in, `href` will be ignored and the item will not be rendered as a link._
|
39
29
|
class BreadcrumbItem < Primer::Slot
|
40
|
-
attr_reader :href, :
|
30
|
+
attr_reader :href, :system_arguments
|
41
31
|
|
42
|
-
|
43
|
-
|
32
|
+
# @param href [String] The URL to link to.
|
33
|
+
# @param selected [Boolean] Whether or not the item is selected and not rendered as a link.
|
34
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
35
|
+
def initialize(href: nil, selected: false, **system_arguments)
|
36
|
+
@href, @system_arguments = href, system_arguments
|
44
37
|
|
45
38
|
@href = nil if selected
|
46
|
-
@
|
47
|
-
@
|
48
|
-
@
|
39
|
+
@system_arguments[:tag] = :li
|
40
|
+
@system_arguments[:"aria-current"] = "page" if selected
|
41
|
+
@system_arguments[:classes] = "breadcrumb-item #{@system_arguments[:classes]}"
|
49
42
|
end
|
50
43
|
end
|
51
44
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
+
# Use buttons for actions (e.g. in forms). Use links for destinations, or moving from one page to another.
|
4
5
|
class ButtonComponent < Primer::Component
|
5
6
|
DEFAULT_BUTTON_TYPE = :default
|
6
7
|
BUTTON_TYPE_MAPPINGS = {
|
@@ -25,26 +26,42 @@ module Primer
|
|
25
26
|
DEFAULT_TYPE = :button
|
26
27
|
TYPE_OPTIONS = [DEFAULT_TYPE, :reset, :submit].freeze
|
27
28
|
|
29
|
+
# @example 50|Button types
|
30
|
+
# <%= render(Primer::ButtonComponent.new) { "Default" } %>
|
31
|
+
# <%= render(Primer::ButtonComponent.new(button_type: :primary)) { "Primary" } %>
|
32
|
+
# <%= render(Primer::ButtonComponent.new(button_type: :danger)) { "Danger" } %>
|
33
|
+
# <%= render(Primer::ButtonComponent.new(button_type: :outline)) { "Outline" } %>
|
34
|
+
#
|
35
|
+
# @example 50|Variants
|
36
|
+
# <%= render(Primer::ButtonComponent.new(variant: :small)) { "Small" } %>
|
37
|
+
# <%= render(Primer::ButtonComponent.new(variant: :medium)) { "Medium" } %>
|
38
|
+
# <%= render(Primer::ButtonComponent.new(variant: :large)) { "Large" } %>
|
39
|
+
#
|
40
|
+
# @param button_type [Symbol] <%= one_of(Primer::ButtonComponent::BUTTON_TYPE_OPTIONS) %>
|
41
|
+
# @param variant [Symbol] <%= one_of(Primer::ButtonComponent::VARIANT_OPTIONS) %>
|
42
|
+
# @param tag [Symbol] <%= one_of(Primer::ButtonComponent::TAG_OPTIONS) %>
|
43
|
+
# @param type [Symbol] <%= one_of(Primer::ButtonComponent::TYPE_OPTIONS) %>
|
44
|
+
# @param group_item [Boolean] Whether button is part of a ButtonGroup.
|
28
45
|
def initialize(
|
29
46
|
button_type: DEFAULT_BUTTON_TYPE,
|
30
47
|
variant: DEFAULT_VARIANT,
|
31
48
|
tag: DEFAULT_TAG,
|
32
49
|
type: DEFAULT_TYPE,
|
33
50
|
group_item: false,
|
34
|
-
**
|
51
|
+
**system_arguments
|
35
52
|
)
|
36
|
-
@
|
37
|
-
@
|
53
|
+
@system_arguments = system_arguments
|
54
|
+
@system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
|
38
55
|
|
39
|
-
if @
|
40
|
-
@
|
56
|
+
if @system_arguments[:tag] == :a
|
57
|
+
@system_arguments[:role] = :button
|
41
58
|
else
|
42
|
-
@
|
59
|
+
@system_arguments[:type] = type
|
43
60
|
end
|
44
61
|
|
45
|
-
@
|
62
|
+
@system_arguments[:classes] = class_names(
|
46
63
|
"btn",
|
47
|
-
|
64
|
+
system_arguments[:classes],
|
48
65
|
BUTTON_TYPE_MAPPINGS[fetch_or_fallback(BUTTON_TYPE_OPTIONS, button_type, DEFAULT_BUTTON_TYPE)],
|
49
66
|
VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant, DEFAULT_VARIANT)],
|
50
67
|
"BtnGroup-item" => group_item
|
@@ -52,7 +69,7 @@ module Primer
|
|
52
69
|
end
|
53
70
|
|
54
71
|
def call
|
55
|
-
render(Primer::BaseComponent.new(**@
|
72
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
56
73
|
end
|
57
74
|
end
|
58
75
|
end
|
@@ -10,13 +10,17 @@ module Primer
|
|
10
10
|
:light_gray => "Counter Counter--gray-light",
|
11
11
|
}.freeze
|
12
12
|
|
13
|
+
#
|
14
|
+
# @example 34|Default
|
15
|
+
# <%= render(Primer::CounterComponent.new(count: 25)) %>
|
16
|
+
#
|
13
17
|
# @param count [Integer, Float::INFINITY, nil] The number to be displayed (e.x. # of issues, pull requests)
|
14
18
|
# @param scheme [Symbol] Color scheme. One of `SCHEME_MAPPINGS.keys`.
|
15
19
|
# @param limit [Integer] Maximum value to display. (e.x. if count == 6,000 and limit == 5000, counter will display "5,000+")
|
16
20
|
# @param hide_if_zero [Boolean] If true, a `hidden` attribute is added to the counter if `count` is zero.
|
17
21
|
# @param text [String] Text to display instead of count.
|
18
22
|
# @param round [Boolean] Whether to apply our standard rounding logic to value.
|
19
|
-
# @param
|
23
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
20
24
|
def initialize(
|
21
25
|
count: 0,
|
22
26
|
scheme: DEFAULT_SCHEME,
|
@@ -24,23 +28,23 @@ module Primer
|
|
24
28
|
hide_if_zero: false,
|
25
29
|
text: "",
|
26
30
|
round: false,
|
27
|
-
**
|
31
|
+
**system_arguments
|
28
32
|
)
|
29
|
-
@count, @limit, @hide_if_zero, @text, @round, @
|
33
|
+
@count, @limit, @hide_if_zero, @text, @round, @system_arguments = count, limit, hide_if_zero, text, round, system_arguments
|
30
34
|
|
31
|
-
@
|
32
|
-
@
|
33
|
-
@
|
34
|
-
@
|
35
|
+
@system_arguments[:title] = title
|
36
|
+
@system_arguments[:tag] = :span
|
37
|
+
@system_arguments[:classes] = class_names(
|
38
|
+
@system_arguments[:classes],
|
35
39
|
SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, DEFAULT_SCHEME)]
|
36
40
|
)
|
37
41
|
if count == 0 && hide_if_zero
|
38
|
-
@
|
42
|
+
@system_arguments[:hidden] = true
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
46
|
def call
|
43
|
-
render(Primer::BaseComponent.new(**@
|
47
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { value }
|
44
48
|
end
|
45
49
|
|
46
50
|
private
|
@@ -9,9 +9,9 @@ module Primer
|
|
9
9
|
class DetailsComponent < Primer::Component
|
10
10
|
include ViewComponent::Slotable
|
11
11
|
|
12
|
-
|
12
|
+
NO_OVERLAY = :none
|
13
13
|
OVERLAY_MAPPINGS = {
|
14
|
-
|
14
|
+
NO_OVERLAY => "",
|
15
15
|
:default => "details-overlay",
|
16
16
|
:dark => "details-overlay details-overlay-dark",
|
17
17
|
}.freeze
|
@@ -19,12 +19,12 @@ module Primer
|
|
19
19
|
with_slot :body, class_name: "Body"
|
20
20
|
with_slot :summary, class_name: "Summary"
|
21
21
|
|
22
|
-
def initialize(overlay:
|
23
|
-
@
|
24
|
-
@
|
25
|
-
@
|
26
|
-
|
27
|
-
OVERLAY_MAPPINGS[fetch_or_fallback(OVERLAY_MAPPINGS.keys, overlay,
|
22
|
+
def initialize(overlay: NO_OVERLAY, reset: false, **system_arguments)
|
23
|
+
@system_arguments = system_arguments
|
24
|
+
@system_arguments[:tag] = :details
|
25
|
+
@system_arguments[:classes] = class_names(
|
26
|
+
system_arguments[:classes],
|
27
|
+
OVERLAY_MAPPINGS[fetch_or_fallback(OVERLAY_MAPPINGS.keys, overlay, NO_OVERLAY)],
|
28
28
|
"details-reset" => reset
|
29
29
|
)
|
30
30
|
end
|
@@ -34,29 +34,29 @@ module Primer
|
|
34
34
|
end
|
35
35
|
|
36
36
|
class Summary < Primer::Slot
|
37
|
-
def initialize(button: true, **
|
37
|
+
def initialize(button: true, **system_arguments)
|
38
38
|
@button = button
|
39
39
|
|
40
|
-
@
|
41
|
-
@
|
42
|
-
@
|
40
|
+
@system_arguments = system_arguments
|
41
|
+
@system_arguments[:tag] = :summary
|
42
|
+
@system_arguments[:role] = "button"
|
43
43
|
end
|
44
44
|
|
45
45
|
def component
|
46
|
-
return Primer::BaseComponent.new(**@
|
46
|
+
return Primer::BaseComponent.new(**@system_arguments) unless @button
|
47
47
|
|
48
|
-
Primer::ButtonComponent.new(**@
|
48
|
+
Primer::ButtonComponent.new(**@system_arguments)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
class Body < Primer::Slot
|
53
|
-
def initialize(**
|
54
|
-
@
|
55
|
-
@
|
53
|
+
def initialize(**system_arguments)
|
54
|
+
@system_arguments = system_arguments
|
55
|
+
@system_arguments[:tag] ||= :div
|
56
56
|
end
|
57
57
|
|
58
58
|
def component
|
59
|
-
Primer::BaseComponent.new(**@
|
59
|
+
Primer::BaseComponent.new(**@system_arguments)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|