Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Y
ygopro-scripts-888
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
3
Merge Requests
3
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
ygopro-scripts-888
Commits
2ecb3ab8
Commit
2ecb3ab8
authored
Jul 14, 2025
by
Vury Leo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tuning 白の枢機竜
parent
70ab2010
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
62 additions
and
51 deletions
+62
-51
c11321089.lua
c11321089.lua
+2
-2
c11765832.lua
c11765832.lua
+20
-10
procedure.lua
procedure.lua
+40
-39
No files found.
c11321089.lua
View file @
2ecb3ab8
...
@@ -30,7 +30,7 @@ function s.initial_effect(c)
...
@@ -30,7 +30,7 @@ function s.initial_effect(c)
end
,
end
,
})
})
},
},
mat
_filter
=
s
.
mat_
filter
,
mat
filter
=
s
.
mat
filter
,
fgoalcheck
=
s
.
fgoalcheck
,
fgoalcheck
=
s
.
fgoalcheck
,
})
})
--material limit
--material limit
...
@@ -96,7 +96,7 @@ function s.fgoalcheck(mg)
...
@@ -96,7 +96,7 @@ function s.fgoalcheck(mg)
return
hand
>=
1
and
field
>=
1
return
hand
>=
1
and
field
>=
1
end
end
function
s
.
mat
_
filter
(
mc
,
tc
)
function
s
.
matfilter
(
mc
,
tc
)
return
mc
:
IsLocation
(
LOCATION_HAND
)
or
mc
:
IsControler
(
tc
:
GetControler
())
and
mc
:
IsOnField
()
return
mc
:
IsLocation
(
LOCATION_HAND
)
or
mc
:
IsControler
(
tc
:
GetControler
())
and
mc
:
IsOnField
()
end
end
...
...
c11765832.lua
View file @
2ecb3ab8
...
@@ -2,13 +2,31 @@
...
@@ -2,13 +2,31 @@
local
s
,
id
,
o
=
GetID
()
local
s
,
id
,
o
=
GetID
()
function
s
.
initial_effect
(
c
)
function
s
.
initial_effect
(
c
)
c
:
EnableReviveLimit
()
c
:
EnableReviveLimit
()
-- aux.AddFusionProcFunRep(c,s.ffilter,2,true)
Fusion
.
AddFusionProcedure
(
c
,{
Fusion
.
AddFusionProcedure
(
c
,{
slots
=
{
slots
=
{
Fusion
.
Slot
.
Group
({
Fusion
.
Slot
.
Group
({
min
=
2
,
min
=
2
,
max
=
2
,
max
=
2
,
unique_by
=
function
(
mc
)
return
{
mc
:
GetCode
(),
mc
:
GetFusionCode
()
}
end
,
--- @param mc Card
unique_by
=
function
(
mc
)
local
function
dedup_represent
(
code
)
if
code
==
78734254
then
return
17955766
elseif
code
==
13857930
then
return
17732278
end
return
code
end
local
code
=
dedup_represent
(
mc
:
GetCode
())
local
res
=
{
code
}
--- Add Fusion Tag names
for
_
,
eff
in
ipairs
({
mc
:
IsHasEffect
(
EFFECT_ADD_FUSION_CODE
)})
do
local
fusion_tag_code
=
eff
:
GetValue
()
assert
(
type
(
fusion_tag_code
)
==
'number'
)
table.insert
(
res
,
dedup_represent
(
fusion_tag_code
))
end
return
res
end
,
has_same
=
{
has_same
=
{
function
(
mc
,
tc
)
return
mc
:
GetFusionAttribute
(
tc
:
GetOwner
())
end
,
function
(
mc
,
tc
)
return
mc
:
GetFusionAttribute
(
tc
:
GetOwner
())
end
,
function
(
mc
)
return
mc
:
GetRace
()
end
,
function
(
mc
)
return
mc
:
GetRace
()
end
,
...
@@ -34,14 +52,6 @@ function s.initial_effect(c)
...
@@ -34,14 +52,6 @@ function s.initial_effect(c)
e2
:
SetOperation
(
s
.
operation
)
e2
:
SetOperation
(
s
.
operation
)
c
:
RegisterEffect
(
e2
)
c
:
RegisterEffect
(
e2
)
end
end
function
s
.
matchfilter
(
c
,
attr
,
race
)
return
c
:
IsFusionAttribute
(
attr
)
and
c
:
IsRace
(
race
)
end
function
s
.
ffilter
(
c
,
fc
,
sub
,
mg
,
sg
)
return
not
sg
or
sg
:
FilterCount
(
aux
.
TRUE
,
c
)
==
0
or
(
sg
:
IsExists
(
s
.
matchfilter
,
#
sg
-
1
,
c
,
c
:
GetFusionAttribute
(),
c
:
GetRace
())
and
not
sg
:
IsExists
(
Card
.
IsFusionCode
,
1
,
c
,
c
:
GetFusionCode
()))
end
function
s
.
target
(
e
,
tp
,
eg
,
ep
,
ev
,
re
,
r
,
rp
,
chk
)
function
s
.
target
(
e
,
tp
,
eg
,
ep
,
ev
,
re
,
r
,
rp
,
chk
)
if
chk
==
0
then
return
Duel
.
IsPlayerCanDraw
(
tp
,
1
)
end
if
chk
==
0
then
return
Duel
.
IsPlayerCanDraw
(
tp
,
1
)
end
Duel
.
SetTargetPlayer
(
tp
)
Duel
.
SetTargetPlayer
(
tp
)
...
...
procedure.lua
View file @
2ecb3ab8
...
@@ -3475,14 +3475,14 @@ function Fusion.AddFusionProcedure(c, opts)
...
@@ -3475,14 +3475,14 @@ function Fusion.AddFusionProcedure(c, opts)
end
end
---@param allow_extras boolean whether to allow extra materials for checking propose
---@param allow_extras boolean whether to allow extra materials for checking propose
function
Fusion
.
BasicCondition
(
tc
,
slots
,
mat
_
filter
,
fgoalcheck
,
allow_extras
,
selected
)
function
Fusion
.
BasicCondition
(
tc
,
slots
,
matfilter
,
fgoalcheck
,
allow_extras
,
selected
)
return
function
(
e
,
g
,
gc
,
chkf
)
return
function
(
e
,
g
,
gc
,
chkf
)
if
not
g
then
return
false
end
if
not
g
then
return
false
end
-- Collect cards and apply global mat
_
filter
-- Collect cards and apply global matfilter
local
cards
=
{}
local
cards
=
{}
for
c
in
aux
.
Next
(
g
)
do
for
c
in
aux
.
Next
(
g
)
do
if
not
mat
_filter
or
mat_
filter
(
c
,
tc
)
then
if
not
mat
filter
or
mat
filter
(
c
,
tc
)
then
table.insert
(
cards
,
c
)
table.insert
(
cards
,
c
)
end
end
end
end
...
@@ -3506,7 +3506,7 @@ function Fusion.BasicCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selec
...
@@ -3506,7 +3506,7 @@ function Fusion.BasicCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selec
end
end
-- Prepare locked flags for substitute materials
-- Prepare locked flags for substitute materials
local
locked
=
{}
local
locked
=
{}
if
Fusion
.
LockedCodes
then
if
Fusion
.
LockedCodes
then
for
_
,
code
in
ipairs
(
Fusion
.
LockedCodes
)
do
for
_
,
code
in
ipairs
(
Fusion
.
LockedCodes
)
do
for
i
,
slot
in
ipairs
(
single_slots
)
do
for
i
,
slot
in
ipairs
(
single_slots
)
do
...
@@ -3531,7 +3531,7 @@ function Fusion.BasicCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selec
...
@@ -3531,7 +3531,7 @@ function Fusion.BasicCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selec
end
end
end
end
--
5)
DFS assign single‐slots
-- DFS assign single‐slots
local
used
=
{}
local
used
=
{}
local
sub_count
=
0
local
sub_count
=
0
local
function
dfs_singles
(
i
)
local
function
dfs_singles
(
i
)
...
@@ -3630,13 +3630,15 @@ function Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
...
@@ -3630,13 +3630,15 @@ function Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
return
false
return
false
end
end
-- has_same on full matched
-- has_same on full matched
if
grp
.
has_same
and
not
Fusion
.
CheckHasSame
(
grp
,
Group
.
FromCards
(
table.unpack
(
matched
)),
e
)
then
if
grp
.
has_same
and
not
Fusion
.
CheckHasSame
(
grp
,
matched
,
e
)
then
Debug
.
Message
(
"rejected by has_same"
)
return
false
return
false
end
end
-- unique_by on full matched
-- unique_by on full matched
if
grp
.
unique_by
then
if
grp
.
unique_by
then
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
#
matched
)
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
#
matched
)
if
not
matcher
(
matched
)
then
if
not
matcher
(
matched
)
then
Debug
.
Message
(
"rejected by unique_by"
)
return
false
return
false
end
end
end
end
...
@@ -3655,6 +3657,7 @@ function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
...
@@ -3655,6 +3657,7 @@ function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
table.insert
(
matched
,
c
)
table.insert
(
matched
,
c
)
end
end
end
end
if
#
matched
<
grp
.
min
then
if
#
matched
<
grp
.
min
then
return
false
return
false
end
end
...
@@ -3666,24 +3669,25 @@ function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
...
@@ -3666,24 +3669,25 @@ function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
return
false
return
false
end
end
end
end
local
comb
=
{}
local
comb
=
{}
local
function
dfs
(
start
,
depth
)
local
function
dfs
(
start
,
depth
)
-- If we have at least grp.min cards, test this subset immediately
-- If we have at least grp.min cards, test this subset immediately
if
depth
>=
grp
.
min
then
if
depth
>=
grp
.
min
then
-- build subset group and merged material group
-- build subset group and merged material group
local
subG
=
Group
.
FromCards
(
table.unpack
(
comb
,
1
,
depth
))
local
sub_g_arr
=
{
table.unpack
(
comb
,
1
,
depth
)}
local
subG
=
Group
.
FromCards
(
table.unpack
(
sub_g_arr
))
local
mg_tmp
=
mg_base
:
Clone
()
local
mg_tmp
=
mg_base
:
Clone
()
mg_tmp
:
Merge
(
subG
)
mg_tmp
:
Merge
(
subG
)
-- has_same check
-- has_same check
local
ok_same
=
not
grp
.
has_same
or
Fusion
.
CheckHasSame
(
grp
,
subG
,
e
)
local
ok_same
=
not
grp
.
has_same
or
Fusion
.
CheckHasSame
(
grp
,
sub_g_arr
,
e
)
-- unique_by check
-- unique_by check
local
ok_unique
=
true
local
ok_unique
=
true
if
grp
.
unique_by
then
if
grp
.
unique_by
then
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
depth
)
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
#
sub_g_arr
)
ok_unique
=
matcher
(
comb
)
ok_unique
=
matcher
(
sub_g_arr
)
end
end
-- final fusion checks
-- final fusion checks
if
ok_same
and
ok_unique
and
Fusion
.
FinalCheck
(
e
,
mg_tmp
,
tc
,
fgoalcheck
,
chkf
)
then
if
ok_same
and
ok_unique
and
Fusion
.
FinalCheck
(
e
,
mg_tmp
,
tc
,
fgoalcheck
,
chkf
)
then
...
@@ -3718,9 +3722,7 @@ end
...
@@ -3718,9 +3722,7 @@ end
-- Shared has_same checker (bitmask or key‐list)
-- Shared has_same checker (bitmask or key‐list)
function
Fusion
.
CheckHasSame
(
grp
,
group_obj
,
e
)
function
Fusion
.
CheckHasSame
(
grp
,
cards
,
e
)
local
cards
=
{}
for
c
in
aux
.
Next
(
group_obj
)
do
table.insert
(
cards
,
c
)
end
for
_
,
fn
in
ipairs
(
grp
.
has_same
)
do
for
_
,
fn
in
ipairs
(
grp
.
has_same
)
do
local
v0
=
fn
(
cards
[
1
],
e
:
GetHandler
())
local
v0
=
fn
(
cards
[
1
],
e
:
GetHandler
())
if
type
(
v0
)
==
"number"
then
if
type
(
v0
)
==
"number"
then
...
@@ -4001,7 +4003,7 @@ end
...
@@ -4001,7 +4003,7 @@ end
--- @param slots table[] your slot definitions
--- @param slots table[] your slot definitions
--- @param tc Card the Fusion monster (for substitutes)
--- @param tc Card the Fusion monster (for substitutes)
--- @return boolean true if ∃ a mapping + completion path
--- @return boolean true if ∃ a mapping + completion path
function
Fusion
.
CanCompleteFromMappings
(
e
,
sel
,
eg
,
slots
,
mat
_
filter
,
fgoalcheck
,
tc
,
gc
,
chkf
)
function
Fusion
.
CanCompleteFromMappings
(
e
,
sel
,
eg
,
slots
,
matfilter
,
fgoalcheck
,
tc
,
gc
,
chkf
)
-- arrayify sel so we can refer by index
-- arrayify sel so we can refer by index
local
cards_sel
=
{}
local
cards_sel
=
{}
for
c
in
aux
.
Next
(
sel
)
do
for
c
in
aux
.
Next
(
sel
)
do
...
@@ -4071,14 +4073,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4071,14 +4073,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
for
i
,
slot
in
ipairs
(
slots
)
do
for
i
,
slot
in
ipairs
(
slots
)
do
if
slot
.
group
then
if
slot
.
group
then
local
need
=
group_need
[
i
]
or
0
local
need
=
group_need
[
i
]
or
0
-- if this slot has a unique_by, wrap its filter to exclude collided keys
local
new_filter
=
slot
.
group
.
filter
local
new_filter
=
slot
.
group
.
filter
if
slot
.
group
.
unique_by
then
local
used_keys
=
Fusion
.
ExtractUsedKeys
(
cards_sel
,
mapping
,
i
,
slot
.
group
.
unique_by
)
new_filter
=
Fusion
.
MakeExcludeFilter
(
new_filter
,
slot
.
group
.
unique_by
,
used_keys
)
end
-- if this slot has a has_same, wrap its filter to include only sames
if
slot
.
group
.
has_same
then
-- only if there is at least one already‐selected card for this slot…
-- only if there is at least one already‐selected card for this slot…
local
has_sel
=
false
local
has_sel
=
false
for
_
,
mapped_i
in
pairs
(
mapping
)
do
for
_
,
mapped_i
in
pairs
(
mapping
)
do
...
@@ -4088,6 +4083,13 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4088,6 +4083,13 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
end
end
end
end
if
has_sel
then
if
has_sel
then
-- if this slot has a unique_by, wrap its filter to exclude collided keys
if
slot
.
group
.
unique_by
then
local
used_keys
=
Fusion
.
ExtractUsedKeys
(
cards_sel
,
mapping
,
i
,
slot
.
group
.
unique_by
)
new_filter
=
Fusion
.
MakeExcludeFilter
(
new_filter
,
slot
.
group
.
unique_by
,
used_keys
)
end
-- if this slot has a has_same, wrap its filter to include only sames
if
slot
.
group
.
has_same
then
-- precompute, for each fn in has_same, the overlap of already-mapped cards
-- precompute, for each fn in has_same, the overlap of already-mapped cards
local
used_overlap
=
{}
-- fn → (number mask) or (table of keys)
local
used_overlap
=
{}
-- fn → (number mask) or (table of keys)
for
_
,
fn
in
ipairs
(
slot
.
group
.
has_same
)
do
for
_
,
fn
in
ipairs
(
slot
.
group
.
has_same
)
do
...
@@ -4152,8 +4154,8 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4152,8 +4154,8 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
min
=
need
,
min
=
need
,
max
=
slot
.
group
.
max
-
slot
.
group
.
min
+
need
,
max
=
slot
.
group
.
max
-
slot
.
group
.
min
+
need
,
filter
=
new_filter
,
filter
=
new_filter
,
unique_by
=
slot
.
unique_by
,
unique_by
=
slot
.
group
.
unique_by
,
has_same
=
slot
.
has_same
,
has_same
=
slot
.
group
.
has_same
,
}
}
})
})
end
end
...
@@ -4177,7 +4179,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4177,7 +4179,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
end
end
-- delegate to FusionCondition (allow_extras=true)
-- delegate to FusionCondition (allow_extras=true)
local
search_cond
=
Fusion
.
BasicCondition
(
tc
,
rem_slots
,
mat
_
filter
,
fgoalcheck
,
true
,
sel
)
local
search_cond
=
Fusion
.
BasicCondition
(
tc
,
rem_slots
,
matfilter
,
fgoalcheck
,
true
,
sel
)
if
search_cond
(
e
,
rem_pool
,
gc
,
chkf
)
then
if
search_cond
(
e
,
rem_pool
,
gc
,
chkf
)
then
Fusion
.
LockedCodes
=
old_locked
Fusion
.
LockedCodes
=
old_locked
return
true
return
true
...
@@ -4215,7 +4217,6 @@ function Fusion.UniqueByMatching(key_func,min_needed)
...
@@ -4215,7 +4217,6 @@ function Fusion.UniqueByMatching(key_func,min_needed)
table.insert
(
card_keys
[
idx
],
id
)
table.insert
(
card_keys
[
idx
],
id
)
end
end
end
end
-- quick reject if fewer distinct keys exist than needed
-- quick reject if fewer distinct keys exist than needed
if
next_key_id
<
min_needed
then
if
next_key_id
<
min_needed
then
return
false
return
false
...
@@ -4300,14 +4301,14 @@ function Fusion.BuildPatterns(opts)
...
@@ -4300,14 +4301,14 @@ function Fusion.BuildPatterns(opts)
for
_
,
v
in
ipairs
(
opts
.
variants
)
do
for
_
,
v
in
ipairs
(
opts
.
variants
)
do
table.insert
(
patterns
,{
table.insert
(
patterns
,{
slots
=
v
.
slots
,
slots
=
v
.
slots
,
mat
_filter
=
v
.
mat_
filter
,
mat
filter
=
v
.
mat
filter
,
fgoalcheck
=
v
.
fgoalcheck
or
aux
.
TRUE
,
fgoalcheck
=
v
.
fgoalcheck
or
aux
.
TRUE
,
})
})
end
end
else
else
table.insert
(
patterns
,{
table.insert
(
patterns
,{
slots
=
opts
.
slots
,
slots
=
opts
.
slots
,
mat
_filter
=
opts
.
mat_
filter
,
mat
filter
=
opts
.
mat
filter
,
fgoalcheck
=
opts
.
fgoalcheck
or
aux
.
TRUE
,
fgoalcheck
=
opts
.
fgoalcheck
or
aux
.
TRUE
,
})
})
end
end
...
@@ -4331,7 +4332,7 @@ function Fusion.MultiCondition(tc,patterns,allow_extras)
...
@@ -4331,7 +4332,7 @@ function Fusion.MultiCondition(tc,patterns,allow_extras)
end
end
end
end
if
ok
then
if
ok
then
local
cond
=
Fusion
.
BasicCondition
(
tc
,
pat
.
slots
,
pat
.
mat
_
filter
,
pat
.
fgoalcheck
,
allow_extras
,
selected
)
local
cond
=
Fusion
.
BasicCondition
(
tc
,
pat
.
slots
,
pat
.
matfilter
,
pat
.
fgoalcheck
,
allow_extras
,
selected
)
if
cond
(
e
,
g
,
gc
,
chkf
)
then
if
cond
(
e
,
g
,
gc
,
chkf
)
then
return
true
return
true
end
end
...
@@ -4409,7 +4410,7 @@ function Fusion.MultiOperation(tc,patterns)
...
@@ -4409,7 +4410,7 @@ function Fusion.MultiOperation(tc,patterns)
sg
:
AddCard
(
mc
)
sg
:
AddCard
(
mc
)
-- completion test against active patterns
-- completion test against active patterns
for
_
,
pat
in
ipairs
(
active_patterns
)
do
for
_
,
pat
in
ipairs
(
active_patterns
)
do
if
Fusion
.
CanCompleteFromMappings
(
e
,
sg
,
eg
,
pat
.
slots
,
pat
.
mat
_
filter
,
pat
.
fgoalcheck
,
tc
,
gc
,
chkf
)
then
if
Fusion
.
CanCompleteFromMappings
(
e
,
sg
,
eg
,
pat
.
slots
,
pat
.
matfilter
,
pat
.
fgoalcheck
,
tc
,
gc
,
chkf
)
then
addable
:
AddCard
(
mc
)
addable
:
AddCard
(
mc
)
break
break
end
end
...
@@ -4480,11 +4481,11 @@ function Fusion.FusionCondition(tc,patterns)
...
@@ -4480,11 +4481,11 @@ function Fusion.FusionCondition(tc,patterns)
-- attempt “search mode” on each pattern
-- attempt “search mode” on each pattern
for
_
,
pat
in
ipairs
(
patterns
)
do
for
_
,
pat
in
ipairs
(
patterns
)
do
if
Fusion
.
CanCompleteFromMappings
(
e
,
selected
,
g
,
pat
.
slots
,
pat
.
mat_filter
,
pat
.
fgoalcheck
or
aux
.
TRUE
,
tc
,
gc
,
chkf
)
if
Fusion
.
CanCompleteFromMappings
(
e
,
selected
,
g
,
pat
.
slots
,
pat
.
matfilter
,
pat
.
fgoalcheck
or
aux
.
TRUE
,
tc
,
gc
,
chkf
)
then
then
return
true
return
true
end
end
end
end
return
false
end
end
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment