transactable 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 404d0f0a1a1fb991362a94978a3c75d0867bbbe89d929760c367ccac052199fb
4
- data.tar.gz: 0e4ecc36c6a2d5c7ec907b07b89725603441f597e8b1e420e9547ea2fb9572ca
3
+ metadata.gz: d17683ad67f8fca4a79b13497ad7e19c46b1dd0614783e4296cbe551bae7f6be
4
+ data.tar.gz: 22c0954b70991d59a4637548580f692db6413236e35393b5d352bc8ef9acebee
5
5
  SHA512:
6
- metadata.gz: 0e5c5320afa0b195e513caff0ca9e00f2a03671c5aa3816104f0e45f93f01ac5ebb0afb72e40a32a747652e39a651e0f4891c76de6a6794080e0cbc2918f81a0
7
- data.tar.gz: 1ce19a3efd0c0585b01f8cc2c1558d875af07fe05e32042d993522655c3c0bcb50ff1ba4622a5249be2d994339893828e2dfff7cfb1a492758706c0fa6d96fff
6
+ metadata.gz: 26348144c79119b8eeb8748ca30f6af243a1bb8f554bfda111dbcf037440338573c14610ae7138b977edbac4db8375cfd9797409012a871087ee5c6aa51eab4a
7
+ data.tar.gz: 7ade67cf3843ad63694575e27269269fe5cb4043673465a254095a8468c6cf59e74a1e7455d6e34aa63a0934b4ab380ece8cbd3971ee2124f660d551e3b715bf
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -3,26 +3,31 @@
3
3
  :figure-caption!:
4
4
 
5
5
  :command_pattern_link: link:https://alchemists.io/articles/command_pattern[Command Pattern]
6
- :function_composition_link: link:https://alchemists.io/articles/ruby_function_composition[Function Composition]
7
6
  :debug_link: link:https://github.com/ruby/debug[Debug]
8
7
  :dry_container_link: link:https://dry-rb.org/gems/dry-container[Dry Container]
9
8
  :dry_events_link: link:https://dry-rb.org/gems/dry-events[Dry Events]
10
9
  :dry_monads_link: link:https://dry-rb.org/gems/dry-monads[Dry Monads]
11
10
  :dry_schema_link: link:https://dry-rb.org/gems/dry-schema[Dry Schema]
12
11
  :dry_validation_link: link:https://dry-rb.org/gems/dry-validation[Dry Validation]
12
+ :function_composition_link: link:https://alchemists.io/articles/ruby_function_composition[Function Composition]
13
+ :infusible_link: link:https://alchemists.io/projects/infusible[Infusible]
14
+ :railway_pattern_link: link:https://fsharpforfunandprofit.com/posts/recipe-part2[Railway Pattern]
13
15
 
14
16
  = Transactable
15
17
 
16
- A DSL for transactional workflows built atop function composition. This allows you to write in a syntax that builds upon -- and abstracts away -- native function composition support while allowing you to cleanly read the code from left-to-right or top-to-bottom sequentially.
18
+ A DSL for transactional workflows built atop native {function_composition_link} which leverages the {railway_pattern_link}. This allows you to write a sequence of _steps_ that cleanly read from left-to-right or top-to-bottom which results in a success or a failure without having to rely on exceptions which are expensive.
17
19
 
18
20
  toc::[]
19
21
 
20
22
  == Features
21
23
 
22
- * Built on top of native function composition capabilities.
23
- * Customizable with additional or entirely different steps.
24
- * Chainable where you can couple together multiple transactions to build more complex architectures.
25
- * Instrumentable so you can track metrics, log usage, and much more.
24
+ * Built atop of native {function_composition_link}.
25
+ * Adheres to the {railway_pattern_link}.
26
+ * Provides built-in and customizable domain-specific steps.
27
+ * Provides chainable _pipes_ which can be used to build more complex workflows.
28
+ * Supports instrumentation for tracking metrics, logging usage, and much more.
29
+ * Compatible with {dry_monads_link}.
30
+ * Compatible with {infusible_link}.
26
31
 
