deacon 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +625 -0
- data/README.md +131 -0
- data/Rakefile +17 -0
- data/data/gfnames.txt +256 -0
- data/data/gmnames.txt +256 -0
- data/data/srnames.txt +65536 -0
- data/lib/deacon.rb +7 -0
- data/lib/deacon/generator.rb +37 -0
- data/lib/deacon/mac_generator.rb +17 -0
- data/lib/deacon/random_generator.rb +42 -0
- data/lib/deacon/version.rb +3 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/mac_generator_test.rb +33 -0
- data/test/unit/random_generator_test.rb +121 -0
- metadata +77 -0
data/lib/deacon.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Deacon
|
2
|
+
class Generator
|
3
|
+
DEFAULT_DATA_DIR = File.expand_path('../../../data', __FILE__)
|
4
|
+
GIVEN_MALE_NAMES_FILE = 'gmnames.txt'
|
5
|
+
GIVEN_FEMALE_NAMES_FILE = 'gfnames.txt'
|
6
|
+
SURNAMES_FILE = 'srnames.txt'
|
7
|
+
RECORD_LENGTH_GIVEN = 6
|
8
|
+
RECORD_LENGTH_SURNAME = 9
|
9
|
+
|
10
|
+
def initialize(data_dir = DEFAULT_DATA_DIR)
|
11
|
+
@data_dir = data_dir
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def data_file(filename)
|
17
|
+
File.join(@data_dir, filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_name(index, filename, length)
|
21
|
+
File.open(filename, 'r') do |f|
|
22
|
+
f.seek(index * length)
|
23
|
+
f.readline.chomp.strip
|
24
|
+
end
|
25
|
+
rescue Exception => e
|
26
|
+
raise "Error when seeking to #{index} in #{filename}: #{e}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def mac_to_bytes(mac)
|
30
|
+
mac.split(/[:-]/).collect{|x| x.to_i(16)}
|
31
|
+
end
|
32
|
+
|
33
|
+
def mac_to_shorts(mac)
|
34
|
+
mac_to_bytes(mac).each_slice(2).collect { |a, b| (a << 8) + b }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Deacon
|
2
|
+
class MacGenerator < Generator
|
3
|
+
def generate(mac, female = false)
|
4
|
+
return [] if mac.nil? || mac.empty?
|
5
|
+
# B0 B1 B2 B3 B4 B5
|
6
|
+
# SHRT0 SHRT1 SHRT2
|
7
|
+
bytes = mac_to_bytes(mac)
|
8
|
+
shorts = mac_to_shorts(mac)
|
9
|
+
filename = (shorts[0] & 0x1) == 0 ? GIVEN_MALE_NAMES_FILE : GIVEN_FEMALE_NAMES_FILE
|
10
|
+
firstname1 = find_name(bytes[2], data_file(filename), RECORD_LENGTH_GIVEN)
|
11
|
+
firstname2 = find_name(bytes[3], data_file(filename), RECORD_LENGTH_GIVEN)
|
12
|
+
surname1 = find_name(shorts[0], data_file(SURNAMES_FILE), RECORD_LENGTH_SURNAME)
|
13
|
+
surname2 = find_name(shorts[2], data_file(SURNAMES_FILE), RECORD_LENGTH_SURNAME)
|
14
|
+
[firstname2, firstname1, surname1, surname2]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Deacon
|
2
|
+
class RandomGenerator < Generator
|
3
|
+
MASK = 0x1ffffff
|
4
|
+
|
5
|
+
# Fibonacci linear feedback shift register with x^25 + x^24 + x^23 + x^22 + 1 poly
|
6
|
+
def next_lfsr25(seed)
|
7
|
+
i = 1
|
8
|
+
i = (seed + 1) & MASK
|
9
|
+
raise ArgumentError, "Seed #{seed} out of bounds" if seed && i == 0
|
10
|
+
i = (seed + 1) & MASK while i == 0
|
11
|
+
i = (i >> 1) | ((i[0]^i[1]^i[2]^i[3]) << 0x18)
|
12
|
+
i = (i >> 1) | ((i[0]^i[1]^i[2]^i[3]) << 0x18) while i > MASK
|
13
|
+
i - 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate(seed = Time.now.utc.to_i)
|
17
|
+
return [] if seed.nil? || seed == 0
|
18
|
+
index = seed
|
19
|
+
loop do
|
20
|
+
index = next_lfsr25(index)
|
21
|
+
break if unique?(seed, index)
|
22
|
+
end
|
23
|
+
given_file = (index & 0x1000000) == 0 ? GIVEN_MALE_NAMES_FILE : GIVEN_FEMALE_NAMES_FILE
|
24
|
+
givenname_ix = (index & 0xff0000) >> 16
|
25
|
+
surnname_ix = index & 0xffff
|
26
|
+
firstname = find_name(givenname_ix, data_file(given_file), RECORD_LENGTH_GIVEN)
|
27
|
+
surname = find_name(surnname_ix, data_file(SURNAMES_FILE), RECORD_LENGTH_SURNAME)
|
28
|
+
[index, firstname, surname]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.random_initial_seed
|
32
|
+
rand(MASK - 2) + 1
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# is first (or gender) and last name different from the old value?
|
38
|
+
def unique?(ix1, ix2)
|
39
|
+
(((ix1 & 0xff0000) != (ix2 & 0xff0000)) || ((ix1 & 0x1000000) != (ix2 & 0x1000000))) && ((ix1 & 0xffff) != (ix2 & 0xffff))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class MacGeneratorTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
dir = File.expand_path('../../../data', __FILE__)
|
6
|
+
@generator = Deacon::MacGenerator.new(dir)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_generates_empty_array_for_nil
|
10
|
+
assert_equal [], @generator.generate(nil)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_generates_empty_array_for_empty_string
|
14
|
+
assert_equal [], @generator.generate("")
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_generates_a_male_name
|
18
|
+
assert_equal ["DEREK", "LEVI", "PRATICO", "CEDILLO"], @generator.generate("00:00:ca:fe:01:01")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_generates_a_female_name
|
22
|
+
assert_equal ["KATHY", "ALTA", "ROMEO", "CEDILLO"], @generator.generate("00:01:ca:fe:01:01")
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_generates_same_middle_names_for_single_oid
|
26
|
+
name1 = @generator.generate("24:a4:3c:ec:76:06")
|
27
|
+
name2 = @generator.generate("24:a4:3c:e3:d3:92")
|
28
|
+
#puts name1.inspect
|
29
|
+
#puts name2.inspect
|
30
|
+
assert_equal name1[1], name2[1]
|
31
|
+
assert_equal name1[2], name2[2]
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class RandomGeneratorTest < MiniTest::Unit::TestCase
|
4
|
+
# number of test iterations for some tests
|
5
|
+
TEST_ITERATIONS=10_000
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@dir = File.expand_path('../../../data', __FILE__)
|
9
|
+
@generator = Deacon::RandomGenerator.new(@dir)
|
10
|
+
@random = rand((2 ** 25) - (TEST_ITERATIONS+3))
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_generates_empty_array_for_nil
|
14
|
+
assert_equal [], @generator.generate(nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_generates_a_deterministic_sequence
|
18
|
+
expected = [
|
19
|
+
[0x1000000, 'VELMA', 'PRATICO'],
|
20
|
+
[0x17fffff, 'ANGIE', 'WARMBROD'],
|
21
|
+
[0x0017fff, 'GRANT', 'GOODGINE'],
|
22
|
+
[0x000bfff, 'ALTON', 'SIEBER'],
|
23
|
+
[0x100000b, 'VELMA', 'VANBEEK'],
|
24
|
+
[0x0800005, 'DON', 'OTERO'],
|
25
|
+
[0x0400002, 'SAM', 'HULAN'],
|
26
|
+
[0x0200000, 'AARON', 'PRATICO'],
|
27
|
+
[0x10fffff, 'SALLY', 'WARMBROD'],
|
28
|
+
[0x0087fff, 'TED', 'GOODGINE'],
|
29
|
+
[0x0043fff, 'CORY', 'THURSBY'],
|
30
|
+
[0x0021fff, 'GARRY', 'HANDREN'],
|
31
|
+
[0x0010fff, 'GRANT', 'STELMAN'],
|
32
|
+
[0x00087ff, 'ALTON', 'KAWSKI'],
|
33
|
+
[0x1000043, 'VELMA', 'MIRRA'],
|
34
|
+
[0x1800021, 'SUSAN', 'DARBY'],
|
35
|
+
[0x1c00010, 'MARIA', 'BOURDON'],
|
36
|
+
[0x1e00007, 'ANNIE', 'SCHMANDT'],
|
37
|
+
[0x1f00003, 'MAYRA', 'BURNAUGH'],
|
38
|
+
[0x1f80001, 'FAYE', 'ROMEO'],
|
39
|
+
[0x1fc0000, 'OPAL', 'PRATICO'],
|
40
|
+
[0x1fdffff, 'CLARA', 'WARMBROD'],
|
41
|
+
[0x07f7fff, 'DUANE', 'GOODGINE'],
|
42
|
+
[0x03fbfff, 'ERVIN', 'SIEBER'],
|
43
|
+
[0x01fdfff, 'ELDON', 'LEYUA'],
|
44
|
+
[0x00fefff, 'GARY', 'TRASHER'],
|
45
|
+
[0x007f7ff, 'BRET', 'ONDRICK'],
|
46
|
+
[0x003fbff, 'LANCE', 'BISTER'],
|
47
|
+
[0x001fdff, 'GRANT', 'KUZIEL'],
|
48
|
+
[0x000feff, 'ALTON', 'THOMPON'],
|
49
|
+
[0x10003fb, 'VELMA', 'SWILLE'],
|
50
|
+
[0x08001fd, 'DON', 'DEBRECHT'],
|
51
|
+
[0x14000fe, 'TARA', 'VAUGHNS'],
|
52
|
+
[0x0a0007e, 'HEATH', 'RUSHTON'],
|
53
|
+
[0x050003e, 'BRUCE', 'PHEONIX'],
|
54
|
+
[0x028001e, 'KURT', 'VEAZEY'],
|
55
|
+
[0x014000e, 'DEWEY', 'MOHSENI'],
|
56
|
+
[0x00a0006, 'ELI', 'DEWEY'],
|
57
|
+
[0x1050002, 'ROSA', 'HULAN'],
|
58
|
+
[0x0828000, 'JESUS', 'PONTON'],
|
59
|
+
[0x1413fff, 'MABEL', 'THURSBY'],
|
60
|
+
[0x0a09fff, 'HEATH', 'ZEHNDER'],
|
61
|
+
[0x0504fff, 'BRUCE', 'BARTOLO'],
|
62
|
+
[0x02827ff, 'KURT', 'MCCLEE'],
|
63
|
+
[0x01413ff, 'DEWEY', 'PASKELL'],
|
64
|
+
[0x00a09ff, 'ELI', 'HASFJORD'],
|
65
|
+
[0x00504ff, 'KARL', 'ANIBAL'],
|
66
|
+
[0x002827f, 'GARRY', 'SHALA'],
|
67
|
+
[0x001413f, 'GRANT', 'HIEBER'],
|
68
|
+
[0x000a09f, 'ALTON', 'PERIGO'],
|
69
|
+
]
|
70
|
+
seq = []
|
71
|
+
ix = 1
|
72
|
+
(1..50).each do |_|
|
73
|
+
ix, first, last = tuple = @generator.generate(ix)
|
74
|
+
#puts "[0x#{sprintf("%07x", ix)}, '#{first}', '#{last}'],"
|
75
|
+
seq << tuple
|
76
|
+
end
|
77
|
+
assert_equal expected, seq
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_generates_a_name_for_the_initial_round
|
81
|
+
assert_equal [16777216, "VELMA", "PRATICO"], @generator.generate(1)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_generates_a_name_for_the_last_round
|
85
|
+
assert_equal [32766, "ALTON", "MCCORY"], @generator.generate((2**25) - 2)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_generates_a_name_for_each_value_in_a_sequence
|
89
|
+
@random.step(@random + TEST_ITERATIONS, 1) do |i|
|
90
|
+
@generator.generate(i)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_generates_non_repeating_index_sequence
|
95
|
+
test_hash = {}
|
96
|
+
ix = 1
|
97
|
+
@random.step(@random + TEST_ITERATIONS, 1) do |i|
|
98
|
+
ix = @generator.next_lfsr25(ix)
|
99
|
+
if test_hash.include? ix
|
100
|
+
fail("Found duplicated index #{ix} (iteration #{i})")
|
101
|
+
else
|
102
|
+
test_hash[ix] = 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_never_generates_two_same_names
|
108
|
+
test_hash = {}
|
109
|
+
ix = old_ix = 1
|
110
|
+
@random.step(@random + TEST_ITERATIONS, 1) do |i|
|
111
|
+
ix, first, last = @generator.generate(ix)
|
112
|
+
hash = first + last
|
113
|
+
if test_hash.include? hash
|
114
|
+
fail("Found duplicated name #{fn} #{sn} index #{old_ix}->#{ix} (iteration #{i})")
|
115
|
+
else
|
116
|
+
test_hash[hash] = 1
|
117
|
+
end
|
118
|
+
old_ix = ix
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deacon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lukas Zapletal
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rdoc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Provides human readable name using continious LFSR
|
28
|
+
email:
|
29
|
+
- lukas-x@zapletalovi.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/deacon/random_generator.rb
|
35
|
+
- lib/deacon/mac_generator.rb
|
36
|
+
- lib/deacon/generator.rb
|
37
|
+
- lib/deacon/version.rb
|
38
|
+
- lib/deacon.rb
|
39
|
+
- data/gmnames.txt
|
40
|
+
- data/srnames.txt
|
41
|
+
- data/gfnames.txt
|
42
|
+
- LICENSE
|
43
|
+
- Rakefile
|
44
|
+
- README.md
|
45
|
+
- test/unit/mac_generator_test.rb
|
46
|
+
- test/unit/random_generator_test.rb
|
47
|
+
- test/test_helper.rb
|
48
|
+
homepage: https://github.com/lzap/deacon
|
49
|
+
licenses:
|
50
|
+
- GPLv3
|
51
|
+
- Public domain
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 2.0.14
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: Human readable random name generator
|
73
|
+
test_files:
|
74
|
+
- test/unit/mac_generator_test.rb
|
75
|
+
- test/unit/random_generator_test.rb
|
76
|
+
- test/test_helper.rb
|
77
|
+
has_rdoc:
|