da_funk 0.4.4

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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.yardopts +12 -0
  4. data/Gemfile +7 -0
  5. data/Gemfile.lock +21 -0
  6. data/README.md +108 -0
  7. data/README_GUIDE.md +52 -0
  8. data/RELEASE_NOTES.md +23 -0
  9. data/Rakefile +69 -0
  10. data/da_funk.gemspec +31 -0
  11. data/ext/da_funk/Makefile +5 -0
  12. data/ext/da_funk/extconf.rb +8 -0
  13. data/guides/sample_input_output.rb +14 -0
  14. data/guides/sample_message_iso8583.rb +14 -0
  15. data/guides/sample_network_gprs.rb +26 -0
  16. data/guides/sample_read_magnect_card.rb +8 -0
  17. data/guides/sample_socket.rb +29 -0
  18. data/guides/sample_transaction.rb +23 -0
  19. data/guides/sample_transaction_download_application.rb +9 -0
  20. data/guides/sample_transaction_download_file.rb +6 -0
  21. data/guides/sample_transaction_download_parameter_file.rb +18 -0
  22. data/guides/sample_transaction_iso8583.rb +222 -0
  23. data/imgs/daft-punk-da-funk.jpg +0 -0
  24. data/lib/da_funk/rake_task.rb +129 -0
  25. data/lib/da_funk/test.rb +87 -0
  26. data/lib/da_funk.rb +39 -0
  27. data/lib/device/application.rb +41 -0
  28. data/lib/device/audio.rb +17 -0
  29. data/lib/device/crypto.rb +52 -0
  30. data/lib/device/display.rb +47 -0
  31. data/lib/device/helper.rb +161 -0
  32. data/lib/device/io.rb +86 -0
  33. data/lib/device/magnetic.rb +79 -0
  34. data/lib/device/network.rb +192 -0
  35. data/lib/device/notification.rb +116 -0
  36. data/lib/device/notification_callback.rb +47 -0
  37. data/lib/device/notification_event.rb +29 -0
  38. data/lib/device/params_dat.rb +119 -0
  39. data/lib/device/printer.rb +35 -0
  40. data/lib/device/runtime.rb +22 -0
  41. data/lib/device/setting.rb +63 -0
  42. data/lib/device/support.rb +28 -0
  43. data/lib/device/system.rb +61 -0
  44. data/lib/device/transaction/download.rb +268 -0
  45. data/lib/device/transaction/emv.rb +45 -0
  46. data/lib/device/transaction/iso.rb +75 -0
  47. data/lib/device/version.rb +11 -0
  48. data/lib/device/walk.rb +8 -0
  49. data/lib/device.rb +28 -0
  50. data/lib/ext/kernel.rb +9 -0
  51. data/lib/file_db.rb +47 -0
  52. data/lib/iso8583/bitmap.rb +114 -0
  53. data/lib/iso8583/codec.rb +197 -0
  54. data/lib/iso8583/exception.rb +4 -0
  55. data/lib/iso8583/field.rb +90 -0
  56. data/lib/iso8583/fields.rb +171 -0
  57. data/lib/iso8583/message.rb +455 -0
  58. data/lib/iso8583/util.rb +91 -0
  59. data/lib/iso8583/version.rb +6 -0
  60. data/lib/serfx/commands.rb +191 -0
  61. data/lib/serfx/connection.rb +160 -0
  62. data/lib/serfx/exceptions.rb +5 -0
  63. data/lib/serfx/response.rb +28 -0
  64. data/lib/serfx.rb +27 -0
  65. data/lib/version.rb +5 -0
  66. data/lib/zip.rb +29 -0
  67. data/test/integration/getc_test.rb +6 -0
  68. data/test/integration/mrb_eval_test.rb +36 -0
  69. data/test/integration/notification_test.rb +20 -0
  70. data/test/integration/params_dat_test.rb +11 -0
  71. data/test/test_helper.rb +18 -0
  72. data/test/unit/device/display_test.rb +43 -0
  73. data/test/unit/device/helper_test.rb +61 -0
  74. data/test/unit/device/notification_callback_test.rb +6 -0
  75. data/test/unit/device/notification_event_test.rb +73 -0
  76. data/test/unit/device/notification_test.rb +21 -0
  77. data/utils/command_line_platform.rb +67 -0
  78. data/utils/test_run.rb +3 -0
  79. metadata +177 -0
