safedb 0.01.0001
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 +8 -0
- data/.yardopts +3 -0
- data/Gemfile +10 -0
- data/LICENSE +21 -0
- data/README.md +793 -0
- data/Rakefile +16 -0
- data/bin/safe +5 -0
- data/lib/configs/README.md +58 -0
- data/lib/extension/array.rb +162 -0
- data/lib/extension/dir.rb +35 -0
- data/lib/extension/file.rb +123 -0
- data/lib/extension/hash.rb +33 -0
- data/lib/extension/string.rb +572 -0
- data/lib/factbase/facts.safedb.net.ini +38 -0
- data/lib/interprete.rb +462 -0
- data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
- data/lib/keytools/kdf.api.rb +243 -0
- data/lib/keytools/kdf.bcrypt.rb +265 -0
- data/lib/keytools/kdf.pbkdf2.rb +262 -0
- data/lib/keytools/kdf.scrypt.rb +190 -0
- data/lib/keytools/key.64.rb +326 -0
- data/lib/keytools/key.algo.rb +109 -0
- data/lib/keytools/key.api.rb +1391 -0
- data/lib/keytools/key.db.rb +330 -0
- data/lib/keytools/key.docs.rb +195 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.ident.rb +243 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +259 -0
- data/lib/keytools/key.now.rb +402 -0
- data/lib/keytools/key.pair.rb +259 -0
- data/lib/keytools/key.pass.rb +120 -0
- data/lib/keytools/key.rb +585 -0
- data/lib/logging/gem.logging.rb +132 -0
- data/lib/modules/README.md +43 -0
- data/lib/modules/cryptology/aes-256.rb +154 -0
- data/lib/modules/cryptology/amalgam.rb +70 -0
- data/lib/modules/cryptology/blowfish.rb +130 -0
- data/lib/modules/cryptology/cipher.rb +207 -0
- data/lib/modules/cryptology/collect.rb +138 -0
- data/lib/modules/cryptology/crypt.io.rb +225 -0
- data/lib/modules/cryptology/engineer.rb +99 -0
- data/lib/modules/mappers/dictionary.rb +288 -0
- data/lib/modules/storage/coldstore.rb +186 -0
- data/lib/modules/storage/git.store.rb +399 -0
- data/lib/session/fact.finder.rb +334 -0
- data/lib/session/require.gem.rb +112 -0
- data/lib/session/time.stamp.rb +340 -0
- data/lib/session/user.home.rb +49 -0
- data/lib/usecase/cmd.rb +487 -0
- data/lib/usecase/config/README.md +57 -0
- data/lib/usecase/docker/README.md +146 -0
- data/lib/usecase/docker/docker.rb +49 -0
- data/lib/usecase/edit/README.md +43 -0
- data/lib/usecase/edit/delete.rb +46 -0
- data/lib/usecase/export.rb +40 -0
- data/lib/usecase/files/README.md +37 -0
- data/lib/usecase/files/eject.rb +56 -0
- data/lib/usecase/files/file_me.rb +78 -0
- data/lib/usecase/files/read.rb +169 -0
- data/lib/usecase/files/write.rb +89 -0
- data/lib/usecase/goto.rb +57 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +157 -0
- data/lib/usecase/init.rb +63 -0
- data/lib/usecase/jenkins/README.md +146 -0
- data/lib/usecase/jenkins/jenkins.rb +208 -0
- data/lib/usecase/login.rb +71 -0
- data/lib/usecase/logout.rb +28 -0
- data/lib/usecase/open.rb +71 -0
- data/lib/usecase/print.rb +40 -0
- data/lib/usecase/put.rb +81 -0
- data/lib/usecase/set.rb +44 -0
- data/lib/usecase/show.rb +138 -0
- data/lib/usecase/terraform/README.md +91 -0
- data/lib/usecase/terraform/terraform.rb +121 -0
- data/lib/usecase/token.rb +35 -0
- data/lib/usecase/update/README.md +55 -0
- data/lib/usecase/update/rename.rb +180 -0
- data/lib/usecase/use.rb +41 -0
- data/lib/usecase/verse.rb +20 -0
- data/lib/usecase/view.rb +71 -0
- data/lib/usecase/vpn/README.md +150 -0
- data/lib/usecase/vpn/vpn.ini +31 -0
- data/lib/usecase/vpn/vpn.rb +54 -0
- data/lib/version.rb +3 -0
- data/safedb.gemspec +34 -0
- metadata +193 -0
@@ -0,0 +1,326 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# First use the class methods to source keys, then use a key's instance
|
6
|
+
# methods to access its properties and in concert with other symmetrical
|
7
|
+
# information, you can use the keys to lock (encrypt) or unlock (decrypt)
|
8
|
+
# other keys and objects.
|
9
|
+
#
|
10
|
+
# == Sourcing and Deriving Keys
|
11
|
+
#
|
12
|
+
# Keys can be
|
13
|
+
#
|
14
|
+
# - sourced from a secure random byte generating function
|
15
|
+
# - sourced from ciphertext and another (decryption) key
|
16
|
+
# - generated by passing a secret through key derivation functions
|
17
|
+
# - regenerated from a secret and previously stored salts
|
18
|
+
# - sourced from the current unique workstation shell environment
|
19
|
+
# - sourced from an environment variable containing ciphertext
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# Keys need to be viewed (represented) in multiple ways and the essence
|
23
|
+
# of the key viewer is to input keys {as_bits}, {as_bytes} and {as_base64}
|
24
|
+
# and then output the same key (in as far as is possible) - as bits, as
|
25
|
+
# bytes and as base64.
|
26
|
+
#
|
27
|
+
# == Key | To and From Behaviour
|
28
|
+
#
|
29
|
+
# Use the <b>From</b> methods to create Keys from a variety of resources
|
30
|
+
# such as
|
31
|
+
#
|
32
|
+
# - a base64 encoded string
|
33
|
+
# - a binary byte string
|
34
|
+
# - a string of one and zero bits
|
35
|
+
# - a hexadecimal representation
|
36
|
+
#
|
37
|
+
# Once you have instantiated the key, you will then be able to convert it
|
38
|
+
# (within reason due to bit, byte and base64 lengths) to any of the above
|
39
|
+
# key representations.
|
40
|
+
#
|
41
|
+
# == Key | Bits Bytes and Base64
|
42
|
+
#
|
43
|
+
# The shoe doesn't always fit when its on the other foot and this is best
|
44
|
+
# illustratd with a table that maps bits to 8 bit bytes and 6 bit Base64
|
45
|
+
# characters.
|
46
|
+
#
|
47
|
+
# | --------- | -------- | ------------ | ------------------------------- |
|
48
|
+
# | Fit? | Bits | Bytes | (and) Base64 |
|
49
|
+
# | --------- | -------- | ------------ | ------------------------------- |
|
50
|
+
# | Perfect | 168 Bits | is 21 bytes | 28 Chars - bcrypt chops to this |
|
51
|
+
# | Perfect | 216 Bits | is 27 bytes | 36 Chars - |
|
52
|
+
# | Perfect | 264 Bits | is 33 bytes | 44 Chars - holder 4 256bit keys |
|
53
|
+
# | Perfect | 384 Bits | is 48 bytes | 64 Chars - 216 + 168 equals 384 |
|
54
|
+
# | --------- | -------- | ------------ | ------------------------------- |
|
55
|
+
# | Imperfect | 128 Bits | 16 precisely | 22 Chars - 21 + 2 remain bits |
|
56
|
+
# | Imperfect | 186 Bits | 23 remain 2 | 31 Characers precisely |
|
57
|
+
# | Imperfect | 256 Bits | 32 precisely | 43 Chars - 42 + 4 remain bits |
|
58
|
+
# | --------- | -------- | ------------ | ------------------------------- |
|
59
|
+
#
|
60
|
+
# Yes, the shoe doesn't always fit when it's on the other foot.
|
61
|
+
#
|
62
|
+
# == Schoolboy Error
|
63
|
+
#
|
64
|
+
# <b>The strategy is so simple, we call it a schoolboy error.</b>
|
65
|
+
#
|
66
|
+
# If we want to use a key with n bits and either n % 6 or n % 8 (or both)
|
67
|
+
# are not zero - <b>we instantiate a Key</b> with the lowest common
|
68
|
+
# denominator of 6 and 8 that exceeds n.
|
69
|
+
#
|
70
|
+
# So when we request a byte, or base64 representation the viewer will
|
71
|
+
# truncate (not round down) to the desired length.
|
72
|
+
#
|
73
|
+
#
|
74
|
+
# == YACHT 64 | Yet Another Character Table
|
75
|
+
#
|
76
|
+
# This binary key class is a dab hand at converting base64 strings
|
77
|
+
# into their 6-bit binary string equivalents.
|
78
|
+
#
|
79
|
+
# It can convert non-alphanumeric characters within either Base64 or
|
80
|
+
# Radix64 into the SafeDb YACHT64 standard which has a forward slash
|
81
|
+
# but neither a plus sign nor a period character.
|
82
|
+
#
|
83
|
+
# <b>The Big4 Character Sets | Base64 | UrlSafe64 | Radix64 | YACHT64</b>
|
84
|
+
#
|
85
|
+
# Base64 and Radix64 (from OpenBSD) differ in both the order of characters
|
86
|
+
# and their choice of the two non-alphanumeric characters. Base64 can also
|
87
|
+
# contain line breaks and equal signs for padding. UrlSafe base64 has different
|
88
|
+
# choices for the two non alphanum characters in keeping with URL standards.
|
89
|
+
#
|
90
|
+
# The character sets for each of the four 64 fomats are as follows.
|
91
|
+
#
|
92
|
+
# - Base-64 is <b>A to Z</b> then <b>a to z</b> then <b>0 to 9</b> then <b>+</b> then <b>/</b>
|
93
|
+
# - Radix64 is <b>.</b> then <b>/</b> then <b>0 to 9</b> then <b>A to Z</b> then <b>a to z</b>
|
94
|
+
# - UrlSafeBase64 is Base64 but chars 63/64 are an <b>underscore (_)</b> and <b>hyphen (-)</b>
|
95
|
+
# - UrlSafeBase64 <b>does not have line breaks and carriage returns</b> (unlike Base64)
|
96
|
+
# - <b>SafeDb 64 (YACHT64)</b> uses the same 62 characters plus an @ sign and a forward slash
|
97
|
+
# - The 64 <b>SafeDb 64</b> characters are <b>obfuscated into a random order</b>
|
98
|
+
#
|
99
|
+
# == 4 Non-AlphaNumerics | Base64 | Radix64 | YACHT64
|
100
|
+
#
|
101
|
+
# The behaviour here is happy to convert base64 strings produced by either
|
102
|
+
# Radix64 or Base64 or UrlSafe Base64. Howeverr it aware of the
|
103
|
+
# <b>non alpha-numeric characters</b> and converts them before processing
|
104
|
+
# with the modus operandi that says
|
105
|
+
#
|
106
|
+
# - ignore the forward slash in <b>YACHT64, Base64 and Radix64</b>
|
107
|
+
# - convert the <b>plus (+)</b> in Base64 to the <b>@ symbol</b> in YACHT64
|
108
|
+
# - convert the <b>period (.)</b> in <b>Radix64</b> to the @ symbol in YACHT64
|
109
|
+
# - convert <b>hyphen (-)</b> in <b>Url Safe Base64</b> into a fwd slash
|
110
|
+
# - convert <b>underscore (_)</b> in <b>Url Safe Base64</b> to an @ sign
|
111
|
+
# - <b>delete the (=) equals</b> padding character used by Base64
|
112
|
+
#
|
113
|
+
# Neither the OpenBSD backed Radix64 nor the SafeDb (YACHT64) entertain the
|
114
|
+
# concept of padding.
|
115
|
+
#
|
116
|
+
# == Mapping Each Character to 6 Binary Bits
|
117
|
+
#
|
118
|
+
# We need 6 binary bits to represent a base64 character (and 4
|
119
|
+
# bits for hexadecimal). Here is an example mapping between
|
120
|
+
# a base 64 character, an integer and the six bit binary.
|
121
|
+
#
|
122
|
+
# Character Integer Binary (6 Bit)
|
123
|
+
#
|
124
|
+
# a 0 000000
|
125
|
+
# b 1 000001
|
126
|
+
# c 2 000010
|
127
|
+
#
|
128
|
+
# y 25 011001
|
129
|
+
# z 26 011010
|
130
|
+
# A 27 011011
|
131
|
+
# B 28 011100
|
132
|
+
#
|
133
|
+
# 8 60 111100
|
134
|
+
# 9 61 111101
|
135
|
+
# / 62 111110
|
136
|
+
# + 63 111111
|
137
|
+
#
|
138
|
+
class Key64
|
139
|
+
|
140
|
+
# YACHT stands for <b>Yet Another Character Table</b> and it
|
141
|
+
# can map binary sequences onto 64 well chosen characters.
|
142
|
+
#
|
143
|
+
# The 64 character sets are all similar in that they hold 64
|
144
|
+
# characters and they define two non alphanumeric characters
|
145
|
+
# because the 26 lowercase, 26 uppercase and 10 digits only
|
146
|
+
# adds up to an <b><em>agonisingly close</em></b> 62 characters.
|
147
|
+
#
|
148
|
+
YACHT64_CHARACTER_SET = [
|
149
|
+
"a", "9", "W", "B", "f", "K", "O", "z",
|
150
|
+
"3", "s", "1", "5", "c", "n", "E", "J",
|
151
|
+
"L", "A", "l", "6", "I", "w", "o", "g",
|
152
|
+
"k", "N", "t", "Y", "S", "%", "T", "b",
|
153
|
+
"V", "R", "H", "0", "@", "Z", "8", "F",
|
154
|
+
"G", "j", "u", "m", "M", "h", "4", "p",
|
155
|
+
"q", "d", "7", "v", "e", "2", "U", "X",
|
156
|
+
"r", "C", "y", "Q", "D", "x", "P", "i"
|
157
|
+
]
|
158
|
+
|
159
|
+
|
160
|
+
# Radix64 strings can contain period characters in their midst.
|
161
|
+
PERIOD = "."
|
162
|
+
|
163
|
+
# Radix64 strings can contain forward slashes in their midst.
|
164
|
+
FORWARD_SLASH = "/"
|
165
|
+
|
166
|
+
# YACHT64 strings can contain at symbols in their midst.
|
167
|
+
AT_SYMBOL = "@"
|
168
|
+
|
169
|
+
# YACHT64 strings can contain percent signs in their midst.
|
170
|
+
PERCENT_SIGN = "%"
|
171
|
+
|
172
|
+
|
173
|
+
# Convert the parameter string of ones and zeroes into an
|
174
|
+
# internal base64 character set known as YACHT for yet another
|
175
|
+
# character table.
|
176
|
+
#
|
177
|
+
# @param bit_string [String]
|
178
|
+
# a string of ones and zeroes that can be sliced into
|
179
|
+
# six character chunks with each chunk then being mapped
|
180
|
+
# to a YACHT64 character.
|
181
|
+
#
|
182
|
+
# @return [String]
|
183
|
+
# printable characters from a set of 62 alpha-numerics
|
184
|
+
# plus an @ symbol and a percent % sign.
|
185
|
+
#
|
186
|
+
# @raise ArgumentError
|
187
|
+
# If the bit string is nil.
|
188
|
+
# Or if the bit string length is not a multiple of six.
|
189
|
+
# Or if it contains any character that is not a 1 or 0.
|
190
|
+
def self.from_bits bit_string
|
191
|
+
|
192
|
+
nil_err_msg = "The parameter bit string cannot be nil."
|
193
|
+
raise ArgumentError, nil_err_msg if bit_string.nil?
|
194
|
+
|
195
|
+
bit_size_msg = "The bit string length is not a multiple of #{SIX}."
|
196
|
+
raise ArgumentError, bit_size_msg unless bit_string.length % SIX == 0
|
197
|
+
|
198
|
+
num_unknowns = bit_string.delete("10").length
|
199
|
+
unknowns_msg = "The bit string has #{num_unknowns} characters that are not 1 or 0."
|
200
|
+
raise ArgumentError, unknowns_msg if num_unknowns > 0
|
201
|
+
|
202
|
+
characters64 = ""
|
203
|
+
char_count = bit_string.length / SIX
|
204
|
+
for n in 0 .. (char_count-1)
|
205
|
+
six_bit_chunk = bit_string[ (n*SIX), SIX ]
|
206
|
+
six_bit_index = six_bit_chunk.to_i(2)
|
207
|
+
characters64 += Key64.character(six_bit_index)
|
208
|
+
end
|
209
|
+
|
210
|
+
code_size_msg = "Length is #{characters64.length} but #{char_count} is expected."
|
211
|
+
raise RuntimeError, code_size_msg unless characters64.length == char_count
|
212
|
+
|
213
|
+
return characters64
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# Convert the parameter characters based on an internal base64
|
219
|
+
# character set (known as YACHT) into a <b>bit string</b> of ones
|
220
|
+
# and zeroes.
|
221
|
+
#
|
222
|
+
# @param char64_string [String]
|
223
|
+
# The base64 character sequence which which will be used to
|
224
|
+
# derive the returned bit string. Naturally this character
|
225
|
+
# sequencee cannot be nil, nor can it contain any characters
|
226
|
+
# that are not present in {Key64::YACHT64_CHARACTER_SET}.
|
227
|
+
#
|
228
|
+
# @return [String]
|
229
|
+
# a string of ones and zeroes that have been strung out
|
230
|
+
# from each YACHT64 character. The returned string length of
|
231
|
+
# ones and zeroes will be exactly 6 times the length of the
|
232
|
+
# input parameter.
|
233
|
+
#
|
234
|
+
# @raise [ArgumentError]
|
235
|
+
# If a nil or zero length character string is received.
|
236
|
+
# Or if the character sequence contains a character not present
|
237
|
+
# in the {Key64::YACHT64_CHARACTER_SET}.
|
238
|
+
#
|
239
|
+
# @raise [RuntimeError]
|
240
|
+
# if the conversion does not result in 6 bits for every character
|
241
|
+
# in the parameter string.
|
242
|
+
def self.to_bits char64_string
|
243
|
+
|
244
|
+
bit_string = ""
|
245
|
+
char64_string.each_char do |the_char|
|
246
|
+
|
247
|
+
yacht64_index = YACHT64_CHARACTER_SET.index(the_char)
|
248
|
+
assert_yacht64_index( the_char, yacht64_index )
|
249
|
+
bit_string += "%06d" % [ yacht64_index.to_s(2) ]
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
assert_bit_lengths char64_string, bit_string
|
254
|
+
return bit_string
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
# Convert a string of Radix64 characters into a bit representation which
|
260
|
+
# will be 6 times longer than the input parameter. This method first
|
261
|
+
# converts the string into the internal YACHT64 format and then converts
|
262
|
+
# that to a bit string using the {Key64.to_bits} method.
|
263
|
+
#
|
264
|
+
# @param radix64_string [String]
|
265
|
+
# the radix64 string to convert into bits. This string will be a subset
|
266
|
+
# of the usual 62 character suspects together with period and forward
|
267
|
+
# slash characters.
|
268
|
+
#
|
269
|
+
# This parameter should not contain newlines nor carriage returns.
|
270
|
+
#
|
271
|
+
# @return [String]
|
272
|
+
# a string of ones and zeroes that represent the bits converted from the
|
273
|
+
# radix64 input. The return value will be exactly 6 times the number of
|
274
|
+
# input characters.
|
275
|
+
def self.from_radix64_to_bits radix64_string
|
276
|
+
|
277
|
+
yacht64_chars = radix64_string.gsub( PERIOD, AT_SYMBOL ).gsub( FORWARD_SLASH, PERCENT_SIGN )
|
278
|
+
out_bitstring = to_bits( yacht64_chars )
|
279
|
+
assert_bit_lengths( radix64_string, out_bitstring )
|
280
|
+
return out_bitstring
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
|
286
|
+
private
|
287
|
+
|
288
|
+
|
289
|
+
|
290
|
+
SIX = 6
|
291
|
+
|
292
|
+
def self.character char_index
|
293
|
+
|
294
|
+
index_oob_msg = "The character index must be between 0 and 63 inclusive."
|
295
|
+
index_is_oob = char_index < 0 || char_index > 63
|
296
|
+
raise ArgumentError, index_oob_msg if index_is_oob
|
297
|
+
return YACHT64_CHARACTER_SET[ char_index ]
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
def self.assert_bit_lengths( in_string, out_string )
|
302
|
+
|
303
|
+
in_length = in_string.length
|
304
|
+
out_length = out_string.length
|
305
|
+
good_ratio = out_length == in_length * SIX
|
306
|
+
size_msg = "Bit string length [#{out_length}] not 6 times more than [#{in_length}]."
|
307
|
+
raise RuntimeError, size_msg unless good_ratio
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
def self.assert_yacht64_index the_char, yacht64_index
|
312
|
+
|
313
|
+
nil_msg = "Character [ #{the_char} ] not in YACHT character set."
|
314
|
+
raise ArgumentError, nil_msg if yacht64_index.nil?
|
315
|
+
|
316
|
+
index_msg = "Index of character [ #{the_char} ] not within expected bounds."
|
317
|
+
all_good = ( yacht64_index >= 0 ) && ( yacht64_index <= 63 )
|
318
|
+
raise ArgumentError, index_msg unless all_good
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
|
326
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
module SafeDb
|
5
|
+
|
6
|
+
# Algorithms that are quality catalysts in the derivation and entropy spread
|
7
|
+
# of keys, identifiers and base64 character numbers.
|
8
|
+
class KeyAlgo
|
9
|
+
|
10
|
+
|
11
|
+
# Cherry pick a given number of characters from the character pool
|
12
|
+
# so that a good spread is achieved. This picker is the anti-pattern
|
13
|
+
# of just axing the first 5 characters from a 100 character string
|
14
|
+
# essentially wasting over 90% of the available entropy.
|
15
|
+
#
|
16
|
+
# This is the <b>algorithem to cherry pick</b> a spread of characters
|
17
|
+
# from the pool in the second parameter.
|
18
|
+
#
|
19
|
+
# - if the character pool length is a multiple of num_chars all is good otherwise
|
20
|
+
# - constrict to the <b>highest multiple of the pick size below</b> the pool length
|
21
|
+
# - divide that number by num_chars to get the first offset and character spacing
|
22
|
+
# - if spacing is 3, the first character is the 3rd, the second the 6th and so on
|
23
|
+
# - then return the cherry picked characters
|
24
|
+
#
|
25
|
+
# @param pick_size [FixNum] the number of characters to cherry pick
|
26
|
+
# @param char_pool [String] a pool of characters to cherry pick from
|
27
|
+
# @return [String]
|
28
|
+
# a string whose length is the one indicated by the first parameter
|
29
|
+
# and whose characters contain a predictable, repeatable spread from
|
30
|
+
# the character pool parameter
|
31
|
+
def self.cherry_picker( pick_size, char_pool )
|
32
|
+
|
33
|
+
hmb_limit = highest_multiple_below( pick_size, char_pool.length )
|
34
|
+
jump_size = hmb_limit / pick_size
|
35
|
+
read_point = jump_size
|
36
|
+
picked_chars = ""
|
37
|
+
loop do
|
38
|
+
picked_chars += char_pool[ read_point - 1 ]
|
39
|
+
read_point += jump_size
|
40
|
+
break if read_point > hmb_limit
|
41
|
+
end
|
42
|
+
|
43
|
+
err_msg = "Expected cherry pick size to be #{pick_size} but it was #{picked_chars.length}."
|
44
|
+
raise RuntimeError, err_msg unless picked_chars.length == pick_size
|
45
|
+
|
46
|
+
return picked_chars
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Affectionately known as <b>a hmb</b>, this method returns the
|
52
|
+
# <b>highest multiple</b> of the first parameter that is below
|
53
|
+
# <b>(either less than or equal to)</b> the second parameter.
|
54
|
+
#
|
55
|
+
# - -------- - ------- - ----------------- -
|
56
|
+
# | Small | Big | Highest Multiple |
|
57
|
+
# | Number | Number | Below Big Num |
|
58
|
+
# | -------- - ------- - ----------------- |
|
59
|
+
# | 5 | 25 | 25 |
|
60
|
+
# | 3 | 20 | 18 |
|
61
|
+
# | 8 | 63 | 56 |
|
62
|
+
# | 1 | 1 | 1 |
|
63
|
+
# | 26 | 28 | 26 |
|
64
|
+
# | 1 | 7 | 7 |
|
65
|
+
# | 16 | 16 | 16 |
|
66
|
+
# | -------- - ------- - ----------------- |
|
67
|
+
# | 10 | 8 | ERROR |
|
68
|
+
# | -4 | 17 | ERROR |
|
69
|
+
# | 4 | -17 | ERROR |
|
70
|
+
# | 0 | 32 | ERROR |
|
71
|
+
# | 29 | 0 | ERROR |
|
72
|
+
# | -4 | 0 | ERROR |
|
73
|
+
# | -------- - ------- - ----------------- |
|
74
|
+
# - -------- - ------- - ----------------- -
|
75
|
+
#
|
76
|
+
# Zeroes and negative numbers cannot be entertained, nor can the
|
77
|
+
# small number be larger than the big one.
|
78
|
+
#
|
79
|
+
# @param small_num [FixNum]
|
80
|
+
# the highest multiple of this number below the one in the
|
81
|
+
# next parameter is what will be returned.
|
82
|
+
#
|
83
|
+
# @param big_num [FixNum]
|
84
|
+
# returns either this number or the nearest below it that is
|
85
|
+
# a multiple of the number in the first parameter.
|
86
|
+
#
|
87
|
+
# @raise [ArgumentError]
|
88
|
+
# if the first parameter is greater than the second
|
89
|
+
# if either or both parameters are zero or negative
|
90
|
+
def self.highest_multiple_below small_num, big_num
|
91
|
+
|
92
|
+
arg_issue = (small_num > big_num) || small_num < 1 || big_num < 1
|
93
|
+
err_msg = "Invalid args #{small_num} and #{big_num} to HMB function."
|
94
|
+
raise ArgumentError, err_msg if arg_issue
|
95
|
+
|
96
|
+
for index in 0 .. ( big_num - 1 )
|
97
|
+
invex = big_num - index # an [invex] is an inverted index
|
98
|
+
return invex if invex % small_num == 0
|
99
|
+
end
|
100
|
+
|
101
|
+
raise ArgumentError, "Could not find a multiple of #{small_num} lower than #{big_num}"
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
end
|