27
32
  == Requirements
28
33
 
@@ -80,7 +85,7 @@ class Demo
80
85
  def call data
81
86
  pipe data,
82
87
  check(/Book.+Price/, :match?),
83
- method(:parse),
88
+ :parse,
84
89
  map { |item| "#{item[:book]}: #{item[:price]}" }
85
90
  end
86
91
 
@@ -98,21 +103,17 @@ class Demo
98
103
  end
99
104
  ----
100
105
 
101
- The above allows the `Demo#call` method to be a _transactional_ series of composed steps which may pass or fail where each step is piped together via {dry_monads_link}. This is the essence of the _Railway Pattern_.
106
+ The above allows `Demo#call` to be a _transactional_ sequence steps which may pass or fail due to all step being {dry_monads_link}. This is the essence of the {railway_pattern_link}.
102
107
 
103
108
  To execute the above example, you'd only need to pass CSV content to it:
104
109
 
105
110
  [source,ruby]
106
111
  ----
107
- csv = <<~CSV
112
+ Demo.new.call <<~CSV
108
113
  Book,Author,Price,At
109
114
  Mystics,urGoh,10.50,2022-01-01
110
115
  Skeksis,skekSil,20.75,2022-02-13
111
116
  CSV
112
-
113
- demo = Demo.new
114
-
115
- demo.call csv
116
117
  ----
117
118
 
118
119
  The computed result is a success with each book listing a price:
@@ -123,22 +124,22 @@ Success ["Mystics: 10.50", "Skeksis: 20.75"]
123
124
 
124
125
  === Pipe
125
126
 
126
- Once you've included the `Transactable` module within your class, the `#pipe` method is available to you and is how you build a series of steps for processing. The method signature is:
127
+ Once you've included the `Transactable` module within your class, the `#pipe` method is available to you and is how you build a sequence of steps for processing. The method signature is:
127
128
 
128
129
  [source,ruby]
129
130
  ----
130
131
  pipe(input, *steps)
131
132
  ----
132
133
 
133
- The first argument is your input which can be a Ruby primitive or a monad. Regardless, the input will be automatically wrapped as a `Success` -- but only if not a `Result` to begin with -- before passing to the first step. From there, all steps are _required_ to answer a monad in order to adhere to the _Railway Pattern_.
134
+ The first argument is your input which can be a Ruby primitive or a monad. Regardless, the input will be automatically wrapped as a `Success` -- but only if not a `Result` to begin with -- before passing to the first step. From there, all steps are _required_ to answer a monad in order to adhere to the {railway_pattern_link}.
134
135
 
135
- Behind the scenes, the `#pipe` method is syntactic sugar on top of function composition which means if this code were to be rewritten:
136
+ Behind the scenes, the `#pipe` method is syntactic sugar on top of {function_composition_link} which means if this code were to be rewritten:
136
137
 
137
138
  [source,ruby]
138
139
  ----
139
140
  pipe csv,
140
141
  check(/Book.+Price/, :match?),
141
- method(:parse),
142
+ :parse,
142
143
  map { |item| "#{item[:book]}: #{item[:price]}" }
143
144
  ----
144
145
 
@@ -153,7 +154,7 @@ Then the above would look like this using native Ruby:
153
154
  ).call Success(csv)
154
155
  ----
155
156
 
156
- The only problem with native function composition is that it reads backwards by passing in your input at the end of all sequential steps. With the `#pipe` method, you have the benefit of allowing your eye to read the code from top to bottom in addition to not having to type multiple _forward composition_ operators.
157
+ The problem with native function composition is that it reads backwards by passing your input at the end of all sequential steps. With the `#pipe` method, you have the benefit of allowing your eye to read the code from top to bottom in addition to not having to type multiple _forward composition_ operators.
157
158
 
158
159
  === Steps
159
160
 
@@ -379,7 +380,7 @@ class Demo
379
380
  def call input
380
381
  pipe :a,
