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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f102d8ba269aad3742c05649bbb698c01d639ee794c8adc9abe66fb285674f42
4
- data.tar.gz: 2f01f158959ed48ad413bb91970c7824efeb42392aca97b91e4d1be50a149e47
3
+ metadata.gz: 8ed77be628881ddd6bd6df0f7a60935e193db7cf91f5c928319eed9ac24295bf
4
+ data.tar.gz: 20906d11011e8ab3f95dcc9f20cae21b6945999a979b11c452b23f02726abda6
5
5
  SHA512:
6
- metadata.gz: c05246356ff182b57ca9acd01b6ee95269c4264a5d9cb1d947229de9ee9974e30a3860e4d860cec946c1ef22d9d9baa90dcf2f89bf843d8f5c749b3a0d64867c
7
- data.tar.gz: 1dc9944425d5a9105ebe59eb0b1dab1a06bb98ff94e032b476714ebc23281560ea78a0ffebb4a086f7da42a6fdcd1502f296a1f45f84d94b99d63461d00c25eb
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
- Layout/LineLength:
13
- Max: 120
38
+ Style/NegatedIf:
39
+ Enabled: false
40
+
41
+ Style/SymbolArray:
42
+ Enabled: false
43
+
44
+ Style/WordArray:
45
+ Enabled: false
data/.travis.yml CHANGED
@@ -2,5 +2,5 @@
2
2
  language: ruby
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.6.6
5
+ - 2.5.9
6
6
  before_install: gem install bundler -v 2.2.15
data/CHANGELOG.md CHANGED
@@ -1,4 +1,14 @@
1
- ## [Unreleased]
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
- gem "rake", "~> 13.0"
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 "rspec", "~> 3.0"
11
-
12
- gem "rubocop", "~> 1.7"
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.0)
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
- This is a direct Ruby port of Dropbox's [zxcvbn.js][zxcvbn.js] JavaScript library.
4
- The intention is to provide all the same features and same results as close to the original JS fucntion would do.
3
+ [![Gem Version](https://badge.fury.io/rb/zxcvbn.svg)](https://badge.fury.io/rb/zxcvbn)
4
+ [![Build Status](https://travis-ci.com/formigarafa/zxcvbn-rb.svg?branch=master)](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
- :password => "pasword",
28
- :guesses => 3566,
29
- :guesses_log10 => 3.5521813388393357,
30
- :sequence => [
31
+ "password" => "password",
32
+ "guesses" => 3,
33
+ "guesses_log10" => 0.47712125471966244,
34
+ "sequence" => [
31
35
  {
32
- :pattern => "dictionary",
33
- :i => 0,
34
- :j => 6,
35
- :token => "pasword",
36
- :matched_word => "pasword",
37
- :rank => 3565,
38
- :dictionary_name => "passwords",
39
- :reversed => false,
40
- :l33t => false,
41
- :base_guesses => 3565,
42
- :uppercase_variations => 1,
43
- :l33t_variations => 1,
44
- :guesses => 3565,
45
- :guesses_log10 => 3.5520595341878844
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
- :calc_time => 0,
49
- :crack_times_seconds => {
50
- :online_throttling_100_per_hour => 128376.0,
51
- :online_no_throttling_10_per_second => 356.6,
52
- :offline_slow_hashing_1e4_per_second => 0.3566,
53
- :offline_fast_hashing_1e10_per_second => 3.566e-07
54
- },
55
- :crack_times_display => {
56
- :online_throttling_100_per_hour => "1 day",
57
- :online_no_throttling_10_per_second => "6 minutes",
58
- :offline_slow_hashing_1e4_per_second => "less than a second",
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
- :score => 1,
62
- :feedback =>
63
- {
64
- :warning => "This is a very common password",
65
- :suggestions => ["Add another word or two. Uncommon words are better."]
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
@@ -11,5 +11,8 @@ require "zxcvbn"
11
11
  # require "pry"
12
12
  # Pry.start
13
13
 
14
- require "irb"
15
- IRB.start(__FILE__)
14
+ # require "irb"
15
+ # IRB.start(__FILE__)
16
+
17
+ require "pry"
18
+ Pry.start("main")
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.set_user_input_dictionary(sanitized_inputs)
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[:calc_time] = (Time.now.to_f * 1000).to_i - start
27
- attack_times = TimeEstimates.estimate_attack_times(result[:guesses])
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[:feedback] = Feedback.get_feedback(result[:score], result[:sequence])
32
- return result
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
- "\"" => [";:", "[{", "]}", nil, nil, "/?"],
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
- "/" => [".>", ";:", "'\"", nil, nil, nil],
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
- "?" => [".>", ";:", "'\"", nil, nil, nil],
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
- "\\" => ["]}", nil, nil, nil, nil, nil],
67
- "]" => ["[{", "=+", nil, "\\|", 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, "\\|", nil, "'\""],
101
+ "}" => ["[{", "=+", nil, "\\|", nil, "'\""],
100
102
  "~" => [ nil, nil, nil, "1!", nil, nil]
101
103
  },
102
- dvorak: {
103
- "!" => ["`~", nil, nil, "2@", "'\"", nil],
104
- "\"" => [ nil, "1!", "2@", ",<", "aA", nil],
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, "\\|", 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@", "'\"", nil],
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", ";:", nil],
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
- "\\" => ["=+", nil, nil, nil, nil, nil],
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", ";:", nil],
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
- "*" => ["/", nil, nil, nil, "-", "+", "9", "8"],
200
- "+" => ["9", "*", "-", nil, nil, nil, nil, "6"],
201
- "-" => ["*", nil, nil, nil, nil, nil, "+", "9"],
202
- "." => ["0", "2", "3", nil, nil, nil, nil, nil],
203
- "/" => [ nil, nil, nil, nil, "*", "9", "8", "7"],
204
- "0" => [ nil, "1", "2", "3", ".", nil, nil, nil],
205
- "1" => [ nil, nil, "4", "5", "2", "0", nil, nil],
206
- "2" => ["1", "4", "5", "6", "3", ".", "0", nil],
207
- "3" => ["2", "5", "6", nil, nil, nil, ".", "0"],
208
- "4" => [ nil, nil, "7", "8", "5", "2", "1", nil],
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", "+", nil, nil, "3", "2"],
211
- "7" => [ nil, nil, nil, "/", "8", "5", "4", nil],
212
- "8" => ["7", nil, "/", "*", "9", "6", "5", "4"],
213
- "9" => ["8", "/", "*", "-", "+", nil, "6", "5"]
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
- "*" => ["/", nil, nil, nil, nil, nil, "-", "9"],
217
- "+" => ["6", "9", "-", nil, nil, nil, nil, "3"],
218
- "-" => ["9", "/", "*", nil, nil, nil, "+", "6"],
219
- "." => ["0", "2", "3", nil, nil, nil, nil, nil],
220
- "/" => ["=", nil, nil, nil, "*", "-", "9", "8"],
221
- "0" => [ nil, "1", "2", "3", ".", nil, nil, nil],
222
- "1" => [ nil, nil, "4", "5", "2", "0", nil, nil],
223
- "2" => ["1", "4", "5", "6", "3", ".", "0", nil],
224
- "3" => ["2", "5", "6", "+", nil, nil, ".", "0"],
225
- "4" => [ nil, nil, "7", "8", "5", "2", "1", nil],
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", "-", "+", nil, "3", "2"],
228
- "7" => [ nil, nil, nil, "=", "8", "5", "4", nil],
229
- "8" => ["7", nil, "=", "/", "9", "6", "5", "4"],
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
- "=" => [ nil, nil, nil, nil, "/", "9", "8", "7"]
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