bonio-scatter_swap 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +105 -0
- data/Rakefile +1 -0
- data/bonio-scatter_swap.gemspec +36 -0
- data/lib/bonio-scatter_swap.rb +3 -0
- data/lib/scatter_swap.rb +14 -0
- data/lib/scatter_swap/hasher.rb +75 -0
- data/lib/scatter_swap/run.rb +95 -0
- data/lib/scatter_swap/swapper.rb +36 -0
- data/lib/scatter_swap/version.rb +5 -0
- metadata +62 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 45d027873e1e1d8ae6967520352c54f93587576e6ee7b50d0c5b923901061fbb
|
|
4
|
+
data.tar.gz: 0fec3718818cc64f0919f7f2b3b28b3abc145d80caa27174fda70151ae773957
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8adea79c3f2ef9b61dd26baa4930ea7b7a293e0c799be1a6f1892e61ca5661cac7db8350ea2f0dea5bf2af9a133a44e35d271c3d540549d7b566565bdcae424f
|
|
7
|
+
data.tar.gz: cd50a3dbc1e6fa29601742e710757b44ce16ae4de597ecc638d89b3119a38ea2fa37530ed3778629544b01815c251959179d6ef8ba26963c8480b2830e1530d1
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Nathan and David Amick
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# ScatterSwap
|
|
2
|
+
|
|
3
|
+
This is the integer hashing function behind [obfuscate_id](https://github.com/namick/obfuscate_id).
|
|
4
|
+
|
|
5
|
+
> Designing a hash function is a bit of a black art and
|
|
6
|
+
> being that I don't have math background, I must resort
|
|
7
|
+
> to this simplistic swaping and scattering of array elements.
|
|
8
|
+
|
|
9
|
+
> After writing this and reading/learning some elemental hashing techniques,
|
|
10
|
+
> I realized that this library is an example of what is known as a [minimal perfect hash function](http://en.wikipedia.org/wiki/Perfect_hash_function#Minimal_perfect_hash_function).
|
|
11
|
+
|
|
12
|
+
> I welcome all improvements via pull-requests :-)
|
|
13
|
+
|
|
14
|
+
> If you have some comments or suggestions, please contact me at `github@nathanamick.com` - nathan amick
|
|
15
|
+
|
|
16
|
+
## Goals
|
|
17
|
+
|
|
18
|
+
We want to transform an integer into another random looking integer and then reliably tranform it back.
|
|
19
|
+
|
|
20
|
+
It will turn the number `3` into `2356513904`, and it can then reliably reverse that scrambled `2356513904` number back into `3`
|
|
21
|
+
|
|
22
|
+
We also want sequential integers to become non-sequential.
|
|
23
|
+
|
|
24
|
+
So for example it will turn `7001, 7002, 7003` into `5270192353, 7107163820, 3296163828`, and back again.
|
|
25
|
+
|
|
26
|
+
Please note, this is not encryption or related to security in any way. It lightly obfuscates an integer in a reversible way.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
Pass a number (as an integer or string) to the 'hash' method and it will return an obfuscated version of it.
|
|
31
|
+
|
|
32
|
+
ScatterSwap.hash(1).to_i
|
|
33
|
+
#=> 4517239960
|
|
34
|
+
|
|
35
|
+
Pass that obfuscated version in and it will return the original (as a zero padded string).
|
|
36
|
+
|
|
37
|
+
ScatterSwap.reverse_hash(4517239960).to_i
|
|
38
|
+
#=> 1
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
*Because this was originally built for urls like this `example.com/users/00000000001` it outputs strings. This is why the examples above have `to_i` tacked on to them. Since extracting it to its own library, that may not make sense anymore. I'm considering output the same type as it is input. Thoughts?*
|
|
42
|
+
|
|
43
|
+
## How it works
|
|
44
|
+
|
|
45
|
+
This library is built for integers that can be expressed with 10 digits.
|
|
46
|
+
It zero pads smaller numbers.
|
|
47
|
+
|
|
48
|
+
The number 1 is expressed with:
|
|
49
|
+
|
|
50
|
+
0000000001
|
|
51
|
+
|
|
52
|
+
The biggest number it can deal with is 10 billion - 1:
|
|
53
|
+
|
|
54
|
+
9999999999
|
|
55
|
+
|
|
56
|
+
Since we are working with a limited sequential set of input integers, 10 billion,
|
|
57
|
+
this algorithm will suffice for simple id obfuscation for many web apps.
|
|
58
|
+
|
|
59
|
+
The largest value that Ruby on Rails default id, Mysql INT type, is just over 2 billion (2147483647)
|
|
60
|
+
which is the same as 2 to the power of 31 minus 1, but considerably less than 10 billion.
|
|
61
|
+
|
|
62
|
+
## Strategies
|
|
63
|
+
|
|
64
|
+
ScatterSwap is an integer hash function designed to have:
|
|
65
|
+
|
|
66
|
+
- zero collisions ( http://en.wikipedia.org/wiki/Perfect_hash_function )
|
|
67
|
+
- achieve avalanche ( http://en.wikipedia.org/wiki/Avalanche_effect )
|
|
68
|
+
- reversible
|
|
69
|
+
|
|
70
|
+
We do that by combining two distinct strategies.
|
|
71
|
+
|
|
72
|
+
1. Scattering - whereby we take the whole number, slice it up into 10 digits
|
|
73
|
+
and rearange their places, yet retaining the same 10 digits. This allows
|
|
74
|
+
us to preserve the sum of all the digits, regardless of order. This sum acts
|
|
75
|
+
as a key to reverse this scattering effect.
|
|
76
|
+
|
|
77
|
+
2. Swapping - when dealing with many sequential numbers that we don't want
|
|
78
|
+
to look similar, scattering wont do us much good because so many of the
|
|
79
|
+
digits are the same; it deoesn't help to scatter 9 zeros around, so we need
|
|
80
|
+
to swap out each of those zeros for something else.. something different
|
|
81
|
+
for each place in the 10 digit array; for this, we need a map so that we
|
|
82
|
+
can reverse it.
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## Installation
|
|
86
|
+
|
|
87
|
+
Add this line to your application's Gemfile:
|
|
88
|
+
|
|
89
|
+
gem 'bonio-scatter_swap'
|
|
90
|
+
|
|
91
|
+
And then execute:
|
|
92
|
+
|
|
93
|
+
$ bundle
|
|
94
|
+
|
|
95
|
+
Or install it yourself as:
|
|
96
|
+
|
|
97
|
+
$ gem install bonio-scatter_swap
|
|
98
|
+
|
|
99
|
+
## Contributing
|
|
100
|
+
|
|
101
|
+
1. Fork it
|
|
102
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
103
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
104
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
105
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'scatter_swap/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'bonio-scatter_swap'
|
|
8
|
+
spec.version = ScatterSwap::VERSION
|
|
9
|
+
spec.authors = ['khiav reoy']
|
|
10
|
+
spec.email = ['mrtmrt15xn@yahoo.com.tw']
|
|
11
|
+
|
|
12
|
+
spec.description = %q{ScatterSwap is an integer hash function designed to have zero collisions, achieve avalanche, and be reversible.}
|
|
13
|
+
spec.summary = %q{Minimal perfect hash function for 10 digit integers}
|
|
14
|
+
spec.homepage = 'https://github.com/khiav223577/scatter_swap'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
|
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
|
19
|
+
# if spec.respond_to?(:metadata)
|
|
20
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
|
21
|
+
# else
|
|
22
|
+
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
|
23
|
+
# end
|
|
24
|
+
|
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject{|f| f.match(%r{^(test|spec|features)/}) }
|
|
26
|
+
spec.bindir = 'exe'
|
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}){|f| File.basename(f) }
|
|
28
|
+
spec.require_paths = ['lib']
|
|
29
|
+
spec.metadata = {
|
|
30
|
+
'homepage_uri' => 'https://github.com/khiav223577/scatter_swap',
|
|
31
|
+
'changelog_uri' => 'https://github.com/khiav223577/scatter_swap/blob/master/CHANGELOG.md',
|
|
32
|
+
'source_code_uri' => 'https://github.com/khiav223577/scatter_swap',
|
|
33
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/scatter_swap',
|
|
34
|
+
'bug_tracker_uri' => 'https://github.com/khiav223577/scatter_swap/issues',
|
|
35
|
+
}
|
|
36
|
+
end
|
data/lib/scatter_swap.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'scatter_swap/version'
|
|
4
|
+
require 'scatter_swap/hasher'
|
|
5
|
+
|
|
6
|
+
module ScatterSwap
|
|
7
|
+
def self.hash(plain_integer, spin = 0, length = 10)
|
|
8
|
+
Hasher.new(plain_integer, spin, length).hash
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.reverse_hash(hashed_integer, spin = 0, length = 10)
|
|
12
|
+
Hasher.new(hashed_integer, spin, length).reverse_hash
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'scatter_swap/swapper'
|
|
4
|
+
|
|
5
|
+
module ScatterSwap
|
|
6
|
+
class Hasher
|
|
7
|
+
DIGITS = (0..9).to_a.freeze
|
|
8
|
+
|
|
9
|
+
attr_accessor :working_array
|
|
10
|
+
|
|
11
|
+
def initialize(original_integer, spin = 0, length = 10)
|
|
12
|
+
@original_integer = original_integer
|
|
13
|
+
@spin = spin
|
|
14
|
+
@length = length
|
|
15
|
+
zero_pad = original_integer.to_s.rjust(length, '0')
|
|
16
|
+
@working_array = zero_pad.chars.map(&:to_i)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# obfuscates an integer up to @length digits in length
|
|
20
|
+
def hash
|
|
21
|
+
swap
|
|
22
|
+
scatter
|
|
23
|
+
@working_array.join
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# de-obfuscates an integer
|
|
27
|
+
def reverse_hash
|
|
28
|
+
unscatter
|
|
29
|
+
unswap
|
|
30
|
+
@working_array.join
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def swapper_map(index)
|
|
34
|
+
Swapper.instance(@spin).generate(index)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Using a unique map for each of the ten places,
|
|
38
|
+
# we swap out one number for another
|
|
39
|
+
def swap
|
|
40
|
+
@working_array = @working_array.map.with_index do |digit, index|
|
|
41
|
+
swapper_map(index)[digit]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Reverse swap
|
|
46
|
+
def unswap
|
|
47
|
+
@working_array = @working_array.map.with_index do |digit, index|
|
|
48
|
+
swapper_map(index).rindex(digit)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Rearrange the order of each digit in a reversible way by using the
|
|
53
|
+
# sum of the digits (which doesn't change regardless of order)
|
|
54
|
+
# as a key to record how they were scattered
|
|
55
|
+
def scatter
|
|
56
|
+
sum_of_digits = @working_array.inject(:+).to_i
|
|
57
|
+
@working_array = @length.times.map do
|
|
58
|
+
@working_array.rotate!(@spin ^ sum_of_digits).pop
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Reverse the scatter
|
|
63
|
+
def unscatter
|
|
64
|
+
scattered_array = @working_array
|
|
65
|
+
sum_of_digits = scattered_array.inject(:+).to_i
|
|
66
|
+
@working_array = []
|
|
67
|
+
@working_array.tap do |unscatter|
|
|
68
|
+
@length.times do
|
|
69
|
+
unscatter.push scattered_array.pop
|
|
70
|
+
unscatter.rotate! (sum_of_digits ^ @spin) * -1
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'scatter_swap'
|
|
4
|
+
|
|
5
|
+
# This file is spike code and is not part of the library
|
|
6
|
+
#
|
|
7
|
+
# While developing this, I used this file to visualize what was going on with the numbers
|
|
8
|
+
#
|
|
9
|
+
# You can uncomment various methods at the bottom and then run it like this:
|
|
10
|
+
#
|
|
11
|
+
# watch -n1 ruby run_scatter_swap.rb
|
|
12
|
+
#
|
|
13
|
+
# tweak the code a bit and see instant visual changes in the generated numbers
|
|
14
|
+
|
|
15
|
+
def visualize_scatter_and_unscatter
|
|
16
|
+
# change this number to experiment with different values
|
|
17
|
+
rotations = 99
|
|
18
|
+
|
|
19
|
+
original = ScatterSwap.arrayify(123456789)
|
|
20
|
+
scattered = []
|
|
21
|
+
unscattered = []
|
|
22
|
+
puts original.join
|
|
23
|
+
puts "rotate!(#{rotations})"
|
|
24
|
+
10.times do
|
|
25
|
+
puts original.rotate!(rotations).join + "->" + scattered.push(original.pop).join
|
|
26
|
+
end
|
|
27
|
+
puts "scattered"
|
|
28
|
+
puts scattered.join
|
|
29
|
+
10.times do
|
|
30
|
+
puts unscattered.push(scattered.pop).join + "->" + unscattered.rotate!(rotations * -1).join
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
puts unscattered.join
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def visualize_swapper_map
|
|
38
|
+
puts "swapper map"
|
|
39
|
+
10.times do |index|
|
|
40
|
+
key = 1
|
|
41
|
+
puts ScatterSwap.swapper_map(index).join.to_s
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def visualize_hash
|
|
46
|
+
puts "hash"
|
|
47
|
+
40.times do |integer|
|
|
48
|
+
output = "|"
|
|
49
|
+
3.times do |index|
|
|
50
|
+
output += " #{(integer + (123456789 * index)).to_s.rjust(5, ' ')}"
|
|
51
|
+
output += " => #{hashed = ScatterSwap.hash(integer + (123456789 * index) ) }"
|
|
52
|
+
output += " => #{ScatterSwap.reverse_hash(hashed) } |"
|
|
53
|
+
end
|
|
54
|
+
puts output
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def visualize_scatter
|
|
60
|
+
puts "original scattered unscattered"
|
|
61
|
+
20.times do |integer|
|
|
62
|
+
output = ""
|
|
63
|
+
2.times do |index|
|
|
64
|
+
original = ScatterSwap.arrayify(integer + (123456789 * index))
|
|
65
|
+
scattered = ScatterSwap.scatter(original.clone)
|
|
66
|
+
unscattered = ScatterSwap.unscatter(scattered.clone)
|
|
67
|
+
output += "#{original.join}"
|
|
68
|
+
output += " => #{scattered.join}"
|
|
69
|
+
output += " => #{unscattered.join} | "
|
|
70
|
+
end
|
|
71
|
+
puts output
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# find hash for lots of spins
|
|
77
|
+
def visualize_spin
|
|
78
|
+
2000.times do |original|
|
|
79
|
+
hashed_values = []
|
|
80
|
+
9000000000.times do |spin|
|
|
81
|
+
hashed = ScatterSwap.hash(original, spin)
|
|
82
|
+
if hashed_values.include? hashed
|
|
83
|
+
puts "collision: #{original} - #{spin} - #{hashed}"
|
|
84
|
+
break
|
|
85
|
+
end
|
|
86
|
+
hashed_values.push hashed
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
#visualize_spin
|
|
92
|
+
#visualize_hash
|
|
93
|
+
#visualize_scatter_and_unscatter
|
|
94
|
+
#visualize_scatter
|
|
95
|
+
#visualize_swapper_map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# We want a unique map for each place in the original number
|
|
4
|
+
module ScatterSwap
|
|
5
|
+
class Swapper
|
|
6
|
+
@all_swapper_maps = {}
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def instance(spin)
|
|
10
|
+
@all_swapper_maps[spin] ||= new(spin)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
DIGITS = (0..9).to_a.freeze
|
|
15
|
+
|
|
16
|
+
def initialize(spin)
|
|
17
|
+
@spin = spin
|
|
18
|
+
@caches = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def generate(index)
|
|
22
|
+
@caches[index] ||= generate_without_cache(index)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def generate_without_cache(index)
|
|
28
|
+
array = DIGITS.dup
|
|
29
|
+
sum = 0
|
|
30
|
+
10.times.map.with_index do |i|
|
|
31
|
+
sum = (sum + ((index + i) ^ @spin) - 1) % (10 - i)
|
|
32
|
+
next array.delete_at(sum)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bonio-scatter_swap
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- khiav reoy
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2019-12-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: ScatterSwap is an integer hash function designed to have zero collisions,
|
|
14
|
+
achieve avalanche, and be reversible.
|
|
15
|
+
email:
|
|
16
|
+
- mrtmrt15xn@yahoo.com.tw
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- ".gitignore"
|
|
22
|
+
- ".rspec"
|
|
23
|
+
- Gemfile
|
|
24
|
+
- LICENSE.txt
|
|
25
|
+
- README.md
|
|
26
|
+
- Rakefile
|
|
27
|
+
- bonio-scatter_swap.gemspec
|
|
28
|
+
- lib/bonio-scatter_swap.rb
|
|
29
|
+
- lib/scatter_swap.rb
|
|
30
|
+
- lib/scatter_swap/hasher.rb
|
|
31
|
+
- lib/scatter_swap/run.rb
|
|
32
|
+
- lib/scatter_swap/swapper.rb
|
|
33
|
+
- lib/scatter_swap/version.rb
|
|
34
|
+
homepage: https://github.com/khiav223577/scatter_swap
|
|
35
|
+
licenses:
|
|
36
|
+
- MIT
|
|
37
|
+
metadata:
|
|
38
|
+
homepage_uri: https://github.com/khiav223577/scatter_swap
|
|
39
|
+
changelog_uri: https://github.com/khiav223577/scatter_swap/blob/master/CHANGELOG.md
|
|
40
|
+
source_code_uri: https://github.com/khiav223577/scatter_swap
|
|
41
|
+
documentation_uri: https://www.rubydoc.info/gems/scatter_swap
|
|
42
|
+
bug_tracker_uri: https://github.com/khiav223577/scatter_swap/issues
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubygems_version: 3.0.3
|
|
59
|
+
signing_key:
|
|
60
|
+
specification_version: 4
|
|
61
|
+
summary: Minimal perfect hash function for 10 digit integers
|
|
62
|
+
test_files: []
|