381
382
  insert(:b),
382
- method(:join),
383
+ :join,
383
384
  as(:to_sym)
384
385
  end
385
386
 
@@ -391,6 +392,8 @@ end
391
392
  Demo.new.call :a # Yields: Success :a_b
392
393
  ----
393
394
 
395
+ All methods can be referenced by symbol as shown via `:join` above. Using a symbol is syntactic sugar for link:https://rubyapi.org/o/object#method-i-method[Object#method] so the use of the `:join` symbol is the same as using `method(:join)`. Both work but the former requires less typing than the latter.
396
+
394
397
  ℹ️ You won't be able to instrument these method calls (unless you inject instrumentation) but are great when needing additional behavior between the default steps.
395
398
 
396
399
  ===== Custom
@@ -406,8 +409,6 @@ Here's what this would look like:
406
409
  ----
407
410
  module MySteps
408
411
  class Join < Transactable::Steps::Abstract
409
- prepend Transactable::Instrumentable
410
-
411
412
  def initialize(delimiter = "_", **)
412
413
  super(**)
413
414
  @delimiter = delimiter
@@ -425,18 +426,10 @@ Transactable::Steps::Container.register(:join) { MySteps::Join }
425
426
 
426
427
  include Transactable
427
428
 
428
- pipe :a,
429
- insert(:b),
430
- join,
431
- as(:to_sym)
432
-
429
+ pipe :a, insert(:b), join, as(:to_sym)
433
430
  # Yields: Success :a_b
434
431
 
435
- pipe :a,
436
- insert(:b),
437
- join(""),
438
- as(:to_sym)
439
-
432
+ pipe :a, insert(:b), join(""), as(:to_sym)
440
433
  # Yields: Success :ab
441
434
  ----
442
435
 
