edits 0.3.0 → 0.5.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: 1c829d27a322f8c9b3ad50437a3b66d2548ccfc40d435ebaee4c362b22802fb8
4
- data.tar.gz: dd351b715125154bd7f9b37b98fd1f75aea504163fe550795c0615af1fea9b65
3
+ metadata.gz: e464255bd53bdeea1b7a599d4a8463518a46d4b836fca0a65be8148de7e793db
4
+ data.tar.gz: b65f244baa43185798e50bd0ee486cb40e923e200242d15f5c59ba2df02e0eec
5
5
  SHA512:
6
- metadata.gz: 8d5b3cd301621b913768f63c50f4876a340f620c22c2fbe68d1659bd1566141f6a737264dfb3da15f0b7a7e1a567a1036dcd978cd9c2001210f843a1e5da8f93
7
- data.tar.gz: 821c4cd4acf9e2b9e25c21ce2f61a4f489838c4252fd6c4e0fd323fe9b5f3baaa1948e3ab87b0c1448830e39c9ff2362aa457e4fe9ce902994545dd8c986137e
6
+ metadata.gz: e3ee90cc881ae7e73affb987052c3bc542e68c9e3538babd25f72c38d22adf76e6eda178ee8fa2b837b06cc84b610faa2695796b690336310a0219c806ea343b
7
+ data.tar.gz: 71999dca3d06c3cedba61b8ffbe4a9c844884149269b20f0e45a3f9191cdb900f465f61f0b0f3cd3cf0bf67f16a7c071cb20da474a1be88db91df4cf2e09ac33
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
@@ -0,0 +1,43 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ tags: [ 'v*.*.*' ]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ packages: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - name: Set up Ruby 2.7
18
+ uses: actions/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.7.x
21
+
22
+ - name: Publish to GPR
23
+ run: |
24
+ mkdir -p $HOME/.gem
25
+ touch $HOME/.gem/credentials
26
+ chmod 0600 $HOME/.gem/credentials
27
+ printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
28
+ gem build *.gemspec
29
+ gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
30
+ env:
31
+ GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
32
+ OWNER: ${{ github.repository_owner }}
33
+
34
+ - name: Publish to RubyGems
35
+ run: |
36
+ mkdir -p $HOME/.gem
37
+ touch $HOME/.gem/credentials
38
+ chmod 0600 $HOME/.gem/credentials
39
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
40
+ gem build *.gemspec
41
+ gem push *.gem
42
+ env:
43
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -0,0 +1,41 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ pull_request:
13
+ branches: [ main ]
14
+
15
+ jobs:
16
+ test:
17
+
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ ruby-version: ["2.7", "3.0", "3.1"]
22
+ allow-failure: [false]
23
+ include:
24
+ - ruby-version: "ruby-head"
25
+ allow-failure: true
26
+ continue-on-error: ${{ matrix.allow-failure }}
27
+
28
+ steps:
29
+ - name: Checkout 🛎
30
+ uses: actions/checkout@v2
31
+ - name: Set up Ruby
32
+ uses: ruby/setup-ruby@v1
33
+ with:
34
+ ruby-version: ${{ matrix.ruby-version }}
35
+ bundler-cache: true
36
+ - name: Run tests
37
+ run: bundle exec rake
38
+ - name: Run codacy-coverage-reporter 📈
39
+ uses: codacy/codacy-coverage-reporter-action@v1
40
+ with:
41
+ project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.5
2
+ TargetRubyVersion: 2.7
3
3
  Metrics/AbcSize:
4
4
  Enabled: false
5
5
  Metrics/CyclomaticComplexity:
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # Edits
2
2
 
