infopark_cloud_connector 6.8.3.115.227021242 → 6.8.3.174.51542603
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.
- data/lib/rails_connector/basic_obj.rb +1 -2
- data/lib/rails_connector/blob.rb +19 -52
- data/lib/rails_connector/cache_middleware.rb +0 -1
- data/lib/rails_connector/cms_backend.rb +179 -17
- data/lib/rails_connector/model_identity.rb +13 -0
- data/lib/rails_connector/workspace.rb +2 -11
- metadata +4 -49
- data/lib/rails_connector/chain.rb +0 -175
- data/lib/rails_connector/cms_base_model.rb +0 -55
- data/lib/rails_connector/content_cache.rb +0 -23
- data/lib/rails_connector/dict_storage.rb +0 -66
- data/lib/rails_connector/dynamo_cms_backend.rb +0 -136
- data/lib/rails_connector/obj_data_from_database.rb +0 -109
- data/lib/rails_connector/path_conversion.rb +0 -21
- data/lib/rails_connector/permission.rb +0 -39
- data/lib/rails_connector/revision.rb +0 -75
- data/lib/rails_connector/s3_blob.rb +0 -89
- data/lib/rails_connector/service_blob.rb +0 -48
- data/lib/rails_connector/service_cms_backend.rb +0 -194
- data/lib/rails_connector/version.rb +0 -38
- data/lib/rails_connector/workspace_data_from_database.rb +0 -19
@@ -1,109 +0,0 @@
|
|
1
|
-
module RailsConnector
|
2
|
-
|
3
|
-
class ObjDataFromDatabase < ObjData
|
4
|
-
|
5
|
-
def initialize(data, revision)
|
6
|
-
@rtc_ref = data["rtc_ref"]
|
7
|
-
@values = data["values"]
|
8
|
-
@ext_ref = data["ext_ref"]
|
9
|
-
@revision = revision
|
10
|
-
end
|
11
|
-
|
12
|
-
def value_and_type_of(attribute_name)
|
13
|
-
if internal_attribute?(attribute_name)
|
14
|
-
attribute_type = type_of_internal(attribute_name)
|
15
|
-
|
16
|
-
attribute_value = read_value(attribute_name)
|
17
|
-
if attribute_name == '_text_links'
|
18
|
-
attribute_value = attribute_value && attribute_value.values
|
19
|
-
elsif attribute_name == '_path'
|
20
|
-
attribute_value = PathConversion.path_from_list(attribute_value)
|
21
|
-
end
|
22
|
-
else
|
23
|
-
attribute_type = current_attribute_type(attribute_name)
|
24
|
-
if legacy_attribute_type(attribute_name) == attribute_type
|
25
|
-
attribute_value = read_value(attribute_name)
|
26
|
-
else
|
27
|
-
attribute_value = default_attribute_value(attribute_type)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
[attribute_value, attribute_type]
|
32
|
-
end
|
33
|
-
|
34
|
-
def has_custom_attribute?(name)
|
35
|
-
obj_class_attributes.include?(name)
|
36
|
-
end
|
37
|
-
|
38
|
-
def all_custom_attributes
|
39
|
-
obj_class_attributes
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
attr_reader :values, :rtc_ref, :revision
|
45
|
-
|
46
|
-
def current_attribute_type(name)
|
47
|
-
revision.attributes[name]["type"]
|
48
|
-
end
|
49
|
-
|
50
|
-
def obj_class_attributes
|
51
|
-
@obj_class_attributes ||=
|
52
|
-
begin
|
53
|
-
name = values["_obj_class"]
|
54
|
-
if data = revision.obj_classes[name]
|
55
|
-
Set.new(data["attributes"]) || Set.new
|
56
|
-
else
|
57
|
-
raise "Could not find ObjClass with name #{name} in Revision #{revision.id}!"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def read_value(attribute_name)
|
63
|
-
return values[attribute_name] if values.key?(attribute_name)
|
64
|
-
if @ext_ref && (attribute_name == "_text_links" || attribute_name[0] != ?_)
|
65
|
-
extend_values_with_dict_storage_values
|
66
|
-
end
|
67
|
-
values[attribute_name]
|
68
|
-
end
|
69
|
-
|
70
|
-
def extend_values_with_dict_storage_values
|
71
|
-
return unless @ext_ref
|
72
|
-
|
73
|
-
# may raise Kvom::Storage::NotFound
|
74
|
-
ext_values = DictStorage.get(@ext_ref)
|
75
|
-
values.reverse_merge!(ext_values)
|
76
|
-
@ext_ref = nil
|
77
|
-
end
|
78
|
-
|
79
|
-
SPECIAL_INTERNAL_ATTRIBUTES = Set.new(%w[title body blob])
|
80
|
-
|
81
|
-
def internal_attribute?(attribute_name)
|
82
|
-
?_ == attribute_name[0] || SPECIAL_INTERNAL_ATTRIBUTES.include?(attribute_name)
|
83
|
-
end
|
84
|
-
|
85
|
-
def legacy_attribute_type(name)
|
86
|
-
if attr_def = legacy_attributes[name]
|
87
|
-
attr_def["type"]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def legacy_attributes
|
92
|
-
@attributes ||=
|
93
|
-
begin
|
94
|
-
rtc = DictStorage.get(rtc_ref)
|
95
|
-
if rtc['obj_classes'] && rtc['attributes'] && oc = rtc['obj_classes'][values['_obj_class']]
|
96
|
-
rtc['attributes'].inject({}) do |attrs, (name, value)|
|
97
|
-
attrs[name] = value if oc['attributes'] && oc['attributes'].include?(name)
|
98
|
-
attrs
|
99
|
-
end
|
100
|
-
else
|
101
|
-
{}
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|
109
|
-
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module RailsConnector
|
2
|
-
|
3
|
-
module PathConversion
|
4
|
-
|
5
|
-
def self.path_from_list(components)
|
6
|
-
if components
|
7
|
-
"/#{components.join("/")}"
|
8
|
-
else
|
9
|
-
"/"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def path_from_list(components)
|
16
|
-
PathConversion.path_from_list(components)
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module RailsConnector
|
2
|
-
|
3
|
-
# The permissions assigned to an Obj.
|
4
|
-
class Permission < CmsBaseModel
|
5
|
-
# Returns the Array of the names of the user groups to which read permission has been granted.
|
6
|
-
def self.read
|
7
|
-
user_groups_for_permission_type(1)
|
8
|
-
end
|
9
|
-
|
10
|
-
# Returns the Array of the names of the user groups to which write permission has been granted
|
11
|
-
def self.write
|
12
|
-
user_groups_for_permission_type(2)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Returns the Array of the names of the user groups to which root permission has been granted
|
16
|
-
def self.root
|
17
|
-
user_groups_for_permission_type(3)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Returns the Array of the names of the user groups to which the children creation permission has been granted.
|
21
|
-
def self.create_children
|
22
|
-
user_groups_for_permission_type(4)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns the Array of the names of the user groups to which live read permission has been granted.
|
26
|
-
def self.live
|
27
|
-
user_groups_for_permission_type(5)
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def self.user_groups_for_permission_type(permission_type)
|
33
|
-
# Field name "user_login" is a legacy from CM tables.
|
34
|
-
# Actually the field contains the user group.
|
35
|
-
select(:user_login).where(:permission_type => permission_type).map(&:user_login)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
module RailsConnector
|
2
|
-
|
3
|
-
class Revision < CmsBaseModel
|
4
|
-
self.key_prefix = "rev"
|
5
|
-
|
6
|
-
property :generation
|
7
|
-
property :base_revision_id
|
8
|
-
property :title
|
9
|
-
property :content_cache_id
|
10
|
-
property :editable
|
11
|
-
|
12
|
-
def self.current=(revision_or_proc)
|
13
|
-
raise "Do not use Revision.current=, use Workspace.current= instead."
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.current
|
17
|
-
raise "Do not use Revision.current, use Workspace.current instead."
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.find_by_label(label_name)
|
21
|
-
workspace = Workspace.find(label_name)
|
22
|
-
find(workspace.revision_id)
|
23
|
-
end
|
24
|
-
|
25
|
-
def chain
|
26
|
-
@chain ||= Chain.build_for(self, content_cache)
|
27
|
-
end
|
28
|
-
|
29
|
-
def invalidate_chain
|
30
|
-
@chain = nil
|
31
|
-
end
|
32
|
-
|
33
|
-
# returns the base revision or nil for an initial revision
|
34
|
-
def base_revision
|
35
|
-
@base_revision ||= base_revision_id ? Revision.find(base_revision_id) : nil
|
36
|
-
end
|
37
|
-
|
38
|
-
# returns the content cache to be used with this revision or nil if not available
|
39
|
-
def content_cache
|
40
|
-
if content_cache_id
|
41
|
-
if @content_cache && content_cache_id == @content_cache.id
|
42
|
-
@content_cache
|
43
|
-
else
|
44
|
-
@content_cache = ContentCache.find_by_id(content_cache_id)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def inspect
|
50
|
-
"<#{self.class} id=\"#{id}\" title=\"#{title}\">"
|
51
|
-
end
|
52
|
-
|
53
|
-
def obj_classes
|
54
|
-
rtc['obj_classes']
|
55
|
-
end
|
56
|
-
|
57
|
-
def attributes
|
58
|
-
rtc['attributes']
|
59
|
-
end
|
60
|
-
|
61
|
-
def rtc_id
|
62
|
-
rtc_ref['id']
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def rtc
|
68
|
-
@rtc ||= DictStorage.get(rtc_ref)
|
69
|
-
end
|
70
|
-
|
71
|
-
def rtc_ref
|
72
|
-
read_attribute('rtc_ref')
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
module RailsConnector
|
2
|
-
|
3
|
-
class S3Blob
|
4
|
-
class << self
|
5
|
-
|
6
|
-
def s3_objects
|
7
|
-
@s3_objects ||= bucket.objects
|
8
|
-
end
|
9
|
-
|
10
|
-
def bucket_url
|
11
|
-
@cached_bucket_url ||= bucket.url
|
12
|
-
end
|
13
|
-
|
14
|
-
def configure(spec)
|
15
|
-
@spec = spec.symbolize_keys
|
16
|
-
|
17
|
-
# invalidate cache
|
18
|
-
@cached_bucket_url = nil
|
19
|
-
@s3_objects = nil
|
20
|
-
end
|
21
|
-
|
22
|
-
def find(id)
|
23
|
-
new(id)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
attr_reader :spec
|
29
|
-
|
30
|
-
def s3_api
|
31
|
-
AWS::S3.new(
|
32
|
-
:access_key_id => access_key_id,
|
33
|
-
:secret_access_key => secret_access_key
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
def bucket
|
38
|
-
s3_api.buckets[bucket_name]
|
39
|
-
end
|
40
|
-
|
41
|
-
def bucket_name
|
42
|
-
spec[:bucket_name]
|
43
|
-
end
|
44
|
-
|
45
|
-
def access_key_id
|
46
|
-
spec[:access_key_id]
|
47
|
-
end
|
48
|
-
|
49
|
-
def secret_access_key
|
50
|
-
spec[:secret_access_key]
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
attr_reader :id
|
56
|
-
|
57
|
-
def initialize(id)
|
58
|
-
@id = id
|
59
|
-
end
|
60
|
-
|
61
|
-
def s3_object
|
62
|
-
@s3_object ||= self.class.s3_objects[id]
|
63
|
-
end
|
64
|
-
|
65
|
-
def url
|
66
|
-
# the 'official' way to calculate an s3 url is as follows:
|
67
|
-
# s3_object.public_url.to_s
|
68
|
-
#
|
69
|
-
# this is about 25x faster:
|
70
|
-
# assumption: 'id' does not contain any characters that need escaping.
|
71
|
-
# the assumptions is valid for cms blobs.
|
72
|
-
"#{self.class.bucket_url}#{@id}"
|
73
|
-
end
|
74
|
-
|
75
|
-
def meta_url
|
76
|
-
url
|
77
|
-
end
|
78
|
-
|
79
|
-
def content_type
|
80
|
-
s3_object.content_type
|
81
|
-
end
|
82
|
-
|
83
|
-
def length
|
84
|
-
s3_object.content_length
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
end # module RailsConnector
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module RailsConnector
|
2
|
-
|
3
|
-
# TODO Caching:
|
4
|
-
# unlimited urls: ewig
|
5
|
-
# limited urls: zeitlimit - x (x fuer mindestverwendbarkeitszeit)
|
6
|
-
class ServiceBlob
|
7
|
-
|
8
|
-
class << self
|
9
|
-
|
10
|
-
def configure(config)
|
11
|
-
end
|
12
|
-
|
13
|
-
def find(id)
|
14
|
-
new(id)
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_reader :id
|
20
|
-
|
21
|
-
def initialize(id)
|
22
|
-
@id = id
|
23
|
-
end
|
24
|
-
|
25
|
-
def url
|
26
|
-
raw_data["url"]
|
27
|
-
end
|
28
|
-
|
29
|
-
def content_type
|
30
|
-
meta_data[:content_type]
|
31
|
-
end
|
32
|
-
|
33
|
-
def length
|
34
|
-
meta_data[:content_length].to_i
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def raw_data
|
40
|
-
@raw_data ||= CmsBackend.find_blob_data_by_id(id)
|
41
|
-
end
|
42
|
-
|
43
|
-
def meta_data
|
44
|
-
@meta_data ||= RestClient.head(raw_data["meta_url"]).headers
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
@@ -1,194 +0,0 @@
|
|
1
|
-
require 'rest_client'
|
2
|
-
|
3
|
-
module RailsConnector
|
4
|
-
|
5
|
-
class ContentServiceObjQueries
|
6
|
-
def initialize(queries)
|
7
|
-
@queries = queries
|
8
|
-
@open_queries = queries.dup
|
9
|
-
@results = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def open_queries
|
13
|
-
@open_queries[0..99]
|
14
|
-
end
|
15
|
-
|
16
|
-
def handle_response(response)
|
17
|
-
objs = {}
|
18
|
-
response["objs"].each do |obj|
|
19
|
-
objs[obj["_id"].first] = obj
|
20
|
-
end
|
21
|
-
|
22
|
-
queries_to_delete = []
|
23
|
-
response["results"].each_with_index do |response, i|
|
24
|
-
query = @open_queries[i]
|
25
|
-
if response["continuation_handle"]
|
26
|
-
query[:continuation_handle] = response["continuation_handle"]
|
27
|
-
else
|
28
|
-
queries_to_delete << i
|
29
|
-
end
|
30
|
-
result = (@results[query.__id__] ||= [])
|
31
|
-
response["refs"].each do |obj_ref|
|
32
|
-
id = obj_ref["id"]
|
33
|
-
# TODO fetch missing ObjData from Service
|
34
|
-
result << (objs[id] or raise "Data for Obj with id #{id} missing!")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
queries_to_delete.reverse_each {|i| @open_queries.delete_at(i) }
|
38
|
-
end
|
39
|
-
|
40
|
-
def results
|
41
|
-
@queries.map {|query| @results[query.__id__] || [] }
|
42
|
-
end
|
43
|
-
|
44
|
-
def finished?
|
45
|
-
open_queries.empty?
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# connects the cloud connector to the connector service
|
50
|
-
class ServiceCmsBackend < CmsBackend
|
51
|
-
BLOB_DATA_CACHE_PREFIX = 'blob_data'.freeze
|
52
|
-
VALID_INDEX_NAMES = %w[id path ppath permalink].freeze
|
53
|
-
|
54
|
-
def initialize
|
55
|
-
@query_counter = 0
|
56
|
-
end
|
57
|
-
|
58
|
-
def begin_caching
|
59
|
-
@caching = true
|
60
|
-
end
|
61
|
-
|
62
|
-
def end_caching
|
63
|
-
CmsCacheStorage.cache.clear
|
64
|
-
@caching = false
|
65
|
-
end
|
66
|
-
|
67
|
-
def caching?
|
68
|
-
!!@caching
|
69
|
-
end
|
70
|
-
|
71
|
-
def query_counter
|
72
|
-
@query_counter
|
73
|
-
end
|
74
|
-
|
75
|
-
def find_workspace_data_by_id(id)
|
76
|
-
from_content_state_id = ContentStateCaching.find_content_state_id(id)
|
77
|
-
request_params = {:workspace_id => id}
|
78
|
-
request_params[:content_state_id] = from_content_state_id if from_content_state_id
|
79
|
-
raw_data = ContentService.query('workspaces/query', request_params)
|
80
|
-
if raw_workspace_data = raw_data['workspace']
|
81
|
-
workspace_data = WorkspaceDataFromService.new(raw_workspace_data)
|
82
|
-
if from_content_state_id != workspace_data.content_state_id
|
83
|
-
ContentStateCaching.store_content_state(workspace_data)
|
84
|
-
ContentStateCaching.store_content_state_id(workspace_data.id,
|
85
|
-
workspace_data.content_state_id)
|
86
|
-
end
|
87
|
-
workspace_data
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def find_obj_data_by(workspace_data, index, keys)
|
92
|
-
index = index.to_s
|
93
|
-
assert_valid_index_name(index)
|
94
|
-
raw_data = find_raw_data_from_cache_or_database_by(workspace_data, index, keys)
|
95
|
-
raw_data.map do |raw_list|
|
96
|
-
raw_list.map do |raw_obj_data|
|
97
|
-
ObjDataFromService.new(raw_obj_data)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def find_blob_data_by_id(id)
|
103
|
-
cache_key = "#{BLOB_DATA_CACHE_PREFIX}/#{id}"
|
104
|
-
if data_from_cache = CmsCacheStorage.cache.read(cache_key)
|
105
|
-
data_from_cache
|
106
|
-
else
|
107
|
-
data_from_database = find_blob_data_from_database_by(id)
|
108
|
-
if maxage = data_from_database['maxage']
|
109
|
-
CmsCacheStorage.cache.write(cache_key, data_from_database, :expires_in => maxage)
|
110
|
-
end
|
111
|
-
data_from_database
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
private
|
116
|
-
|
117
|
-
def find_raw_data_from_cache_or_database_by(workspace_data, index, keys)
|
118
|
-
keys_from_database = []
|
119
|
-
# load results from cache
|
120
|
-
results_from_cache = keys.map do |key|
|
121
|
-
find_raw_data_from_cache_by(workspace_data, index, key).tap do |objs|
|
122
|
-
keys_from_database << key unless objs
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# load cache misses from database and store them in cache
|
127
|
-
results_from_database =
|
128
|
-
find_raw_data_from_database_by(workspace_data, index, keys_from_database)
|
129
|
-
keys_from_database.each_with_index do |key, key_number|
|
130
|
-
store_raw_data_list_in_cache(workspace_data, index, key, results_from_database[key_number])
|
131
|
-
end
|
132
|
-
|
133
|
-
# combine the results
|
134
|
-
results_from_cache.map do |objs_from_cache|
|
135
|
-
objs_from_cache || results_from_database.shift
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def find_raw_data_from_cache_by(workspace_data, index, key)
|
140
|
-
ContentStateCaching.find_obj_data(workspace_data, index, key) if caching?
|
141
|
-
end
|
142
|
-
|
143
|
-
def find_raw_data_from_database_by(workspace_data, index, keys)
|
144
|
-
return [] if keys.blank?
|
145
|
-
instrumenter = ActiveSupport::Notifications.instrumenter
|
146
|
-
instrumenter.instrument(
|
147
|
-
"cms_load.rails_connector", :name => "Obj Load", :index => index, :keys => keys
|
148
|
-
) do
|
149
|
-
@query_counter += 1
|
150
|
-
queries = ContentServiceObjQueries.new(keys.map {|key| {:type => index, :param => key} })
|
151
|
-
until queries.finished?
|
152
|
-
queries.handle_response(ContentService.query(
|
153
|
-
"objs/query",
|
154
|
-
:queries => queries.open_queries,
|
155
|
-
:workspace_id => workspace_data.id,
|
156
|
-
:revision_id => workspace_data.revision_id
|
157
|
-
))
|
158
|
-
end
|
159
|
-
queries.results
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
UNIQUE_INDICES = [:id, :path, :permalink].freeze
|
164
|
-
|
165
|
-
def store_raw_data_list_in_cache(workspace_data, index, key, raw_data_list)
|
166
|
-
raw_data_list.each do |values|
|
167
|
-
UNIQUE_INDICES.each do |unique_index|
|
168
|
-
unique_index_values = values["_#{unique_index}"]
|
169
|
-
if unique_index_values.present?
|
170
|
-
store_item_in_cache(workspace_data, unique_index, unique_index_values.first, [values])
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
unless UNIQUE_INDICES.include?(index)
|
175
|
-
store_item_in_cache(workspace_data, index, key, raw_data_list)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def store_item_in_cache(workspace_data, index, key, item)
|
180
|
-
ContentStateCaching.store_obj_data(workspace_data, index, key, item)
|
181
|
-
end
|
182
|
-
|
183
|
-
def find_blob_data_from_database_by(id)
|
184
|
-
@query_counter += 1
|
185
|
-
ContentService.query('blobs/query', :blob_ids => [id])['blobs'][id]
|
186
|
-
end
|
187
|
-
|
188
|
-
def assert_valid_index_name(index)
|
189
|
-
raise ArgumentError, "invalid index name '#{index}'" unless VALID_INDEX_NAMES.include?(index)
|
190
|
-
end
|
191
|
-
|
192
|
-
end
|
193
|
-
|
194
|
-
end
|