documentrix 0.0.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 +7 -0
- data/.yardopts +1 -0
- data/Gemfile +5 -0
- data/README.md +71 -0
- data/Rakefile +48 -0
- data/documentrix.gemspec +41 -0
- data/lib/documentrix/documents/cache/common.rb +43 -0
- data/lib/documentrix/documents/cache/memory_cache.rb +91 -0
- data/lib/documentrix/documents/cache/records.rb +145 -0
- data/lib/documentrix/documents/cache/redis_backed_memory_cache.rb +64 -0
- data/lib/documentrix/documents/cache/redis_cache.rb +128 -0
- data/lib/documentrix/documents/cache/sqlite_cache.rb +335 -0
- data/lib/documentrix/documents/splitters/character.rb +72 -0
- data/lib/documentrix/documents/splitters/semantic.rb +91 -0
- data/lib/documentrix/documents.rb +328 -0
- data/lib/documentrix/utils/colorize_texts.rb +65 -0
- data/lib/documentrix/utils/math.rb +48 -0
- data/lib/documentrix/utils/tags.rb +112 -0
- data/lib/documentrix/utils.rb +5 -0
- data/lib/documentrix/version.rb +8 -0
- data/lib/documentrix.rb +11 -0
- data/spec/assets/embeddings.json +1 -0
- data/spec/documentrix/documents/cache/memory_cache_spec.rb +98 -0
- data/spec/documentrix/documents/cache/redis_backed_memory_cache_spec.rb +121 -0
- data/spec/documentrix/documents/cache/redis_cache_spec.rb +123 -0
- data/spec/documentrix/documents/cache/sqlite_cache_spec.rb +141 -0
- data/spec/documentrix/documents/splitters/character_spec.rb +110 -0
- data/spec/documentrix/documents/splitters/semantic_spec.rb +56 -0
- data/spec/documents_spec.rb +174 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/utils/colorize_texts_spec.rb +13 -0
- data/spec/utils/tags_spec.rb +53 -0
- metadata +329 -0
@@ -0,0 +1,328 @@
|
|
1
|
+
require 'numo/narray'
|
2
|
+
require 'digest'
|
3
|
+
require 'kramdown/ansi'
|
4
|
+
|
5
|
+
class Documentrix::Documents
|
6
|
+
end
|
7
|
+
module Documentrix::Documents::Cache
|
8
|
+
end
|
9
|
+
require 'documentrix/documents/cache/records'
|
10
|
+
require 'documentrix/documents/cache/memory_cache'
|
11
|
+
require 'documentrix/documents/cache/redis_cache'
|
12
|
+
require 'documentrix/documents/cache/redis_backed_memory_cache'
|
13
|
+
require 'documentrix/documents/cache/sqlite_cache'
|
14
|
+
module Documentrix::Documents::Splitters
|
15
|
+
end
|
16
|
+
require 'documentrix/documents/splitters/character'
|
17
|
+
require 'documentrix/documents/splitters/semantic'
|
18
|
+
|
19
|
+
class Documentrix::Documents
|
20
|
+
include Kramdown::ANSI::Width
|
21
|
+
include Documentrix::Documents::Cache
|
22
|
+
|
23
|
+
Record = Class.new Documentrix::Documents::Cache::Records::Record
|
24
|
+
|
25
|
+
# The initialize method sets up the Documentrix::Documents instance by
|
26
|
+
# configuring its components.
|
27
|
+
#
|
28
|
+
# @param ollama [ Ollama::Client ] the client used for embedding
|
29
|
+
# @param model [ String ] the name of the model to use for embeddings
|
30
|
+
# @param model_options [ Hash ] optional parameters for the model
|
31
|
+
# @param collection [ Symbol ] the default collection to use (defaults to :default)
|
32
|
+
# @param embedding_length [ Integer ] the length of the embeddings (defaults to 1024)
|
33
|
+
# @param cache [ Documentrix::Cache ] the cache to use for storing documents (defaults to MemoryCache)
|
34
|
+
# @param database_filename [ String ] the filename of the SQLite database to use (defaults to ':memory:')
|
35
|
+
# @param redis_url [ String ] the URL of the Redis server to use (defaults to nil)
|
36
|
+
# @param debug [ FalseClass, TrueClass ] whether to enable debugging mode (defaults to false)
|
37
|
+
def initialize(ollama:, model:, model_options: nil, collection: nil, embedding_length: 1_024, cache: MemoryCache, database_filename: nil, redis_url: nil, debug: false)
|
38
|
+
collection ||= default_collection
|
39
|
+
@ollama, @model, @model_options, @collection, @debug =
|
40
|
+
ollama, model, model_options, collection.to_sym, debug
|
41
|
+
database_filename ||= ':memory:'
|
42
|
+
@cache = connect_cache(cache, redis_url, embedding_length, database_filename)
|
43
|
+
end
|
44
|
+
|
45
|
+
# The default_collection method returns the default collection name.
|
46
|
+
#
|
47
|
+
# @return [:default] The default collection name.
|
48
|
+
def default_collection
|
49
|
+
:default
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_reader :ollama, :model, :collection, :cache
|
53
|
+
|
54
|
+
# The collection= method sets the new collection for this documents instance.
|
55
|
+
#
|
56
|
+
# @param new_collection [ Symbol ] the name of the new collection
|
57
|
+
def collection=(new_collection)
|
58
|
+
@collection = new_collection.to_sym
|
59
|
+
@cache.prefix = prefix
|
60
|
+
end
|
61
|
+
|
62
|
+
# The prepare_texts method filters out existing texts from the input array
|
63
|
+
# and returns the filtered array.
|
64
|
+
#
|
65
|
+
# @param texts [ Array ] an array of text strings or #read objects.
|
66
|
+
#
|
67
|
+
# @return [ Array ] the filtered array of text strings
|
68
|
+
private def prepare_texts(texts)
|
69
|
+
texts = Array(texts).map! { |i| i.respond_to?(:read) ? i.read : i.to_s }
|
70
|
+
texts.reject! { |i| exist?(i) }
|
71
|
+
texts.empty? and return
|
72
|
+
if @debug
|
73
|
+
puts Documentrix::Utils::ColorizeTexts.new(texts)
|
74
|
+
end
|
75
|
+
texts
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# The method adds new texts `texts` to the documents collection by
|
80
|
+
# processing them through various stages. It first filters out existing texts
|
81
|
+
# from the input array using the `prepare_texts` method, then fetches
|
82
|
+
# embeddings for each text using the specified model and options. The fetched
|
83
|
+
# embeddings are used to create a new record in the cache, which is
|
84
|
+
# associated with the original text and tags (if any). The method processes
|
85
|
+
# the texts in batches of size , displaying progress information
|
86
|
+
# in the console. It also accepts an optional string to associate
|
87
|
+
# with the added texts and an array of to attach to each record. Once
|
88
|
+
# all texts have been processed, it returns the `Documentrix::Documents`
|
89
|
+
# instance itself, allowing for method chaining.
|
90
|
+
#
|
91
|
+
# @param texts [Array] an array of input texts
|
92
|
+
# @param batch_size [Integer] the number of texts to process in one batch
|
93
|
+
# @param source [String] the source URL for the added texts
|
94
|
+
# @param tags [Array] an array of tags associated with the added texts
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# documents.add(%w[ foo bar ], batch_size: 23, source: 'https://example.com', tags: %w[tag1 tag2])
|
98
|
+
#
|
99
|
+
# @return [Documentrix::Documents] self
|
100
|
+
def add(texts, batch_size: nil, source: nil, tags: [])
|
101
|
+
texts = prepare_texts(texts) or return self
|
102
|
+
tags = Documentrix::Utils::Tags.new(tags, source:)
|
103
|
+
if source
|
104
|
+
tags.add(File.basename(source).gsub(/\?.*/, ''), source:)
|
105
|
+
end
|
106
|
+
batches = texts.each_slice(batch_size || 10).
|
107
|
+
with_infobar(
|
108
|
+
label: "Add #{truncate(tags.to_s(link: false), percentage: 25)}",
|
109
|
+
total: texts.size
|
110
|
+
)
|
111
|
+
batches.each do |batch|
|
112
|
+
embeddings = fetch_embeddings(model:, options: @model_options, input: batch)
|
113
|
+
batch.zip(embeddings) do |text, embedding|
|
114
|
+
norm = @cache.norm(embedding)
|
115
|
+
self[text] = Record[text:, embedding:, norm:, source:, tags: tags.to_a]
|
116
|
+
end
|
117
|
+
infobar.progress by: batch.size
|
118
|
+
end
|
119
|
+
infobar.newline
|
120
|
+
self
|
121
|
+
end
|
122
|
+
alias << add
|
123
|
+
|
124
|
+
# The [] method retrieves the value associated with the given text from the
|
125
|
+
# cache.
|
126
|
+
#
|
127
|
+
# @param text [String] the text for which to retrieve the cached value
|
128
|
+
#
|
129
|
+
# @return [Object] the cached value, or nil if not found
|
130
|
+
def [](text)
|
131
|
+
@cache[key(text)]
|
132
|
+
end
|
133
|
+
|
134
|
+
# The []= method sets the value for a given text in the cache.
|
135
|
+
#
|
136
|
+
# @param text [ String ] the text to set
|
137
|
+
# @param record [ Hash ] the value to store
|
138
|
+
def []=(text, record)
|
139
|
+
@cache[key(text)] = record
|
140
|
+
end
|
141
|
+
|
142
|
+
# The exist? method checks if the given text exists in the cache.
|
143
|
+
#
|
144
|
+
# @param text [ String ] the text to check for existence
|
145
|
+
#
|
146
|
+
# @return [ FalseClass, TrueClass ] true if the text exists, false otherwise.
|
147
|
+
def exist?(text)
|
148
|
+
@cache.key?(key(text))
|
149
|
+
end
|
150
|
+
|
151
|
+
# The delete method removes the specified text from the cache by calling the
|
152
|
+
# delete method on the underlying cache object.
|
153
|
+
#
|
154
|
+
# @param text [ String ] the text for which to remove the value
|
155
|
+
#
|
156
|
+
# @return [ FalseClass, TrueClass ] true if the text was removed, false
|
157
|
+
# otherwise.
|
158
|
+
def delete(text)
|
159
|
+
@cache.delete(key(text))
|
160
|
+
end
|
161
|
+
|
162
|
+
# The size method returns the number of texts stored in the cache of this
|
163
|
+
# Documentrix::Documents instance.
|
164
|
+
#
|
165
|
+
# @return [ Integer ] The total count of cached texts.
|
166
|
+
def size
|
167
|
+
@cache.size
|
168
|
+
end
|
169
|
+
|
170
|
+
# The clear method clears all texts from the cache or tags was given the ones
|
171
|
+
# tagged with the .
|
172
|
+
#
|
173
|
+
# @param tags [ NilClass, Array<String> ] the tag name to filter by
|
174
|
+
#
|
175
|
+
# @return [ Documentrix::Documents ] self
|
176
|
+
def clear(tags: nil)
|
177
|
+
@cache.clear(tags:)
|
178
|
+
self
|
179
|
+
end
|
180
|
+
|
181
|
+
# The find method searches for strings within the cache by computing their
|
182
|
+
# similarity scores.
|
183
|
+
#
|
184
|
+
# @param string [String] the input string
|
185
|
+
# @param tags [Array<String>] an array of tags to filter results by (optional)
|
186
|
+
# @param prompt [String] a prompt to use when searching for similar strings (optional)
|
187
|
+
# @param max_records [Integer] the maximum number of records to return (optional)
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# documents.find("foo")
|
191
|
+
#
|
192
|
+
# @return [Array<Documentrix::Documents::Record>]
|
193
|
+
def find(string, tags: nil, prompt: nil, max_records: nil)
|
194
|
+
needle = convert_to_vector(string, prompt:)
|
195
|
+
@cache.find_records(needle, tags:, max_records: nil)
|
196
|
+
end
|
197
|
+
|
198
|
+
# The method filters the records returned by find based on text
|
199
|
+
# size and count.
|
200
|
+
#
|
201
|
+
# @param string [String] the search query
|
202
|
+
# @param text_size [Integer] the maximum allowed text size to return
|
203
|
+
# @param text_count [Integer] the maximum number of texts to return
|
204
|
+
#
|
205
|
+
# @example
|
206
|
+
# documents.find_where('foo', text_size: 3, text_count: 1)
|
207
|
+
# @return [Array<Documentrix::Documents::Record>] the filtered records
|
208
|
+
def find_where(string, text_size: nil, text_count: nil, **opts)
|
209
|
+
if text_count
|
210
|
+
opts[:max_records] = text_count
|
211
|
+
end
|
212
|
+
records = find(string, **opts)
|
213
|
+
size, count = 0, 0
|
214
|
+
records.take_while do |record|
|
215
|
+
if text_size and (size += record.text.size) > text_size
|
216
|
+
next false
|
217
|
+
end
|
218
|
+
if text_count and (count += 1) > text_count
|
219
|
+
next false
|
220
|
+
end
|
221
|
+
true
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# The collections method returns an array of unique collection names
|
226
|
+
#
|
227
|
+
# @return [Array] An array of unique collection names
|
228
|
+
def collections
|
229
|
+
([ default_collection ] + @cache.collections('%s-' % class_prefix)).uniq
|
230
|
+
end
|
231
|
+
|
232
|
+
# The tags method returns an array of unique tags from the cache.
|
233
|
+
#
|
234
|
+
# @return [Documentrix::Utils::Tags] A set of unique tags
|
235
|
+
def tags
|
236
|
+
@cache.tags
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
# The connect_cache method initializes and returns an instance of the
|
242
|
+
# specified cache class.
|
243
|
+
#
|
244
|
+
# @param cache_class [Class] the class of the cache to be instantiated
|
245
|
+
# @param redis_url [String] the URL of the Redis server
|
246
|
+
# @param embedding_length [Integer] the length of the embeddings used in the cache
|
247
|
+
# @param database_filename [String] the filename of the SQLite database file
|
248
|
+
#
|
249
|
+
# @return [CacheInstance] an instance of the specified cache class
|
250
|
+
def connect_cache(cache_class, redis_url, embedding_length, database_filename)
|
251
|
+
cache = nil
|
252
|
+
if (cache_class.instance_method(:redis) rescue nil)
|
253
|
+
begin
|
254
|
+
cache = cache_class.new(prefix:, url: redis_url, object_class: Record)
|
255
|
+
cache.size
|
256
|
+
rescue Redis::CannotConnectError
|
257
|
+
STDERR.puts(
|
258
|
+
"Cannot connect to redis URL #{redis_url.inspect}, "\
|
259
|
+
"falling back to MemoryCache."
|
260
|
+
)
|
261
|
+
end
|
262
|
+
elsif cache_class == SQLiteCache
|
263
|
+
cache = cache_class.new(
|
264
|
+
prefix:,
|
265
|
+
embedding_length:,
|
266
|
+
filename: database_filename,
|
267
|
+
debug: @debug
|
268
|
+
)
|
269
|
+
end
|
270
|
+
ensure
|
271
|
+
cache ||= MemoryCache.new(prefix:,)
|
272
|
+
cache.respond_to?(:find_records) or cache.extend(Records::FindRecords)
|
273
|
+
cache.extend(Records::Tags)
|
274
|
+
if cache.respond_to?(:redis)
|
275
|
+
cache.extend(Records::RedisFullEach)
|
276
|
+
end
|
277
|
+
return cache
|
278
|
+
end
|
279
|
+
|
280
|
+
# The convert_to_vector method converts the input into a vector by fetching
|
281
|
+
# embeddings from the model and then converting it using the cache's
|
282
|
+
# convert_to_vector method.
|
283
|
+
#
|
284
|
+
# @param input [String] the string to be converted
|
285
|
+
# @param prompt [String, nil] an optional prompt to be used in the conversion process
|
286
|
+
#
|
287
|
+
# @return [Array] the converted vector
|
288
|
+
def convert_to_vector(input, prompt: nil)
|
289
|
+
if prompt
|
290
|
+
input = prompt % input
|
291
|
+
end
|
292
|
+
input.is_a?(String) and input = fetch_embeddings(model:, input:).first
|
293
|
+
@cache.convert_to_vector(input)
|
294
|
+
end
|
295
|
+
|
296
|
+
# The fetch_embeddings method retrieves the embeddings for a given input
|
297
|
+
# using the specified model and options.
|
298
|
+
#
|
299
|
+
# @param model [ String ] the name of the model used for embedding
|
300
|
+
# @param input [ Array<String> ] the text(s) to be embedded
|
301
|
+
# @param options [ Hash ] optional parameters for the embedding process
|
302
|
+
#
|
303
|
+
# @return [ Array<Array<Float>> ] an array containing the embeddings for each input string
|
304
|
+
def fetch_embeddings(model:, input:, options: nil)
|
305
|
+
@ollama.embed(model:, input:, options:).embeddings
|
306
|
+
end
|
307
|
+
|
308
|
+
def class_prefix
|
309
|
+
'Documents'
|
310
|
+
end
|
311
|
+
|
312
|
+
# The prefix method returns a string that is used as the prefix for keys in
|
313
|
+
# the cache of the currently configured collection.
|
314
|
+
#
|
315
|
+
# @return [ String ] The prefix string
|
316
|
+
def prefix
|
317
|
+
'%s-%s-' % [ class_prefix, @collection ]
|
318
|
+
end
|
319
|
+
|
320
|
+
# The key method generates a SHA256 hash for the given input string.
|
321
|
+
#
|
322
|
+
# @param input [String] the input string to be hashed
|
323
|
+
#
|
324
|
+
# @return [String] the SHA256 hash of the input string
|
325
|
+
def key(input)
|
326
|
+
Digest::SHA256.hexdigest(input)
|
327
|
+
end
|
328
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
require 'kramdown/ansi'
|
3
|
+
|
4
|
+
class Documentrix::Utils::ColorizeTexts
|
5
|
+
include Math
|
6
|
+
include Term::ANSIColor
|
7
|
+
include Kramdown::ANSI::Width
|
8
|
+
|
9
|
+
# Initializes a new instance of Documentrix::::ColorizeTexts
|
10
|
+
#
|
11
|
+
# @param [Array<String>] texts the array of strings to be displayed with colors
|
12
|
+
#
|
13
|
+
# @return [Documentrix::::ColorizeTexts] an instance of Documentrix::::ColorizeTexts
|
14
|
+
def initialize(*texts)
|
15
|
+
texts = texts.map(&:to_a)
|
16
|
+
@texts = Array(texts.flatten)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a string representation of the object, including all texts content,
|
20
|
+
# colored differently and their sizes.
|
21
|
+
#
|
22
|
+
# @return [String] The formatted string.
|
23
|
+
def to_s
|
24
|
+
result = +''
|
25
|
+
@texts.each_with_index do |t, i|
|
26
|
+
color = colors[(t.hash ^ i.hash) % colors.size]
|
27
|
+
wrap(t, percentage: 90).each_line { |l|
|
28
|
+
result << on_color(color) { color(text_color(color)) { l } }
|
29
|
+
}
|
30
|
+
result << "\n##{bold{t.size.to_s}} \n\n"
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Returns the nearest RGB color to the given ANSI color
|
38
|
+
#
|
39
|
+
# @param [color] color The ANSI color attribute
|
40
|
+
#
|
41
|
+
# @return [Array<RGBTriple>] An array containing two RGB colors, one for black and
|
42
|
+
# one for white text, where the first is the closest match to the input color
|
43
|
+
# when printed on a black background, and the second is the closest match
|
44
|
+
# when printed on a white background.
|
45
|
+
def text_color(color)
|
46
|
+
color = Term::ANSIColor::Attribute[color]
|
47
|
+
[
|
48
|
+
Attribute.nearest_rgb_color('#000'),
|
49
|
+
Attribute.nearest_rgb_color('#fff'),
|
50
|
+
].max_by { |t| t.distance_to(color) }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns an array of colors for each step in the gradient
|
54
|
+
#
|
55
|
+
# @return [Array<Array<Integer>>] An array of RGB color arrays
|
56
|
+
def colors
|
57
|
+
@colors ||= (0..255).map { |i|
|
58
|
+
[
|
59
|
+
128 + 128 * sin(PI * i / 32.0),
|
60
|
+
128 + 128 * sin(PI * i / 64.0),
|
61
|
+
128 + 128 * sin(PI * i / 128.0),
|
62
|
+
].map { _1.clamp(0, 255).round }
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Documentrix::Utils::Math
|
2
|
+
# Returns the cosine similarity between two vectors `a` and `b`, 1.0 is
|
3
|
+
# exactly the same, 0.0 means decorrelated.
|
4
|
+
#
|
5
|
+
# @param [Vector] a The first vector
|
6
|
+
# @param [Vector] b The second vector
|
7
|
+
# @option a_norm [Float] a The Euclidean norm of vector a (default: calculated from a)
|
8
|
+
# @option b_norm [Float] b The Euclidean norm of vector b (default: calculated from b)
|
9
|
+
#
|
10
|
+
# @return [Float] The cosine similarity between the two vectors
|
11
|
+
#
|
12
|
+
# @example Calculate the cosine similarity between two vectors
|
13
|
+
# cosine_similarity(a: [1, 2], b: [3, 4])
|
14
|
+
#
|
15
|
+
# @see #convert_to_vector
|
16
|
+
# @see #norm
|
17
|
+
def cosine_similarity(a:, b:, a_norm: norm(a), b_norm: norm(b))
|
18
|
+
a, b = convert_to_vector(a), convert_to_vector(b)
|
19
|
+
a.dot(b) / (a_norm * b_norm)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the Euclidean norm (magnitude) of a vector.
|
23
|
+
#
|
24
|
+
# @param vector [Array] The input vector.
|
25
|
+
#
|
26
|
+
# @return [Float] The magnitude of the vector.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# norm([3, 4]) # => 5.0
|
30
|
+
def norm(vector)
|
31
|
+
s = 0.0
|
32
|
+
vector.each { s += _1.abs2 }
|
33
|
+
Math.sqrt(s)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Converts an array to a Numo NArray.
|
37
|
+
#
|
38
|
+
# @param [Array] vector The input array to be converted.
|
39
|
+
#
|
40
|
+
# @return [Numo::NArray] The converted NArray, or the original if it's already a Numo NArray.
|
41
|
+
#
|
42
|
+
# @example Convert an array to a Numo NArray
|
43
|
+
# convert_to_vector([1, 2, 3]) # => Numo::NArray[1, 2, 3]
|
44
|
+
def convert_to_vector(vector)
|
45
|
+
vector.is_a?(Numo::NArray) and return vector
|
46
|
+
Numo::NArray[*vector]
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
class Documentrix::Utils::Tags
|
4
|
+
class Tag < String
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
# The initialize method sets up the Tag object by calling its superclass's
|
8
|
+
# constructor and setting the source attribute.
|
9
|
+
#
|
10
|
+
# @param tag [String] the string representation of the tag
|
11
|
+
# @param source [String, nil] the source URL for the tag (default: nil)
|
12
|
+
def initialize(tag, source: nil)
|
13
|
+
super(tag.to_s.gsub(/\A#+/, ''))
|
14
|
+
self.source = source
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :source # the source URL for the tag
|
18
|
+
|
19
|
+
# The to_s method formats the tag string for output, including source URL
|
20
|
+
# if requested.
|
21
|
+
#
|
22
|
+
# @param link [FalseClass, TrueClass] whether to include source URL (default: true)
|
23
|
+
#
|
24
|
+
# @return [String] the formatted tag string
|
25
|
+
def to_s(link: true)
|
26
|
+
tag_string = start_with?(?#) ? super() : ?# + super()
|
27
|
+
my_source = source
|
28
|
+
if link && my_source
|
29
|
+
unless my_source =~ %r(\A(https?|file)://)
|
30
|
+
my_source = 'file://%s' % File.expand_path(my_source)
|
31
|
+
end
|
32
|
+
hyperlink(my_source) { tag_string }
|
33
|
+
else
|
34
|
+
tag_string
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# The initialize method sets up the Documentrix::Utils::Tags object by
|
40
|
+
# processing an array of tags and adding them to the internal set.
|
41
|
+
#
|
42
|
+
# @param tags [Array<String>] the input array of strings representing tags
|
43
|
+
# @param source [String, nil] the optional source URL for the tags (default: nil)
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# Documentrix::Utils::Tags.new(%w[ foo bar ])
|
47
|
+
#
|
48
|
+
# @return [Documentrix::Utils::Tags] an instance of Documentrix::Utils::Tags
|
49
|
+
def initialize(tags = [], source: nil)
|
50
|
+
tags = Array(tags)
|
51
|
+
@set = []
|
52
|
+
tags.each { |tag| add(tag, source:) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def add(tag, source: nil)
|
56
|
+
unless tag.is_a?(Tag)
|
57
|
+
tag = Tag.new(tag, source:)
|
58
|
+
end
|
59
|
+
index = @set.bsearch_index { _1 >= tag }
|
60
|
+
if index == nil
|
61
|
+
@set.push(tag)
|
62
|
+
elsif @set.at(index) != tag
|
63
|
+
@set.insert(index, tag)
|
64
|
+
end
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# The empty? method checks if the Tags instance's set is empty.
|
69
|
+
#
|
70
|
+
# @return [TrueClass] true if the set is empty, false otherwise
|
71
|
+
def empty?
|
72
|
+
@set.empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
# The size method returns the number of elements in the set.
|
76
|
+
#
|
77
|
+
# @return [Integer] The size of the set.
|
78
|
+
def size
|
79
|
+
@set.size
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# The clear method resets the Documentrix::Utils::Tags instance's set by
|
84
|
+
# calling its clear method.
|
85
|
+
#
|
86
|
+
# @return [Documentrix::Utils::Tags] self
|
87
|
+
def clear
|
88
|
+
@set.clear
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# The each method iterates over this Tags instance's set and yields each tags
|
93
|
+
# to the given block.
|
94
|
+
#
|
95
|
+
# @yield [element] Each tag in the set
|
96
|
+
#
|
97
|
+
# @return [Documentrix::Utils::Tags] self
|
98
|
+
def each(&block)
|
99
|
+
@set.each(&block)
|
100
|
+
self
|
101
|
+
end
|
102
|
+
include Enumerable
|
103
|
+
|
104
|
+
# The to_s method formats the tags string for output, including source URL if requested.
|
105
|
+
#
|
106
|
+
# @param link [FalseClass, TrueClass] whether to include source URL (default: true)
|
107
|
+
#
|
108
|
+
# @return [Array<String>] the array of formatted tags strings
|
109
|
+
def to_s(link: true)
|
110
|
+
@set.map { |tag| tag.to_s(link:) } * ' '
|
111
|
+
end
|
112
|
+
end
|
data/lib/documentrix.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
[[-0.009,-0.0,-0.035,-0.002,-0.044,-0.063,0.1,0.03,0.052,-0.06,-0.027,0.012,0.03,-0.04,-0.013,0.023,-0.028,0.015,-0.066,-0.032,0.052,0.028,0.063,0.037,-0.005,-0.024,0.006,0.008,0.014,-0.007,-0.042,-0.018,0.012,-0.061,-0.03,0.004,-0.019,0.003,0.065,0.058,0.004,-0.032,0.023,-0.016,0.03,-0.009,-0.022,-0.026,0.057,-0.013,0.002,0.004,-0.059,-0.047,0.084,0.085,0.048,-0.008,0.11,0.041,-0.018,0.071,-0.022,-0.067,0.015,-0.031,0.037,-0.034,0.032,0.121,0.063,0.003,-0.016,-0.007,0.011,0.093,0.056,-0.054,0.028,0.014,-0.008,-0.102,-0.072,-0.042,0.025,0.005,-0.005,-0.083,-0.008,0.018,-0.076,0.07,0.03,0.003,-0.029,0.021,0.016,0.036,-0.101,0.194,-0.01,-0.014,0.07,-0.004,0.001,-0.087,0.001,-0.0,0.02,0.0,-0.061,-0.108,-0.039,0.068,-0.015,0.033,0.008,0.044,0.016,-0.017,-0.034,-0.018,0.023,-0.018,-0.031,-0.068,0.021,0.0,-0.006,0.032,-0.019,0.019,-0.004,0.063,-0.018,-0.057,0.021,-0.054,-0.047,0.035,-0.113,-0.005,0.065,0.033,-0.018,0.055,-0.033,0.01,-0.095,0.008,0.008,0.053,-0.03,-0.036,0.068,-0.128,-0.011,0.034,-0.022,0.01,-0.012,0.033,-0.016,0.127,0.081,-0.028,-0.07,0.004,-0.067,0.063,-0.056,0.025,-0.014,0.094,-0.012,-0.016,0.065,0.045,0.082,0.001,-0.023,0.014,-0.04,-0.002,0.024,0.001,0.03,0.051,-0.017,-0.071,0.108,-0.028,0.004,-0.048,-0.026,0.041,-0.038,0.05,0.002,-0.027,-0.005,0.019,-0.045,-0.077,-0.16,0.021,0.05,-0.068,0.069,-0.045,0.041,-0.091,-0.024,0.025,-0.052,-0.046,0.066,-0.114,-0.002,0.004,0.063,-0.056,-0.004,0.0,0.071,0.08,0.022,-0.087,-0.02,-0.078,0.002,0.081,-0.038,-0.001,-0.072,0.003,0.014,0.005,0.022,-0.008,0.094,0.011,0.068,-0.013,-0.015,-0.046,0.055,0.013,-0.004,-0.001,-0.015,0.01,-0.014,0.013,-0.036,-0.007,-0.07,-0.061,-0.08,0.018,0.005,-0.001,-0.017,0.027,0.031,-0.023,0.001,0.167,-0.007,-0.031,0.035,0.032,-0.009,0.122,-0.037,-0.032,-0.011,0.018,-0.042,0.051,-0.002,-0.081,0.06,-0.009,0.061,0.065,-0.037,0.076,0.05,0.083,-0.026,0.034,-0.097,-0.016,0.116,0.026,-0.173,0.011,0.051,-0.055,0.013,0.045,-0.017,-0.121,-0.071,-0.025,0.075,-0.031,0.047,0.062,0.05,0.101,-0.036,-0.018,0.051,-0.072,0.004,-0.023,0.019,0.0,-0.024,0.073,0.018,-0.063,0.079,0.012,-0.076,-0.006,-0.009,0.002,-0.025,0.063,-0.011,0.104,0.004,0.025,0.009,-0.071,-0.032,-0.051,-0.096,-0.072,-0.116,-0.06,-0.035,-0.021,0.016,0.045,0.014,0.036,-0.03,0.009,-0.091,-0.045,0.02,-0.105,-0.006,0.046,-0.028,-0.116,-0.078,-0.013,0.019,0.004,-0.05,0.023,0.046,-0.03,-0.021,0.001,0.022,0.02,-0.015,0.059,0.132,0.022,-0.01,-0.003,-0.002,0.021,0.052,-0.023,0.017,0.009],[-0.009,-0.0,-0.035,-0.002,-0.044,-0.063,0.1,0.03,0.052,-0.06,-0.027,0.012,0.03,-0.04,-0.013,0.023,-0.028,0.015,-0.066,-0.032,0.052,0.028,0.063,0.037,-0.005,-0.024,0.006,0.008,0.014,-0.007,-0.042,-0.018,0.012,-0.061,-0.03,0.004,-0.019,0.003,0.065,0.058,0.004,-0.032,0.023,-0.016,0.03,-0.009,-0.022,-0.026,0.057,-0.013,0.002,0.004,-0.059,-0.047,0.084,0.085,0.048,-0.008,0.11,0.041,-0.018,0.071,-0.022,-0.067,0.015,-0.031,0.037,-0.034,0.032,0.121,0.063,0.003,-0.016,-0.007,0.011,0.093,0.056,-0.054,0.028,0.014,-0.008,-0.102,-0.072,-0.042,0.025,0.005,-0.005,-0.083,-0.008,0.018,-0.076,0.07,0.03,0.003,-0.029,0.021,0.016,0.036,-0.101,0.194,-0.01,-0.014,0.07,-0.004,0.001,-0.087,0.001,-0.0,0.02,0.0,-0.061,-0.108,-0.039,0.068,-0.015,0.033,0.008,0.044,0.016,-0.017,-0.034,-0.018,0.023,-0.018,-0.031,-0.068,0.021,0.0,-0.006,0.032,-0.019,0.019,-0.004,0.063,-0.018,-0.057,0.021,-0.054,-0.047,0.035,-0.113,-0.005,0.065,0.033,-0.018,0.055,-0.033,0.01,-0.095,0.008,0.008,0.053,-0.03,-0.036,0.068,-0.128,-0.011,0.034,-0.022,0.01,-0.012,0.033,-0.016,0.127,0.081,-0.028,-0.07,0.004,-0.067,0.063,-0.056,0.025,-0.014,0.094,-0.012,-0.016,0.065,0.045,0.082,0.001,-0.023,0.014,-0.04,-0.002,0.024,0.001,0.03,0.051,-0.017,-0.071,0.108,-0.028,0.004,-0.048,-0.026,0.041,-0.038,0.05,0.002,-0.027,-0.005,0.019,-0.045,-0.077,-0.16,0.021,0.05,-0.068,0.069,-0.045,0.041,-0.091,-0.024,0.025,-0.052,-0.046,0.066,-0.114,-0.002,0.004,0.063,-0.056,-0.004,0.0,0.071,0.08,0.022,-0.087,-0.02,-0.078,0.002,0.081,-0.038,-0.001,-0.072,0.003,0.014,0.005,0.022,-0.008,0.094,0.011,0.068,-0.013,-0.015,-0.046,0.055,0.013,-0.004,-0.001,-0.015,0.01,-0.014,0.013,-0.036,-0.007,-0.07,-0.061,-0.08,0.018,0.005,-0.001,-0.017,0.027,0.031,-0.023,0.001,0.167,-0.007,-0.031,0.035,0.032,-0.009,0.122,-0.037,-0.032,-0.011,0.018,-0.042,0.051,-0.002,-0.081,0.06,-0.009,0.061,0.065,-0.037,0.076,0.05,0.083,-0.026,0.034,-0.097,-0.016,0.116,0.026,-0.173,0.011,0.051,-0.055,0.013,0.045,-0.017,-0.121,-0.071,-0.025,0.075,-0.031,0.047,0.062,0.05,0.101,-0.036,-0.018,0.051,-0.072,0.004,-0.023,0.019,0.0,-0.024,0.073,0.018,-0.063,0.079,0.012,-0.076,-0.006,-0.009,0.002,-0.025,0.063,-0.011,0.104,0.004,0.025,0.009,-0.071,-0.032,-0.051,-0.096,-0.072,-0.116,-0.06,-0.035,-0.021,0.016,0.045,0.014,0.036,-0.03,0.009,-0.091,-0.045,0.02,-0.105,-0.006,0.046,-0.028,-0.116,-0.078,-0.013,0.019,0.004,-0.05,0.023,0.046,-0.03,-0.021,0.001,0.022,0.02,-0.015,0.059,0.132,0.022,-0.01,-0.003,-0.002,0.021,0.052,-0.023,0.017,0.009],[-0.009,-0.0,-0.035,-0.002,-0.044,-0.063,0.1,0.03,0.052,-0.06,-0.027,0.012,0.03,-0.04,-0.013,0.023,-0.028,0.015,-0.066,-0.032,0.052,0.028,0.063,0.037,-0.005,-0.024,0.006,0.008,0.014,-0.007,-0.042,-0.018,0.012,-0.061,-0.03,0.004,-0.019,0.003,0.065,0.058,0.004,-0.032,0.023,-0.016,0.03,-0.009,-0.022,-0.026,0.057,-0.013,0.002,0.004,-0.059,-0.047,0.084,0.085,0.048,-0.008,0.11,0.041,-0.018,0.071,-0.022,-0.067,0.015,-0.031,0.037,-0.034,0.032,0.121,0.063,0.003,-0.016,-0.007,0.011,0.093,0.056,-0.054,0.028,0.014,-0.008,-0.102,-0.072,-0.042,0.025,0.005,-0.005,-0.083,-0.008,0.018,-0.076,0.07,0.03,0.003,-0.029,0.021,0.016,0.036,-0.101,0.194,-0.01,-0.014,0.07,-0.004,0.001,-0.087,0.001,-0.0,0.02,0.0,-0.061,-0.108,-0.039,0.068,-0.015,0.033,0.008,0.044,0.016,-0.017,-0.034,-0.018,0.023,-0.018,-0.031,-0.068,0.021,0.0,-0.006,0.032,-0.019,0.019,-0.004,0.063,-0.018,-0.057,0.021,-0.054,-0.047,0.035,-0.113,-0.005,0.065,0.033,-0.018,0.055,-0.033,0.01,-0.095,0.008,0.008,0.053,-0.03,-0.036,0.068,-0.128,-0.011,0.034,-0.022,0.01,-0.012,0.033,-0.016,0.127,0.081,-0.028,-0.07,0.004,-0.067,0.063,-0.056,0.025,-0.014,0.094,-0.012,-0.016,0.065,0.045,0.082,0.001,-0.023,0.014,-0.04,-0.002,0.024,0.001,0.03,0.051,-0.017,-0.071,0.108,-0.028,0.004,-0.048,-0.026,0.041,-0.038,0.05,0.002,-0.027,-0.005,0.019,-0.045,-0.077,-0.16,0.021,0.05,-0.068,0.069,-0.045,0.041,-0.091,-0.024,0.025,-0.052,-0.046,0.066,-0.114,-0.002,0.004,0.063,-0.056,-0.004,0.0,0.071,0.08,0.022,-0.087,-0.02,-0.078,0.002,0.081,-0.038,-0.001,-0.072,0.003,0.014,0.005,0.022,-0.008,0.094,0.011,0.068,-0.013,-0.015,-0.046,0.055,0.013,-0.004,-0.001,-0.015,0.01,-0.014,0.013,-0.036,-0.007,-0.07,-0.061,-0.08,0.018,0.005,-0.001,-0.017,0.027,0.031,-0.023,0.001,0.167,-0.007,-0.031,0.035,0.032,-0.009,0.122,-0.037,-0.032,-0.011,0.018,-0.042,0.051,-0.002,-0.081,0.06,-0.009,0.061,0.065,-0.037,0.076,0.05,0.083,-0.026,0.034,-0.097,-0.016,0.116,0.026,-0.173,0.011,0.051,-0.055,0.013,0.045,-0.017,-0.121,-0.071,-0.025,0.075,-0.031,0.047,0.062,0.05,0.101,-0.036,-0.018,0.051,-0.072,0.004,-0.023,0.019,0.0,-0.024,0.073,0.018,-0.063,0.079,0.012,-0.076,-0.006,-0.009,0.002,-0.025,0.063,-0.011,0.104,0.004,0.025,0.009,-0.071,-0.032,-0.051,-0.096,-0.072,-0.116,-0.06,-0.035,-0.021,0.016,0.045,0.014,0.036,-0.03,0.009,-0.091,-0.045,0.02,-0.105,-0.006,0.046,-0.028,-0.116,-0.078,-0.013,0.019,0.004,-0.05,0.023,0.046,-0.03,-0.021,0.001,0.022,0.02,-0.015,0.059,0.132,0.022,-0.01,-0.003,-0.002,0.021,0.052,-0.023,0.017,0.009],[-0.003,-0.038,-0.045,0.046,-0.102,-0.023,0.163,0.003,0.041,-0.042,-0.026,-0.083,0.078,-0.014,-0.057,-0.018,0.034,0.022,-0.025,-0.026,-0.071,0.043,-0.062,0.067,-0.012,0.032,0.025,-0.009,-0.046,-0.135,0.026,0.067,0.036,-0.041,0.038,-0.023,0.021,0.026,0.025,-0.019,-0.01,-0.081,0.029,0.08,-0.012,-0.001,0.067,-0.012,0.044,-0.042,-0.009,-0.039,-0.065,0.078,0.041,0.087,-0.023,0.046,0.056,-0.025,-0.047,0.068,0.01,0.019,0.0,0.036,-0.061,-0.014,-0.012,-0.019,0.033,0.033,0.023,0.072,0.037,0.016,0.064,0.038,0.129,-0.029,-0.119,-0.086,-0.025,-0.006,-0.011,0.028,-0.016,-0.061,-0.08,0.019,0.026,0.045,0.058,0.002,-0.123,-0.047,-0.0,-0.029,-0.029,0.163,0.016,0.011,-0.031,-0.029,0.05,-0.093,0.036,-0.011,-0.008,0.014,0.003,-0.074,-0.017,0.004,0.039,-0.053,-0.025,0.031,0.047,-0.023,-0.009,0.08,-0.031,-0.049,-0.15,0.012,-0.007,0.0,0.02,-0.068,0.069,0.07,-0.043,0.048,-0.092,-0.012,-0.027,0.017,-0.026,0.008,-0.006,0.02,0.132,0.001,-0.086,-0.017,-0.021,0.039,-0.083,0.04,-0.021,0.122,-0.01,-0.053,0.057,-0.07,-0.041,0.062,0.004,-0.033,-0.041,-0.018,0.008,-0.074,0.024,-0.012,-0.052,-0.039,0.011,-0.062,-0.087,-0.064,0.048,0.061,0.074,0.073,-0.044,0.04,-0.002,-0.034,0.037,0.051,-0.001,-0.005,0.016,0.009,-0.001,0.12,0.061,0.094,0.037,-0.052,-0.037,-0.028,0.016,-0.075,-0.006,-0.128,-0.031,-0.026,0.061,0.017,-0.038,0.021,-0.045,-0.055,-0.066,-0.007,-0.03,-0.019,0.044,-0.018,-0.036,0.04,-0.007,-0.102,0.008,0.049,-0.135,-0.006,0.079,-0.002,-0.039,0.0,0.029,-0.087,-0.023,0.024,-0.036,-0.038,0.027,-0.04,0.064,0.028,-0.056,-0.043,0.044,-0.041,0.033,0.004,0.015,0.007,-0.019,0.056,-0.04,0.012,-0.089,0.063,-0.071,0.088,0.027,0.014,0.09,0.006,0.013,0.017,-0.016,-0.001,-0.082,0.079,0.053,0.0,-0.03,-0.044,-0.061,0.033,-0.03,0.081,0.05,0.013,0.036,0.029,-0.01,0.048,-0.106,-0.021,-0.049,0.043,-0.047,-0.043,-0.037,0.027,0.098,-0.017,0.04,0.024,0.049,0.036,-0.005,-0.005,-0.01,-0.002,-0.05,-0.049,0.105,0.077,-0.073,0.042,0.028,0.074,-0.001,0.002,-0.05,0.087,-0.02,0.029,-0.018,0.066,-0.027,-0.015,0.039,0.031,0.001,-0.055,-0.018,0.021,-0.031,-0.061,0.029,0.0,0.014,0.031,0.003,0.033,0.071,-0.007,0.077,0.067,0.014,0.004,0.055,0.038,-0.009,0.091,0.073,0.028,-0.006,-0.04,-0.008,0.027,0.006,0.0,0.016,-0.056,-0.052,-0.055,-0.032,0.024,0.071,0.023,0.055,0.107,-0.057,-0.124,0.001,0.004,-0.013,0.077,0.02,-0.007,-0.029,-0.037,0.006,-0.052,-0.046,-0.113,0.037,0.002,-0.02,-0.036,-0.059,0.1,0.042,0.007,0.068,0.047,-0.036,-0.011,-0.078,0.084,0.033,-0.053,0.011,-0.054],[-0.003,-0.038,-0.045,0.046,-0.102,-0.023,0.163,0.003,0.041,-0.042,-0.026,-0.083,0.078,-0.014,-0.057,-0.018,0.034,0.022,-0.025,-0.026,-0.071,0.043,-0.062,0.067,-0.012,0.032,0.025,-0.009,-0.046,-0.135,0.026,0.067,0.036,-0.041,0.038,-0.023,0.021,0.026,0.025,-0.019,-0.01,-0.081,0.029,0.08,-0.012,-0.001,0.067,-0.012,0.044,-0.042,-0.009,-0.039,-0.065,0.078,0.041,0.087,-0.023,0.046,0.056,-0.025,-0.047,0.068,0.01,0.019,0.0,0.036,-0.061,-0.014,-0.012,-0.019,0.033,0.033,0.023,0.072,0.037,0.016,0.064,0.038,0.129,-0.029,-0.119,-0.086,-0.025,-0.006,-0.011,0.028,-0.016,-0.061,-0.08,0.019,0.026,0.045,0.058,0.002,-0.123,-0.047,-0.0,-0.029,-0.029,0.163,0.016,0.011,-0.031,-0.029,0.05,-0.093,0.036,-0.011,-0.008,0.014,0.003,-0.074,-0.017,0.004,0.039,-0.053,-0.025,0.031,0.047,-0.023,-0.009,0.08,-0.031,-0.049,-0.15,0.012,-0.007,0.0,0.02,-0.068,0.069,0.07,-0.043,0.048,-0.092,-0.012,-0.027,0.017,-0.026,0.008,-0.006,0.02,0.132,0.001,-0.086,-0.017,-0.021,0.039,-0.083,0.04,-0.021,0.122,-0.01,-0.053,0.057,-0.07,-0.041,0.062,0.004,-0.033,-0.041,-0.018,0.008,-0.074,0.024,-0.012,-0.052,-0.039,0.011,-0.062,-0.087,-0.064,0.048,0.061,0.074,0.073,-0.044,0.04,-0.002,-0.034,0.037,0.051,-0.001,-0.005,0.016,0.009,-0.001,0.12,0.061,0.094,0.037,-0.052,-0.037,-0.028,0.016,-0.075,-0.006,-0.128,-0.031,-0.026,0.061,0.017,-0.038,0.021,-0.045,-0.055,-0.066,-0.007,-0.03,-0.019,0.044,-0.018,-0.036,0.04,-0.007,-0.102,0.008,0.049,-0.135,-0.006,0.079,-0.002,-0.039,0.0,0.029,-0.087,-0.023,0.024,-0.036,-0.038,0.027,-0.04,0.064,0.028,-0.056,-0.043,0.044,-0.041,0.033,0.004,0.015,0.007,-0.019,0.056,-0.04,0.012,-0.089,0.063,-0.071,0.088,0.027,0.014,0.09,0.006,0.013,0.017,-0.016,-0.001,-0.082,0.079,0.053,0.0,-0.03,-0.044,-0.061,0.033,-0.03,0.081,0.05,0.013,0.036,0.029,-0.01,0.048,-0.106,-0.021,-0.049,0.043,-0.047,-0.043,-0.037,0.027,0.098,-0.017,0.04,0.024,0.049,0.036,-0.005,-0.005,-0.01,-0.002,-0.05,-0.049,0.105,0.077,-0.073,0.042,0.028,0.074,-0.001,0.002,-0.05,0.087,-0.02,0.029,-0.018,0.066,-0.027,-0.015,0.039,0.031,0.001,-0.055,-0.018,0.021,-0.031,-0.061,0.029,0.0,0.014,0.031,0.003,0.033,0.071,-0.007,0.077,0.067,0.014,0.004,0.055,0.038,-0.009,0.091,0.073,0.028,-0.006,-0.04,-0.008,0.027,0.006,0.0,0.016,-0.056,-0.052,-0.055,-0.032,0.024,0.071,0.023,0.055,0.107,-0.057,-0.124,0.001,0.004,-0.013,0.077,0.02,-0.007,-0.029,-0.037,0.006,-0.052,-0.046,-0.113,0.037,0.002,-0.02,-0.036,-0.059,0.1,0.042,0.007,0.068,0.047,-0.036,-0.011,-0.078,0.084,0.033,-0.053,0.011,-0.054],[-0.003,-0.038,-0.045,0.046,-0.102,-0.023,0.163,0.003,0.041,-0.042,-0.026,-0.083,0.078,-0.014,-0.057,-0.018,0.034,0.022,-0.025,-0.026,-0.071,0.043,-0.062,0.067,-0.012,0.032,0.025,-0.009,-0.046,-0.135,0.026,0.067,0.036,-0.041,0.038,-0.023,0.021,0.026,0.025,-0.019,-0.01,-0.081,0.029,0.08,-0.012,-0.001,0.067,-0.012,0.044,-0.042,-0.009,-0.039,-0.065,0.078,0.041,0.087,-0.023,0.046,0.056,-0.025,-0.047,0.068,0.01,0.019,0.0,0.036,-0.061,-0.014,-0.012,-0.019,0.033,0.033,0.023,0.072,0.037,0.016,0.064,0.038,0.129,-0.029,-0.119,-0.086,-0.025,-0.006,-0.011,0.028,-0.016,-0.061,-0.08,0.019,0.026,0.045,0.058,0.002,-0.123,-0.047,-0.0,-0.029,-0.029,0.163,0.016,0.011,-0.031,-0.029,0.05,-0.093,0.036,-0.011,-0.008,0.014,0.003,-0.074,-0.017,0.004,0.039,-0.053,-0.025,0.031,0.047,-0.023,-0.009,0.08,-0.031,-0.049,-0.15,0.012,-0.007,0.0,0.02,-0.068,0.069,0.07,-0.043,0.048,-0.092,-0.012,-0.027,0.017,-0.026,0.008,-0.006,0.02,0.132,0.001,-0.086,-0.017,-0.021,0.039,-0.083,0.04,-0.021,0.122,-0.01,-0.053,0.057,-0.07,-0.041,0.062,0.004,-0.033,-0.041,-0.018,0.008,-0.074,0.024,-0.012,-0.052,-0.039,0.011,-0.062,-0.087,-0.064,0.048,0.061,0.074,0.073,-0.044,0.04,-0.002,-0.034,0.037,0.051,-0.001,-0.005,0.016,0.009,-0.001,0.12,0.061,0.094,0.037,-0.052,-0.037,-0.028,0.016,-0.075,-0.006,-0.128,-0.031,-0.026,0.061,0.017,-0.038,0.021,-0.045,-0.055,-0.066,-0.007,-0.03,-0.019,0.044,-0.018,-0.036,0.04,-0.007,-0.102,0.008,0.049,-0.135,-0.006,0.079,-0.002,-0.039,0.0,0.029,-0.087,-0.023,0.024,-0.036,-0.038,0.027,-0.04,0.064,0.028,-0.056,-0.043,0.044,-0.041,0.033,0.004,0.015,0.007,-0.019,0.056,-0.04,0.012,-0.089,0.063,-0.071,0.088,0.027,0.014,0.09,0.006,0.013,0.017,-0.016,-0.001,-0.082,0.079,0.053,0.0,-0.03,-0.044,-0.061,0.033,-0.03,0.081,0.05,0.013,0.036,0.029,-0.01,0.048,-0.106,-0.021,-0.049,0.043,-0.047,-0.043,-0.037,0.027,0.098,-0.017,0.04,0.024,0.049,0.036,-0.005,-0.005,-0.01,-0.002,-0.05,-0.049,0.105,0.077,-0.073,0.042,0.028,0.074,-0.001,0.002,-0.05,0.087,-0.02,0.029,-0.018,0.066,-0.027,-0.015,0.039,0.031,0.001,-0.055,-0.018,0.021,-0.031,-0.061,0.029,0.0,0.014,0.031,0.003,0.033,0.071,-0.007,0.077,0.067,0.014,0.004,0.055,0.038,-0.009,0.091,0.073,0.028,-0.006,-0.04,-0.008,0.027,0.006,0.0,0.016,-0.056,-0.052,-0.055,-0.032,0.024,0.071,0.023,0.055,0.107,-0.057,-0.124,0.001,0.004,-0.013,0.077,0.02,-0.007,-0.029,-0.037,0.006,-0.052,-0.046,-0.113,0.037,0.002,-0.02,-0.036,-0.059,0.1,0.042,0.007,0.068,0.047,-0.036,-0.011,-0.078,0.084,0.033,-0.053,0.011,-0.054],[-0.009,-0.0,-0.035,-0.002,-0.044,-0.063,0.1,0.03,0.052,-0.06,-0.027,0.012,0.03,-0.04,-0.013,0.023,-0.028,0.015,-0.066,-0.032,0.052,0.028,0.063,0.037,-0.005,-0.024,0.006,0.008,0.014,-0.007,-0.042,-0.018,0.012,-0.061,-0.03,0.004,-0.019,0.003,0.065,0.058,0.004,-0.032,0.023,-0.016,0.03,-0.009,-0.022,-0.026,0.057,-0.013,0.002,0.004,-0.059,-0.047,0.084,0.085,0.048,-0.008,0.11,0.041,-0.018,0.071,-0.022,-0.067,0.015,-0.031,0.037,-0.034,0.032,0.121,0.063,0.003,-0.016,-0.007,0.011,0.093,0.056,-0.054,0.028,0.014,-0.008,-0.102,-0.072,-0.042,0.025,0.005,-0.005,-0.083,-0.008,0.018,-0.076,0.07,0.03,0.003,-0.029,0.021,0.016,0.036,-0.101,0.194,-0.01,-0.014,0.07,-0.004,0.001,-0.087,0.001,-0.0,0.02,0.0,-0.061,-0.108,-0.039,0.068,-0.015,0.033,0.008,0.044,0.016,-0.017,-0.034,-0.018,0.023,-0.018,-0.031,-0.068,0.021,0.0,-0.006,0.032,-0.019,0.019,-0.004,0.063,-0.018,-0.057,0.021,-0.054,-0.047,0.035,-0.113,-0.005,0.065,0.033,-0.018,0.055,-0.033,0.01,-0.095,0.008,0.008,0.053,-0.03,-0.036,0.068,-0.128,-0.011,0.034,-0.022,0.01,-0.012,0.033,-0.016,0.127,0.081,-0.028,-0.07,0.004,-0.067,0.063,-0.056,0.025,-0.014,0.094,-0.012,-0.016,0.065,0.045,0.082,0.001,-0.023,0.014,-0.04,-0.002,0.024,0.001,0.03,0.051,-0.017,-0.071,0.108,-0.028,0.004,-0.048,-0.026,0.041,-0.038,0.05,0.002,-0.027,-0.005,0.019,-0.045,-0.077,-0.16,0.021,0.05,-0.068,0.069,-0.045,0.041,-0.091,-0.024,0.025,-0.052,-0.046,0.066,-0.114,-0.002,0.004,0.063,-0.056,-0.004,0.0,0.071,0.08,0.022,-0.087,-0.02,-0.078,0.002,0.081,-0.038,-0.001,-0.072,0.003,0.014,0.005,0.022,-0.008,0.094,0.011,0.068,-0.013,-0.015,-0.046,0.055,0.013,-0.004,-0.001,-0.015,0.01,-0.014,0.013,-0.036,-0.007,-0.07,-0.061,-0.08,0.018,0.005,-0.001,-0.017,0.027,0.031,-0.023,0.001,0.167,-0.007,-0.031,0.035,0.032,-0.009,0.122,-0.037,-0.032,-0.011,0.018,-0.042,0.051,-0.002,-0.081,0.06,-0.009,0.061,0.065,-0.037,0.076,0.05,0.083,-0.026,0.034,-0.097,-0.016,0.116,0.026,-0.173,0.011,0.051,-0.055,0.013,0.045,-0.017,-0.121,-0.071,-0.025,0.075,-0.031,0.047,0.062,0.05,0.101,-0.036,-0.018,0.051,-0.072,0.004,-0.023,0.019,0.0,-0.024,0.073,0.018,-0.063,0.079,0.012,-0.076,-0.006,-0.009,0.002,-0.025,0.063,-0.011,0.104,0.004,0.025,0.009,-0.071,-0.032,-0.051,-0.096,-0.072,-0.116,-0.06,-0.035,-0.021,0.016,0.045,0.014,0.036,-0.03,0.009,-0.091,-0.045,0.02,-0.105,-0.006,0.046,-0.028,-0.116,-0.078,-0.013,0.019,0.004,-0.05,0.023,0.046,-0.03,-0.021,0.001,0.022,0.02,-0.015,0.059,0.132,0.022,-0.01,-0.003,-0.002,0.021,0.052,-0.023,0.017,0.009],[-0.009,-0.0,-0.035,-0.002,-0.044,-0.063,0.1,0.03,0.052,-0.06,-0.027,0.012,0.03,-0.04,-0.013,0.023,-0.028,0.015,-0.066,-0.032,0.052,0.028,0.063,0.037,-0.005,-0.024,0.006,0.008,0.014,-0.007,-0.042,-0.018,0.012,-0.061,-0.03,0.004,-0.019,0.003,0.065,0.058,0.004,-0.032,0.023,-0.016,0.03,-0.009,-0.022,-0.026,0.057,-0.013,0.002,0.004,-0.059,-0.047,0.084,0.085,0.048,-0.008,0.11,0.041,-0.018,0.071,-0.022,-0.067,0.015,-0.031,0.037,-0.034,0.032,0.121,0.063,0.003,-0.016,-0.007,0.011,0.093,0.056,-0.054,0.028,0.014,-0.008,-0.102,-0.072,-0.042,0.025,0.005,-0.005,-0.083,-0.008,0.018,-0.076,0.07,0.03,0.003,-0.029,0.021,0.016,0.036,-0.101,0.194,-0.01,-0.014,0.07,-0.004,0.001,-0.087,0.001,-0.0,0.02,0.0,-0.061,-0.108,-0.039,0.068,-0.015,0.033,0.008,0.044,0.016,-0.017,-0.034,-0.018,0.023,-0.018,-0.031,-0.068,0.021,0.0,-0.006,0.032,-0.019,0.019,-0.004,0.063,-0.018,-0.057,0.021,-0.054,-0.047,0.035,-0.113,-0.005,0.065,0.033,-0.018,0.055,-0.033,0.01,-0.095,0.008,0.008,0.053,-0.03,-0.036,0.068,-0.128,-0.011,0.034,-0.022,0.01,-0.012,0.033,-0.016,0.127,0.081,-0.028,-0.07,0.004,-0.067,0.063,-0.056,0.025,-0.014,0.094,-0.012,-0.016,0.065,0.045,0.082,0.001,-0.023,0.014,-0.04,-0.002,0.024,0.001,0.03,0.051,-0.017,-0.071,0.108,-0.028,0.004,-0.048,-0.026,0.041,-0.038,0.05,0.002,-0.027,-0.005,0.019,-0.045,-0.077,-0.16,0.021,0.05,-0.068,0.069,-0.045,0.041,-0.091,-0.024,0.025,-0.052,-0.046,0.066,-0.114,-0.002,0.004,0.063,-0.056,-0.004,0.0,0.071,0.08,0.022,-0.087,-0.02,-0.078,0.002,0.081,-0.038,-0.001,-0.072,0.003,0.014,0.005,0.022,-0.008,0.094,0.011,0.068,-0.013,-0.015,-0.046,0.055,0.013,-0.004,-0.001,-0.015,0.01,-0.014,0.013,-0.036,-0.007,-0.07,-0.061,-0.08,0.018,0.005,-0.001,-0.017,0.027,0.031,-0.023,0.001,0.167,-0.007,-0.031,0.035,0.032,-0.009,0.122,-0.037,-0.032,-0.011,0.018,-0.042,0.051,-0.002,-0.081,0.06,-0.009,0.061,0.065,-0.037,0.076,0.05,0.083,-0.026,0.034,-0.097,-0.016,0.116,0.026,-0.173,0.011,0.051,-0.055,0.013,0.045,-0.017,-0.121,-0.071,-0.025,0.075,-0.031,0.047,0.062,0.05,0.101,-0.036,-0.018,0.051,-0.072,0.004,-0.023,0.019,0.0,-0.024,0.073,0.018,-0.063,0.079,0.012,-0.076,-0.006,-0.009,0.002,-0.025,0.063,-0.011,0.104,0.004,0.025,0.009,-0.071,-0.032,-0.051,-0.096,-0.072,-0.116,-0.06,-0.035,-0.021,0.016,0.045,0.014,0.036,-0.03,0.009,-0.091,-0.045,0.02,-0.105,-0.006,0.046,-0.028,-0.116,-0.078,-0.013,0.019,0.004,-0.05,0.023,0.046,-0.03,-0.021,0.001,0.022,0.02,-0.015,0.059,0.132,0.022,-0.01,-0.003,-0.002,0.021,0.052,-0.023,0.017,0.009],[-0.009,-0.0,-0.035,-0.002,-0.044,-0.063,0.1,0.03,0.052,-0.06,-0.027,0.012,0.03,-0.04,-0.013,0.023,-0.028,0.015,-0.066,-0.032,0.052,0.028,0.063,0.037,-0.005,-0.024,0.006,0.008,0.014,-0.007,-0.042,-0.018,0.012,-0.061,-0.03,0.004,-0.019,0.003,0.065,0.058,0.004,-0.032,0.023,-0.016,0.03,-0.009,-0.022,-0.026,0.057,-0.013,0.002,0.004,-0.059,-0.047,0.084,0.085,0.048,-0.008,0.11,0.041,-0.018,0.071,-0.022,-0.067,0.015,-0.031,0.037,-0.034,0.032,0.121,0.063,0.003,-0.016,-0.007,0.011,0.093,0.056,-0.054,0.028,0.014,-0.008,-0.102,-0.072,-0.042,0.025,0.005,-0.005,-0.083,-0.008,0.018,-0.076,0.07,0.03,0.003,-0.029,0.021,0.016,0.036,-0.101,0.194,-0.01,-0.014,0.07,-0.004,0.001,-0.087,0.001,-0.0,0.02,0.0,-0.061,-0.108,-0.039,0.068,-0.015,0.033,0.008,0.044,0.016,-0.017,-0.034,-0.018,0.023,-0.018,-0.031,-0.068,0.021,0.0,-0.006,0.032,-0.019,0.019,-0.004,0.063,-0.018,-0.057,0.021,-0.054,-0.047,0.035,-0.113,-0.005,0.065,0.033,-0.018,0.055,-0.033,0.01,-0.095,0.008,0.008,0.053,-0.03,-0.036,0.068,-0.128,-0.011,0.034,-0.022,0.01,-0.012,0.033,-0.016,0.127,0.081,-0.028,-0.07,0.004,-0.067,0.063,-0.056,0.025,-0.014,0.094,-0.012,-0.016,0.065,0.045,0.082,0.001,-0.023,0.014,-0.04,-0.002,0.024,0.001,0.03,0.051,-0.017,-0.071,0.108,-0.028,0.004,-0.048,-0.026,0.041,-0.038,0.05,0.002,-0.027,-0.005,0.019,-0.045,-0.077,-0.16,0.021,0.05,-0.068,0.069,-0.045,0.041,-0.091,-0.024,0.025,-0.052,-0.046,0.066,-0.114,-0.002,0.004,0.063,-0.056,-0.004,0.0,0.071,0.08,0.022,-0.087,-0.02,-0.078,0.002,0.081,-0.038,-0.001,-0.072,0.003,0.014,0.005,0.022,-0.008,0.094,0.011,0.068,-0.013,-0.015,-0.046,0.055,0.013,-0.004,-0.001,-0.015,0.01,-0.014,0.013,-0.036,-0.007,-0.07,-0.061,-0.08,0.018,0.005,-0.001,-0.017,0.027,0.031,-0.023,0.001,0.167,-0.007,-0.031,0.035,0.032,-0.009,0.122,-0.037,-0.032,-0.011,0.018,-0.042,0.051,-0.002,-0.081,0.06,-0.009,0.061,0.065,-0.037,0.076,0.05,0.083,-0.026,0.034,-0.097,-0.016,0.116,0.026,-0.173,0.011,0.051,-0.055,0.013,0.045,-0.017,-0.121,-0.071,-0.025,0.075,-0.031,0.047,0.062,0.05,0.101,-0.036,-0.018,0.051,-0.072,0.004,-0.023,0.019,0.0,-0.024,0.073,0.018,-0.063,0.079,0.012,-0.076,-0.006,-0.009,0.002,-0.025,0.063,-0.011,0.104,0.004,0.025,0.009,-0.071,-0.032,-0.051,-0.096,-0.072,-0.116,-0.06,-0.035,-0.021,0.016,0.045,0.014,0.036,-0.03,0.009,-0.091,-0.045,0.02,-0.105,-0.006,0.046,-0.028,-0.116,-0.078,-0.013,0.019,0.004,-0.05,0.023,0.046,-0.03,-0.021,0.001,0.022,0.02,-0.015,0.059,0.132,0.022,-0.01,-0.003,-0.002,0.021,0.052,-0.023,0.017,0.009]]
|