pwn 0.4.658 → 0.4.659
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/.gitignore +1 -0
- data/Gemfile +1 -1
- data/README.md +2 -2
- data/lib/pwn/plugins/open_ai.rb +383 -12
- data/lib/pwn/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0eb080cab0eea6cae868fb9d0cebac5614531ec77d43a581e9bee728b0d207a
|
4
|
+
data.tar.gz: fa6165a643f5e062047eb695528e5c1c04d8f62d2804bf4a5092a9febb224b48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77265b7ee61cce81ef319ed3f86a07d0a4f025562f167534ed6e1bef56e7e07a3d11bc46bb27ef65626fec3678808961f1661a98673e51b32024c56f3abf8fa1
|
7
|
+
data.tar.gz: 93534d53a13e0a065ff026d68d5090d22e51a8a84f2e61485499e880d623b8361eeffb23805eb9aba4a60fdb4960754fa4c34e6f73f0fdaf4adfd96ac1475206
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -37,7 +37,7 @@ $ rvm use ruby-3.2.2@pwn
|
|
37
37
|
$ rvm list gemsets
|
38
38
|
$ gem install --verbose pwn
|
39
39
|
$ pwn
|
40
|
-
pwn[v0.4.
|
40
|
+
pwn[v0.4.659]:001 >>> PWN.help
|
41
41
|
```
|
42
42
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.2.2@pwn
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
53
53
|
$ gem install --verbose pwn
|
54
54
|
$ pwn
|
55
|
-
pwn[v0.4.
|
55
|
+
pwn[v0.4.659]:001 >>> PWN.help
|
56
56
|
```
|
57
57
|
|
58
58
|
|
data/lib/pwn/plugins/open_ai.rb
CHANGED
@@ -30,39 +30,66 @@ module PWN
|
|
30
30
|
end
|
31
31
|
rest_call = opts[:rest_call].to_s.scrub
|
32
32
|
params = opts[:params]
|
33
|
-
http_body = opts[:http_body]
|
33
|
+
http_body = opts[:http_body]
|
34
|
+
http_body ||= {}
|
34
35
|
base_open_ai_api_uri = 'https://api.openai.com/v1'
|
35
36
|
token = opts[:token]
|
36
37
|
|
38
|
+
content_type = 'application/json; charset=UTF-8'
|
39
|
+
|
37
40
|
rest_client = PWN::Plugins::TransparentBrowser.open(browser_type: :rest)::Request
|
38
41
|
spinner = TTY::Spinner.new
|
39
42
|
spinner.auto_spin
|
40
43
|
|
41
44
|
case http_method
|
42
|
-
when :
|
45
|
+
when :delete
|
43
46
|
response = rest_client.execute(
|
44
|
-
method: :
|
47
|
+
method: :delete,
|
45
48
|
url: "#{base_open_ai_api_uri}/#{rest_call}",
|
46
49
|
headers: {
|
47
|
-
content_type:
|
50
|
+
content_type: content_type,
|
48
51
|
authorization: "Bearer #{token}",
|
49
52
|
params: params
|
50
53
|
},
|
51
54
|
verify_ssl: false
|
52
55
|
)
|
53
56
|
|
54
|
-
when :
|
57
|
+
when :get
|
55
58
|
response = rest_client.execute(
|
56
|
-
method: :
|
59
|
+
method: :get,
|
57
60
|
url: "#{base_open_ai_api_uri}/#{rest_call}",
|
58
61
|
headers: {
|
59
|
-
content_type:
|
60
|
-
authorization: "Bearer #{token}"
|
62
|
+
content_type: content_type,
|
63
|
+
authorization: "Bearer #{token}",
|
64
|
+
params: params
|
61
65
|
},
|
62
|
-
payload: http_body,
|
63
66
|
verify_ssl: false
|
64
67
|
)
|
65
68
|
|
69
|
+
when :post
|
70
|
+
if http_body.key?(:multipart)
|
71
|
+
response = rest_client.execute(
|
72
|
+
method: :post,
|
73
|
+
url: "#{base_open_ai_api_uri}/#{rest_call}",
|
74
|
+
headers: {
|
75
|
+
authorization: "Bearer #{token}"
|
76
|
+
},
|
77
|
+
payload: http_body,
|
78
|
+
verify_ssl: false
|
79
|
+
)
|
80
|
+
else
|
81
|
+
response = rest_client.execute(
|
82
|
+
method: :post,
|
83
|
+
url: "#{base_open_ai_api_uri}/#{rest_call}",
|
84
|
+
headers: {
|
85
|
+
content_type: content_type,
|
86
|
+
authorization: "Bearer #{token}"
|
87
|
+
},
|
88
|
+
payload: http_body.to_json,
|
89
|
+
verify_ssl: false
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
66
93
|
else
|
67
94
|
raise @@logger.error("Unsupported HTTP Method #{http_method} for #{self} Plugin")
|
68
95
|
end
|
@@ -80,7 +107,7 @@ module PWN
|
|
80
107
|
|
81
108
|
# Supported Method Parameters::
|
82
109
|
# response = PWN::Plugins::OpenAI.get_models(
|
83
|
-
# token: 'required - Bearer token'
|
110
|
+
# token: 'required - Bearer token'
|
84
111
|
# )
|
85
112
|
|
86
113
|
public_class_method def self.get_models(opts = {})
|
@@ -181,7 +208,7 @@ module PWN
|
|
181
208
|
http_method: :post,
|
182
209
|
token: token,
|
183
210
|
rest_call: rest_call,
|
184
|
-
http_body: http_body
|
211
|
+
http_body: http_body
|
185
212
|
)
|
186
213
|
|
187
214
|
json_resp = JSON.parse(response, symbolize_names: true)
|
@@ -259,7 +286,298 @@ module PWN
|
|
259
286
|
http_method: :post,
|
260
287
|
token: token,
|
261
288
|
rest_call: rest_call,
|
262
|
-
http_body: http_body
|
289
|
+
http_body: http_body
|
290
|
+
)
|
291
|
+
|
292
|
+
JSON.parse(response, symbolize_names: true)
|
293
|
+
rescue StandardError => e
|
294
|
+
raise e
|
295
|
+
end
|
296
|
+
|
297
|
+
# Supported Method Parameters::
|
298
|
+
# response = PWN::Plugins::OpenAI.create_fine_tune(
|
299
|
+
# token: 'required - Bearer token',
|
300
|
+
# training_file: 'required - JSONL that contains OpenAI training data'
|
301
|
+
# validation_file: 'optional - JSONL that contains OpenAI validation data'
|
302
|
+
# model: 'optional - :ada||:babbage||:curie||:davinci (defaults to :davinci)',
|
303
|
+
# n_epochs: 'optional - iterate N times through training_file to train the model (defaults to 4)',
|
304
|
+
# batch_size: 'optional - batch size to use for training (defaults to nil)',
|
305
|
+
# learning_rate_multipler: 'optional - fine-tuning learning rate is the original learning rate used for pretraining multiplied by this value (defaults to nil)',
|
306
|
+
# prompt_loss_weight: 'optional - (defaults to 0.01)',
|
307
|
+
# computer_classification_metrics: 'optional - calculate classification-specific metrics such as accuracy and F-1 score using the validation set at the end of every epoch (defaults to false)',
|
308
|
+
# classification_n_classes: 'optional - number of classes in a classification task (defaults to nil)',
|
309
|
+
# classification_positive_class: 'optional - generate precision, recall, and F1 metrics when doing binary classification (defaults to nil)',
|
310
|
+
# classification_betas: 'optional - calculate F-beta scores at the specified beta values (defaults to nil)',
|
311
|
+
# suffix: 'optional - string of up to 40 characters that will be added to your fine-tuned model name (defaults to nil)',
|
312
|
+
# )
|
313
|
+
|
314
|
+
public_class_method def self.create_fine_tune(opts = {})
|
315
|
+
token = opts[:token]
|
316
|
+
training_file = opts[:training_file]
|
317
|
+
validation_file = opts[:validation_file]
|
318
|
+
model = opts[:model]
|
319
|
+
model ||= :davinci
|
320
|
+
|
321
|
+
n_epochs = opts[:n_epochs]
|
322
|
+
n_epochs ||= 4
|
323
|
+
|
324
|
+
batch_size = opts[:batch_size]
|
325
|
+
learning_rate_multipler = opts[:learning_rate_multipler]
|
326
|
+
|
327
|
+
prompt_loss_weight = opts[:prompt_loss_weight]
|
328
|
+
prompt_loss_weight ||= 0.01
|
329
|
+
|
330
|
+
computer_classification_metrics = true if opts[:computer_classification_metrics]
|
331
|
+
classification_n_classes = opts[:classification_n_classes]
|
332
|
+
classification_positive_class = opts[:classification_positive_class]
|
333
|
+
classification_betas = opts[:classification_betas]
|
334
|
+
suffix = opts[:suffix]
|
335
|
+
|
336
|
+
response = upload_file(
|
337
|
+
token: token,
|
338
|
+
file: training_file
|
339
|
+
)
|
340
|
+
training_file = response[:id]
|
341
|
+
|
342
|
+
if validation_file
|
343
|
+
response = upload_file(
|
344
|
+
token: token,
|
345
|
+
file: validation_file
|
346
|
+
)
|
347
|
+
validation_file = response[:id]
|
348
|
+
end
|
349
|
+
|
350
|
+
http_body = {}
|
351
|
+
http_body[:training_file] = training_file
|
352
|
+
http_body[:validation_file] = validation_file if validation_file
|
353
|
+
http_body[:model] = model
|
354
|
+
http_body[:n_epochs] = n_epochs
|
355
|
+
http_body[:batch_size] = batch_size if batch_size
|
356
|
+
http_body[:learning_rate_multipler] = learning_rate_multipler if learning_rate_multipler
|
357
|
+
http_body[:prompt_loss_weight] = prompt_loss_weight if prompt_loss_weight
|
358
|
+
http_body[:computer_classification_metrics] = computer_classification_metrics if computer_classification_metrics
|
359
|
+
http_body[:classification_n_classes] = classification_n_classes if classification_n_classes
|
360
|
+
http_body[:classification_positive_class] = classification_positive_class if classification_positive_class
|
361
|
+
http_body[:classification_betas] = classification_betas if classification_betas
|
362
|
+
http_body[:suffix] = suffix if suffix
|
363
|
+
|
364
|
+
response = open_ai_rest_call(
|
365
|
+
http_method: :post,
|
366
|
+
token: token,
|
367
|
+
rest_call: 'fine-tunes',
|
368
|
+
http_body: http_body
|
369
|
+
)
|
370
|
+
|
371
|
+
JSON.parse(response, symbolize_names: true)
|
372
|
+
rescue StandardError => e
|
373
|
+
raise e
|
374
|
+
end
|
375
|
+
|
376
|
+
# Supported Method Parameters::
|
377
|
+
# response = PWN::Plugins::OpenAI.list_fine_tunes(
|
378
|
+
# token: 'required - Bearer token'
|
379
|
+
# )
|
380
|
+
|
381
|
+
public_class_method def self.list_fine_tunes(opts = {})
|
382
|
+
token = opts[:token]
|
383
|
+
|
384
|
+
response = open_ai_rest_call(
|
385
|
+
token: token,
|
386
|
+
rest_call: 'fine-tunes'
|
387
|
+
)
|
388
|
+
|
389
|
+
JSON.parse(response, symbolize_names: true)
|
390
|
+
rescue StandardError => e
|
391
|
+
raise e
|
392
|
+
end
|
393
|
+
|
394
|
+
# Supported Method Parameters::
|
395
|
+
# response = PWN::Plugins::OpenAI.get_fine_tune_status(
|
396
|
+
# token: 'required - Bearer token',
|
397
|
+
# fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
|
398
|
+
# )
|
399
|
+
|
400
|
+
public_class_method def self.get_fine_tune_status(opts = {})
|
401
|
+
token = opts[:token]
|
402
|
+
fine_tune_id = opts[:fine_tune_id]
|
403
|
+
|
404
|
+
rest_call = "fine-tunes/#{fine_tune_id}"
|
405
|
+
|
406
|
+
response = open_ai_rest_call(
|
407
|
+
token: token,
|
408
|
+
rest_call: rest_call
|
409
|
+
)
|
410
|
+
|
411
|
+
JSON.parse(response, symbolize_names: true)
|
412
|
+
rescue StandardError => e
|
413
|
+
raise e
|
414
|
+
end
|
415
|
+
|
416
|
+
# Supported Method Parameters::
|
417
|
+
# response = PWN::Plugins::OpenAI.cancel_fine_tune(
|
418
|
+
# token: 'required - Bearer token',
|
419
|
+
# fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
|
420
|
+
# )
|
421
|
+
|
422
|
+
public_class_method def self.cancel_fine_tune(opts = {})
|
423
|
+
token = opts[:token]
|
424
|
+
fine_tune_id = opts[:fine_tune_id]
|
425
|
+
|
426
|
+
rest_call = "fine-tunes/#{fine_tune_id}/cancel"
|
427
|
+
|
428
|
+
response = open_ai_rest_call(
|
429
|
+
http_method: :post,
|
430
|
+
token: token,
|
431
|
+
rest_call: rest_call
|
432
|
+
)
|
433
|
+
|
434
|
+
JSON.parse(response, symbolize_names: true)
|
435
|
+
rescue StandardError => e
|
436
|
+
raise e
|
437
|
+
end
|
438
|
+
|
439
|
+
# Supported Method Parameters::
|
440
|
+
# response = PWN::Plugins::OpenAI.get_fine_tune_events(
|
441
|
+
# token: 'required - Bearer token',
|
442
|
+
# fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
|
443
|
+
# )
|
444
|
+
|
445
|
+
public_class_method def self.get_fine_tune_events(opts = {})
|
446
|
+
token = opts[:token]
|
447
|
+
fine_tune_id = opts[:fine_tune_id]
|
448
|
+
|
449
|
+
rest_call = "fine-tunes/#{fine_tune_id}/events"
|
450
|
+
|
451
|
+
response = open_ai_rest_call(
|
452
|
+
token: token,
|
453
|
+
rest_call: rest_call
|
454
|
+
)
|
455
|
+
|
456
|
+
JSON.parse(response, symbolize_names: true)
|
457
|
+
rescue StandardError => e
|
458
|
+
raise e
|
459
|
+
end
|
460
|
+
|
461
|
+
# Supported Method Parameters::
|
462
|
+
# response = PWN::Plugins::OpenAI.delete_fine_tune_model(
|
463
|
+
# token: 'required - Bearer token',
|
464
|
+
# model: 'required - model to delete'
|
465
|
+
# )
|
466
|
+
|
467
|
+
public_class_method def self.delete_fine_tune_model(opts = {})
|
468
|
+
token = opts[:token]
|
469
|
+
model = opts[:model]
|
470
|
+
|
471
|
+
rest_call = "models/#{model}"
|
472
|
+
|
473
|
+
response = open_ai_rest_call(
|
474
|
+
http_method: :delete,
|
475
|
+
token: token,
|
476
|
+
rest_call: rest_call
|
477
|
+
)
|
478
|
+
|
479
|
+
JSON.parse(response, symbolize_names: true)
|
480
|
+
rescue StandardError => e
|
481
|
+
raise e
|
482
|
+
end
|
483
|
+
|
484
|
+
# Supported Method Parameters::
|
485
|
+
# response = PWN::Plugins::OpenAI.list_files(
|
486
|
+
# token: 'required - Bearer token'
|
487
|
+
# )
|
488
|
+
|
489
|
+
public_class_method def self.list_files(opts = {})
|
490
|
+
token = opts[:token]
|
491
|
+
|
492
|
+
response = open_ai_rest_call(
|
493
|
+
token: token,
|
494
|
+
rest_call: 'files'
|
495
|
+
)
|
496
|
+
|
497
|
+
JSON.parse(response, symbolize_names: true)
|
498
|
+
rescue StandardError => e
|
499
|
+
raise e
|
500
|
+
end
|
501
|
+
|
502
|
+
# Supported Method Parameters::
|
503
|
+
# response = PWN::Plugins::OpenAI.upload_file(
|
504
|
+
# token: 'required - Bearer token',
|
505
|
+
# file: 'required - file to upload',
|
506
|
+
# purpose: 'optional - intended purpose of the uploaded documents (defaults to fine-tune'
|
507
|
+
# )
|
508
|
+
|
509
|
+
public_class_method def self.upload_file(opts = {})
|
510
|
+
token = opts[:token]
|
511
|
+
file = opts[:file]
|
512
|
+
raise "ERROR: #{file} not found." unless File.exist?(file)
|
513
|
+
|
514
|
+
purpose = opts[:purpose]
|
515
|
+
purpose ||= 'fine-tune'
|
516
|
+
|
517
|
+
http_body = {
|
518
|
+
multipart: true,
|
519
|
+
file: File.new(file, 'rb'),
|
520
|
+
purpose: purpose
|
521
|
+
}
|
522
|
+
|
523
|
+
response = open_ai_rest_call(
|
524
|
+
http_method: :post,
|
525
|
+
token: token,
|
526
|
+
rest_call: 'files',
|
527
|
+
http_body: http_body
|
528
|
+
)
|
529
|
+
|
530
|
+
JSON.parse(response, symbolize_names: true)
|
531
|
+
rescue StandardError => e
|
532
|
+
raise e
|
533
|
+
end
|
534
|
+
|
535
|
+
# Supported Method Parameters::
|
536
|
+
# response = PWN::Plugins::OpenAI.delete_file(
|
537
|
+
# token: 'required - Bearer token',
|
538
|
+
# file: 'required - file to delete'
|
539
|
+
# )
|
540
|
+
|
541
|
+
public_class_method def self.delete_file(opts = {})
|
542
|
+
token = opts[:token]
|
543
|
+
file = opts[:file]
|
544
|
+
raise "ERROR: #{file} not found." unless File.exist?(file)
|
545
|
+
|
546
|
+
response = list_files(token: token)
|
547
|
+
file_id = response[:data].select { |f| f if f[:filename] == File.basename(file) }.first[:id]
|
548
|
+
|
549
|
+
rest_call = "files/#{file_id}"
|
550
|
+
|
551
|
+
response = open_ai_rest_call(
|
552
|
+
http_method: :delete,
|
553
|
+
token: token,
|
554
|
+
rest_call: rest_call
|
555
|
+
)
|
556
|
+
|
557
|
+
JSON.parse(response, symbolize_names: true)
|
558
|
+
rescue StandardError => e
|
559
|
+
raise e
|
560
|
+
end
|
561
|
+
|
562
|
+
# Supported Method Parameters::
|
563
|
+
# response = PWN::Plugins::OpenAI.get_file(
|
564
|
+
# token: 'required - Bearer token',
|
565
|
+
# file: 'required - file to delete'
|
566
|
+
# )
|
567
|
+
|
568
|
+
public_class_method def self.get_file(opts = {})
|
569
|
+
token = opts[:token]
|
570
|
+
file = opts[:file]
|
571
|
+
raise "ERROR: #{file} not found." unless File.exist?(file)
|
572
|
+
|
573
|
+
response = list_files(token: token)
|
574
|
+
file_id = response[:data].select { |f| f if f[:filename] == File.basename(file) }.first[:id]
|
575
|
+
|
576
|
+
rest_call = "files/#{file_id}"
|
577
|
+
|
578
|
+
response = open_ai_rest_call(
|
579
|
+
token: token,
|
580
|
+
rest_call: rest_call
|
263
581
|
)
|
264
582
|
|
265
583
|
JSON.parse(response, symbolize_names: true)
|
@@ -279,6 +597,10 @@ module PWN
|
|
279
597
|
|
280
598
|
public_class_method def self.help
|
281
599
|
puts "USAGE:
|
600
|
+
response = #{self}.get_models(
|
601
|
+
token: 'required - Bearer token'
|
602
|
+
)
|
603
|
+
|
282
604
|
response = #{self}.chat(
|
283
605
|
token: 'required - Bearer token',
|
284
606
|
request: 'required - message to ChatGPT',
|
@@ -296,6 +618,55 @@ module PWN
|
|
296
618
|
size: 'optional - size of image (defaults to \"1024x1024\")'
|
297
619
|
)
|
298
620
|
|
621
|
+
response = #{self}.create_fine_tune(
|
622
|
+
token: 'required - Bearer token',
|
623
|
+
training_file: 'required - JSONL that contains OpenAI training data'
|
624
|
+
validation_file: 'optional - JSONL that contains OpenAI validation data'
|
625
|
+
model: 'optional - :ada||:babbage||:curie||:davinci (defaults to :davinci)',
|
626
|
+
n_epochs: 'optional - iterate N times through training_file to train the model (defaults to 4)',
|
627
|
+
batch_size: 'optional - batch size to use for training (defaults to nil)',
|
628
|
+
learning_rate_multipler: 'optional - fine-tuning learning rate is the original learning rate used for pretraining multiplied by this value (defaults to nill)',
|
629
|
+
prompt_loss_weight: 'optional - (defaults to nil)',
|
630
|
+
computer_classification_metrics: 'optional - calculate classification-specific metrics such as accuracy and F-1 score using the validation set at the end of every epoch (defaults to false)',
|
631
|
+
classification_n_classes: 'optional - number of classes in a classification task (defaults to nil)',
|
632
|
+
classification_positive_class: 'optional - generate precision, recall, and F1 metrics when doing binary classification (defaults to nil)',
|
633
|
+
classification_betas: 'optional - calculate F-beta scores at the specified beta values (defaults to nil)',
|
634
|
+
suffix: 'optional - string of up to 40 characters that will be added to your fine-tuned model name (defaults to nil)',
|
635
|
+
)
|
636
|
+
|
637
|
+
response = #{self}.list_fine_tunes(
|
638
|
+
token: 'required - Bearer token'
|
639
|
+
)
|
640
|
+
|
641
|
+
response = #{self}.get_fine_tune_status(
|
642
|
+
token: 'required - Bearer token',
|
643
|
+
fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
|
644
|
+
)
|
645
|
+
|
646
|
+
response = #{self}.get_fine_tune_events(
|
647
|
+
token: 'required - Bearer token',
|
648
|
+
fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
|
649
|
+
)
|
650
|
+
|
651
|
+
response = #{self}.list_files(
|
652
|
+
token: 'required - Bearer token'
|
653
|
+
)
|
654
|
+
|
655
|
+
response = #{self}.upload_file(
|
656
|
+
token: 'required - Bearer token',
|
657
|
+
file: 'required - file to upload'
|
658
|
+
)
|
659
|
+
|
660
|
+
response = #{self}.delete_file(
|
661
|
+
token: 'required - Bearer token',
|
662
|
+
file: 'required - file to delete'
|
663
|
+
)
|
664
|
+
|
665
|
+
response = #{self}.get_file(
|
666
|
+
token: 'required - Bearer token',
|
667
|
+
file: 'required - file to delete'
|
668
|
+
)
|
669
|
+
|
299
670
|
#{self}.authors
|
300
671
|
"
|
301
672
|
end
|
data/lib/pwn/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.659
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -590,14 +590,14 @@ dependencies:
|
|
590
590
|
requirements:
|
591
591
|
- - '='
|
592
592
|
- !ruby/object:Gem::Version
|
593
|
-
version: 1.5.
|
593
|
+
version: 1.5.3
|
594
594
|
type: :runtime
|
595
595
|
prerelease: false
|
596
596
|
version_requirements: !ruby/object:Gem::Requirement
|
597
597
|
requirements:
|
598
598
|
- - '='
|
599
599
|
- !ruby/object:Gem::Version
|
600
|
-
version: 1.5.
|
600
|
+
version: 1.5.3
|
601
601
|
- !ruby/object:Gem::Dependency
|
602
602
|
name: pry
|
603
603
|
requirement: !ruby/object:Gem::Requirement
|