card 1.101.3 → 1.101.4
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/VERSION +1 -1
- data/config/initializers/02_patches/active_record.rb +1 -1
- data/config/locales/en.yml +155 -378
- data/db/migrate_core_cards/20150202143810_import_bootstrap_layout.rb +1 -1
- data/lib/card.rb +15 -2
- data/lib/card/auth.rb +5 -2
- data/lib/card/auth/current.rb +39 -100
- data/lib/card/auth/proxy.rb +36 -16
- data/lib/card/auth/token.rb +6 -0
- data/lib/card/cache/all.rb +83 -0
- data/lib/card/cache/card_class.rb +41 -0
- data/lib/card/cache/persistent.rb +3 -34
- data/lib/card/cache/persistent_class.rb +28 -0
- data/lib/card/codename.rb +1 -1
- data/lib/card/content.rb +16 -2
- data/lib/card/content/all.rb +59 -0
- data/lib/card/director/act_direction.rb +4 -0
- data/lib/card/director/all.rb +61 -0
- data/lib/card/director/card_class.rb +18 -0
- data/lib/card/director/phases.rb +0 -1
- data/lib/card/dirty.rb +13 -3
- data/lib/card/env/success.rb +14 -14
- data/lib/card/env/success/target.rb +9 -11
- data/lib/card/error.rb +1 -1
- data/lib/card/fetch/all.rb +32 -0
- data/lib/card/fetch/card_class.rb +147 -0
- data/lib/card/format.rb +1 -1
- data/lib/card/format/error.rb +3 -3
- data/lib/card/format/nest.rb +1 -1
- data/lib/card/format/nest/fetch.rb +1 -1
- data/lib/card/lexicon.rb +2 -2
- data/lib/card/name/all.rb +8 -0
- data/lib/card/name/all/descendants.rb +6 -3
- data/lib/card/name/card_class.rb +26 -0
- data/lib/card/reference/all.rb +131 -0
- data/lib/card/rule/all.rb +75 -0
- data/lib/card/set/event/all.rb +95 -0
- data/lib/card/set/event/skip_and_trigger.rb +89 -0
- data/lib/card/set/pattern/all.rb +63 -0
- data/lib/card/subcards/all.rb +103 -0
- data/lib/cardio/migration/import.rb +1 -1
- data/lib/cardio/utils.rb +5 -3
- data/mod/admin/set/self/admin_info.rb +3 -5
- data/mod/admin/set/self/trash.rb +2 -2
- data/mod/core/set/all/autoname.rb +17 -0
- data/mod/core/set/all/codename.rb +2 -2
- data/mod/core/set/all/content.rb +52 -97
- data/mod/core/set/all/name_events.rb +69 -58
- data/mod/core/set/all/reference_events.rb +67 -0
- data/mod/core/set/all/states.rb +2 -2
- data/mod/core/set/all/subcards.rb +0 -100
- data/mod/core/set/all/trash.rb +11 -13
- data/mod/core/set/all/type.rb +7 -9
- data/mod/core/set/all/utils.rb +3 -0
- data/mod/core/set/type/cardtype.rb +3 -3
- data/mod/core/set_pattern/06_rule.rb +1 -1
- data/mod/core/spec/set/all/{rules2_spec.rb → clean_me_spec.rb} +0 -0
- data/mod/core/spec/set/all/name_events_spec.rb +204 -0
- metadata +30 -37
- data/lib/card/mod_inflector.rb +0 -16
- data/lib/card/name/all/class_methods.rb +0 -28
- data/mod/core/set/all/actify.rb +0 -68
- data/mod/core/set/all/cache.rb +0 -109
- data/mod/core/set/all/event_conditions.rb +0 -172
- data/mod/core/set/all/fetch.rb +0 -122
- data/mod/core/set/all/fetch_helper.rb +0 -35
- data/mod/core/set/all/i18n.rb +0 -9
- data/mod/core/set/all/pattern.rb +0 -54
- data/mod/core/set/all/references.rb +0 -191
- data/mod/core/set/all/rename.rb +0 -33
- data/mod/core/set/all/rules.rb +0 -81
- data/mod/core/spec/set/all/actify_spec.rb +0 -58
- data/mod/core/spec/set/all/content_spec.rb +0 -15
- data/mod/core/spec/set/all/event_conditions_spec.rb +0 -217
- data/mod/core/spec/set/all/fetch_helper_spec.rb +0 -65
- data/mod/core/spec/set/all/fetch_spec.rb +0 -338
- data/mod/core/spec/set/all/i18n_spec.rb +0 -17
- data/mod/core/spec/set/all/pattern_spec.rb +0 -101
- data/mod/core/spec/set/all/permissions/reader_rules_spec.rb +0 -166
- data/mod/core/spec/set/all/references_spec.rb +0 -62
- data/mod/core/spec/set/all/rename_spec.rb +0 -189
- data/mod/core/spec/set/all/rules_spec.rb +0 -100
- data/mod/core/spec/set/all/subcards_spec.rb +0 -102
@@ -0,0 +1,147 @@
|
|
1
|
+
class Card
|
2
|
+
class Fetch
|
3
|
+
# = Card#fetch
|
4
|
+
#
|
5
|
+
# A multipurpose retrieval operator that integrates caching, database lookups,
|
6
|
+
# and "virtual" card construction
|
7
|
+
module CardClass
|
8
|
+
# Look for cards in
|
9
|
+
# * cache
|
10
|
+
# * database
|
11
|
+
# * virtual cards
|
12
|
+
#
|
13
|
+
# @param args [Integer, String, Card::Name, Symbol, Array]
|
14
|
+
# one or more of the three unique identifiers
|
15
|
+
# 1. a numeric id (Integer)
|
16
|
+
# 2. a name/key (String or Card::Name)
|
17
|
+
# 3. a codename (Symbol)
|
18
|
+
# If you pass more then one mark or an array of marks they get joined with a '+'.
|
19
|
+
# The final argument can be a hash to set the following options
|
20
|
+
# :skip_virtual Real cards only
|
21
|
+
# :skip_modules Don't load Set modules
|
22
|
+
# :look_in_trash Return trashed card objects
|
23
|
+
# :local_only Use only local cache for lookup and storing
|
24
|
+
# new: { opts for Card#new } Return a new card when not found
|
25
|
+
# @return [Card]
|
26
|
+
def fetch *args
|
27
|
+
Card::Fetch.new(*args)&.retrieve_or_new
|
28
|
+
rescue ActiveModel::RangeError => _e
|
29
|
+
return Card.new name: "card id out of range: #{f.mark}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# fetch only real (no virtual) cards
|
33
|
+
#
|
34
|
+
# @param mark - see #fetch
|
35
|
+
# @return [Card]
|
36
|
+
def [] *mark
|
37
|
+
fetch(*mark, skip_virtual: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
# fetch real cards without set modules loaded. Should only be used for
|
41
|
+
# simple attributes
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# quick_fetch "A", :self, :structure
|
45
|
+
#
|
46
|
+
# @param mark - see #fetch
|
47
|
+
# @return [Card]
|
48
|
+
def quick_fetch *mark
|
49
|
+
fetch(*mark, skip_virtual: true, skip_modules: true)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Card]
|
53
|
+
def fetch_from_cast cast
|
54
|
+
fetch_args = cast[:id] ? [cast[:id].to_i] : [cast[:name], { new: cast }]
|
55
|
+
fetch(*fetch_args)
|
56
|
+
end
|
57
|
+
|
58
|
+
#----------------------------------------------------------------------
|
59
|
+
# ATTRIBUTE FETCHING
|
60
|
+
# The following methods optimize fetching of specific attributes
|
61
|
+
|
62
|
+
def id cardish
|
63
|
+
case cardish
|
64
|
+
when Integer then cardish
|
65
|
+
when Card then cardish.id
|
66
|
+
when Symbol then Card::Codename.id cardish
|
67
|
+
else fetch_id cardish
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# @param mark_parts - see #fetch
|
72
|
+
# @return [Integer]
|
73
|
+
def fetch_id *mark_parts
|
74
|
+
mark = Card::Fetch.new(*mark_parts)&.mark
|
75
|
+
mark.is_a?(Integer) ? mark : quick_fetch(mark.to_s)&.id
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param mark - see #fetch
|
79
|
+
# @return [Card::Name]
|
80
|
+
def fetch_name *mark, &block
|
81
|
+
if (card = quick_fetch(*mark))
|
82
|
+
card.name
|
83
|
+
elsif block_given?
|
84
|
+
yield.to_name
|
85
|
+
end
|
86
|
+
rescue => error
|
87
|
+
rescue_fetch_name error, &block
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param mark - see #fetch
|
91
|
+
# @return [Integer]
|
92
|
+
def fetch_type_id *mark
|
93
|
+
fetch(*mark, skip_modules: true)&.type_id
|
94
|
+
end
|
95
|
+
|
96
|
+
# a fetch method to support the needs of the card controller.
|
97
|
+
# should be in Decko?
|
98
|
+
def controller_fetch args
|
99
|
+
card_opts = controller_fetch_opts args
|
100
|
+
if args[:action] == "create"
|
101
|
+
# FIXME: we currently need a "new" card to catch duplicates
|
102
|
+
# (otherwise save will just act like a normal update)
|
103
|
+
# We may need a "#create" instance method to handle this checking?
|
104
|
+
Card.new card_opts
|
105
|
+
else
|
106
|
+
standard_controller_fetch args, card_opts
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def standard_controller_fetch args, card_opts
|
113
|
+
mark = args[:mark] || card_opts[:name]
|
114
|
+
card = Card.fetch mark, skip_modules: true,
|
115
|
+
look_in_trash: args[:look_in_trash],
|
116
|
+
new: card_opts
|
117
|
+
card.assign_attributes card_opts if args[:assign] && card&.real?
|
118
|
+
card&.include_set_modules
|
119
|
+
card
|
120
|
+
end
|
121
|
+
|
122
|
+
def controller_fetch_opts args
|
123
|
+
opts = Env.hash args[:card]
|
124
|
+
opts[:type] ||= args[:type] if args[:type]
|
125
|
+
# for /new/:type shortcut. we should handle in routing and deprecate this
|
126
|
+
opts[:name] ||= Name.url_key_to_standard args[:mark]
|
127
|
+
opts
|
128
|
+
end
|
129
|
+
|
130
|
+
def rescue_fetch_name error, &block
|
131
|
+
if rescued_fetch_name_to_name? error, &block
|
132
|
+
yield.to_name
|
133
|
+
elsif error.is_a? ActiveModel::RangeError
|
134
|
+
nil
|
135
|
+
else
|
136
|
+
raise error
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def rescued_fetch_name_to_name? error
|
141
|
+
return unless block_given?
|
142
|
+
|
143
|
+
error.is_a?(ActiveModel::RangeError) || error.is_a?(Error::CodenameNotFound)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
data/lib/card/format.rb
CHANGED
data/lib/card/format/error.rb
CHANGED
@@ -29,7 +29,7 @@ class Card
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def monitor_depth
|
32
|
-
raise Card::Error::UserError,
|
32
|
+
raise Card::Error::UserError, t(:format_too_deep) if depth >= Card.config.max_depth
|
33
33
|
yield
|
34
34
|
end
|
35
35
|
|
@@ -42,7 +42,7 @@ class Card
|
|
42
42
|
if card&.name.present?
|
43
43
|
safe_name
|
44
44
|
else
|
45
|
-
Cardio.
|
45
|
+
Cardio.t :lib_no_cardname
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -71,7 +71,7 @@ class Card
|
|
71
71
|
if exception.is_a? Card::Error::UserError
|
72
72
|
exception.message
|
73
73
|
else
|
74
|
-
|
74
|
+
t :lib_error_rendering, cardname: error_cardname(exception), view: view
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
data/lib/card/format/nest.rb
CHANGED
data/lib/card/lexicon.rb
CHANGED
@@ -36,12 +36,12 @@ class Card
|
|
36
36
|
|
37
37
|
def update card
|
38
38
|
add card
|
39
|
-
cache.delete cache_key(card.
|
39
|
+
cache.delete cache_key(card.lex_before_act)
|
40
40
|
end
|
41
41
|
|
42
42
|
# def delete card
|
43
43
|
# cache.delete card.id.to_s
|
44
|
-
# cache.delete cache_key(card.
|
44
|
+
# cache.delete cache_key(card.lex_before_act)
|
45
45
|
# end
|
46
46
|
|
47
47
|
def lex_to_name lex
|
data/lib/card/name/all.rb
CHANGED
@@ -35,6 +35,10 @@ class Card
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def lex
|
39
|
+
simple? ? name : [left_id, right_id]
|
40
|
+
end
|
41
|
+
|
38
42
|
def autoname name
|
39
43
|
if Card.exists?(name) || Director.include?(name)
|
40
44
|
autoname name.next
|
@@ -64,6 +68,10 @@ class Card
|
|
64
68
|
@key
|
65
69
|
end
|
66
70
|
|
71
|
+
def field tag, opts={}
|
72
|
+
Card.fetch name.field(tag), opts
|
73
|
+
end
|
74
|
+
|
67
75
|
private
|
68
76
|
|
69
77
|
def assign_side_ids
|
@@ -19,9 +19,12 @@ class Card
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def each_child
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
return unless id
|
23
|
+
|
24
|
+
Card.where(
|
25
|
+
"(left_id = #{id} or right_id = #{id}) and trash is false"
|
26
|
+
).each do |child|
|
27
|
+
yield child
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Card
|
2
|
+
class Name
|
3
|
+
# Name-related Card class methods
|
4
|
+
module CardClass
|
5
|
+
def rename! oldname, newname
|
6
|
+
Card[oldname].update! name: newname, update_referers: true
|
7
|
+
end
|
8
|
+
|
9
|
+
def uniquify_name name, rename=:new
|
10
|
+
return name unless Card.exists? name
|
11
|
+
uniq_name = generate_alternative_name name
|
12
|
+
return uniq_name unless rename == :old
|
13
|
+
rename!(name, uniq_name)
|
14
|
+
name
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def generate_alternative_name name
|
20
|
+
uniq_name = "#{name} 1"
|
21
|
+
uniq_name.next! while Card.exists?(uniq_name)
|
22
|
+
uniq_name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
class Card
|
2
|
+
class Reference < ApplicationRecord
|
3
|
+
module All
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
# Cards can refer to other cards in their content, eg via links and nests.
|
7
|
+
# The card that refers is the "referer", the card that is referred to is
|
8
|
+
# the "referee". The reference itself has its own class (Card::Reference),
|
9
|
+
# which handles id-based reference tracking.
|
10
|
+
|
11
|
+
PARTIAL_REF_CODE = "P".freeze
|
12
|
+
|
13
|
+
# cards that refer to self
|
14
|
+
def referers
|
15
|
+
referer_cards_from_references references_in
|
16
|
+
end
|
17
|
+
|
18
|
+
# cards that include self
|
19
|
+
def nesters
|
20
|
+
referer_cards_from_references references_in.where(ref_type: "I")
|
21
|
+
end
|
22
|
+
|
23
|
+
def referer_cards_from_references references
|
24
|
+
references.map(&:referer_id).uniq.map(&Card.method(:fetch)).compact
|
25
|
+
end
|
26
|
+
|
27
|
+
# cards that self refers to
|
28
|
+
def referees
|
29
|
+
referees_from_references references_out
|
30
|
+
end
|
31
|
+
|
32
|
+
# cards that self includes
|
33
|
+
def nestees
|
34
|
+
referees_from_references references_out.where(ref_type: "I")
|
35
|
+
end
|
36
|
+
|
37
|
+
def referees_from_references references
|
38
|
+
references.map(&:referee_key).uniq.map { |key| Card.fetch key, new: {} }
|
39
|
+
end
|
40
|
+
|
41
|
+
# cards that refer to self by name
|
42
|
+
# (finds cards not yet linked by id)
|
43
|
+
def name_referers
|
44
|
+
Card.joins(:references_out).where card_references: { referee_key: key }
|
45
|
+
end
|
46
|
+
|
47
|
+
# delete old references from this card's content, create new ones
|
48
|
+
def update_references_out
|
49
|
+
delete_references_out
|
50
|
+
create_references_out
|
51
|
+
end
|
52
|
+
|
53
|
+
# interpret references from this card's content and
|
54
|
+
# insert entries in reference table
|
55
|
+
def create_references_out
|
56
|
+
ref_hash = {}
|
57
|
+
each_reference_out do |referee_name, ref_type|
|
58
|
+
interpret_reference ref_hash, referee_name, ref_type
|
59
|
+
end
|
60
|
+
return if ref_hash.empty?
|
61
|
+
Reference.mass_insert reference_values_array(ref_hash)
|
62
|
+
end
|
63
|
+
|
64
|
+
# delete references from this card
|
65
|
+
def delete_references_out
|
66
|
+
raise "id required to delete references" if id.nil?
|
67
|
+
Reference.where(referer_id: id).delete_all
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def with_normalized_referee referee_name
|
73
|
+
return unless referee_name # eg commented nest has no referee_name
|
74
|
+
referee_name = referee_name.to_name
|
75
|
+
referee_key = referee_name.key
|
76
|
+
return if referee_key == key # don't create self reference
|
77
|
+
yield referee_name, referee_key, Lexicon.id(referee_name)
|
78
|
+
end
|
79
|
+
|
80
|
+
# interpretation phase helps to prevent duplicate references
|
81
|
+
# results in hash like:
|
82
|
+
# { referee1_key: [referee1_id, referee1_type2],
|
83
|
+
# referee2_key...
|
84
|
+
# }
|
85
|
+
def interpret_reference ref_hash, raw_referee_name, ref_type
|
86
|
+
with_normalized_referee raw_referee_name do |name, key, id|
|
87
|
+
ref_hash[key] ||= [id]
|
88
|
+
ref_hash[key] << ref_type
|
89
|
+
interpret_partial_references ref_hash, name unless id
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# translate interpreted reference hash into values array,
|
94
|
+
# removing duplicate and unnecessary ref_types
|
95
|
+
def reference_values_array ref_hash
|
96
|
+
[].tap do |values|
|
97
|
+
ref_hash.each do |referee_key, hash_val|
|
98
|
+
referee_id = hash_val.shift || "null"
|
99
|
+
each_reference_type hash_val.uniq do |ref_type|
|
100
|
+
values << [id, referee_id, "'#{referee_key}'", "'#{ref_type}'"]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def each_reference_type ref_types
|
107
|
+
ref_types.delete PARTIAL_REF_CODE if ref_types.size > 1
|
108
|
+
# partial references are not necessary if there are explicit references
|
109
|
+
ref_types.each { |ref_type| yield ref_type }
|
110
|
+
end
|
111
|
+
|
112
|
+
# invokes the given block for each reference in content with
|
113
|
+
# the reference name and reference type
|
114
|
+
def each_reference_out
|
115
|
+
content_object.find_chunks(:Reference).each do |chunk|
|
116
|
+
yield chunk.referee_name, chunk.reference_code
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Partial references are needed to track references to virtual cards.
|
121
|
+
# For example a link to virual card [[A+*self]] won't have a referee_id,
|
122
|
+
# but when A's name is changed we have to find and update that link.
|
123
|
+
def interpret_partial_references ref_hash, referee_name
|
124
|
+
return if referee_name.simple?
|
125
|
+
[referee_name.left, referee_name.right].each do |sidename|
|
126
|
+
interpret_reference ref_hash, sidename, PARTIAL_REF_CODE
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Card
|
2
|
+
module Rule
|
3
|
+
# rule-related Card instance methods
|
4
|
+
module All
|
5
|
+
def rule setting_code
|
6
|
+
rule_card(setting_code, skip_modules: true)&.db_content
|
7
|
+
end
|
8
|
+
|
9
|
+
def rule_card setting_code, options={}
|
10
|
+
Card.fetch rule_card_id(setting_code), options
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_card_id setting_code
|
14
|
+
rule_id_lookup Card::Rule.rule_cache, setting_code
|
15
|
+
end
|
16
|
+
|
17
|
+
def preference setting_code, user=nil
|
18
|
+
preference_card(setting_code, user, skip_modules: true)&.db_content
|
19
|
+
end
|
20
|
+
|
21
|
+
def preference_card setting_code, user=nil, options={}
|
22
|
+
Card.fetch preference_card_id(setting_code, user), options
|
23
|
+
end
|
24
|
+
|
25
|
+
def preference_card_id setting_code, user=nil
|
26
|
+
return unless (user_id = preference_user_id user)
|
27
|
+
rule_id_lookup Card::Rule.preference_cache,
|
28
|
+
"#{setting_code}+#{user_id}",
|
29
|
+
"#{setting_code}+#{AllID}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def rule?
|
33
|
+
standard_rule? || preference?
|
34
|
+
end
|
35
|
+
|
36
|
+
def standard_rule?
|
37
|
+
(Card.fetch_type_id(name.right) == SettingID) &&
|
38
|
+
(Card.fetch_type_id(name.left) == SetID)
|
39
|
+
end
|
40
|
+
|
41
|
+
def preference?
|
42
|
+
name.parts.length > 2 &&
|
43
|
+
(Card.fetch_type_id(name.right) == SettingID) &&
|
44
|
+
(Card.fetch_type_id(name[0..-3]) == SetID) &&
|
45
|
+
valid_preferer?
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def valid_preferer?
|
51
|
+
preferer = self[-2, skip_modules: true]
|
52
|
+
(preferer.type_id == UserID) || (preferer.codename == :all)
|
53
|
+
end
|
54
|
+
|
55
|
+
def preference_user_id user
|
56
|
+
case user
|
57
|
+
when Integer then user
|
58
|
+
when Card then user.id
|
59
|
+
when nil then Auth.current_id
|
60
|
+
else
|
61
|
+
raise Card::ServerError, "invalid preference user"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def rule_id_lookup lookup_hash, cache_suffix, fallback_suffix=nil
|
66
|
+
rule_set_keys.each do |rule_set_key|
|
67
|
+
rule_id = lookup_hash["#{rule_set_key}+#{cache_suffix}"]
|
68
|
+
rule_id ||= fallback_suffix && lookup_hash["#{rule_set_key}+#{fallback_suffix}"]
|
69
|
+
return rule_id if rule_id
|
70
|
+
end
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|