blackstack-core 1.2.27 → 1.2.29
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/lib/functions.rb +194 -167
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61e89c40560e966edd297c6fbce7e0099a94bce4dd88c0653f7e20feceb8234e
|
4
|
+
data.tar.gz: 28543d06207cc6399371e857b0982ec7432801e5344372304165a0aaa4053660
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8545ef59846393d06cb272b8e503847b3c11e9837933ac770c546acf724265a6e560407dea7bcbe67bccf49ec505b89463b4aab52bb83094fdeb792b517f7479
|
7
|
+
data.tar.gz: 3eaac8af64b460a4cf941d3756faa219da65a75300cbe47fe1574ae4bb9426e3a5d6a2c028dcb81e940646bc4566f433ed48493cbf4665c5eee58d76b341823f
|
data/lib/functions.rb
CHANGED
@@ -20,7 +20,7 @@ module BlackStack
|
|
20
20
|
|
21
21
|
def self.api_url
|
22
22
|
@@api_url
|
23
|
-
end
|
23
|
+
end
|
24
24
|
|
25
25
|
def self.api_port
|
26
26
|
@@api_port
|
@@ -34,14 +34,10 @@ module BlackStack
|
|
34
34
|
@@backtrace
|
35
35
|
end # def self.backtrace
|
36
36
|
|
37
|
-
def self.api_url()
|
38
|
-
"#{BlackStack::API.api_protocol}://#{BlackStack::API.api_domain}:#{BlackStack::API.api_port}"
|
39
|
-
end
|
40
|
-
|
41
37
|
def self.classes
|
42
38
|
@@classes
|
43
39
|
end # def self.classes
|
44
|
-
|
40
|
+
|
45
41
|
def self.set_client(
|
46
42
|
api_key: ,
|
47
43
|
api_url: ,
|
@@ -64,7 +60,7 @@ module BlackStack
|
|
64
60
|
end # def self.set_server
|
65
61
|
|
66
62
|
def self.post(
|
67
|
-
endpoint: ,
|
63
|
+
endpoint: ,
|
68
64
|
params: {}
|
69
65
|
)
|
70
66
|
begin
|
@@ -88,7 +84,7 @@ module BlackStack
|
|
88
84
|
|
89
85
|
# Base class.
|
90
86
|
# List of methods you have to overload if you develop a profile type.
|
91
|
-
#
|
87
|
+
#
|
92
88
|
class Base
|
93
89
|
# object json descriptor
|
94
90
|
attr_accessor :desc
|
@@ -124,10 +120,10 @@ module BlackStack
|
|
124
120
|
|
125
121
|
|
126
122
|
# Get array of hash descriptor of profile.
|
127
|
-
#
|
128
|
-
# Parameters:
|
123
|
+
#
|
124
|
+
# Parameters:
|
129
125
|
# - id_account: guid. Id of the account to bring the profiles. Sysowner must provide the id_account for getting an account value. For non sysowner it is assigned to his account.
|
130
|
-
# - promiscuous: boolean. It works only for Sysowner. If true, it will bring all non-deleted rows. If false, it will bring only rows matching id_profile. Default: false.
|
126
|
+
# - promiscuous: boolean. It works only for Sysowner. If true, it will bring all non-deleted rows, including the ones that are not owned by Sysowner. If false, it will bring only rows matching id_profile. Default: false.
|
131
127
|
# - page: integer. Page number.
|
132
128
|
# - limit: integer. Number of profiles per page.
|
133
129
|
# - params: hash. Additional filter parameters used by the specific child class.
|
@@ -151,8 +147,8 @@ module BlackStack
|
|
151
147
|
end # def self.base
|
152
148
|
|
153
149
|
# Get array of hash descriptors of profiles.
|
154
|
-
#
|
155
|
-
# Parameters:
|
150
|
+
#
|
151
|
+
# Parameters:
|
156
152
|
# - id: guid. Id of the profile to bring.
|
157
153
|
#
|
158
154
|
def self.count
|
@@ -167,8 +163,8 @@ module BlackStack
|
|
167
163
|
end # def self.count
|
168
164
|
|
169
165
|
# Get array of hash descriptors of profiles.
|
170
|
-
#
|
171
|
-
# Parameters:
|
166
|
+
#
|
167
|
+
# Parameters:
|
172
168
|
# - id: guid. Id of the profile to bring.
|
173
169
|
#
|
174
170
|
def self.get(id)
|
@@ -183,6 +179,23 @@ module BlackStack
|
|
183
179
|
return self.new(ret['result']).child_class_instance
|
184
180
|
end # def self.get
|
185
181
|
|
182
|
+
# Delete object.
|
183
|
+
#
|
184
|
+
# Parameters:
|
185
|
+
# - id: guid. Id of the profile to bring.
|
186
|
+
#
|
187
|
+
def self.delete(id)
|
188
|
+
params = {}
|
189
|
+
params['id'] = id
|
190
|
+
params['backtrace'] = BlackStack::API.backtrace
|
191
|
+
ret = BlackStack::API.post(
|
192
|
+
endpoint: "#{self.object_name}/delete",
|
193
|
+
params: params
|
194
|
+
)
|
195
|
+
raise "Error calling get endpoint: #{ret['status']}" if ret['status'] != 'success'
|
196
|
+
return self.new(ret['result']).child_class_instance
|
197
|
+
end # def self.get
|
198
|
+
|
186
199
|
# Submit a hash descriptor to the server for an update
|
187
200
|
#
|
188
201
|
def self.update(desc)
|
@@ -252,6 +265,20 @@ module BlackStack
|
|
252
265
|
return ret['result'] == {} ? nil : self.new(ret['result']).child_class_instance
|
253
266
|
end # def self.upsert
|
254
267
|
|
268
|
+
# Submit a hash descriptor to the server for an upsert
|
269
|
+
#
|
270
|
+
def self.upsert2(desc)
|
271
|
+
params = {}
|
272
|
+
params['desc'] = desc
|
273
|
+
params['backtrace'] = BlackStack::API.backtrace
|
274
|
+
ret = BlackStack::API.post(
|
275
|
+
endpoint: "#{self.object_name}/upsert2",
|
276
|
+
params: params
|
277
|
+
)
|
278
|
+
raise "Error calling upsert endpoint: #{ret['status']}" if ret['status'] != 'success'
|
279
|
+
return ret['result'] == {} ? nil : self.new(ret['result']).child_class_instance
|
280
|
+
end # def self.upsert
|
281
|
+
|
255
282
|
# Submit a hash descriptor to the server for an upsert
|
256
283
|
#
|
257
284
|
def upsert
|
@@ -270,7 +297,7 @@ module BlackStack
|
|
270
297
|
ret = nil
|
271
298
|
# getting the HTML
|
272
299
|
zyte = ZyteClient.new(key: api_key)
|
273
|
-
html = zyte.extract(url: url, options: options, data_filename: data_filename)
|
300
|
+
html = zyte.extract(url: url, options: options, data_filename: data_filename)
|
274
301
|
# return the URL of the file in the cloud
|
275
302
|
return html
|
276
303
|
end # def zyte_html
|
@@ -288,7 +315,7 @@ module BlackStack
|
|
288
315
|
def zyte_snapshot(url, api_key:, options:, data_filename:, dropbox_folder:nil, retry_times: 3)
|
289
316
|
# "The garbage character must be due to the 520 error code which was caused on the second request."
|
290
317
|
garbage = "\x9E\xE9e"
|
291
|
-
|
318
|
+
|
292
319
|
ret = nil
|
293
320
|
raise "Either dropbox_folder parameter or self.desc['id_account'] are required." if dropbox_folder.nil? && self.desc['id_account'].nil?
|
294
321
|
dropbox_folder = self.desc['id_account'] if dropbox_folder.nil?
|
@@ -306,7 +333,7 @@ module BlackStack
|
|
306
333
|
try = 0
|
307
334
|
html = garbage
|
308
335
|
while try < retry_times && html == garbage
|
309
|
-
html = zyte.extract(url: url, options: options, data_filename: data_filename)
|
336
|
+
html = zyte.extract(url: url, options: options, data_filename: data_filename)
|
310
337
|
try += 1
|
311
338
|
end
|
312
339
|
# save the HTML in the local file in /tmp
|
@@ -322,9 +349,9 @@ module BlackStack
|
|
322
349
|
|
323
350
|
end # class Base
|
324
351
|
|
325
|
-
# -----------------------------------------------------------------------------------------
|
352
|
+
# -----------------------------------------------------------------------------------------
|
326
353
|
# PRY Supporting Functions
|
327
|
-
# -----------------------------------------------------------------------------------------
|
354
|
+
# -----------------------------------------------------------------------------------------
|
328
355
|
module Debugging
|
329
356
|
@@allow_breakpoints = false
|
330
357
|
@@verbose = false
|
@@ -345,7 +372,7 @@ module BlackStack
|
|
345
372
|
print "Breakpoint are not allowed" if @@verbose
|
346
373
|
end
|
347
374
|
|
348
|
-
Binding.class_eval do
|
375
|
+
Binding.class_eval do
|
349
376
|
alias_method :old_pry, :pry
|
350
377
|
define_method :pry, new_pry
|
351
378
|
end
|
@@ -353,21 +380,21 @@ module BlackStack
|
|
353
380
|
end
|
354
381
|
end
|
355
382
|
|
356
|
-
# -----------------------------------------------------------------------------------------
|
383
|
+
# -----------------------------------------------------------------------------------------
|
357
384
|
# OCRA Supporting Functions
|
358
|
-
# -----------------------------------------------------------------------------------------
|
385
|
+
# -----------------------------------------------------------------------------------------
|
359
386
|
module OCRA
|
360
387
|
# OCRA files run into a temp folder, where the script is unpacked.
|
361
|
-
#
|
388
|
+
#
|
362
389
|
# This function is useful to require a configuration file when the
|
363
390
|
# script is running inside an OCRA temp folder, since the local folder
|
364
391
|
# of the running command is not the filder where the exe file is hosted.
|
365
|
-
#
|
366
|
-
# More information:
|
392
|
+
#
|
393
|
+
# More information:
|
367
394
|
# * https://stackoverflow.com/questions/1937743/how-to-get-the-current-working-directorys-absolute-path-from-irb
|
368
395
|
# * https://stackoverflow.com/questions/8577223/ruby-get-the-file-being-executed
|
369
396
|
# * https://stackoverflow.com/questions/7399882/ruby-getting-path-from-pathfilename/7400057
|
370
|
-
#
|
397
|
+
#
|
371
398
|
def self.require_in_working_path(filename, path, show_path_info=false)
|
372
399
|
puts '' if show_path_info
|
373
400
|
path = File.expand_path File.dirname(path)
|
@@ -379,13 +406,13 @@ module BlackStack
|
|
379
406
|
end
|
380
407
|
end # module OCRA
|
381
408
|
|
382
|
-
# -----------------------------------------------------------------------------------------
|
409
|
+
# -----------------------------------------------------------------------------------------
|
383
410
|
# DateTime Functions
|
384
|
-
# -----------------------------------------------------------------------------------------
|
385
|
-
module DateTime
|
386
|
-
# -----------------------------------------------------------------------------------------
|
411
|
+
# -----------------------------------------------------------------------------------------
|
412
|
+
module DateTime
|
413
|
+
# -----------------------------------------------------------------------------------------
|
387
414
|
# Encoding
|
388
|
-
# -----------------------------------------------------------------------------------------
|
415
|
+
# -----------------------------------------------------------------------------------------
|
389
416
|
module Encoding
|
390
417
|
# Convierte un objeto date-time a un string con formato sql-datetime (yyyy-mm-dd hh:mm:ss).
|
391
418
|
def self.datetime_to_sql(o)
|
@@ -393,50 +420,50 @@ module BlackStack
|
|
393
420
|
end
|
394
421
|
end # module Encode
|
395
422
|
|
396
|
-
# -----------------------------------------------------------------------------------------
|
423
|
+
# -----------------------------------------------------------------------------------------
|
397
424
|
# Miscelaneous
|
398
|
-
# -----------------------------------------------------------------------------------------
|
425
|
+
# -----------------------------------------------------------------------------------------
|
399
426
|
module Misc
|
400
427
|
def self.datetime_values_check(year,month,day,hour,minute,second)
|
401
428
|
if (year.to_i<1900 || year.to_i>=2100)
|
402
429
|
return false
|
403
430
|
end
|
404
|
-
|
431
|
+
|
405
432
|
if (month.to_i<1 || month.to_i>12)
|
406
433
|
return false
|
407
434
|
end
|
408
|
-
|
435
|
+
|
409
436
|
# TODO: Considerar la cantidad de dias de cada mes, y los anios biciestos. Buscar alguna funcion existente.
|
410
437
|
if (day.to_i<1 || day.to_i>31)
|
411
438
|
return false
|
412
439
|
end
|
413
|
-
|
440
|
+
|
414
441
|
if (hour.to_i<0 || hour.to_i>23)
|
415
442
|
return false
|
416
443
|
end
|
417
|
-
|
444
|
+
|
418
445
|
if (minute.to_i<0 || minute.to_i>59)
|
419
446
|
return false
|
420
447
|
end
|
421
|
-
|
448
|
+
|
422
449
|
if (second.to_i<0 || second.to_i>59)
|
423
450
|
return false
|
424
451
|
end
|
425
|
-
|
452
|
+
|
426
453
|
return true
|
427
454
|
end # datetime_values_check
|
428
455
|
end # module Misc
|
429
456
|
end # module DateTime
|
430
457
|
|
431
|
-
# -----------------------------------------------------------------------------------------
|
458
|
+
# -----------------------------------------------------------------------------------------
|
432
459
|
# Numeric Functions
|
433
|
-
# -----------------------------------------------------------------------------------------
|
460
|
+
# -----------------------------------------------------------------------------------------
|
434
461
|
module Number
|
435
|
-
# -----------------------------------------------------------------------------------------
|
462
|
+
# -----------------------------------------------------------------------------------------
|
436
463
|
# Encoding
|
437
|
-
# -----------------------------------------------------------------------------------------
|
464
|
+
# -----------------------------------------------------------------------------------------
|
438
465
|
module Encoding
|
439
|
-
# Converts number to a string with a format like xx,xxx,xxx.xxxx
|
466
|
+
# Converts number to a string with a format like xx,xxx,xxx.xxxx
|
440
467
|
# number: it may be int or float
|
441
468
|
def self.format_with_separator(number)
|
442
469
|
whole_part, decimal_part = number.to_s.split('.')
|
@@ -448,7 +475,7 @@ module BlackStack
|
|
448
475
|
# Ejemplo: "4 hours, 30 minutes"
|
449
476
|
# Ejemplo: "3 days, 4 hour"
|
450
477
|
def self.encode_minutes(n)
|
451
|
-
# TODO: validar que n sea un entero mayor a 0
|
478
|
+
# TODO: validar que n sea un entero mayor a 0
|
452
479
|
if (n<0)
|
453
480
|
return "?"
|
454
481
|
end
|
@@ -463,13 +490,13 @@ module BlackStack
|
|
463
490
|
end # module Encode
|
464
491
|
end # module Number
|
465
492
|
|
466
|
-
# -----------------------------------------------------------------------------------------
|
493
|
+
# -----------------------------------------------------------------------------------------
|
467
494
|
# String Functions
|
468
|
-
# -----------------------------------------------------------------------------------------
|
495
|
+
# -----------------------------------------------------------------------------------------
|
469
496
|
module Strings
|
470
497
|
|
471
498
|
GUID_SIZE = 36
|
472
|
-
MATCH_PASSWORD = /(?=.*[a-zA-Z])(?=.*[0-9]).{6,}/
|
499
|
+
MATCH_PASSWORD = /(?=.*[a-zA-Z])(?=.*[0-9]).{6,}/
|
473
500
|
MATCH_GUID = /{?[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]}?/
|
474
501
|
MATCH_FILENAME = /[\w\-\_\.]+/
|
475
502
|
MATCH_EMAIL = /[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{1,25}/
|
@@ -478,7 +505,7 @@ module BlackStack
|
|
478
505
|
MATCH_PHONE = /(?:\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}/
|
479
506
|
|
480
507
|
# Note: MATCH_URL gets the URL up to '?', but it doesn't retrieves the parameters.
|
481
|
-
# Exmaple:
|
508
|
+
# Exmaple:
|
482
509
|
# https://foo.com/bar?param1=value1¶m2=value2 --> https://foo.com/bar?
|
483
510
|
# https://foo.com/bar/?param1=value1¶m2=value2 --> https://foo.com/bar/?
|
484
511
|
MATCH_URL = /(https?:\/\/)?([\da-z\.-]+)([\.\:])([\da-z]{2,6})([\/[\da-z\.\-]+]*[\da-z])(\/)?(\?)?/i
|
@@ -488,32 +515,32 @@ module BlackStack
|
|
488
515
|
MATCH_CONTENT_SPINNING = /{[^}]+}/
|
489
516
|
MATCH_SPINNED_TEXT = /code me/ # TODO: define this regex for the issue #1226
|
490
517
|
|
491
|
-
# -----------------------------------------------------------------------------------------
|
518
|
+
# -----------------------------------------------------------------------------------------
|
492
519
|
# Fuzzy String Comparsion Functions: How similar are 2 strings that are not exactly equal.
|
493
|
-
# -----------------------------------------------------------------------------------------
|
520
|
+
# -----------------------------------------------------------------------------------------
|
494
521
|
module SQL
|
495
522
|
def self.string_to_sql_string(s)
|
496
523
|
#return s.force_encoding("UTF-8").gsub("'", "''").to_s
|
497
524
|
return s.gsub("'", "''").to_s
|
498
525
|
end
|
499
526
|
end
|
500
|
-
|
501
|
-
# -----------------------------------------------------------------------------------------
|
527
|
+
|
528
|
+
# -----------------------------------------------------------------------------------------
|
502
529
|
# Fuzzy String Comparsion Functions: How similar are 2 strings that are not exactly equal.
|
503
|
-
# -----------------------------------------------------------------------------------------
|
530
|
+
# -----------------------------------------------------------------------------------------
|
504
531
|
module Comparing
|
505
532
|
# retorna 0 si los strings son iguales
|
506
533
|
# https://stackoverflow.com/questions/16323571/measure-the-distance-between-two-strings-with-ruby
|
507
|
-
def self.levenshtein_distance(s, t)
|
534
|
+
def self.levenshtein_distance(s, t)
|
508
535
|
s.downcase!
|
509
536
|
t.downcase!
|
510
|
-
|
537
|
+
|
511
538
|
m = s.length
|
512
539
|
n = t.length
|
513
540
|
return m if n == 0
|
514
541
|
return n if m == 0
|
515
542
|
d = Array.new(m+1) {Array.new(n+1)}
|
516
|
-
|
543
|
+
|
517
544
|
(0..m).each {|i| d[i][0] = i}
|
518
545
|
(0..n).each {|j| d[0][j] = j}
|
519
546
|
(1..n).each do |j|
|
@@ -530,7 +557,7 @@ module BlackStack
|
|
530
557
|
end
|
531
558
|
d[m][n]
|
532
559
|
end
|
533
|
-
|
560
|
+
|
534
561
|
# retorna la cantidad de palabras con mas de 3 caracteres que se encuentran en el parametro s
|
535
562
|
def self.max_sardi_distance(s)
|
536
563
|
s.downcase!
|
@@ -545,14 +572,14 @@ module BlackStack
|
|
545
572
|
}
|
546
573
|
n
|
547
574
|
end
|
548
|
-
|
575
|
+
|
549
576
|
# retorna la cantidad de palabras con mas de 3 caracteres del parametro s que se encuentran en el parametro t
|
550
577
|
def self.sardi_distance(s, t)
|
551
578
|
s.downcase!
|
552
579
|
t.downcase!
|
553
580
|
s.gsub!(/-/,' ')
|
554
581
|
t.gsub!(/-/,' ')
|
555
|
-
max_distance = max_sardi_distance(s)
|
582
|
+
max_distance = max_sardi_distance(s)
|
556
583
|
ss = s.scan(/\b([a-z]+)\b/)
|
557
584
|
tt = t.scan(/\b([a-z]+)\b/)
|
558
585
|
n = 0
|
@@ -567,20 +594,20 @@ module BlackStack
|
|
567
594
|
return max_distance - n
|
568
595
|
end
|
569
596
|
end # module Comparing
|
570
|
-
|
571
|
-
# -----------------------------------------------------------------------------------------
|
597
|
+
|
598
|
+
# -----------------------------------------------------------------------------------------
|
572
599
|
# Encoding: Make a string nice to be shown into an HTML string.
|
573
|
-
# -----------------------------------------------------------------------------------------
|
600
|
+
# -----------------------------------------------------------------------------------------
|
574
601
|
module Encoding
|
575
602
|
# Then it makes it compatible with UTF-8.
|
576
|
-
# More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
|
603
|
+
# More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
|
577
604
|
def self.encode_string(s)
|
578
605
|
s.encode("UTF-8")
|
579
606
|
end
|
580
|
-
|
607
|
+
|
581
608
|
# Escape the string to be shown into an HTML screen.
|
582
609
|
# Then it makes it compatible with UTF-8.
|
583
|
-
# More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
|
610
|
+
# More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
|
584
611
|
def self.encode_html(s)
|
585
612
|
encode_string(CGI.escapeHTML(s.to_s))
|
586
613
|
end
|
@@ -588,9 +615,9 @@ module BlackStack
|
|
588
615
|
# Generates a description string from an exception object.
|
589
616
|
# Eescapes the string to be shown into an HTML screen.
|
590
617
|
# Makes it compatible with UTF-8.
|
591
|
-
# More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
|
618
|
+
# More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
|
592
619
|
def self.encode_exception(e, include_backtrace=true)
|
593
|
-
ret = encode_html(e.to_s)
|
620
|
+
ret = encode_html(e.to_s)
|
594
621
|
if (include_backtrace == true)
|
595
622
|
e.backtrace.each { |s|
|
596
623
|
ret += "<br/>" + encode_html(s)
|
@@ -600,8 +627,8 @@ module BlackStack
|
|
600
627
|
end
|
601
628
|
|
602
629
|
# Returns a string with a description of a period of time, to be shown in the screen.
|
603
|
-
# period: it may be 'H', 'D', 'W', 'M', 'Y'
|
604
|
-
# units: it is a positive integer
|
630
|
+
# period: it may be 'H', 'D', 'W', 'M', 'Y'
|
631
|
+
# units: it is a positive integer
|
605
632
|
def self.encode_period(period, units)
|
606
633
|
s = "Last "
|
607
634
|
s += units.to_i.to_s + " " if units.to_i > 1
|
@@ -630,87 +657,87 @@ module BlackStack
|
|
630
657
|
|
631
658
|
end # module Encoding
|
632
659
|
|
633
|
-
# -----------------------------------------------------------------------------------------
|
660
|
+
# -----------------------------------------------------------------------------------------
|
634
661
|
# DateTime
|
635
|
-
# -----------------------------------------------------------------------------------------
|
636
|
-
module DateTime
|
662
|
+
# -----------------------------------------------------------------------------------------
|
663
|
+
module DateTime
|
637
664
|
# Check the string has the format yyyymmddhhmmss.
|
638
665
|
# => Return true if success. Otherwise, return false.
|
639
666
|
# => Year cannot be lower than 1900.
|
640
|
-
# => Year cannot be higher or equal than 2100.
|
667
|
+
# => Year cannot be higher or equal than 2100.
|
641
668
|
def self.datetime_api_check(s)
|
642
|
-
return false if (s.size!=14)
|
669
|
+
return false if (s.size!=14)
|
643
670
|
year = s[0..3]
|
644
671
|
month = s[4..5]
|
645
|
-
day = s[6..7]
|
646
|
-
hour = s[8..9]
|
647
|
-
minute = s[10..11]
|
648
|
-
second = s[12..13]
|
672
|
+
day = s[6..7]
|
673
|
+
hour = s[8..9]
|
674
|
+
minute = s[10..11]
|
675
|
+
second = s[12..13]
|
649
676
|
BlackStack::DateTime::Misc::datetime_values_check(year,month,day,hour,minute,second)
|
650
677
|
end # def datetime_api_check
|
651
678
|
|
652
679
|
# Check the string has the format yyyy-mm-dd hh:mm:ss.
|
653
680
|
# => Return true if success. Otherwise, return false.
|
654
681
|
# => Year cannot be lower than 1900.
|
655
|
-
# => Year cannot be higher or equal than 2100.
|
682
|
+
# => Year cannot be higher or equal than 2100.
|
656
683
|
def self.datetime_sql_check(s)
|
657
684
|
return false if (s.size!=19)
|
658
685
|
year = s[0..3]
|
659
686
|
month = s[5..6]
|
660
|
-
day = s[8..9]
|
661
|
-
hour = s[11..12]
|
662
|
-
minute = s[14..15]
|
663
|
-
second = s[17..18]
|
687
|
+
day = s[8..9]
|
688
|
+
hour = s[11..12]
|
689
|
+
minute = s[14..15]
|
690
|
+
second = s[17..18]
|
664
691
|
BlackStack::DateTime::Misc::datetime_values_check(year,month,day,hour,minute,second)
|
665
692
|
end # def datetime_sql_check
|
666
|
-
|
693
|
+
|
667
694
|
# Convierte un string con formato api-datatime (yyyymmddhhmmss) a un string con formato sql-datetime (yyyy-mm-dd hh:mm:ss).
|
668
695
|
def self.datetime_api_to_sql(s)
|
669
696
|
raise "Wrong Api DataTime Format." if (datetime_api_check(s)==false)
|
670
697
|
year = s[0..3]
|
671
698
|
month = s[4..5]
|
672
|
-
day = s[6..7]
|
673
|
-
hour = s[8..9]
|
674
|
-
minute = s[10..11]
|
675
|
-
second = s[12..13]
|
676
|
-
ret = "#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}"
|
699
|
+
day = s[6..7]
|
700
|
+
hour = s[8..9]
|
701
|
+
minute = s[10..11]
|
702
|
+
second = s[12..13]
|
703
|
+
ret = "#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}"
|
677
704
|
return ret
|
678
|
-
end # def datetime_api_to_sql
|
679
|
-
|
705
|
+
end # def datetime_api_to_sql
|
706
|
+
|
680
707
|
# Convierte un string con formato sql-datatime a un string con formato sql-datetime.
|
681
708
|
def self.datetime_sql_to_api(s)
|
682
709
|
raise "Wrong SQL DataTime Format." if (datetime_sql_check(s)==false)
|
683
710
|
year = s[0..3]
|
684
711
|
month = s[5..6]
|
685
|
-
day = s[8..9]
|
686
|
-
hour = s[11..12]
|
687
|
-
minute = s[14..15]
|
688
|
-
second = s[17..18]
|
689
|
-
ret = "#{year}#{month}#{day}#{hour}#{minute}#{second}"
|
712
|
+
day = s[8..9]
|
713
|
+
hour = s[11..12]
|
714
|
+
minute = s[14..15]
|
715
|
+
second = s[17..18]
|
716
|
+
ret = "#{year}#{month}#{day}#{hour}#{minute}#{second}"
|
690
717
|
return ret
|
691
718
|
end # def datetime_sql_to_api
|
692
719
|
end # module DateTime
|
693
720
|
|
694
721
|
|
695
|
-
# -----------------------------------------------------------------------------------------
|
722
|
+
# -----------------------------------------------------------------------------------------
|
696
723
|
# Spinning
|
697
|
-
# -----------------------------------------------------------------------------------------
|
724
|
+
# -----------------------------------------------------------------------------------------
|
698
725
|
module Spinning
|
699
726
|
# Esta funcion retorna una variacion al azar del texto que se pasa.
|
700
727
|
# Esta funcion se ocupa de dividir el texto en partes, para eviar el error "too big to product" que arroja la libraría.
|
701
728
|
def self.random_spinning_variation(text)
|
702
729
|
ret = text
|
703
|
-
|
730
|
+
|
704
731
|
text.scan(MATCH_CONTENT_SPINNING).each { |s|
|
705
732
|
a = ContentSpinning.new(s).spin
|
706
733
|
rep = a[rand(a.size)]
|
707
734
|
ret = ret.gsub(s, rep)
|
708
735
|
a = nil
|
709
736
|
}
|
710
|
-
|
737
|
+
|
711
738
|
return ret
|
712
739
|
end
|
713
|
-
|
740
|
+
|
714
741
|
# retorna true si la sintaxis del texto spineado es correcta
|
715
742
|
# caso contrario retorna false
|
716
743
|
# no soporta spinnings anidados. ejemplo: {my|our|{a car of mine}}
|
@@ -718,16 +745,16 @@ module BlackStack
|
|
718
745
|
# valido que exste
|
719
746
|
n = 0
|
720
747
|
s.split('').each { |c|
|
721
|
-
n+=1 if c=='{'
|
748
|
+
n+=1 if c=='{'
|
722
749
|
n-=1 if c=='}'
|
723
750
|
if n!=0 && n!=1
|
724
751
|
#raise "Closing spining char '}' with not previous opening spining char '{'." if n<0
|
725
752
|
#raise "Opening spining char '{' inside another spining block." if n>1
|
726
753
|
return false if n<0 # Closing spining char '}' with not previous opening spining char '{'.
|
727
754
|
return false if n>1 # Opening spining char '{' inside another spining block.
|
728
|
-
end
|
755
|
+
end
|
729
756
|
}
|
730
|
-
|
757
|
+
|
731
758
|
return false if n!=0
|
732
759
|
=begin
|
733
760
|
# obtengo cada uno de los spinnings
|
@@ -735,21 +762,21 @@ module BlackStack
|
|
735
762
|
a = x.split('|')
|
736
763
|
raise "No variations delimited by '|' inside spinning block." if a.size <= 1
|
737
764
|
}
|
738
|
-
=end
|
765
|
+
=end
|
739
766
|
true
|
740
767
|
end
|
741
|
-
|
768
|
+
|
742
769
|
# returns true if the text is spinned.
|
743
770
|
# otherwise, returns false.
|
744
771
|
def self.spintax?(s)
|
745
772
|
s.scan(MATCH_CONTENT_SPINNING).size > 0
|
746
773
|
end
|
747
774
|
end # module Spinning
|
748
|
-
|
749
|
-
|
750
|
-
# -----------------------------------------------------------------------------------------
|
775
|
+
|
776
|
+
|
777
|
+
# -----------------------------------------------------------------------------------------
|
751
778
|
# Miscelaneus
|
752
|
-
# -----------------------------------------------------------------------------------------
|
779
|
+
# -----------------------------------------------------------------------------------------
|
753
780
|
module Misc
|
754
781
|
# make a Ruby string safe for a filesystem.
|
755
782
|
# References:
|
@@ -760,7 +787,7 @@ module BlackStack
|
|
760
787
|
# NOTE: File.basename doesn't work right with Windows paths on Unix
|
761
788
|
# get only the filename, not the whole path
|
762
789
|
name.gsub!(/^.*(\\|\/)/, '')
|
763
|
-
|
790
|
+
|
764
791
|
# Strip out the non-ascii character
|
765
792
|
name.gsub!(/[^0-9A-Za-z.\-]/, '_')
|
766
793
|
end
|
@@ -769,9 +796,9 @@ module BlackStack
|
|
769
796
|
end # module Misc
|
770
797
|
|
771
798
|
|
772
|
-
# -----------------------------------------------------------------------------------------
|
799
|
+
# -----------------------------------------------------------------------------------------
|
773
800
|
# Email Appending Functions
|
774
|
-
# -----------------------------------------------------------------------------------------
|
801
|
+
# -----------------------------------------------------------------------------------------
|
775
802
|
module Appending
|
776
803
|
APPEND_PATTERN_FNAME_DOT_LNAME = 0
|
777
804
|
APPEND_PATTERN_FNAME = 1
|
@@ -779,7 +806,7 @@ module BlackStack
|
|
779
806
|
APPEND_PATTERN_F_LNAME = 3
|
780
807
|
APPEND_PATTERN_F_DOT_LNAME = 4
|
781
808
|
|
782
|
-
#
|
809
|
+
#
|
783
810
|
def self.name_pattern(pattern, fname, lname)
|
784
811
|
if (pattern==APPEND_PATTERN_FNAME_DOT_LNAME)
|
785
812
|
return "#{fname}.#{lname}"
|
@@ -796,13 +823,13 @@ module BlackStack
|
|
796
823
|
end
|
797
824
|
end
|
798
825
|
|
799
|
-
#
|
826
|
+
#
|
800
827
|
def self.get_email_variations(first_name, last_name, domain, is_a_big_company)
|
801
828
|
variations = Array.new
|
802
829
|
variations << first_name + "." + last_name + "@" + domain
|
803
830
|
variations << first_name[0] + last_name + "@" + domain
|
804
831
|
variations << first_name + "_" + last_name + "@" + domain
|
805
|
-
variations << first_name[0] + "." + last_name + "@" + domain
|
832
|
+
variations << first_name[0] + "." + last_name + "@" + domain
|
806
833
|
if (is_a_big_company == false)
|
807
834
|
variations << last_name + "@" + domain
|
808
835
|
variations << first_name + "@" + domain
|
@@ -825,20 +852,20 @@ module BlackStack
|
|
825
852
|
end
|
826
853
|
end # module Appending
|
827
854
|
end # module String
|
828
|
-
|
829
|
-
# -----------------------------------------------------------------------------------------
|
855
|
+
|
856
|
+
# -----------------------------------------------------------------------------------------
|
830
857
|
# Network
|
831
|
-
# -----------------------------------------------------------------------------------------
|
858
|
+
# -----------------------------------------------------------------------------------------
|
832
859
|
module Netting
|
833
860
|
CALL_METHOD_GET = 'get'
|
834
861
|
CALL_METHOD_POST = 'post'
|
835
862
|
DEFAULT_SSL_VERIFY_MODE = OpenSSL::SSL::VERIFY_NONE
|
836
863
|
SUCCESS = 'success'
|
837
|
-
|
838
|
-
@@lockfiles = []
|
864
|
+
|
865
|
+
@@lockfiles = []
|
839
866
|
|
840
867
|
@@max_api_call_channels = 0 # 0 means infinite
|
841
|
-
|
868
|
+
|
842
869
|
def self.max_api_call_channels()
|
843
870
|
@@max_api_call_channels
|
844
871
|
end
|
@@ -850,7 +877,7 @@ module BlackStack
|
|
850
877
|
def self.set(h)
|
851
878
|
@@max_api_call_channels = h[:max_api_call_channels]
|
852
879
|
@@lockfiles = []
|
853
|
-
|
880
|
+
|
854
881
|
i = 0
|
855
882
|
while i<@@max_api_call_channels
|
856
883
|
@@lockfiles << File.open("./apicall.channel_#{i.to_s}.lock", "w")
|
@@ -861,18 +888,18 @@ module BlackStack
|
|
861
888
|
|
862
889
|
class ApiCallException < StandardError
|
863
890
|
attr_accessor :description
|
864
|
-
|
891
|
+
|
865
892
|
def initialize(s)
|
866
893
|
self.description = s
|
867
894
|
end
|
868
|
-
|
895
|
+
|
869
896
|
def to_s
|
870
897
|
self.description
|
871
898
|
end
|
872
899
|
end
|
873
|
-
|
900
|
+
|
874
901
|
# New call_get
|
875
|
-
def self.call_get(url, params = {}, ssl_verify_mode=BlackStack::Netting::DEFAULT_SSL_VERIFY_MODE, support_redirections=true)
|
902
|
+
def self.call_get(url, params = {}, ssl_verify_mode=BlackStack::Netting::DEFAULT_SSL_VERIFY_MODE, support_redirections=true)
|
876
903
|
uri = URI(url)
|
877
904
|
uri.query = URI.encode_www_form(params)
|
878
905
|
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https', :verify_mode => ssl_verify_mode) do |http|
|
@@ -887,7 +914,7 @@ module BlackStack
|
|
887
914
|
end
|
888
915
|
end
|
889
916
|
end
|
890
|
-
|
917
|
+
|
891
918
|
# Call the API and return th result.
|
892
919
|
#
|
893
920
|
# Unlike `Net::HTTP::Post`, this method support complex json descriptors in order to submit complex data strucutres to access points.
|
@@ -895,25 +922,25 @@ module BlackStack
|
|
895
922
|
#
|
896
923
|
# url: valid internet address
|
897
924
|
# body: hash of body to attach in the call
|
898
|
-
# ssl_verify_mode: you can disabele SSL verification here.
|
925
|
+
# ssl_verify_mode: you can disabele SSL verification here.
|
899
926
|
# max_channels: this method use lockfiles to prevent an excesive number of API calls from each datacenter. There is not allowed more simultaneous calls than max_channels.
|
900
|
-
#
|
927
|
+
#
|
901
928
|
# TODO: parameter support_redirections has been deprecated.
|
902
929
|
#
|
903
930
|
def self.call_post(url, body = {}, ssl_verify_mode=BlackStack::Netting::DEFAULT_SSL_VERIFY_MODE, support_redirections=true)
|
904
|
-
# issue: https://github.com/leandrosardi/mysaas/issues/59
|
931
|
+
# issue: https://github.com/leandrosardi/mysaas/issues/59
|
905
932
|
#
|
906
933
|
# when ruby pushes hash of hashes (or hash of arrays), all values are converted into strings.
|
907
934
|
# and arrays are mapped to the last element only.
|
908
935
|
#
|
909
936
|
# the solution is to convert each element of the hash into a string using `.to_json` method.
|
910
|
-
#
|
911
|
-
# references:
|
937
|
+
#
|
938
|
+
# references:
|
912
939
|
# - https://stackoverflow.com/questions/1667630/how-do-i-convert-a-string-object-into-a-hash-object
|
913
940
|
# - https://stackoverflow.com/questions/67572866/how-to-build-complex-json-to-post-to-a-web-service-with-rails-5-2-and-faraday-ge
|
914
|
-
#
|
941
|
+
#
|
915
942
|
# iterate the keys of the hash
|
916
|
-
#
|
943
|
+
#
|
917
944
|
params = {} # not needed for post calls to access points
|
918
945
|
path = URI::parse(url).path
|
919
946
|
domain = url.gsub(/#{Regexp.escape(path)}/, '')
|
@@ -943,7 +970,7 @@ module BlackStack
|
|
943
970
|
if (parsed['status']==BlackStack::Netting::SUCCESS)
|
944
971
|
bSuccess = true
|
945
972
|
else
|
946
|
-
sError = "Status: #{parsed['status'].to_s}. Description: #{parsed['value'].to_s}."
|
973
|
+
sError = "Status: #{parsed['status'].to_s}. Description: #{parsed['value'].to_s}."
|
947
974
|
end
|
948
975
|
rescue Errno::ECONNREFUSED => e
|
949
976
|
sError = "Errno::ECONNREFUSED:" + e.to_console
|
@@ -951,7 +978,7 @@ module BlackStack
|
|
951
978
|
sError = "Exception:" + e2.to_console
|
952
979
|
end
|
953
980
|
end # while
|
954
|
-
|
981
|
+
|
955
982
|
if (bSuccess==false)
|
956
983
|
raise "#{sError}"
|
957
984
|
end
|
@@ -962,7 +989,7 @@ module BlackStack
|
|
962
989
|
# to: must be a valid path to a folder.
|
963
990
|
def self.download(url, to)
|
964
991
|
uri = URI(url)
|
965
|
-
domain = uri.host.start_with?('www.') ? uri.host[4..-1] : uri.host
|
992
|
+
domain = uri.host.start_with?('www.') ? uri.host[4..-1] : uri.host
|
966
993
|
path = uri.path
|
967
994
|
filename = path.split("/").last
|
968
995
|
Net::HTTP.start(domain) do |http|
|
@@ -974,7 +1001,7 @@ module BlackStack
|
|
974
1001
|
end
|
975
1002
|
|
976
1003
|
# Return the extension of the last path into an URL.
|
977
|
-
# Example: get_url_extension("http://connect.data.com/sitemap_index.xml?foo_param=foo_value") => ".xml"
|
1004
|
+
# Example: get_url_extension("http://connect.data.com/sitemap_index.xml?foo_param=foo_value") => ".xml"
|
978
1005
|
def self.get_url_extension(url)
|
979
1006
|
return File.extname(URI.parse(url).path.to_s)
|
980
1007
|
end
|
@@ -1015,12 +1042,12 @@ module BlackStack
|
|
1015
1042
|
httpc = HTTPClient.new
|
1016
1043
|
resp = httpc.get(url)
|
1017
1044
|
res = resp.header['Location']
|
1018
|
-
|
1045
|
+
|
1019
1046
|
if res.size == 0
|
1020
1047
|
uri = URI.parse(url)
|
1021
1048
|
uri_params = CGI.parse(uri.query)
|
1022
|
-
redirected_url = uri_params['url'][0]
|
1023
|
-
|
1049
|
+
redirected_url = uri_params['url'][0]
|
1050
|
+
|
1024
1051
|
if ( redirected_url != nil )
|
1025
1052
|
res = redirected_url
|
1026
1053
|
else
|
@@ -1044,25 +1071,25 @@ module BlackStack
|
|
1044
1071
|
# => p = CGI::parse(URI.parse(url).query)
|
1045
1072
|
# => La linea de abajo hace un gsbub que hace que esta url siga funcionando como busqueda de google, y ademas se posible parsearla.
|
1046
1073
|
url = url.gsub("webhp#q=", "webhp?q=")
|
1047
|
-
|
1074
|
+
|
1048
1075
|
return CGI::parse(URI.parse(url).query)
|
1049
1076
|
end
|
1050
|
-
|
1077
|
+
|
1051
1078
|
# Add a parameter to the url. It doesn't validate if the param already exists.
|
1052
1079
|
def self.add_param(url, param_name, param_value)
|
1053
1080
|
uri = URI(url)
|
1054
1081
|
params = URI.decode_www_form(uri.query || '')
|
1055
|
-
|
1082
|
+
|
1056
1083
|
if (params.size==0)
|
1057
1084
|
params << [param_name, param_value]
|
1058
1085
|
uri.query = URI.encode_www_form(params)
|
1059
1086
|
return uri.to_s
|
1060
1087
|
else
|
1061
1088
|
uri.query = URI.encode_www_form(params)
|
1062
|
-
return uri.to_s + "&" + param_name + "=" + param_value
|
1089
|
+
return uri.to_s + "&" + param_name + "=" + param_value
|
1063
1090
|
end
|
1064
1091
|
end
|
1065
|
-
|
1092
|
+
|
1066
1093
|
# Changes the value of a parameter in the url. It doesn't validate if the param already exists.
|
1067
1094
|
def self.change_param(url, param_name, param_value)
|
1068
1095
|
uri = URI(url)
|
@@ -1072,10 +1099,10 @@ module BlackStack
|
|
1072
1099
|
uri.query = URI.encode_www_form(params)
|
1073
1100
|
uri.to_s
|
1074
1101
|
end
|
1075
|
-
|
1102
|
+
|
1076
1103
|
# Change or add the value of a parameter in the url, depending if the parameter already exists or not.
|
1077
1104
|
def self.set_param(url, param_name, param_value)
|
1078
|
-
params = BlackStack::Netting::params(url)
|
1105
|
+
params = BlackStack::Netting::params(url)
|
1079
1106
|
if ( params.has_key?(param_name) == true )
|
1080
1107
|
newurl = BlackStack::Netting::change_param(url, param_name, param_value)
|
1081
1108
|
else
|
@@ -1083,24 +1110,24 @@ module BlackStack
|
|
1083
1110
|
end
|
1084
1111
|
return newurl
|
1085
1112
|
end
|
1086
|
-
|
1113
|
+
|
1087
1114
|
# get the domain from any url
|
1088
1115
|
def self.getDomainFromUrl(url)
|
1089
|
-
if (url !~ /^http:\/\//i && url !~ /^https:\/\//i)
|
1116
|
+
if (url !~ /^http:\/\//i && url !~ /^https:\/\//i)
|
1090
1117
|
url = "http://#{url}"
|
1091
1118
|
end
|
1092
|
-
|
1119
|
+
|
1093
1120
|
if (URI.parse(url).host == nil)
|
1094
|
-
raise "Cannot get domain for #{url}"
|
1121
|
+
raise "Cannot get domain for #{url}"
|
1095
1122
|
end
|
1096
|
-
|
1123
|
+
|
1097
1124
|
if (url.to_s.length>0)
|
1098
1125
|
return URI.parse(url).host.sub(/^www\./, '')
|
1099
1126
|
else
|
1100
1127
|
return nil
|
1101
1128
|
end
|
1102
1129
|
end
|
1103
|
-
|
1130
|
+
|
1104
1131
|
def self.getDomainFromEmail(email)
|
1105
1132
|
if email.email?
|
1106
1133
|
return email.split("@").last
|
@@ -1108,35 +1135,35 @@ module BlackStack
|
|
1108
1135
|
raise "getDomainFromEmail: Wrong email format."
|
1109
1136
|
end
|
1110
1137
|
end
|
1111
|
-
|
1138
|
+
|
1112
1139
|
def self.getWhoisDomains(domain, allow_heuristic_to_avoid_hosting_companies=false)
|
1113
1140
|
a = Array.new
|
1114
1141
|
c = Whois::Client.new
|
1115
1142
|
r = c.lookup(domain)
|
1116
|
-
|
1143
|
+
|
1117
1144
|
res = r.to_s.scan(/Registrant Email: (#{BlackStack::Strings::MATCH_EMAIL})/).first
|
1118
1145
|
if (res!=nil)
|
1119
1146
|
a << BlackStack::Netting::getDomainFromEmail(res[0].downcase)
|
1120
1147
|
end
|
1121
|
-
|
1148
|
+
|
1122
1149
|
res = r.to_s.scan(/Admin Email: (#{BlackStack::Strings::MATCH_EMAIL})/).first
|
1123
1150
|
if (res!=nil)
|
1124
1151
|
a << BlackStack::Netting::getDomainFromEmail(res[0].downcase)
|
1125
1152
|
end
|
1126
|
-
|
1153
|
+
|
1127
1154
|
res = r.to_s.scan(/Tech Email: (#{BlackStack::Strings::MATCH_EMAIL})/).first
|
1128
1155
|
if (res!=nil)
|
1129
1156
|
a << BlackStack::Netting::getDomainFromEmail(res[0].downcase)
|
1130
1157
|
end
|
1131
|
-
|
1158
|
+
|
1132
1159
|
# remover duplicados
|
1133
1160
|
a = a.uniq
|
1134
|
-
|
1135
|
-
#
|
1161
|
+
|
1162
|
+
#
|
1136
1163
|
if (allow_heuristic_to_avoid_hosting_companies==true)
|
1137
1164
|
# TODO: develop this feature
|
1138
1165
|
end
|
1139
|
-
|
1166
|
+
|
1140
1167
|
return a
|
1141
1168
|
end
|
1142
1169
|
|
@@ -1164,11 +1191,11 @@ module BlackStack
|
|
1164
1191
|
raise "Email #{value} is not valid" if !value.email?
|
1165
1192
|
# extract the domain from the email
|
1166
1193
|
domain = value.split('@').last
|
1167
|
-
#
|
1194
|
+
#
|
1168
1195
|
return domain=~/gmail\.com/ || domain=~/hotmail\.com/ || domain=~/outlook\.com/ || domain=~/yahoo\.com/ || domain=~/comcast\.com/ || domain=~/aol\.com/ || domain=~/msn\.com/ || domain=~/sbcglobal\.net/ ? true : false
|
1169
1196
|
end
|
1170
1197
|
|
1171
1198
|
|
1172
1199
|
end # module Netting
|
1173
|
-
|
1200
|
+
|
1174
1201
|
end # module BlackStack
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blackstack-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.29
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leandro Daniel Sardi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: content_spinning
|