extface 0.1.7 → 0.1.8
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/app/controllers/extface/devices_controller.rb +14 -0
- data/app/controllers/extface/handler_controller.rb +1 -1
- data/app/models/extface/driver/daisy/commands_fx1200.rb +11 -2
- data/app/models/extface/driver/daisy_fx1200.rb +261 -15
- data/app/models/extface/driver/epson/fiscal.rb +72 -0
- data/app/views/extface/devices/show.html.erb +7 -0
- data/config/routes.rb +1 -0
- data/lib/extface/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 900544046448abb9c9c713e46a328fb7024a6d7b
|
4
|
+
data.tar.gz: bb25d5f73e3cc268ee61178863c9a40768afa006
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8e3ab792ef789a4a5ae4999ce42837b53b1c898a8f588306f660bf8f59a9707427177b962932800ead930d957f30df9ad0ed1c628cddc40ce16b82cab1d95b1
|
7
|
+
data.tar.gz: 77251dc8768f3ad7645a46d740a8d0b89cbc5082e97129116a59fa47f62de4822f7a51228fd6612ccd838577ab339dfe10c655f0a445bb76b1700d393d7f4857
|
@@ -54,6 +54,20 @@ module Extface
|
|
54
54
|
@job = @device.driver.print_test_page if params[:test_page]
|
55
55
|
render action: :show
|
56
56
|
end
|
57
|
+
|
58
|
+
def fiscal
|
59
|
+
set_device
|
60
|
+
if @device.fiscal?
|
61
|
+
@job = case
|
62
|
+
when params[:non_fiscal_test].present? then @device.driver.non_fiscal_test
|
63
|
+
when params[:fiscal_test].present? then @device.driver.fiscal_test
|
64
|
+
when params[:x_report].present? then @device.driver.x_report_session
|
65
|
+
when params[:z_report].present? then @device.driver.z_report_session
|
66
|
+
when params[:cancel_fiscal_doc].present? then @device.driver.cancel_doc_session
|
67
|
+
end
|
68
|
+
end
|
69
|
+
render action: :show
|
70
|
+
end
|
57
71
|
|
58
72
|
private
|
59
73
|
# Use callbacks to share common setup or constraints between actions.
|
@@ -33,7 +33,7 @@ module Extface
|
|
33
33
|
r.append device.uuid, request.body.read
|
34
34
|
@full_buffer = r.get device.uuid
|
35
35
|
end
|
36
|
-
if bytes_porcessed = device.driver.handle(@full_buffer)
|
36
|
+
if bytes_porcessed = device.driver.handle(@full_buffer.b)
|
37
37
|
Extface.redis_block do |r|
|
38
38
|
r.set device.uuid, r.get(device.uuid)[bytes_porcessed]
|
39
39
|
end
|
@@ -1,5 +1,14 @@
|
|
1
1
|
module Extface
|
2
2
|
module Driver::Daisy::CommandsFx1200
|
3
|
+
|
4
|
+
STX = 0x01
|
5
|
+
PA1 = 0x05
|
6
|
+
PA2 = 0x04
|
7
|
+
ETX = 0x03
|
8
|
+
|
9
|
+
NAK = 0x15
|
10
|
+
SYN = 0x16
|
11
|
+
|
3
12
|
module Init
|
4
13
|
DATE_TIME = 0x3d
|
5
14
|
PRINT_OPTIONS = 0x2b
|
@@ -81,8 +90,8 @@ module Extface
|
|
81
90
|
end
|
82
91
|
|
83
92
|
module Printer
|
84
|
-
|
85
|
-
|
93
|
+
MOVE = 0x2c
|
94
|
+
CUT = 0x2d
|
86
95
|
end
|
87
96
|
|
88
97
|
module Other
|
@@ -21,32 +21,278 @@ module Extface
|
|
21
21
|
RAW = true #responds to #push(data) and #pull
|
22
22
|
PRINT = false #POS, slip printers
|
23
23
|
FISCAL = true #cash registers, fiscal printers
|
24
|
-
REPORT = false #only transmit data that must be parsed by handler, CDR, report devices
|
24
|
+
REPORT = false #only transmit data that must be parsed by handler, CDR, report devices
|
25
|
+
|
26
|
+
RESPONSE_TIMEOUT = 6 #seconds
|
27
|
+
INVALID_FRAME_RETRIES = 6 #seconds
|
28
|
+
|
29
|
+
TAX_GROUPS_MAP = {
|
30
|
+
1 => "\xc0",
|
31
|
+
2 => "\xc1",
|
32
|
+
3 => "\xc2",
|
33
|
+
4 => "\xc3",
|
34
|
+
5 => "\xc4",
|
35
|
+
6 => "\xc5",
|
36
|
+
7 => "\xc6",
|
37
|
+
8 => "\xc7"
|
38
|
+
}
|
25
39
|
|
26
40
|
has_serial_config
|
41
|
+
|
42
|
+
include Extface::Driver::Daisy::CommandsFx1200
|
27
43
|
|
28
|
-
def handle(buffer)
|
29
|
-
|
30
|
-
|
44
|
+
def handle(buffer) #buffer is filled with multiple pushes, wait for full frame (ACKs)STX..PA2..PA1..ETX
|
45
|
+
if buffer[/^\x16+$/] # skip if only ACKs
|
46
|
+
return buffer.length
|
47
|
+
else
|
48
|
+
if frame_len = buffer.index("\x03") || buffer.index("\x15")
|
49
|
+
rpush buffer[0..frame_len]
|
50
|
+
return frame_len+1 # return number of bytes processed
|
51
|
+
else
|
52
|
+
#TODO check buffer.length
|
53
|
+
return 0 #no bytes processed
|
54
|
+
end
|
55
|
+
end
|
56
|
+
return buffer.length
|
57
|
+
end
|
58
|
+
|
59
|
+
def autocut(partial = true) # return "P" - success, "F" - failed
|
60
|
+
resp = fsend(Printer::CUT)
|
61
|
+
resp == "P"
|
62
|
+
end
|
63
|
+
|
64
|
+
def non_fiscal_test
|
65
|
+
device.session("Non Fiscal Text") do |s|
|
66
|
+
s.notify "Printing Non Fiscal Text"
|
67
|
+
s.fsend Sales::START_NON_FISCAL_DOC
|
68
|
+
s.fsend Sales::PRINT_NON_FISCAL_TEXT, "********************************"
|
69
|
+
s.fsend Sales::PRINT_NON_FISCAL_TEXT, "Extface Print Test".center(32)
|
70
|
+
s.fsend Sales::PRINT_NON_FISCAL_TEXT, "********************************"
|
71
|
+
s.fsend Printer::MOVE, "1"
|
72
|
+
s.fsend Sales::PRINT_NON_FISCAL_TEXT, "Driver: " + "#{self.class::NAME}".truncate(24)
|
73
|
+
s.fsend(Sales::END_NON_FISCAL_DOC)
|
74
|
+
s.notify "Printing finished"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fiscal_test
|
79
|
+
sale_and_pay_items_session([
|
80
|
+
{ price: 0.01, text1: "Extface Test" }
|
81
|
+
])
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_sale_data(price, text1 = nil, text2 = nil, tax_group = 2, qty = nil, percent = nil, neto = nil)
|
85
|
+
"".tap() do |data|
|
86
|
+
data << text1 unless text1.blank?
|
87
|
+
data << "\x0a#{text2}" unless text2.blank?
|
88
|
+
data << "\t"
|
89
|
+
data << TAX_GROUPS_MAP[tax_group || 2]
|
90
|
+
data << price.to_s
|
91
|
+
data << "*#{qty.to_s}" unless qty.blank?
|
92
|
+
data << ",#{percent}" unless percent.blank?
|
93
|
+
data << "$#{neto}" unless neto.blank?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def sale_and_pay_items_session(items = [], operator = "1", password = "1")
|
98
|
+
device.session("Fiscal Doc") do |s|
|
99
|
+
s.notify "Fiscal Doc Start"
|
100
|
+
s.fsend Sales::START_FISCAL_DOC, "#{operator},#{password},00001"
|
101
|
+
items.each do |item|
|
102
|
+
s.fsend Sales::SALE_AND_SHOW, build_sale_data(item[:price], item[:text1], item[:text2], item[:tax_group], item[:qty], item[:percent], item[:neto])
|
103
|
+
end
|
104
|
+
s.fsend(Sales::TOTAL, "\t")
|
105
|
+
s.fsend(Sales::END_FISCAL_DOC)
|
106
|
+
s.notify "Fiscal Doc End"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def z_report_session
|
111
|
+
device.session("Z Report") do |s|
|
112
|
+
s.notify "Z Report Start"
|
113
|
+
s.fsend Closure::DAY_FIN_REPORT, "0"
|
114
|
+
s.notify "Z Report End"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def x_report_session
|
119
|
+
device.session("X Report") do |s|
|
120
|
+
s.notify "X Report Start"
|
121
|
+
s.fsend Closure::DAY_FIN_REPORT, "2"
|
122
|
+
s.notify "X Report End"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def cancel_doc_session
|
127
|
+
device.session("Doc cancel") do |s|
|
128
|
+
s.notify "Doc Cancel Start"
|
129
|
+
s.fsend Sales::CANCEL_DOC
|
130
|
+
s.notify "Doc Cancel End"
|
131
|
+
end
|
31
132
|
end
|
32
133
|
|
33
|
-
def
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
#push partial ? "\x1B\x64\x31" : "\x1B\x64\x30"
|
134
|
+
def check_status
|
135
|
+
flush
|
136
|
+
fsend(Info::STATUS) # return 6 byte status
|
137
|
+
errors.empty?
|
38
138
|
end
|
39
139
|
|
40
|
-
|
41
|
-
|
140
|
+
def build_packet(cmd, data = "")
|
141
|
+
String.new.tap() do |packet|
|
142
|
+
packet << STX
|
143
|
+
packet << 0x20 + 4 + data.length
|
144
|
+
packet << sequence_number
|
145
|
+
packet << cmd
|
146
|
+
packet << data
|
147
|
+
packet << PA1
|
148
|
+
packet << bcc(packet[1..-1])
|
149
|
+
packet << ETX
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def fsend!(cmd, data = "") # return data or raise
|
154
|
+
push build_packet(cmd, data) # return 6 byte status
|
155
|
+
if resp = frecv(RESPONSE_TIMEOUT)
|
156
|
+
return resp.data if resp.valid?
|
157
|
+
else
|
158
|
+
raise errors.full_messages.join(', ')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def fsend(cmd, data = "") #return data or nil
|
163
|
+
packet_data = build_packet(cmd, data)
|
164
|
+
result = false
|
165
|
+
INVALID_FRAME_RETRIES.times do |retries|
|
166
|
+
errors.clear
|
167
|
+
push packet_data
|
168
|
+
if resp = frecv(RESPONSE_TIMEOUT)
|
169
|
+
if resp.valid?
|
170
|
+
result = resp.data
|
171
|
+
break
|
172
|
+
end
|
173
|
+
end
|
174
|
+
errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
|
175
|
+
end
|
176
|
+
return result
|
177
|
+
end
|
178
|
+
|
179
|
+
def frecv(timeout) # return RespFrame or nil
|
180
|
+
if frame_bytes = pull(timeout)
|
181
|
+
return RespFrame.new(frame_bytes.b)
|
182
|
+
else
|
183
|
+
errors.add :base, "No data received from device"
|
184
|
+
return nil
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
#private
|
189
|
+
def bcc(buffer)
|
190
|
+
sum = 0
|
191
|
+
buffer.each_byte do |byte|
|
192
|
+
sum += byte
|
193
|
+
end
|
194
|
+
"".tap() do |bcc|
|
195
|
+
4.times do |halfbyte|
|
196
|
+
bcc.insert 0, (0x30 + ((sum >> (halfbyte*4)) & 0x0f)).chr
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def sequence_number(increment = true)
|
202
|
+
@seq ||= 0x1f
|
203
|
+
@seq += 1 if increment
|
204
|
+
@seq = 0x1f if @seq == 0x7f
|
205
|
+
@seq
|
206
|
+
end
|
207
|
+
|
208
|
+
def human_status_errors(status) #6 bytes status
|
209
|
+
errors.add :base, "Fiscal Device General Error" unless (status[0].ord & 0x20).zero?
|
210
|
+
errors.add :base, "Invalid Command" unless (status[0].ord & 0x02).zero?
|
211
|
+
errors.add :base, "Date & Time Not Set" unless (status[0].ord & 0x04).zero?
|
212
|
+
errors.add :base, "Syntax Error" unless (status[0].ord & 0x02).zero?
|
213
|
+
|
214
|
+
errors.add :base, "Wrong Password" unless (status[1].ord & 0x40).zero?
|
215
|
+
errors.add :base, "Cutter Error" unless (status[1].ord & 0x20).zero?
|
216
|
+
errors.add :base, "Unpermitted Command In This Mode" unless (status[1].ord & 0x02).zero?
|
217
|
+
errors.add :base, "Field Overflow" unless (status[1].ord & 0x01).zero?
|
218
|
+
|
219
|
+
#errors.add :base, "Print Doc Allowed" unless (status[2].ord & 0x40).zero?
|
220
|
+
#errors.add :base, "Non Fiscal Doc Open" unless (status[2].ord & 0x20).zero?
|
221
|
+
errors.add :base, "Less Paper (Control)" unless (status[2].ord & 0x20).zero?
|
222
|
+
#errors.add :base, "Fiscal Doc Open" unless (status[2].ord & 0x08).zero?
|
223
|
+
errors.add :base, "No Paper (Control)" unless (status[2].ord & 0x04).zero?
|
224
|
+
errors.add :base, "Less Paper" unless (status[2].ord & 0x02).zero?
|
225
|
+
errors.add :base, "No Paper" unless (status[2].ord & 0x01).zero?
|
42
226
|
|
227
|
+
case (status[3] & 0x7f)
|
228
|
+
when 1 then errors.add :base, "Operation will result in the overflow"
|
229
|
+
when 3 then errors.add :base, "No more sales for this doc"
|
230
|
+
when 4 then errors.add :base, "No more payments for this doc"
|
231
|
+
when 5 then errors.add :base, "Null transaction attempt"
|
232
|
+
when 6 then errors.add :base, "Sale not allowed"
|
233
|
+
when 7 then errors.add :base, "No rights for this operation"
|
234
|
+
when 8 then errors.add :base, "Tax group forbidden"
|
235
|
+
when 11 then errors.add :base, "Multiple decimal points"
|
236
|
+
when 12 then errors.add :base, "Multiple sign symbols"
|
237
|
+
when 13 then errors.add :base, "Sign not at first position"
|
238
|
+
when 14 then errors.add :base, "Wrong symbol"
|
239
|
+
when 15 then errors.add :base, "Too many symbols after decimal point"
|
240
|
+
when 16 then errors.add :base, "Too many symbols"
|
241
|
+
when 20 then errors.add :base, "Service not allowed"
|
242
|
+
when 21 then errors.add :base, "Wrong Value"
|
243
|
+
when 22 then errors.add :base, "Disabled operation"
|
244
|
+
when 23 then errors.add :base, "Deep void after discount"
|
245
|
+
when 24 then errors.add :base, "Deep void for not existing record"
|
246
|
+
when 24 then errors.add :base, "Payment without sale"
|
247
|
+
end
|
248
|
+
|
249
|
+
errors.add :base, "General Fiscal Memory Error" unless (status[4].ord & 0x20).zero?
|
250
|
+
errors.add :base, "Fiscal Memory Full" unless (status[4].ord & 0x10).zero?
|
251
|
+
errors.add :base, "Less Than 50 Fiscal Records" unless (status[4].ord & 0x08).zero?
|
252
|
+
errors.add :base, "Invalid Fiscal Records" unless (status[4].ord & 0x04).zero?
|
253
|
+
errors.add :base, "Fiscal Write Error" unless (status[4].ord & 0x01).zero?
|
254
|
+
|
255
|
+
#errors.add :base, "Fiscal Memory Ready" unless (status[5].ord & 0x40).zero?
|
256
|
+
#errors.add :base, "Fiscal ID Set" unless (status[5].ord & 0x20).zero?
|
257
|
+
#errors.add :base, "Fiscal Tax set" unless (status[5].ord & 0x10).zero?
|
258
|
+
#errors.add :base, "Real Sales Mode" unless (status[5].ord & 0x80).zero?
|
259
|
+
errors.add :base, "Fiscal Memory Full" unless (status[5].ord & 0x01).zero?
|
43
260
|
end
|
44
261
|
|
45
|
-
|
46
|
-
|
47
|
-
data
|
48
|
-
|
262
|
+
class RespFrame
|
263
|
+
include ActiveModel::Validations
|
264
|
+
attr_reader :frame, :len, :seq, :cmd, :data, :status, :bcc
|
265
|
+
|
266
|
+
validates_presence_of :frame
|
267
|
+
#validate :bcc_validation
|
268
|
+
#validate :len_validation
|
269
|
+
|
270
|
+
def initialize(buffer)
|
271
|
+
# test Extface::Driver::DaisyFx1200::RespFrame.new("\x16\x16\x01\x2c\x20\x2dP\x04SSSSSS\x05\BBBB\x03")
|
272
|
+
# LEN SEQ CMD DATA STATUS BCC
|
273
|
+
if match = buffer.match(/\x01(.{1})(.{1})(.{1})(.*)\x04(.{6})\x05(.{4})\x03/n)
|
274
|
+
@frame = match.string[match.pre_match.length..-1]
|
275
|
+
@len, @seq, @cmd, @data, @status, @bcc = match.captures
|
276
|
+
end
|
49
277
|
end
|
278
|
+
|
279
|
+
private
|
280
|
+
def bcc_validation
|
281
|
+
sum = 0
|
282
|
+
frame[1..-6].each_byte do |byte|
|
283
|
+
sum += byte
|
284
|
+
end
|
285
|
+
calc_bcc = "".tap() do |tbcc|
|
286
|
+
4.times do |halfbyte|
|
287
|
+
tbcc.insert 0, (0x30 + ((sum >> (halfbyte*4)) & 0x0f)).chr
|
288
|
+
end
|
289
|
+
end
|
290
|
+
errors.add(:bcc, I18n.t('errors.messages.invalid')) if bcc != calc_bcc
|
291
|
+
end
|
292
|
+
|
293
|
+
def len_validation
|
294
|
+
errors.add(:len, I18n.t('errors.messages.invalid')) if len.ord != (frame[1..-6].length + 0x20)
|
295
|
+
end
|
50
296
|
end
|
51
297
|
end
|
52
298
|
end
|
@@ -1,4 +1,76 @@
|
|
1
1
|
module Extface
|
2
2
|
module Driver::Epson::Fiscal
|
3
|
+
STX = 0x02
|
4
|
+
ETX = 0x03
|
5
|
+
SEP = 0x1c
|
6
|
+
DC2 = 0x12
|
7
|
+
DC4 = 0x14
|
8
|
+
NAK = 0x15
|
9
|
+
|
10
|
+
module Control
|
11
|
+
STATUS_IF = 0x38
|
12
|
+
X_Z_REPORTS = 0x39
|
13
|
+
FISC_MEM_REPORT_DATE = 0x3a
|
14
|
+
FISC_MEM_REPORT = 0x3b
|
15
|
+
end
|
16
|
+
module Vouchers
|
17
|
+
OPEN_FISCAL_VOUCHER = 0x40
|
18
|
+
PRINT_FISCAL_TEXT = 0x41
|
19
|
+
PRINT_FISCAL_ARTICLE = 0x42
|
20
|
+
SUBTOTAL_FISCAL = 0x43
|
21
|
+
FISCAL_VOUCHER = 0x44 # pay / cancel / discount in
|
22
|
+
CLOSE_FISCAL_VOUCHER = 0x45
|
23
|
+
end
|
24
|
+
module NonFiscal
|
25
|
+
OPEN_NON_FISCAL_DOC = 0x48
|
26
|
+
PRINT_NON_FISCAL_TEXT = 0x49
|
27
|
+
CLOSE_NON_FISCAL_DOC = 0x4a
|
28
|
+
end
|
29
|
+
module Printer
|
30
|
+
CUT_PAPER = 0x4b
|
31
|
+
ADVANCE_PAPER = 0x50
|
32
|
+
ACTIVATE_SLIP = 0xa0 #TMU950, TMU675
|
33
|
+
DISABLE_SLIP = 0xa1
|
34
|
+
FORMAT_CHECKS = 0xaa
|
35
|
+
FORMAT_ENDOSEMENT = 0xab
|
36
|
+
end
|
37
|
+
module General
|
38
|
+
SET_DATE_HOUR = 0x58
|
39
|
+
GET_DATE_HOUR = 0x59
|
40
|
+
HEADED = 0x5d
|
41
|
+
FOOT_OF_PAGE = 0x5e
|
42
|
+
OPEN_DRAWER_1 = 0x7b
|
43
|
+
OPEN_DRAWER_2 = 0x7c
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_packet(cmd, fields = [])
|
47
|
+
String.new.tap() do |frame|
|
48
|
+
frame << STX
|
49
|
+
frame << sequence_number
|
50
|
+
frame << cmd
|
51
|
+
fields.each do |field|
|
52
|
+
frame << SEP
|
53
|
+
frame << field
|
54
|
+
end
|
55
|
+
frame << ETX
|
56
|
+
frame << bcc(frame)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def bcc(buffer)
|
62
|
+
sum = 0
|
63
|
+
buffer.each_byte do |b|
|
64
|
+
sum += b
|
65
|
+
end
|
66
|
+
sum.to_s(16).rjust(4, '0')
|
67
|
+
end
|
68
|
+
|
69
|
+
def sequence_number(increment = true)
|
70
|
+
@seq ||= 0x20
|
71
|
+
@seq += 1 if increment
|
72
|
+
@seq = 0x20 if @seq == 0x7f
|
73
|
+
@seq
|
74
|
+
end
|
3
75
|
end
|
4
76
|
end
|
@@ -69,6 +69,13 @@
|
|
69
69
|
<% if @device.print? %>
|
70
70
|
<%= button_to 'Print Test Page', test_page_device_path(@device), remote: true, name: :test_page, value: true, class: 'btn btn-warning' %>
|
71
71
|
<% end %>
|
72
|
+
<% if @device.fiscal? %>
|
73
|
+
<%= button_to 'Non Fiscal Test', fiscal_device_path(@device), remote: true, name: :non_fiscal_test, value: true, class: 'btn btn-warning' %>
|
74
|
+
<%= button_to 'Fiscal Test', fiscal_device_path(@device), remote: true, name: :fiscal_test, value: true, class: 'btn btn-warning' %>
|
75
|
+
<%= button_to 'X Report', fiscal_device_path(@device), remote: true, name: :x_report, value: true, class: 'btn btn-warning' %>
|
76
|
+
<%= button_to 'Z Report', fiscal_device_path(@device), remote: true, name: :z_report, value: true, class: 'btn btn-warning' %>
|
77
|
+
<%= button_to 'Cancel Fiscal Doc', fiscal_device_path(@device), remote: true, name: :cancel_fiscal_doc, value: true, class: 'btn btn-warning' %>
|
78
|
+
<% end %>
|
72
79
|
|
73
80
|
<br />Simulate push data from device
|
74
81
|
|
data/config/routes.rb
CHANGED
data/lib/extface/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: extface
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Vangelov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|