3
- [![Gem Version](https://img.shields.io/gem/v/edits.svg)](https://rubygems.org/gems/edits)
4
- [![Build Status](https://travis-ci.org/tcrouch/edits.svg?branch=master)](https://travis-ci.org/tcrouch/edits)
5
- [![Codacy Badge](https://api.codacy.com/project/badge/Grade/64cb50b8e9ce4ec2a752d091e441b09d)](https://app.codacy.com/app/t.crouch/edits?utm_source=github.com&utm_medium=referral&utm_content=tcrouch/edits&utm_campaign=Badge_Grade_Dashboard)
6
- [![Inline docs](http://inch-ci.org/github/tcrouch/edits.svg?branch=master)](http://inch-ci.org/github/tcrouch/edits)
7
- [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/tcrouch/edits)
3
+ [![Gem](https://img.shields.io/gem/v/edits)](https://rubygems.org/gems/edits)
4
+ [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/tcrouch/edits/Ruby/main)](https://github.com/tcrouch/edits/actions/workflows/ruby.yml)
5
+ [![Inline docs](http://inch-ci.org/github/tcrouch/edits.svg?branch=master)](https://inch-ci.org/github/tcrouch/edits)
6
+ [![Yard Docs](https://img.shields.io/badge/yard-docs-informational)](https://rubydoc.info/github/tcrouch/edits)
8
7
 
9
8
  A collection of edit distance algorithms in Ruby.
10
9
 
11
- Includes Levenshtein, Restricted Edit (Optimal Alignment) and Damerau-Levenshtein distances, and Jaro & Jaro-Winkler similarity.
10
+ Includes Levenshtein, Restricted Edit (Optimal Alignment) and
11
+ Damerau-Levenshtein distances, and Jaro and Jaro-Winkler similarity.
12
12
 
13
13
  ## Installation
14
14
 
@@ -32,62 +32,57 @@ $ gem install edits
32
32
 
33
33
  ## Usage
34
34
 
35
- ### Levenshtein
35
+ ### Levenshtein variants
36
36
 
37
- Edit distance, accounting for deletion, addition and substitution.
37
+ Calculate the edit distance between two sequences with variants of the
38
+ Levenshtein distance algorithm.
38
39
 
39
40
  ```ruby
40
41
  Edits::Levenshtein.distance "raked", "bakers"
41
42
  # => 3
42
- Edits::Levenshtein.distance "iota", "atom"
43
- # => 4
44
- Edits::Levenshtein.distance "acer", "earn"
45
- # => 4
46
-
47
- # Max distance
48
- Edits::Levenshtein.distance_with_max "iota", "atom", 2
49
- # => 2
50
- Edits::Levenshtein.most_similar "atom", %w[tree rota toes racer]
51
- # => "toes"
43
+ Edits::RestrictedEdit.distance "iota", "atom"
44
+ # => 3
45
+ Edits::DamerauLevenshtein.distance "acer", "earn"
46
+ # => 3
52
47
  ```
53
48
 
54
- ### Restricted Edit (Optimal Alignment)
49
+ - **Levenshtein** edit distance, counting insertion, deletion and
50
+ substitution.
51
+ - **Restricted Damerau-Levenshtein** edit distance (aka **Optimal Alignment**),
52
+ counting insertion, deletion, substitution and transposition
53
+ (adjacent symbols swapped). Restricted by the condition that no substring is
54
+ edited more than once.
55
+ - **Damerau-Levenshtein** edit distance, counting insertion, deletion,
56
+ substitution and transposition (adjacent symbols swapped).
55
57
 
56
- Edit distance, accounting for deletion, addition, substitution and
57
- transposition (two adjacent characters are swapped). This variant is
58
- restricted by the condition that no sub-string is edited more than once.
58
+ | | Levenshtein | Restricted Damerau-Levenshtein | Damerau-Levenshtein |
59
+ |----------------------|-------------|--------------------------------|---------------------|
60
+ | "raked" vs. "bakers" | 3 | 3 | 3 |
61
+ | "iota" vs. "atom" | 4 | 3 | 3 |
62
+ | "acer" vs. "earn" | 4 | 4 | 3 |
59
63
 
60
- ```ruby
61
- Edits::RestrictedEdit.distance "raked", "bakers"
62
- # => 3
63
- Edits::RestrictedEdit.distance "iota", "atom"
64
- # => 3
65
- Edits::RestrictedEdit.distance "acer", "earn"
66
- # => 4
64
+ Levenshtein and Restricted Edit distances also have a bounded version.
67
65
 
66
+
67
+ ```ruby
68
68
  # Max distance
69
- Edits::RestrictedEdit.distance_with_max "iota", "atom", 2
70
- # => 2
71
- Edits::RestrictedEdit.most_similar "atom", %w[tree rota toes racer]
72
- # => "rota"
69
+ Edits::Levenshtein.distance_with_max "fghijk", "abcde", 3
70
+ # => 3
73
71
  ```
74
72
 
75
- ### Damerau-Levenshtein
76
-
77
- Edit distance, accounting for deletions, additions, substitution and
78
- transposition (two adjacent characters are swapped).
73
+ The convenience method `most_similar` searches for the best match to a
74
+ given sequence from a collection. It is similar to using `min_by`, but leverages
75
+ a maximum bound.
79
76
 
80
77
  ```ruby
81
- Edits::DamerauLevenshtein.distance "raked", "bakers"
82
- # => 3
83
- Edits::DamerauLevenshtein.distance "iota", "atom"
84
- # => 3
85
- Edits::DamerauLevenshtein.distance "acer", "earn"
86
- # => 3
78
+ Edits::RestrictedEdit.most_similar "atom", ["iota", "tome", "mown", "tame"]
79
+ # => "tome"
87
80
  ```
88
81
 
89
82
  ### Jaro & Jaro-Winkler
90
83
 
84
+ Calculate the Jaro and Jaro-Winkler similarity/distance of two sequences.
85
+
91
86
  ```ruby
92
87
  Edits::Jaro.similarity "information", "informant"
93
88
  # => 0.90235690235690236
@@ -102,6 +97,8 @@ Edits::JaroWinkler.distance "information", "informant"
102
97
 
103
98
  ### Hamming
104
99
 
100
+ Calculate the hamming distance between two sequences.
101
+
105
102
  ```ruby
106
103
  Edits::Hamming.distance("explorer", "exploded")
107
104
  # => 2
data/edits.gemspec CHANGED
@@ -25,13 +25,14 @@ Gem::Specification.new do |spec|
25
25
  spec.bindir = "exe"
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ["lib"]
28
+ spec.required_ruby_version = ">= 2.7"
28
29
 
29
- spec.add_development_dependency "benchmark-ips", "~> 2.7"
30
+ spec.add_development_dependency "benchmark-ips", "~> 2.8"
30
31
  spec.add_development_dependency "bundler", "~> 2.0"
31
32
  spec.add_development_dependency "rake", "~> 13.0"
32
- spec.add_development_dependency "redcarpet", "~> 3.4"
33
- spec.add_development_dependency "rspec", "~> 3.6"
34
- spec.add_development_dependency "simplecov", "~> 0.18"
33
+ spec.add_development_dependency "redcarpet", "~> 3.5"
34
+ spec.add_development_dependency "rspec", "~> 3.9"
35
+ spec.add_development_dependency "simplecov", "~> 0.21"
35
36
  spec.add_development_dependency "simplecov-lcov", "~> 0.8"
36
37
  spec.add_development_dependency "yard", "~> 0.9"
37
38
  end
data/lib/edits/compare.rb CHANGED
@@ -22,7 +22,7 @@ module Edits
22
22
  min_s = strings[0]
23
23
  min_d = distance(prototype, min_s)
24
24
 
25
- strings[1..-1].each do |s|
25
+ strings[1..].each do |s|
26
26
  return min_s if min_d.zero?
27
27
 
28
28
  d = distance_with_max(prototype, s, min_d)
@@ -21,70 +21,66 @@ module Edits
21
21
  seq1, seq2 = seq2, seq1 if seq1.length > seq2.length
22
22
 
23
23
  # array of codepoints outperforms String
24
- seq1 = seq1.codepoints if seq1.is_a? String
25
- seq2 = seq2.codepoints if seq2.is_a? String
24
+ if seq1.is_a?(String) && seq2.is_a?(String)
25
+ seq1 = seq1.codepoints
26
+ seq2 = seq2.codepoints
27
+ end
26
28
 
27
29
  rows = seq1.length
28
30
  cols = seq2.length
29
31
  return cols if rows == 0
30
32
  return rows if cols == 0
31
33
 
32
- # 'infinite' edit distance for padding cost matrix.
33
- # Can be any value > max[rows, cols]
34
- inf = rows + cols
35
-
36
- # Initialize first two rows of cost matrix.
37
- # The full initial state where cols=3, rows=2 (inf=5) would be:
38
- # [[5, 5, 5, 5, 5],
39
- # [5, 0, 1, 2, 3],
40
- # [5, 1, 0, 0, 0],
41
- # [5, 2, 0, 0, 0]]
42
- matrix = [Array.new(cols + 2, inf)]
43
- matrix << 0.upto(cols).to_a.unshift(inf)
34
+ # 'infinite' edit distance to pad cost matrix.
35
+ # Any value > max[rows, cols]
36
+ inf = cols + 1
44
37
 
45
38
  # element => last row seen
46
- item_history = Hash.new(0)
39
+ row_history = Hash.new(0)
47
40
 
48
- 1.upto(rows) do |row|
49
- # generate next row of cost matrix
50
- new_row = Array.new(cols + 2, 0)
51
- new_row[0] = inf
52
- new_row[1] = row
53
- matrix << new_row
41
+ # initialize alphabet-keyed cost matrix
42
+ matrix = {}
43
+ curr_row = 0.upto(cols).to_a
54
44
 
55
- last_match_col = 0
56
- seq1_item = seq1[row - 1]
45
+ rows.times do |row|
46
+ seq1_item = seq1[row]
47
+ match_col = 0
57
48
 
58
- 1.upto(cols) do |col|
59
- seq2_item = seq2[col - 1]
60
- last_match_row = item_history[seq2_item]
49
+ # rotate row arrays & generate next
50
+ matrix[seq1_item] = last_row = curr_row
51
+ curr_row = Array.new(cols + 1, inf)
52
+ curr_row[0] = row + 1
61
53
 
54
+ cols.times do |col|
55
+ seq2_item = seq2[col]
62
56
  sub_cost = seq1_item == seq2_item ? 0 : 1
63
57
 
64
- transposition = 1 + matrix[last_match_row][last_match_col]
65
- transposition += row - last_match_row - 1
66
- transposition += col - last_match_col - 1
67
-
68
- # TODO: do insertion/deletion need to be considered when
69
- # seq1_item == seq2_item ?
70
- #
71
- # substitution, deletion, insertion, transposition
58
+ # | Xs | Xd |
59
+ # | Xi | ? |
60
+ # substitution, deletion, insertion
72
61
  cost = [
73
- matrix[row][col] + sub_cost,
74
- matrix[row][col + 1] + 1,
75
- matrix[row + 1][col] + 1,
76
- transposition
62
+ last_row[col] + sub_cost,
63
+ last_row[col + 1] + 1,
64
+ curr_row[col] + 1
77
65
  ].min
78
66
 
79
- matrix[row + 1][col + 1] = cost
80
-
81
- last_match_col = col if sub_cost == 0
67
+ # transposition cost
68
+ # skip missed matrix lookup (inf cost)
69
+ if sub_cost > 0 && row > 0 && (m = matrix[seq2_item])
70
+ transpose = 1 + m[match_col] \
71
+ + (row - row_history[seq2_item] - 1) \
72
+ + (col - match_col - 1)
73
+ cost = transpose if transpose < cost
74
+ end
75
+
76
+ match_col = col if sub_cost == 0
77
+ curr_row[col + 1] = cost
82
78
  end
83
79
 
84
- item_history[seq1_item] = row
80
+ row_history[seq1_item] = row
85
81
  end
86
82
 
87
- matrix[rows + 1][cols + 1]
83
+ curr_row[cols]
88
84
  end
89
85
  end
90
86
  end
data/lib/edits/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Edits
4
4
  # Current gem version
5
- VERSION = "0.3.0"
5
+ VERSION = "0.5.0"
6
6
  end
@@ -162,7 +162,7 @@ namespace :benchmark do
162
162
 
163
163
  x.report "literal, +" do
164
164
  m = []
165
- m << [rows] + Array.new(cols, 0)
165
+ m << ([rows] + Array.new(cols, 0))
166
166
  end
167
167
 
168
168
  x.compare!
@@ -195,7 +195,7 @@ namespace :benchmark do
195
195
 
196
196
  x.report "literal, +" do
197
197
  m = []
198
- m << [rows, inf] + Array.new(cols, 0)
198
+ m << ([rows, inf] + Array.new(cols, 0))
199
199
  end
200
200
 
201
201
  x.compare!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: edits
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Crouch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-21 00:00:00.000000000 Z
11
+ date: 2022-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.7'
19
+ version: '2.8'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.7'
26
+ version: '2.8'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,42 +58,42 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.4'
61
+ version: '3.5'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.4'
68
+ version: '3.5'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '3.6'
75
+ version: '3.9'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '3.6'
82
+ version: '3.9'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.18'
89
+ version: '0.21'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.18'
96
+ version: '0.21'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov-lcov
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -132,10 +132,12 @@ executables: []
132
132
  extensions: []
133
133
  extra_rdoc_files: []
134
134
  files:
135
+ - ".github/dependabot.yml"
136
+ - ".github/workflows/gem-push.yml"
137
+ - ".github/workflows/ruby.yml"
135
138
  - ".gitignore"
136
139
  - ".rspec"
137
140
  - ".rubocop.yml"
138
- - ".travis.yml"
139
141
  - ".yardopts"
140
142
  - Gemfile
141
143
  - LICENSE.txt
@@ -167,15 +169,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
169
  requirements:
168
170
  - - ">="
169
171
  - !ruby/object:Gem::Version
170
- version: '0'
172
+ version: '2.7'
171
173
  required_rubygems_version: !ruby/object:Gem::Requirement
172
174
  requirements:
173
175
  - - ">="
174
176
  - !ruby/object:Gem::Version
175
177
  version: '0'
176
178
  requirements: []
177
- rubyforge_project:
178
- rubygems_version: 2.7.7
179
+ rubygems_version: 3.1.6
179
180
  signing_key:
180
181
  specification_version: 4
181
182
  summary: A collection of edit distance algorithms.
data/.travis.yml DELETED
@@ -1,35 +0,0 @@
1
- os: linux
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.4
6
- - 2.5
7
- - 2.6.5
8
- - 2.7
9
- - ruby-head
10
- - rbx-3
11
- before_install:
12
- - gem update --system
13
- - gem install bundler
14
- - sudo apt-get install jq
15
- - curl -LSs "$(curl -LSs https://api.github.com/repos/codacy/codacy-coverage-reporter/releases/latest | jq -r '.assets | map({name, browser_download_url} | select(.name | endswith(".jar"))) | .[0].browser_download_url')" -o codacy-coverage-reporter-assembly.jar
16
- after_success:
17
- - java -jar codacy-coverage-reporter-assembly.jar report -l Ruby -r coverage/lcov/edits.lcov
18
- jobs:
19
- allow_failures:
20
- - rvm: ruby-head
21
- - rvm: rbx-3
22
- fast_finish: true
23
- include:
24
- - stage: gem release
25
- if: tag IS present
26
- rvm: 2.6.5
27
- script: echo "Deploying to rubygems.org ..."
28
- deploy:
29
- provider: rubygems
30
- api_key:
31
- secure: NKUWS12yMpsMtPeKL+4X56xZ02p5y4R+HYQmgvxFNajOS42aTMXncx4eTnuHoNdKbh+x5yci+lbPr+j5t9qWo5GzJsxjqnFW4lO2V5O1ONBzcAB/g6BPDMQsWbX34eBVafCEidNoOY1HhLlKerWzlsGRq+P4q+3WKLJihrl99pyv+EQykqS11/YVCsmFjrPVa/aGk84njbnI/kIDOY5HV2gVBazARixRO5y2AUg3hRUf2+Tu/X1ke80YBD9LazW2kRUzz0Rs+1vc653JtYn6MeK/bEkGWvN2Qs/k6Q2nNr6ni4v39Y07yylu1EnYh1H/0OT/H2hehxsjMQCQhDlVKbN7NTmOV026aWXA2HdSxmVhxQCIKRGW3Nm81kBj1/edXLpJActnLeex2iCMcXJk8yAAzF0q+vSHLld0w9Jx95kIJB4tnaonWJxcaWaX58HWFbdOuYKvQhXqcflI4KmNH8xXm/O0FIM8VEJRg9dojZ5S8Us3fZpBFZxVJ3H3Fcb406AmoIqcHOsqJ1GvBM8EdWkwuaH9GsUWf8pydgKFgStYUaKk8DDmJonT748emG4yw+78uMGWPoFxf+Mc8jazRxIaRiQbjVFUcLjaRkRFlL8UT9BB9k7c1egjvKhUo/pqV7KIEsAJrrh6zZIkz4h9AwxWpZjVj9+z63Kh6NC1lUI=
32
- gem: edits
33
- on:
34
- tags: true
35
- repo: tcrouch/edits