@@ -0,0 +1,119 @@
1
+ class Device
2
+ class ParamsDat
3
+ FILE_NAME = "./main/params.dat"
4
+
5
+ include Device::Helper
6
+
7
+ class << self
8
+ attr_accessor :file, :apps, :status
9
+ end
10
+
11
+ self.apps = Array.new
12
+
13
+ # To control if there is any app and parse worked
14
+ self.status = false
15
+
16
+ def self.setup
17
+ if File.exists?(FILE_NAME)
18
+ @file = FileDb.new(FILE_NAME)
19
+ else
20
+ false
21
+ end
22
+ end
23
+
24
+ # TODO Scalone: Change after @bmsatierf change the format
25
+ # For each apps on apps_list We'll have:
26
+ # Today: <label>,<arquivo>,<pages>,<crc>;
27
+ # After: <label>,<arquivo>,<type>,<crc>;
28
+ # Today: "1 - App,pc2_app.posxml,1,E0A0;"
29
+ # After: "1 - App,pc2_app.posxml,posxml,E0A0;"
30
+ # After: "1 - App,pc2_app.zip,ruby,E0A0;"
31
+ def self.parse_apps
32
+ @apps = []
33
+ return unless self.setup
34
+
35
+ self.file["apps_list"].to_s.gsub("\"", "").split(";").each do |app|
36
+ @apps << Device::Application.new(*app.split(","))
37
+ end
38
+
39
+ if (@apps.size >= 1)
40
+ self.status = true
41
+ else
42
+ self.status = false
43
+ end
44
+ end
45
+
46
+ def self.download
47
+ if attach
48
+ Device::Display.clear
49
+ puts "Downloading Params"
50
+ ret = Device::Transaction::Download.request_param_file(FILE_NAME)
51
+ if value = check_download_error(ret)
52
+ puts "Downloaded Successfully"
53
+ Device::Network.close_socket
54
+ # TODO
55
+ #Device::Network.walk_socket.close unless Device::Network.walk_socket.closed?
56
+ parse_apps
57
+ end
58
+ value
59
+ end
60
+ end
61
+
62
+ def self.update_apps(force = false)
63
+ if force || ! self.status
64
+ self.download
65
+ end
66
+ if self.status
67
+ @apps.each do |app|
68
+ self.update_app(app)
69
+ end
70
+ end
71
+ end
72
+
73
+ def self.format!
74
+ self.apps.each do |app|
75
+ File.delete(app.zip) if File.exists?(app.zip)
76
+ Dir.delete(app.file_no_ext) if File.exists?(app.file_no_ext) && File.exists?(app.file_no_ext)
77
+ end
78
+ File.delete(FILE_NAME) if File.exists?(FILE_NAME)
79
+ Device::System.restart
80
+ end
81
+
82
+ def self.update_app(application)
83
+ if attach && application
84
+ Device::Display.clear
85
+ puts "Downloading #{application.file}..."
86
+ ret = Device::Transaction::Download.request_file(application.file, application.zip)
87
+ Device::Network.close_socket
88
+ # TODO
89
+ #Device::Network.walk_socket.close unless Device::Network.walk_socket.closed?
90
+
91
+ unless check_download_error ret
92
+ sleep 2
93
+ end
94
+ end
95
+ end
96
+
97
+ def self.apps
98
+ self.parse_apps unless self.status
99
+ @apps
100
+ end
101
+
102
+ def self.executable_app
103
+ selected = self.executable_apps
104
+ if selected.size == 1
105
+ selected[selected.keys.first]
106
+ end
107
+ end
108
+
109
+ def self.executable_apps
110
+ self.apps.select{|app| app.label != "X"}
111
+ end
112
+
113
+ def self.application_menu
114
+ options = Hash.new
115
+ executable_apps.each { |app| options[app.label] = app }
116
+ menu("Application Menu", options, {:number => true})
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,35 @@
1
+
2
+ class Device
3
+ class Printer
4
+ def self.adapter
5
+ Device.adapter::Printer
6
+ end
7
+
8
+ # Same as print, but add "\n" at end of print
9
+ #
10
+ # @param buf [String] Text to be printed.
11
+ # @param option [Symbol] :big, :bar_code, :bitmap
12
+ # @return [String] buffer read from keyboard
13
+ def self.puts(buf, option=nil)
14
+ adapter.puts(buf, option)
15
+ end
16
+
17
+ # Print buffer
18
+ #
19
+ # @param buf [String] Text to be printed.
20
+ # @param option [Symbol] :big, :bar_code, :bitmap
21
+ # @return [String] buffer read from keyboard
22
+ def self.print(buf, option=nil)
23
+ adapter.print(buf, option)
24
+ end
25
+
26
+ def self.paper?
27
+ adapter.paper?
28
+ end
29
+
30
+ def self.paperfeed
31
+ adapter.paperfeed
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,22 @@
1
+ class Device
2
+ class Runtime
3
+ def self.adapter
4
+ Device.adapter::Runtime
5
+ end
6
+
7
+ # Execute app in new context.
8
+ # To execute the should exists a zip file cotain the app,
9
+ # previously downloaded from CloudWalk.
10
+ #
11
+ # @param app [String] App name, example "app", should exists file app.zip
12
+ # @param json [String] Parameters to confifure new aplication.
13
+ # @return [Object] From the new runtime instance.
14
+ def self.execute(app, json = nil)
15
+ zip = "./#{app}.zip"
16
+ Device::Display.clear
17
+ raise File::FileError, zip unless File.exists?(zip)
18
+ raise "Problem to unzip #{zip}" unless Zip.uncompress(zip, app)
19
+ return mrb_eval "Context.start('#{app}', '#{Device.adapter}', '#{json}')"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,63 @@
1
+
2
+ class Device
3
+ class Setting
4
+ FILE_PATH = "./main/config.dat"
5
+ HOST_PRODUCTION = "switch.cloudwalk.io"
6
+ HOST_STAGING = "switch-staging.cloudwalk.io"
7
+
8
+ DEFAULT = {
9
+ "host" => "switch-staging.cloudwalk.io",
10
+ "host_port" => "31416",
11
+ "ssl" => "1",
12
+ "user" => "",
13
+ "password" => "", #WIFI
14
+ "apn" => "",
15
+ "authentication" => "", #WIFI
16
+ "essid" => "", #WIFI
17
+ "bssid" => "", #WIFI
18
+ "cipher" => "", #WIFI
19
+ "mode" => "", #WIFI
20
+ "channel" => "", #WIFI
21
+ "media" => "",
22
+ "ip" => "",
23
+ "gateway" => "",
24
+ "dns1" => "",
25
+ "dns2" => "",
26
+ "subnet" => "",
27
+ "logical_number" => "",
28
+ "network_configured" => "",
29
+ "environment" => "",
30
+ "notification_timeout" => "",
31
+ "notification_interval" => "",
32
+ "notification_stream_timeout" => "",
33
+ "company_name" => ""
34
+ }
35
+
36
+ def self.setup
37
+ @file = FileDb.new(FILE_PATH, DEFAULT)
38
+ self.host = HOST_STAGING if self.staging?
39
+ @file
40
+ end
41
+
42
+ def self.production?
43
+ self.environment == "production"
44
+ end
45
+
46
+ def self.staging?
47
+ self.environment == "staging"
48
+ end
49
+
50
+ def self.method_missing(method, *args, &block)
51
+ setup unless @file
52
+ param = method.to_s
53
+ if @file[param]
54
+ @file[param]
55
+ elsif (param[-1..-1] == "=" && @file[param[0..-2]])
56
+ @file[param[0..-2]] = args.first
57
+ else
58
+ super
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,28 @@
1
+ class Device
2
+ class Support
3
+ def self.class_to_path(klass)
4
+ klass.to_s.downcase
5
+ end
6
+
7
+ def self.path_to_class(path)
8
+ constantize(camelize(remove_extension(path)))
9
+ end
10
+
11
+ def self.camelize(str)
12
+ str.split('_').map {|w| w.capitalize}.join
13
+ end
14
+
15
+ def self.remove_extension(path)
16
+ path.to_s.split(".")[-2].split("/").last
17
+ end
18
+
19
+ def self.constantize(name)
20
+ if ! name.empty? && Object.const_defined?(name)
21
+ Object.const_get name
22
+ else
23
+ nil
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,61 @@
1
+
2
+ class Device
3
+ class System
4
+ class << self
5
+ attr_reader :serial, :backlight
6
+ attr_accessor :klass
7
+ end
8
+
9
+ def self.adapter
10
+ Device.adapter::System
11
+ end
12
+
13
+ def self.serial
14
+ @serial ||= adapter.serial
15
+ end
16
+
17
+ # Set screen backlight (turn on automatically if there has actions like key-pressing, card-swiping or card-inserting).
18
+ # 0 = Turn off backlight.
19
+ # 1 = (D200): Keep backlight on for 30 seconds ( auto-shut-down after 30 seconds).
20
+ # 1 = (Vx510): On.
21
+ # 2 = (D200): Always on.
22
+ # n = (Evo/Telium 2): Percentage until 100.
23
+ def self.backlight=(level)
24
+ adapter.backlight = level
25
+ @backlight = level
26
+ end
27
+
28
+ def self.backlight
29
+ @backlight ||= adapter.backlight
30
+ end
31
+
32
+ # Read the battery level.
33
+ # 0 Battery voltage low and battery icon blinks. Suggested that do not process transaction, print and wireless communication etc. at this moment. You should recharge the battery immediately to avoid shut down and lost data.
34
+ # 1 Battery icon displays 1 grid
35
+ # 2 Battery icon displays 2 grids
36
+ # 3 Battery icon displays 3 grids
37
+ # 4 Battery icon displays 4 grids
38
+ # 5 Powered by external power supply and the battery in charging. Battery icon displays form empty to full cycle. The battery status indicator on the bottom of terminal is displaying red
39
+ # 6 Powered by external power supply and the battery charging 6 finished. Battery icon displays full grids. The battery status indicator on the bottom of terminal is displaying green.
40
+ def self.battery
41
+ adapter.battery
42
+ end
43
+
44
+ def self.beep
45
+ adapter.beep
46
+ end
47
+
48
+ def self.restart
49
+ adapter.restart
50
+ end
51
+
52
+ def self.app
53
+ self.klass.to_s.downcase
54
+ end
55
+
56
+ def self.model
57
+ adapter.model
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,268 @@
1
+
2
+ class Device
3
+ class Transaction
4
+ class Download
5
+ ERL_VERSION_MAGIC = 131
6
+ ERL_NIL_EXT = 'j'
7
+ ERL_SMALL_TUPLE_EXT = 'h'
8
+ ERL_ATOM_EXT = 'd'
9
+ ERL_BINARY_EXT = 'm'
10
+ ERL_INTEGER_EXT = 'b'
11
+ ERL_CONTENT_TYPE = "application/x-erlang-binary"
12
+ MAXATOMLEN = 255
13
+ PARAMS_FILE = "params.dat"
14
+
15
+ SUCCESS = 0
16
+ FILE_NOT_CHANGE = 1
17
+ FILE_NOT_FOUND = 2
18
+ SERIAL_NUMBER_NOT_FOUND = 3
19
+ COMMUNICATION_ERROR = -1
20
+ MAPREDUCE_RESPONSE_ERROR = -2
21
+ IO_ERROR = -3
22
+
23
+ def self.request_file(remote_path, local_path)
24
+ download = Device::Transaction::Download.new(Device::System.serial, "", Device.version)
25
+ download.perform(Device::Network.walk_socket,
26
+ Device::Setting.company_name,
27
+ remote_path, local_path, Device::System.app,
28
+ Device::Setting.logical_number)
29
+ end
30
+
31
+ def self.request_param_file(file = PARAMS_FILE)
32
+ request_file("#{Device::Setting.logical_number}_#{PARAMS_FILE}", file)
33
+ end
34
+
35
+ attr_accessor :buffer, :request, :first_packet, :socket, :path, :crc
36
+
37
+ def initialize(serial, path, version)
38
+ @serial = serial
39
+ @path = path
40
+ @version = version
41
+ end
42
+
43
+ # 0: Success
44
+ # -1: Commnucation error
45
+ # -2: Mapreduce response error
46
+ # -3: IO Error
47
+ def perform(socket, company_name, remote_path, filepath, current_app, logical_number, file_crc = nil)
48
+ @socket, @buffer, @request, @first_packet = socket, "", "", ""
49
+ @crc = file_crc ? file_crc : generate_crc(filepath)
50
+ key = "#{company_name}_#{remote_path}"
51
+
52
+ ei_encode_version # version
53
+ ei_encode_list_header(3) # mapreduce with 3 tuples
54
+ ei_encode_tuple_header(2) # tuple 1 inputs
55
+ ei_encode_atom("inputs") # atom inputs
56
+ ei_encode_list_header(1) # list inputs
57
+ ei_encode_tuple_header(2) # tuple contendo 2 elementos binarios, bucket and key
58
+ ei_encode_binary("assets") # elemento binario bucket
59
+ ei_encode_binary(key) # elemento binario key
60
+ ei_encode_list_header(0) # fim da list do inputs
61
+
62
+ ei_encode_tuple_header(2) # tuple 2: query
63
+ ei_encode_atom("query") # atom query
64
+ ei_encode_list_header(1) # list da query
65
+ ei_encode_tuple_header(4) # tuple contendo 4 elementos, { map, {modfun,Module,Function}, args, true }
66
+ ei_encode_atom("map") # primeiro elemento, atom type
67
+ ei_encode_tuple_header(3) # segundo elemento, nova tuple contendo 3 atoms
68
+ ei_encode_atom("modfun") # primeiro atom do segundo elemento, modfun
69
+ ei_encode_atom("walk") # segundo atom do segundo elemento, Module
70
+ ei_encode_atom("get_asset") # terceiro atom do segundo elemento, Function
71
+
72
+ ei_encode_list_header(7) # terceiro elemento, uma list com parametros do walk
73
+ ei_encode_binary(@serial) # elemento binario serialterminal
74
+ ei_encode_binary(@version) # elemento binario versao walk
75
+ ei_encode_binary(remote_path) # elemento binario nomeaplicativo
76
+ ei_encode_binary(crc) # elemento binario crc aplicativo
77
+ ei_encode_binary("") # elemento binario buffer do posxml
78
+ ei_encode_binary(logical_number) # elemento binario numero do terminal
79
+ ei_encode_binary(current_app) # elemento binario nome do aplicativo que esta sendo executado
80
+ ei_encode_list_header(0) # fim da list com parametros do walk
81
+
82
+ ei_encode_atom("true") # quarto elemento, atom true
83
+ ei_encode_list_header(0) # fim da list da query
84
+
85
+ ei_encode_tuple_header(2) # tuple 3: timeout
86
+ ei_encode_atom("timeout") # atom timeout
87
+ ei_encode_long(5000) # integer timeout
88
+ ei_encode_list_header(0) # fim da list do mapreduce contendo 3 tuples
89
+
90
+ mount_request # add request to protocol buffers message
91
+
92
+ return COMMUNICATION_ERROR unless @socket
93
+
94
+ # Send Request
95
+ socket.write(@request)
96
+
97
+ return COMMUNICATION_ERROR if (response_size = get_response_size(socket.read(4))) <= 0
98
+
99
+ return MAPREDUCE_RESPONSE_ERROR unless @first_packet = get_binary_term_beginning(response_size)
100
+
101
+ return_code = @first_packet[7].to_s.unpack("C*").first
102
+ file_size = @first_packet[9..12].to_s.unpack("N*").first
103
+
104
+ if return_code != FILE_NOT_CHANGE
105
+ return IO_ERROR if (partial_download_to_store(filepath, response_size, file_size) < 0)
106
+ end
107
+
108
+ # receive 6A
109
+ @socket.read(1) if response_size > 1024
110
+
111
+ return_code
112
+ end
113
+
114
+ def generate_crc(local_path)
115
+ if File.exists?(local_path)
116
+ file = File.open(local_path)
117
+ Device::Crypto.crc16_hex(file.read)
118
+ else
119
+ ""
120
+ end
121
+ ensure
122
+ file.close if file
123
+ end
124
+
125
+ private
126
+
127
+ def get_response_size(bytes)
128
+ return -1 if bytes.to_s.size <= 0
129
+ bytes.to_s.unpack("N*").first
130
+ end
131
+
132
+ def get_binary_term_beginning(response_size)
133
+ if response_size > 1024
134
+ packet = socket.read(1024)
135
+ else
136
+ packet = socket.read(response_size)
137
+ end
138
+
139
+ if packet.include?("\x83\x6c\x00")
140
+ "\x83\x6c\x00#{packet.split("\x83\x6C\x00")[1]}"
141
+ else
142
+ return false
143
+ end
144
+ end
145
+
146
+ def makelong(a, b)
147
+ (a & 0xffff) | ((b & 0xffff) << 16)
148
+ end
149
+
150
+ def makeword(a, b)
151
+ (a & 0xff) | ((b & 0xff) << 8)
152
+ end
153
+
154
+ def partial_download_to_store(filepath, response_size, file_size)
155
+ tmp = tmp_file(filepath)
156
+ file = File.open(tmp, "w+")
157
+
158
+ if (response_size > 1024)
159
+ file.write(@first_packet[13..-1])
160
+ downloaded = 1024
161
+ while(downloaded < (response_size - 1))
162
+
163
+ if (to_download = response_size - downloaded) > 1024
164
+ to_download = 1024
165
+ else
166
+ to_download -= 1 # because of 6A
167
+ end
168
+
169
+ downloaded += file.write(socket.read(to_download))
170
+ end
171
+ else
172
+ # -2 because of 6A
173
+ downloaded = file.write(@first_packet[13..-2])
174
+ end
175
+
176
+ file.close
177
+ File.rename(tmp, filepath)
178
+ downloaded
179
+ end
180
+
181
+ def put(value)
182
+ @buffer << value
183
+ end
184
+
185
+ def put8(value)
186
+ @buffer << value
187
+ end
188
+
189
+ def put32be(value)
190
+ @buffer << [value].pack("N")
191
+ end
192
+
193
+ def put16be(value)
194
+ @buffer << [value].pack("n")
195
+ end
196
+
197
+ def ei_encode_version
198
+ put8(ERL_VERSION_MAGIC.chr)
199
+ end
200
+
201
+ def ei_encode_list_header(arity)
202
+ put8(ERL_NIL_EXT)
203
+ put32be(arity) if arity > 0
204
+ end
205
+
206
+ def ei_encode_tuple_header(arity)
207
+ # if (arity <= 0xff) ERL_SMALL_TUPLE_EXT else ERL_LARGE_TUPLE_EXT
208
+ put8(ERL_SMALL_TUPLE_EXT)
209
+ put8(arity.chr);
210
+ end
211
+
212
+ # TODO: Check why MAXATOMLEN
213
+ def ei_encode_atom(value)
214
+ value.size > MAXATOMLEN ? len = MAXATOMLEN : len = value.size
215
+ put8(ERL_ATOM_EXT)
216
+ put16be(len)
217
+ put(value)
218
+ end
219
+
220
+ def ei_encode_binary(value)
221
+ put8(ERL_BINARY_EXT)
222
+
223
+ # TODO: Check it after to implement on put.
224
+ if value.is_a? Fixnum
225
+ put32be(2)
226
+ @buffer << [value].pack("s")
227
+ else
228
+ put32be(value.size)
229
+ put(value)
230
+ end
231
+ end
232
+
233
+ def ei_encode_long(value)
234
+ put8(ERL_INTEGER_EXT)
235
+ put32be(value)
236
+ end
237
+
238
+ def mount_request
239
+ request_size = [@buffer.size].pack("s") + "\x01"
240
+
241
+ put8("\x12")
242
+ put8("\x1b")
243
+ new_request = [@request.size].pack("N")
244
+ new_request << "\x17"
245
+ new_request << "\x0A"
246
+ new_request << "#{request_size}#{@buffer}#{ERL_CONTENT_TYPE}"
247
+ new_request << @request
248
+ @request = new_request
249
+ end
250
+
251
+ # MRuby do not support String#ljust
252
+ # TODO: duplicated from lib/variable.rb
253
+ def ljust(size, string)
254
+ if size > string.size
255
+ string = string + ("\x00" * (size - string.size))
256
+ end
257
+ string
258
+ end
259
+
260
+ def tmp_file(path)
261
+ paths = path.split("/")
262
+ paths[-1] = "tmp_#{paths.last}"
263
+ paths.join("/")
264
+ end
265
+ end
266
+ end
267
+ end
268
+
@@ -0,0 +1,45 @@
1
+
2
+ class Device
3
+ class Transaction
4
+ class EMV
5
+ class << self
6
+ attr_accessor :status, :mk_slot, :pinpad_type, :pinpad_wk, :show_amout
7
+ end
8
+
9
+ attr_accessor :data, :info
10
+
11
+ def self.open(mk_slot, pinpad_type, pinpad_wk, show_amout)
12
+ end
13
+
14
+ def self.close
15
+ end
16
+
17
+ def self.load_tables(acquirer)
18
+ end
19
+
20
+ def clean
21
+ @data = {:init => {}, :process => {}, :finish => {}}
22
+ @info = {:init => {}, :process => {}, :finish => {}}
23
+ end
24
+
25
+ def init
26
+ end
27
+
28
+ def response
29
+ end
30
+
31
+ def parameters
32
+ end
33
+
34
+ def timeout=(seconds)
35
+ end
36
+
37
+ def timeout
38
+ end
39
+
40
+ def remove_card
41
+ end
42
+ end
43
+ end
44
+ end
45
+