@@ -505,7 +498,7 @@ step: {:name=>"Transactable::Steps::Map", :arguments=>[[], {}, #<Proc:0x00000001
505
498
  step.success: {:name=>"Transactable::Steps::Map", :value=>["Mystics: 10.50", "Skeksis: 20.75"], :arguments=>[[], {}, #<Proc:0x0000000106405900 (irb):15>]}
506
499
  ....
507
500
 
508
- Finally, the `Transactable::Instrumentable` module is available should you need to _prepend_ instrumentation to any of your classes.
501
+ Finally, the `Transactable::Instrumentable` module is available should you need to _prepend_ instrumentation to any of your class' `#call` methods.
509
502
 
510
503
  There is a lot you can do with instrumentation so check out the {dry_events_link} documentation for further details.
511
504
 
@@ -532,12 +525,12 @@ bin/console
532
525
  The architecture of this gem is built on top of the following concepts and gems:
533
526
 
534
527
  * {function_composition_link}: Made possible through the use of the `\#>>` and `#<<` methods on the link:https://rubyapi.org/3.1/o/method[Method] and link:https://rubyapi.org/3.1/o/proc[Proc] objects.
535
- * {dry_container_link} - Allows related dependencies to be grouped together for injection.
536
- * {dry_events_link} - Allows all steps to be observable so you can subscribe to any/all events for metric, logging, and other capabilities.
537
- * {dry_monads_link} - Critical to ensuring the entire pipeline of steps adhere to the _Railway Pattern_ and leans heavily on the `Result` object.
538
- * link:https://dry-rb.org/gems/dry-transaction[Dry Transaction] - Specifically the concept of a _step_ where each step can have an _operation_ and/or _input_ to be processed. Instrumentation is used as well so you can have rich metrics, logging, or any other kind of observer wired up as desired.
539
- * link:https://alchemists.io/projects/infusible[Infusible] - Coupled with {dry_container_link}, allows dependencies to be automatically injected.
540
- * link:https://alchemists.io/projects/marameters[Marameters] - Through the use of the `.categorize` method, dynamic message passing is possible by inspecting the operation method's parameters.
528
+ * {dry_container_link}: Allows related dependencies to be grouped together for injection as desired.
529
+ * {dry_events_link}: Allows all steps to be observable so you can subscribe to any/all events for metric, logging, and other capabilities.
530
+ * {dry_monads_link}: Critical to ensuring the entire pipeline of steps adhere to the {railway_pattern_link} and leans heavily on the `Result` object.
531
+ * link:https://dry-rb.org/gems/dry-transaction[Dry Transaction]: Specifically the concept of a _step_ where each step can have an _operation_ and/or _input_ to be processed. Instrumentation is used as well so you can have rich metrics, logging, or any other kind of observer wired up as desired.
532
+ * link:https://alchemists.io/projects/infusible[Infusible]: Coupled with {dry_container_link}, allows dependencies to be automatically injected.
533
+ * link:https://alchemists.io/projects/marameters[Marameters]: Through the use of the `.categorize` method, dynamic message passing is possible by inspecting the operation method's parameters.
541
534
 
542
535
  === Style Guide
543
536
 
@@ -546,7 +539,6 @@ The architecture of this gem is built on top of the following concepts and gems:
546
539
  * *Steps*
547
540
  ** Inherit from the `Abstract` class in order to gain monad, composition, and dependency behavior. Any dependencies injected are automatically filtered out so all subclasses have direct and clean access to the base positional, keyword, and block arguments. These variables are prefixed with `base_*` in order to not conflict with subclasses which might only want to use non-prefixed variables for convenience.
548
541
  ** All filtered arguments -- in other words, the unused arguments -- need to be passed up to the superclass from the subclass (i.e. `super(*positionals, **keywords, &block)`). Doing so allows the superclass (i.e. `Abstract`) to provide access to `base_positionals`, `base_keywords`, and `base_block` for use if desired by the subclass.
549
- ** Prepend `Instrumentable` to gain instrumentation behavior and remain consistent with existing steps. This includes adding the `with instrumentation` RSpec shared context when testing too.
550
542
  ** The `#call` method must define a single positional `result` parameter since a monad will be passed as an argument. Example: `def call(result) = # Implementation`.
551
543
  ** Each block within the `#call` method should use the `input` parameter to be consistent. More specific parameters like `argument` or `operation` should be used to improve readability when possible. Example: `def call(result) = result.bind { |input| # Implementation }`.
552
544
  ** Use implicit blocks sparingly. Most of the default steps shy away from using blocks because it can make the code more complex. Use private methods, custom steps, and/or separate transactions if the code becomes too complex because you might have a smaller object which needs extraction.
@@ -560,7 +552,7 @@ If you need to debug (i.e. {debug_link}) your pipe, use a lambda. Example:
560
552
  pipe data,
561
553
  check(/Book.+Price/, :match?),
562
554
  -> result { binding.break }, # Breakpoint
563
- method(:parse),
555
+ :parse
564
556
  ----
565
557
 
566
558
  The above breakpoint will allow you inspect the result of the `#check` step and/or build a modified result for passing to the subsequent `#method` step.
@@ -573,7 +565,7 @@ The following might be of aid to as you implement your own transactions.
573
565
 
574
566
  If you get a `TypeError: Step must be functionally composable and answer a monad`, it means:
575
567
 
576
- . The step must be a `Proc` or some object which responds to `\#>>`, `#<<`, and `#call`.
568
+ . The step must be a `Proc`, `Method`, or some object which responds to `\#>>`, `#<<`, and `#call`.
577
569
  . The step doesn't answer a result monad (i.e. `Success some_value` or `Failure some_value`).
578
570
 
579
571
  ==== No Method Errors
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Transactable
6
+ # Provids low-level functionality that can process a sequence of steps.
7
+ Pipe = lambda do |input, *steps|
8
+ fail ArgumentError, "Pipe must have at least one step." if steps.empty?
9
+
10
+ result = input.is_a?(Dry::Monads::Result) ? input : Dry::Monads::Success(input)
11
+
12
+ steps.reduce(&:>>).call result
13
+ rescue NoMethodError
14
+ raise TypeError, "Step must be functionally composable and answer a monad."
15
+ end
16
+ end
@@ -1,13 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/monads"
4
+ require "refinements/arrays"
4
5
 
5
6
  module Transactable
6
7
  # Allows any object to pipe sequential steps together which can be composed into a single result.
7
8
  class Pipeable < Module
8
- def initialize steps = Steps::Container
9
+ include Dry::Monads[:result]
10
+
11
+ using Refinements::Arrays
12
+
13
+ def initialize steps = Steps::Container, pipe: Pipe
9
14
  super()
10
15
  @steps = steps
16
+ @pipe = pipe
11
17
  @instance_module = Class.new(Module).new
12
18
  end
13
19
 
@@ -20,17 +26,14 @@ module Transactable
20
26
 
21
27
  private
22
28
 
23
- attr_reader :steps, :instance_module
29
+ attr_reader :steps, :pipe, :instance_module
24
30
 
25
31
  def define_pipe
26
- instance_module.define_method :pipe do |input, *steps|
27
- fail ArgumentError, "Transaction must have at least one step." if steps.empty?
32
+ local_pipe = pipe
28
33
 
29
- result = input.is_a?(Dry::Monads::Result) ? input : Dry::Monads::Success(input)
30
-
31
- steps.reduce(&:>>).call result
32
- rescue NoMethodError
33
- raise TypeError, "Step must be functionally composable and answer a monad."
34
+ instance_module.define_method :pipe do |input, *steps|
35
+ steps.each { |step| steps.supplant step, method(step) if step.is_a? Symbol }
36
+ local_pipe.call(input, *steps)
34
37
  end
35
38
  end
36
39
 
@@ -12,6 +12,11 @@ module Transactable
12
12
  include Dry::Monads[:result]
13
13
  include Composable
14
14
 
15
+ def self.inherited descendant
16
+ super
17
+ descendant.prepend Instrumentable
18
+ end
19
+
15
20
  def initialize *positionals, **keywords, &block
16
21
  super(**keywords.slice(*DEPENDENCIES))
17
22
  @base_positionals = positionals
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Allows result to be messaged as a callable.
6
6
  class As < Abstract
7
- prepend Instrumentable
8
-
9
7
  def call result
10
8
  result.fmap { |operation| operation.public_send(*base_positionals, **base_keywords) }
11
9
  end
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Wraps Dry Monads `#bind` method as a step.
6
6
  class Bind < Abstract
7
- prepend Instrumentable
8
-
9
7
  def call(result) = result.bind { |input| base_block.call input }
10
8
  end
11
9
  end
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Checks if operation is true and then answers success (passthrough) or failure (with argument).
6
6
  class Check < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize(operation, message, **)
10
8
  super(**)
11
9
  @operation = operation
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Wraps Dry Monads `#fmap` method as a step.
6
6
  class Fmap < Abstract
7
- prepend Instrumentable
8
-
9
7
  def call(result) = result.fmap { |input| base_block.call input }
10
8
  end
11
9
  end
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Inserts elements before, after, or around input.
6
6
  class Insert < Abstract
7
- prepend Instrumentable
8
-
9
7
  LAST = -1
10
8
 
11
9
  def initialize(*positionals, at: LAST, **)
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Maps over a collection, processing each element, and answering a new result.
6
6
  class Map < Abstract
7
- prepend Instrumentable
8
-
9
7
  def call(result) = result.fmap { |collection| collection.map(&base_block) }
10
8
  end
11
9
  end
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Merges initialized attributes with step argument for use by a subsequent step.
6
6
  class Merge < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize as: :step, **keywords
10
8
  super(**keywords)
11
9
  @as = as
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Wraps Dry Monads `#or` method as a step.
6
6
  class Or < Abstract
7
- prepend Instrumentable
8
-
9
7
  def call(result) = result.or { |input| base_block.call input }
10
8
  end
11
9
  end
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Messages operation, without any response checks, while passing input through as output.
6
6
  class Tee < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize(operation, *, **)
10
8
  super(*, **)
11
9
  @operation = operation
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Delegates to a non-callable operation which automatically wraps the result if necessary.
6
6
  class To < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize(operation, message, **)
10
8
  super(**)
11
9
  @operation = operation
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Messages a risky operation which may pass or fail.
6
6
  class Try < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize *positionals, catch:, **keywords
10
8
  super(*positionals, **keywords)
11
9
  @catch = catch
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Use another transaction -- or any command -- which answers a result.
6
6
  class Use < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize(operation, **)
10
8
  super(**)
11
9
  @operation = operation
@@ -4,8 +4,6 @@ module Transactable
4
4
  module Steps
5
5
  # Validates a result via a callable operation.
6
6
  class Validate < Abstract
7
- prepend Instrumentable
8
-
9
7
  def initialize(operation, as: :to_h, **)
10
8
  super(**)
11
9
  @operation = operation
data/lib/transactable.rb CHANGED
@@ -6,7 +6,7 @@ Zeitwerk::Loader.for_gem.setup
6
6
 
7
7
  # Main namespace.
8
8
  module Transactable
9
- def self.included(klass) = klass.include Pipeable.new
9
+ def self.included(descendant) = descendant.include Pipeable.new
10
10
 
11
11
  def self.with(...) = Pipeable.new(...)
12
12
  end
data/transactable.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "transactable"
5
- spec.version = "0.5.2"
5
+ spec.version = "0.6.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/transactable"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transactable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -35,7 +35,7 @@ cert_chain:
35
35
  3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
36
36
  gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
37
37
  -----END CERTIFICATE-----
38
- date: 2023-07-23 00:00:00.000000000 Z
38
+ date: 2023-09-16 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: dry-container
@@ -152,6 +152,7 @@ files:
152
152
  - lib/transactable/import.rb
153
153
  - lib/transactable/instrument.rb
154
154
  - lib/transactable/instrumentable.rb
155
+ - lib/transactable/pipe.rb
155
156
  - lib/transactable/pipeable.rb
156
157
  - lib/transactable/steps/abstract.rb
157
158
  - lib/transactable/steps/as.rb
@@ -195,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
196
  - !ruby/object:Gem::Version
196
197
  version: '0'
197
198
  requirements: []
198
- rubygems_version: 3.4.17
199
+ rubygems_version: 3.4.19
199
200
  signing_key:
200
201
  specification_version: 4
201
202
  summary: A domain specific language for functionally composable transactional workflows.
metadata.gz.sig CHANGED
@@ -1,4 +1 @@
1
- SHW�[�9"��q�jAFzM��#��,5���)����E�[�iN�'|�q:��3_�~d8�'��E6[(ڂ�j�F��Q��[y��u*>0��)�� әC�&R~BLGP��
2
- ��d>�-�_y!�g��o��pP�:��.a1&�z���"eF7P���[ ��r��r�%d�/=��1>�P`Je����"��"�&w��nR?g� ��1���\�������~�;~��
3
- *�'N?�_g�n��hsU�^�/ ��pҷ�;U��jP6h���C_4KS^'��n���9^ V�����輇XC� ��y��u8���"`��ARx���0�Ջ� M��]vkU�~� {f
4
- �,�m�*&�j�e2fͨI��4���v
1
+ }��6��,�������-Kش�aP�&d���Dž����x��)���`����[Y��#�r��y��k�s1r�ծ8Y ��-�����_L �0�Ԗ09�Z��m�G�ﳦ0p���q+�U���K(&l��&�GKi��Ph��e��r䞪��n`5��ޯb|�eY��ˑxP��K`gQ��x~ΰ�Xu��*����G���7��P�תuqlC��� _}O�y;��B���g�h#��)���[.p3_��������bEm���P��x0W��q5��0�.a�� ����d;�qKfbe���$ !2��2���No�Mɷ'�8G1-�g��vB��'���#ؼR"NL�F�p*���]��?˘A��ڪ��