zxcvbn 0.1.1 → 0.1.6
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 +4 -4
- data/.rubocop.yml +34 -2
- data/.travis.yml +1 -1
- data/CHANGELOG.md +11 -1
- data/Gemfile +9 -4
- data/Gemfile.lock +26 -1
- data/README.md +45 -37
- data/bin/console +5 -2
- data/lib/zxcvbn.rb +17 -9
- data/lib/zxcvbn/adjacency_graphs.rb +50 -46
- data/lib/zxcvbn/feedback.rb +68 -70
- data/lib/zxcvbn/frequency_lists.rb +9 -7
- data/lib/zxcvbn/matching.rb +232 -249
- data/lib/zxcvbn/scoring.rb +153 -167
- data/lib/zxcvbn/time_estimates.rb +18 -20
- data/lib/zxcvbn/version.rb +1 -1
- data/zxcvbn.gemspec +2 -2
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ed77be628881ddd6bd6df0f7a60935e193db7cf91f5c928319eed9ac24295bf
|
4
|
+
data.tar.gz: 20906d11011e8ab3f95dcc9f20cae21b6945999a979b11c452b23f02726abda6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6ac81d9c47f5f4a006b7e5e071f0f2fd119d0f9f721d28d7725ab07f8eafa4478f727652b7e51a87d82d5022e761550cecc6f83ff2f38b8cd0171d51061f97b
|
7
|
+
data.tar.gz: ec59a970bc9037714b93c3d73738b995afa224c25cdca4dd8309e74f7e11df58fe7f618f72805ea004f23ac3387a8f98fa2548d9d2c00419231f7e0e07307db7
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
AllCops:
|
2
2
|
TargetRubyVersion: 2.5
|
3
|
+
NewCops: enable
|
4
|
+
SuggestExtensions: false
|
5
|
+
|
6
|
+
Layout/EndAlignment:
|
7
|
+
EnforcedStyleAlignWith: start_of_line
|
8
|
+
|
9
|
+
Layout/LineLength:
|
10
|
+
Max: 120
|
11
|
+
|
12
|
+
Lint/UnderscorePrefixedVariableName:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Metrics:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Naming/VariableNumber:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/Documentation:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Style/Next:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/NumericPredicate:
|
28
|
+
Enabled: false
|
3
29
|
|
4
30
|
Style/StringLiterals:
|
5
31
|
Enabled: true
|
@@ -9,5 +35,11 @@ Style/StringLiteralsInInterpolation:
|
|
9
35
|
Enabled: true
|
10
36
|
EnforcedStyle: double_quotes
|
11
37
|
|
12
|
-
|
13
|
-
|
38
|
+
Style/NegatedIf:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/SymbolArray:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/WordArray:
|
45
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
## [
|
1
|
+
## [0.1.6] - 2021-05-28
|
2
|
+
- Added test methods for compatibility with zxcvbn-js and zxcvbn-ruby.
|
3
|
+
|
4
|
+
## [0.1.5] - 2021-05-27
|
5
|
+
- Fix classification of scoring causing differences between js and ruby.
|
6
|
+
|
7
|
+
## [0.1.4] - 2021-05-16
|
8
|
+
|
9
|
+
- Bunch of fixes, all example passwords included have same result as js version.
|
10
|
+
- consistent code style applied.
|
11
|
+
|
2
12
|
|
3
13
|
## [0.1.0] - 2021-05-16
|
4
14
|
|
data/Gemfile
CHANGED
@@ -5,8 +5,13 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in zxcvbn.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
|
8
|
+
group :development do
|
9
|
+
gem "mini_racer"
|
10
|
+
gem "rake", "~> 13.0"
|
11
|
+
gem "rspec", "~> 3.0"
|
12
|
+
gem "rubocop", "~> 1.7"
|
9
13
|
|
10
|
-
gem "
|
11
|
-
|
12
|
-
gem "
|
14
|
+
gem "pry"
|
15
|
+
gem "pry-byebug"
|
16
|
+
gem "simplecov", require: false
|
17
|
+
end
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,30 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
zxcvbn (0.1.
|
4
|
+
zxcvbn (0.1.6)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.4.2)
|
10
|
+
byebug (11.1.3)
|
11
|
+
coderay (1.1.3)
|
10
12
|
diff-lcs (1.4.4)
|
13
|
+
docile (1.4.0)
|
14
|
+
libv8-node (15.14.0.1-x86_64-darwin-19)
|
15
|
+
libv8-node (15.14.0.1-x86_64-linux)
|
16
|
+
method_source (1.0.0)
|
17
|
+
mini_racer (0.4.0)
|
18
|
+
libv8-node (~> 15.14.0.0)
|
11
19
|
parallel (1.20.1)
|
12
20
|
parser (3.0.1.1)
|
13
21
|
ast (~> 2.4.1)
|
22
|
+
pry (0.14.1)
|
23
|
+
coderay (~> 1.1)
|
24
|
+
method_source (~> 1.0)
|
25
|
+
pry-byebug (3.8.0)
|
26
|
+
byebug (~> 11.0)
|
27
|
+
pry (~> 0.10)
|
14
28
|
rainbow (3.0.0)
|
15
29
|
rake (13.0.3)
|
16
30
|
regexp_parser (2.1.1)
|
@@ -40,15 +54,26 @@ GEM
|
|
40
54
|
rubocop-ast (1.5.0)
|
41
55
|
parser (>= 3.0.1.1)
|
42
56
|
ruby-progressbar (1.11.0)
|
57
|
+
simplecov (0.21.2)
|
58
|
+
docile (~> 1.1)
|
59
|
+
simplecov-html (~> 0.11)
|
60
|
+
simplecov_json_formatter (~> 0.1)
|
61
|
+
simplecov-html (0.12.3)
|
62
|
+
simplecov_json_formatter (0.1.3)
|
43
63
|
unicode-display_width (2.0.0)
|
44
64
|
|
45
65
|
PLATFORMS
|
46
66
|
x86_64-darwin-19
|
67
|
+
x86_64-linux
|
47
68
|
|
48
69
|
DEPENDENCIES
|
70
|
+
mini_racer
|
71
|
+
pry
|
72
|
+
pry-byebug
|
49
73
|
rake (~> 13.0)
|
50
74
|
rspec (~> 3.0)
|
51
75
|
rubocop (~> 1.7)
|
76
|
+
simplecov
|
52
77
|
zxcvbn!
|
53
78
|
|
54
79
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
# Zxcvbn
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
[](https://badge.fury.io/rb/zxcvbn)
|
4
|
+
[](https://travis-ci.com/formigarafa/zxcvbn-rb)
|
5
|
+
|
6
|
+
Ruby port of Dropbox's [zxcvbn.js][zxcvbn.js] JavaScript library running completely in Ruby (no need to load execjs or libv8).
|
7
|
+
|
8
|
+
The intention is to provide an option 100% Ruby solution with all the same features and same results (or as close to the original JS function as possible).
|
5
9
|
|
6
10
|
## Installation
|
7
11
|
|
@@ -24,49 +28,53 @@ Or install it yourself as:
|
|
24
28
|
```
|
25
29
|
Zxcvbn.zxcvbn("password")
|
26
30
|
=> {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
"password" => "password",
|
32
|
+
"guesses" => 3,
|
33
|
+
"guesses_log10" => 0.47712125471966244,
|
34
|
+
"sequence" => [
|
31
35
|
{
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
"pattern" => "dictionary",
|
37
|
+
"i" => 0,
|
38
|
+
"j" => 7,
|
39
|
+
"token" => "password",
|
40
|
+
"matched_word" => "password",
|
41
|
+
"rank" => 2,
|
42
|
+
"dictionary_name" => "passwords",
|
43
|
+
"reversed" => false,
|
44
|
+
"l33t" => false,
|
45
|
+
"base_guesses" => 2,
|
46
|
+
"uppercase_variations" => 1,
|
47
|
+
"l33t_variations" => 1,
|
48
|
+
"guesses" => 2,
|
49
|
+
"guesses_log10" => 0.3010299956639812
|
46
50
|
}
|
47
51
|
],
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
:offline_fast_hashing_1e10_per_second => "less than a second"
|
52
|
+
"calc_time" => 1,
|
53
|
+
"crack_times_seconds" => {
|
54
|
+
"online_throttling_100_per_hour" => 108.0,
|
55
|
+
"online_no_throttling_10_per_second" => 0.3,
|
56
|
+
"offline_slow_hashing_1e4_per_second" => 0.0003,
|
57
|
+
"offline_fast_hashing_1e10_per_second" => 3.0e-10},
|
58
|
+
"crack_times_display" => {
|
59
|
+
"online_throttling_100_per_hour" => "2 minutes",
|
60
|
+
"online_no_throttling_10_per_second" => "less than a second",
|
61
|
+
"offline_slow_hashing_1e4_per_second" => "less than a second",
|
62
|
+
"offline_fast_hashing_1e10_per_second" => "less than a second"
|
60
63
|
},
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
"score" => 0,
|
65
|
+
"feedback" => {
|
66
|
+
"warning" => "This is a top-10 common password",
|
67
|
+
"suggestions" => [
|
68
|
+
"Add another word or two. Uncommon words are better."
|
69
|
+
]
|
66
70
|
}
|
67
71
|
}
|
68
72
|
```
|
69
73
|
|
74
|
+
### Compatible with `zxcvbn-js` and `zxcvbn-ruby`
|
75
|
+
|
76
|
+
This gem include a compatible interface so it can be used as a drop-in substitution for `zxcvbn-js` or `zxcvbn-ruby`. You can just call `Zxcvbn.test` or use `Zxcvbn::Tester.new` the same way as you would if you were using `zxcvbn-js` or `zxcvbn-ruby`.
|
77
|
+
|
70
78
|
## Development
|
71
79
|
|
72
80
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/console
CHANGED
data/lib/zxcvbn.rb
CHANGED
@@ -14,21 +14,29 @@ module Zxcvbn
|
|
14
14
|
def self.zxcvbn(password, user_inputs = [])
|
15
15
|
start = (Time.now.to_f * 1000).to_i
|
16
16
|
# reset the user inputs matcher on a per-request basis to keep things stateless
|
17
|
-
sanitized_inputs = []
|
17
|
+
sanitized_inputs = []
|
18
18
|
user_inputs.each do |arg|
|
19
|
-
if arg.is_a?(String) || arg.is_a?(Numeric) || arg == true || arg == false
|
20
|
-
sanitized_inputs << arg.to_s.downcase
|
21
|
-
end
|
19
|
+
sanitized_inputs << arg.to_s.downcase if arg.is_a?(String) || arg.is_a?(Numeric) || arg == true || arg == false
|
22
20
|
end
|
23
|
-
Matching.
|
21
|
+
Matching.user_input_dictionary = sanitized_inputs
|
24
22
|
matches = Matching.omnimatch(password)
|
25
23
|
result = Scoring.most_guessable_match_sequence(password, matches)
|
26
|
-
result[
|
27
|
-
attack_times = TimeEstimates.estimate_attack_times(result[
|
24
|
+
result["calc_time"] = (Time.now.to_f * 1000).to_i - start
|
25
|
+
attack_times = TimeEstimates.estimate_attack_times(result["guesses"])
|
28
26
|
attack_times.each do |prop, val|
|
29
27
|
result[prop] = val
|
30
28
|
end
|
31
|
-
result[
|
32
|
-
|
29
|
+
result["feedback"] = Feedback.get_feedback(result["score"], result["sequence"])
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.test(password, user_inputs = [])
|
34
|
+
OpenStruct.new(Zxcvbn.zxcvbn(password, user_inputs))
|
35
|
+
end
|
36
|
+
|
37
|
+
class Tester
|
38
|
+
def test(password, user_inputs = [])
|
39
|
+
Zxcvbn.test(password, user_inputs)
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
# generated by scripts/build_keyboard_adjacency_graphs.py
|
4
4
|
module Zxcvbn
|
5
|
+
# rubocop:disable Layout/SpaceInsideArrayLiteralBrackets
|
6
|
+
# rubocop:disable Layout/ExtraSpacing
|
5
7
|
ADJACENCY_GRAPHS = {
|
6
|
-
qwerty
|
8
|
+
"qwerty" => {
|
7
9
|
"!" => ["`~", nil, nil, "2@", "qQ", nil],
|
8
|
-
"\"" => [";:", "[{", "]}",
|
10
|
+
"\"" => [";:", "[{", "]}", nil, nil, "/?"],
|
9
11
|
"#" => ["2@", nil, nil, "4$", "eE", "wW"],
|
10
12
|
"$" => ["3#", nil, nil, "5%", "rR", "eE"],
|
11
13
|
"%" => ["4$", nil, nil, "6^", "tT", "rR"],
|
@@ -18,7 +20,7 @@ module Zxcvbn
|
|
18
20
|
"," => ["mM", "kK", "lL", ".>", nil, nil],
|
19
21
|
"-" => ["0)", nil, nil, "=+", "[{", "pP"],
|
20
22
|
"." => [",<", "lL", ";:", "/?", nil, nil],
|
21
|
-
"/" => [".>", ";:", "'\"",
|
23
|
+
"/" => [".>", ";:", "'\"", nil, nil, nil],
|
22
24
|
"0" => ["9(", nil, nil, "-_", "pP", "oO"],
|
23
25
|
"1" => ["`~", nil, nil, "2@", "qQ", nil],
|
24
26
|
"2" => ["1!", nil, nil, "3#", "wW", "qQ"],
|
@@ -34,7 +36,7 @@ module Zxcvbn
|
|
34
36
|
"<" => ["mM", "kK", "lL", ".>", nil, nil],
|
35
37
|
"=" => ["-_", nil, nil, nil, "]}", "[{"],
|
36
38
|
">" => [",<", "lL", ";:", "/?", nil, nil],
|
37
|
-
"?" => [".>", ";:", "'\"",
|
39
|
+
"?" => [".>", ";:", "'\"", nil, nil, nil],
|
38
40
|
"@" => ["1!", nil, nil, "3#", "wW", "qQ"],
|
39
41
|
"A" => [ nil, "qQ", "wW", "sS", "zZ", nil],
|
40
42
|
"B" => ["vV", "gG", "hH", "nN", nil, nil],
|
@@ -63,8 +65,8 @@ module Zxcvbn
|
|
63
65
|
"Y" => ["tT", "6^", "7&", "uU", "hH", "gG"],
|
64
66
|
"Z" => [ nil, "aA", "sS", "xX", nil, nil],
|
65
67
|
"[" => ["pP", "-_", "=+", "]}", "'\"", ";:"],
|
66
|
-
"\\" => ["]}",
|
67
|
-
"]" => ["[{", "=+", nil, "\\|",
|
68
|
+
"\\" => ["]}", nil, nil, nil, nil, nil],
|
69
|
+
"]" => ["[{", "=+", nil, "\\|", nil, "'\""],
|
68
70
|
"^" => ["5%", nil, nil, "7&", "yY", "tT"],
|
69
71
|
"_" => ["0)", nil, nil, "=+", "[{", "pP"],
|
70
72
|
"`" => [ nil, nil, nil, "1!", nil, nil],
|
@@ -96,12 +98,12 @@ module Zxcvbn
|
|
96
98
|
"z" => [ nil, "aA", "sS", "xX", nil, nil],
|
97
99
|
"{" => ["pP", "-_", "=+", "]}", "'\"", ";:"],
|
98
100
|
"|" => ["]}", nil, nil, nil, nil, nil],
|
99
|
-
"}" => ["[{", "=+", nil, "\\|",
|
101
|
+
"}" => ["[{", "=+", nil, "\\|", nil, "'\""],
|
100
102
|
"~" => [ nil, nil, nil, "1!", nil, nil]
|
101
103
|
},
|
102
|
-
dvorak
|
103
|
-
"!" => ["`~", nil, nil, "2@", "'\"",
|
104
|
-
"\"" => [ nil, "1!", "2@", ",<", "aA",
|
104
|
+
"dvorak" => {
|
105
|
+
"!" => ["`~", nil, nil, "2@", "'\"", nil],
|
106
|
+
"\"" => [ nil, "1!", "2@", ",<", "aA", nil],
|
105
107
|
"#" => ["2@", nil, nil, "4$", ".>", ",<"],
|
106
108
|
"$" => ["3#", nil, nil, "5%", "pP", ".>"],
|
107
109
|
"%" => ["4$", nil, nil, "6^", "yY", "pP"],
|
@@ -110,13 +112,13 @@ module Zxcvbn
|
|
110
112
|
"(" => ["8*", nil, nil, "0)", "rR", "cC"],
|
111
113
|
")" => ["9(", nil, nil, "[{", "lL", "rR"],
|
112
114
|
"*" => ["7&", nil, nil, "9(", "cC", "gG"],
|
113
|
-
"+" => ["/?", "]}", nil, "\\|",
|
115
|
+
"+" => ["/?", "]}", nil, "\\|", nil, "-_"],
|
114
116
|
"," => ["'\"", "2@", "3#", ".>", "oO", "aA"],
|
115
117
|
"-" => ["sS", "/?", "=+", nil, nil, "zZ"],
|
116
118
|
"." => [",<", "3#", "4$", "pP", "eE", "oO"],
|
117
119
|
"/" => ["lL", "[{", "]}", "=+", "-_", "sS"],
|
118
120
|
"0" => ["9(", nil, nil, "[{", "lL", "rR"],
|
119
|
-
"1" => ["`~", nil, nil, "2@", "'\"",
|
121
|
+
"1" => ["`~", nil, nil, "2@", "'\"", nil],
|
120
122
|
"2" => ["1!", nil, nil, "3#", ",<", "'\""],
|
121
123
|
"3" => ["2@", nil, nil, "4$", ".>", ",<"],
|
122
124
|
"4" => ["3#", nil, nil, "5%", "pP", ".>"],
|
@@ -132,7 +134,7 @@ module Zxcvbn
|
|
132
134
|
">" => [",<", "3#", "4$", "pP", "eE", "oO"],
|
133
135
|
"?" => ["lL", "[{", "]}", "=+", "-_", "sS"],
|
134
136
|
"@" => ["1!", nil, nil, "3#", ",<", "'\""],
|
135
|
-
"A" => [ nil, "'\"", ",<", "oO", ";:",
|
137
|
+
"A" => [ nil, "'\"", ",<", "oO", ";:", nil],
|
136
138
|
"B" => ["xX", "dD", "hH", "mM", nil, nil],
|
137
139
|
"C" => ["gG", "8*", "9(", "rR", "tT", "hH"],
|
138
140
|
"D" => ["iI", "fF", "gG", "hH", "bB", "xX"],
|
@@ -159,12 +161,12 @@ module Zxcvbn
|
|
159
161
|
"Y" => ["pP", "5%", "6^", "fF", "iI", "uU"],
|
160
162
|
"Z" => ["vV", "sS", "-_", nil, nil, nil],
|
161
163
|
"[" => ["0)", nil, nil, "]}", "/?", "lL"],
|
162
|
-
"\\" => ["=+",
|
164
|
+
"\\" => ["=+", nil, nil, nil, nil, nil],
|
163
165
|
"]" => ["[{", nil, nil, nil, "=+", "/?"],
|
164
166
|
"^" => ["5%", nil, nil, "7&", "fF", "yY"],
|
165
167
|
"_" => ["sS", "/?", "=+", nil, nil, "zZ"],
|
166
168
|
"`" => [ nil, nil, nil, "1!", nil, nil],
|
167
|
-
"a" => [ nil, "'\"", ",<", "oO", ";:",
|
169
|
+
"a" => [ nil, "'\"", ",<", "oO", ";:", nil],
|
168
170
|
"b" => ["xX", "dD", "hH", "mM", nil, nil],
|
169
171
|
"c" => ["gG", "8*", "9(", "rR", "tT", "hH"],
|
170
172
|
"d" => ["iI", "fF", "gG", "hH", "bB", "xX"],
|
@@ -195,40 +197,42 @@ module Zxcvbn
|
|
195
197
|
"}" => ["[{", nil, nil, nil, "=+", "/?"],
|
196
198
|
"~" => [ nil, nil, nil, "1!", nil, nil]
|
197
199
|
},
|
198
|
-
keypad
|
199
|
-
"*" => ["/",
|
200
|
-
"+" => ["9", "*", "-",
|
201
|
-
"-" => ["*",
|
202
|
-
"." => ["0", "2", "3",
|
203
|
-
"/" => [
|
204
|
-
"0" => [
|
205
|
-
"1" => [
|
206
|
-
"2" => ["1", "4", "5", "6", "3", ".", "0",
|
207
|
-
"3" => ["2", "5", "6",
|
208
|
-
"4" => [
|
200
|
+
"keypad" => {
|
201
|
+
"*" => ["/", nil, nil, nil, "-", "+", "9", "8"],
|
202
|
+
"+" => ["9", "*", "-", nil, nil, nil, nil, "6"],
|
203
|
+
"-" => ["*", nil, nil, nil, nil, nil, "+", "9"],
|
204
|
+
"." => ["0", "2", "3", nil, nil, nil, nil, nil],
|
205
|
+
"/" => [nil, nil, nil, nil, "*", "9", "8", "7"],
|
206
|
+
"0" => [nil, "1", "2", "3", ".", nil, nil, nil],
|
207
|
+
"1" => [nil, nil, "4", "5", "2", "0", nil, nil],
|
208
|
+
"2" => ["1", "4", "5", "6", "3", ".", "0", nil],
|
209
|
+
"3" => ["2", "5", "6", nil, nil, nil, ".", "0"],
|
210
|
+
"4" => [nil, nil, "7", "8", "5", "2", "1", nil],
|
209
211
|
"5" => ["4", "7", "8", "9", "6", "3", "2", "1"],
|
210
|
-
"6" => ["5", "8", "9", "+",
|
211
|
-
"7" => [
|
212
|
-
"8" => ["7",
|
213
|
-
"9" => ["8", "/", "*", "-", "+",
|
212
|
+
"6" => ["5", "8", "9", "+", nil, nil, "3", "2"],
|
213
|
+
"7" => [nil, nil, nil, "/", "8", "5", "4", nil],
|
214
|
+
"8" => ["7", nil, "/", "*", "9", "6", "5", "4"],
|
215
|
+
"9" => ["8", "/", "*", "-", "+", nil, "6", "5"]
|
214
216
|
},
|
215
|
-
mac_keypad
|
216
|
-
"*" => ["/",
|
217
|
-
"+" => ["6", "9", "-",
|
218
|
-
"-" => ["9", "/", "*",
|
219
|
-
"." => ["0", "2", "3",
|
220
|
-
"/" => ["=",
|
221
|
-
"0" => [
|
222
|
-
"1" => [
|
223
|
-
"2" => ["1", "4", "5", "6", "3", ".", "0",
|
224
|
-
"3" => ["2", "5", "6", "+",
|
225
|
-
"4" => [
|
217
|
+
"mac_keypad" => {
|
218
|
+
"*" => ["/", nil, nil, nil, nil, nil, "-", "9"],
|
219
|
+
"+" => ["6", "9", "-", nil, nil, nil, nil, "3"],
|
220
|
+
"-" => ["9", "/", "*", nil, nil, nil, "+", "6"],
|
221
|
+
"." => ["0", "2", "3", nil, nil, nil, nil, nil],
|
222
|
+
"/" => ["=", nil, nil, nil, "*", "-", "9", "8"],
|
223
|
+
"0" => [nil, "1", "2", "3", ".", nil, nil, nil],
|
224
|
+
"1" => [nil, nil, "4", "5", "2", "0", nil, nil],
|
225
|
+
"2" => ["1", "4", "5", "6", "3", ".", "0", nil],
|
226
|
+
"3" => ["2", "5", "6", "+", nil, nil, ".", "0"],
|
227
|
+
"4" => [nil, nil, "7", "8", "5", "2", "1", nil],
|
226
228
|
"5" => ["4", "7", "8", "9", "6", "3", "2", "1"],
|
227
|
-
"6" => ["5", "8", "9", "-", "+",
|
228
|
-
"7" => [
|
229
|
-
"8" => ["7",
|
229
|
+
"6" => ["5", "8", "9", "-", "+", nil, "3", "2"],
|
230
|
+
"7" => [nil, nil, nil, "=", "8", "5", "4", nil],
|
231
|
+
"8" => ["7", nil, "=", "/", "9", "6", "5", "4"],
|
230
232
|
"9" => ["8", "=", "/", "*", "-", "+", "6", "5"],
|
231
|
-
"=" => [
|
233
|
+
"=" => [nil, nil, nil, nil, "/", "9", "8", "7"]
|
232
234
|
}
|
233
|
-
}
|
235
|
+
}.freeze
|
236
|
+
# rubocop:enable Layout/ExtraSpacing
|
237
|
+
# rubocop:enable Layout/SpaceInsideArrayLiteralBrackets
|
234
238
|
end
|