client_for_poslynx 0.2.5 → 0.2.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 +8 -8
- data/CHANGELOG +7 -1
- data/README.md +8 -7
- data/bin/poslynx_client_console +24 -7
- data/lib/client_for_poslynx/bit_sequence.rb +30 -19
- data/lib/client_for_poslynx/data/properties_xml_parser.rb +0 -6
- data/lib/client_for_poslynx/data/responses/credit_card_sale.rb +7 -0
- data/lib/client_for_poslynx/experimental.rb +1 -11
- data/lib/client_for_poslynx/has_client_console_support.rb +2 -4
- data/lib/client_for_poslynx/message_handling/xml_extractor.rb +0 -1
- data/lib/client_for_poslynx/signature_image/draw.rb +6 -6
- data/lib/client_for_poslynx/signature_image/metrics.rb +17 -0
- data/lib/client_for_poslynx/signature_image/move.rb +11 -11
- data/lib/client_for_poslynx/signature_image/to_svg_converter.rb +4 -3
- data/lib/client_for_poslynx/signature_image.rb +58 -9
- data/lib/client_for_poslynx/version.rb +1 -1
- data/lib/client_for_poslynx.rb +2 -0
- data/spec/client_for_poslynx/bit_sequence_spec.rb +36 -21
- data/spec/client_for_poslynx/data/responses/credit_card_sale_spec.rb +11 -0
- data/spec/client_for_poslynx/signature_image_spec.rb +179 -46
- metadata +3 -3
- data/foo.svg +0 -20
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YzhiNDI0YzUzYjUzNTZjMTQ0ZDQ0ZmYzOTk1MmY2ZWUyNjY4ZjNlNw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
N2Y1MDE0NGU2NDczOWNiYzVjMTU0ODMwMWQ5MDNjNTM3NWE5NDVjNg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OWJmOGE4ZWFiZWJkNDIwMDgzYzhkOTdhNDYyOGI5NjA1ZjRhYjllMzM5OGUx
|
10
|
+
MzVjNjkyNmEzOGUyNWQxNThjM2Q0MWM0ZjJjMjNlYWZkODMxNmY0YTA4ZDhh
|
11
|
+
ZDNkOTA1ZTc3NWU1MjA3MWY5OGMwZGFmOWRkYjgxOTExODMxZmI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Mjk2YjA5MWU2Zjg4NTQ3M2YxMDEwOGM5YzJjYjc2MTAwYWNlNDJjMmQwMDM5
|
14
|
+
NGJkNDEzM2I2YmNlZDRkMDNiMWU0YWQ5MmYwYjBiM2JmMWQ5YjdlODI5NDhm
|
15
|
+
MmMwMDlkMTAzMzgzOWExM2ZlNWZiMGE0Mjc2Mzk2YmIzNTE5OTk=
|
data/CHANGELOG
CHANGED
@@ -24,8 +24,14 @@ Version 0.2.4
|
|
24
24
|
- Fix bug: Fake terminal script crashes during user interaction
|
25
25
|
for a debit sale request without a specified cash back amount.
|
26
26
|
|
27
|
-
Version 0.2.
|
27
|
+
Version 0.2.5
|
28
28
|
- Introduce experimental signature image parsing and conversion
|
29
29
|
to SVG.
|
30
30
|
- Fix bug: New format of POSLynx response message XML was causing
|
31
31
|
client to hang.
|
32
|
+
|
33
|
+
Version 0.2.6
|
34
|
+
- Add enhanced-format signature data handling.
|
35
|
+
- Fix misconception about signed number representation in
|
36
|
+
signature image data.
|
37
|
+
- Bring signature image handling out of experimental status.
|
data/README.md
CHANGED
@@ -20,11 +20,12 @@ unit with IP address 192.168.1.123, listening on port 54321, with
|
|
20
20
|
a registered client MAC of 000000000000, an example poslynx
|
21
21
|
client session might look like...
|
22
22
|
|
23
|
-
bundle exec poslynx_client_console
|
24
|
-
1.9.3-p545 :001 >
|
25
|
-
=> "
|
26
|
-
1.9.3-p545 :002 > resp = poslynx_client.send_request(
|
27
|
-
|
23
|
+
$ bundle exec poslynx_client_console 173.195.60.144:14270 --client_mac=000000000000
|
24
|
+
1.9.3-p545 :001 > req = poslynx_client.example_pin_pad_display_message_request
|
25
|
+
=> #<ClientForPoslynx::Data::Requests::PinPadDisplayMessage:0x007f941b4b1fe8 @client_mac="001C42E644FE", @text_lines=["First example line", "Second example line"], @line_count=2, @button_labels=["1st of optional buttons", "2nd button"]>
|
26
|
+
1.9.3-p545 :002 > resp = poslynx_client.send_request(req)
|
27
|
+
<?xml version="1.0" standalone="yes" ?><PLResponse><Command>PPDISPLAY</Command><Result>Success</Result><ResultText>Success</ResultText><Response>2nd button</Response></PLResponse>
|
28
|
+
=> #<ClientForPoslynx::Data::Responses::PinPadDisplayMessage:0x007f941b4b8230 @result="Success", @result_text="Success", @button_response="2nd button", @source_data="<?xml version=\"1.0\" standalone=\"yes\" ?><PLResponse><Command>PPDISPLAY</Command><Result>Success</Result><ResultText>Success</ResultText><Response>2nd button</Response></PLResponse>\r\n">
|
28
29
|
|
29
30
|
This gem also provides a fake POS/terminal application that you
|
30
31
|
can run in a separate console window when you are working without
|
@@ -41,7 +42,7 @@ fake POS/terminal instance on the same machine...
|
|
41
42
|
## Usage
|
42
43
|
|
43
44
|
The code in the
|
44
|
-
lib/client_for_poslynx/
|
45
|
+
lib/client_for_poslynx/has_client_console_support.rb file
|
45
46
|
provides a good example of how to use the facilities that this
|
46
47
|
gem provides.
|
47
48
|
|
@@ -53,7 +54,7 @@ be separately loaded by requiring "client_for_poslynx/experimental'.
|
|
53
54
|
* Only a subset of the possible messages and elements is supported.
|
54
55
|
__More will be added. Contributions are welcome and encouraged. :)__
|
55
56
|
* Performs serialization of requests and parsing of responses, but
|
56
|
-
does not
|
57
|
+
does not encapsulate actually making TCP connections and requests.
|
57
58
|
|
58
59
|
## Installation
|
59
60
|
|
data/bin/poslynx_client_console
CHANGED
@@ -12,8 +12,13 @@ end
|
|
12
12
|
# file name for input.
|
13
13
|
$*.replace []
|
14
14
|
|
15
|
-
#
|
16
|
-
|
15
|
+
# Take --client_mac=<hexadecimal-value> if present.
|
16
|
+
client_mac_opts = option_args.select{ |opt| opt =~ /^--client_mac=[0-9a-fA-F]+$/ }
|
17
|
+
option_args -= client_mac_opts
|
18
|
+
client_mac_option = client_mac_opts.last
|
19
|
+
|
20
|
+
# The only remaining option we care about is --help, so we either
|
21
|
+
# show usage for --help or because an unrecognized option was given.
|
17
22
|
show_usage = option_args.length > 0
|
18
23
|
|
19
24
|
# Should have exactly 1 value argument for the address + port number.
|
@@ -33,19 +38,27 @@ if show_usage
|
|
33
38
|
|
34
39
|
puts <<-EOS
|
35
40
|
|
36
|
-
Usage: poslynx_client_console [<host>]:<port-number>
|
37
|
-
|
38
|
-
|
41
|
+
Usage: poslynx_client_console [<host>]:<port-number>
|
42
|
+
|
43
|
+
Host is the domain name or IP address of the POSLynx or fake POS
|
44
|
+
terminal host. If this is not supplied, then 127.0.0.1 is
|
45
|
+
assumed.
|
46
|
+
|
47
|
+
Options:
|
48
|
+
|
49
|
+
--client_mac=<hexadecimal> The client MAC value to be assigned
|
50
|
+
to example-request objects.
|
51
|
+
|
52
|
+
--help Prints this usage information.
|
39
53
|
|
40
54
|
Opens an interactive Ruby shell with a globally acccessible
|
41
55
|
poslynx_client method that returns an object with conveniences
|
42
56
|
for making requests to a POSLynx or to your fake
|
43
57
|
POSLynx+terminal host.
|
44
58
|
|
45
|
-
For example, you might execute the following
|
59
|
+
For example, you might execute the following command from
|
46
60
|
within the console...
|
47
61
|
|
48
|
-
poslynx_client.client_mac_for_examples = '123456789012'
|
49
62
|
resp = poslynx_client.send_request( poslynx_client.example_credit_card_sale_request )
|
50
63
|
|
51
64
|
To see what else the poslynx_client object provides, see the
|
@@ -70,6 +83,10 @@ else
|
|
70
83
|
config.host = host
|
71
84
|
config.port = port
|
72
85
|
|
86
|
+
if client_mac_option
|
87
|
+
config.client_mac_for_examples = client_mac_option.split('=').last
|
88
|
+
end
|
89
|
+
|
73
90
|
IRB.start
|
74
91
|
|
75
92
|
end
|
@@ -41,15 +41,25 @@ module ClientForPoslynx
|
|
41
41
|
bit_seq
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
def from_signed(value, seq_length)
|
45
|
+
if seq_length > 64
|
46
|
+
raise TooManyBitsLong, "Can't build a representation more than 64 bits long from a signed number"
|
47
|
+
end
|
48
|
+
max_magnitude = 2 ** (seq_length - 1)
|
49
|
+
if value < -max_magnitude
|
50
|
+
raise NumberOutOfBounds, "The largest negative value representable in #{seq_length} bits is smaller than than #{value}"
|
51
|
+
end
|
52
|
+
if value >= max_magnitude
|
53
|
+
raise NumberOutOfBounds, "The largest positive value representable in #{seq_length} bits is less than #{value}"
|
54
|
+
end
|
55
|
+
packed_bits = [ value ].pack('q>')
|
56
|
+
bit_seq = from_packed_bits( packed_bits )
|
57
|
+
bit_seq.shift( 64 - seq_length )
|
58
|
+
bit_seq
|
49
59
|
end
|
50
60
|
|
51
|
-
def
|
52
|
-
packed_bits =
|
61
|
+
def from_base64(encoded)
|
62
|
+
packed_bits = encoded.unpack('m0').first
|
53
63
|
from_packed_bits( packed_bits )
|
54
64
|
end
|
55
65
|
end
|
@@ -81,8 +91,8 @@ module ClientForPoslynx
|
|
81
91
|
digits_string
|
82
92
|
end
|
83
93
|
|
84
|
-
def
|
85
|
-
[ to_packed_bits ].pack('
|
94
|
+
def base64_encode
|
95
|
+
[ to_packed_bits ].pack('m0')
|
86
96
|
end
|
87
97
|
|
88
98
|
def length
|
@@ -111,24 +121,25 @@ module ClientForPoslynx
|
|
111
121
|
self
|
112
122
|
end
|
113
123
|
|
114
|
-
def
|
124
|
+
def as_signed
|
115
125
|
if length > 64
|
116
126
|
raise TooManyBitsLong,
|
117
|
-
"Cannot coerce sequence longer than 64 bits to
|
127
|
+
"Cannot coerce sequence longer than 64 bits to signed number"
|
118
128
|
end
|
119
|
-
|
129
|
+
fill = first_bit_digit * 64
|
130
|
+
little_endian_digits = digits_string.reverse + fill
|
120
131
|
packed_little_endian = [ little_endian_digits ].pack('b*')
|
121
|
-
packed_little_endian.unpack('
|
132
|
+
packed_little_endian.unpack('q<').first
|
122
133
|
end
|
123
134
|
|
124
|
-
def
|
125
|
-
if length >
|
135
|
+
def as_unsigned
|
136
|
+
if length > 64
|
126
137
|
raise TooManyBitsLong,
|
127
|
-
"Cannot coerce sequence longer than
|
138
|
+
"Cannot coerce sequence longer than 64 bits to unsigned number"
|
128
139
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
140
|
+
little_endian_digits = digits_string.reverse + '0' * 64
|
141
|
+
packed_little_endian = [ little_endian_digits ].pack('b*')
|
142
|
+
packed_little_endian.unpack('Q<').first
|
132
143
|
end
|
133
144
|
|
134
145
|
private
|
@@ -15,12 +15,6 @@ module ClientForPoslynx
|
|
15
15
|
def initialize(root_element_name)
|
16
16
|
@root_element_name = root_element_name
|
17
17
|
end
|
18
|
-
|
19
|
-
# def parse(source_xml)
|
20
|
-
# xml_document = XmlDocument.new( source_xml )
|
21
|
-
# xml_document.property_element_values
|
22
|
-
# end
|
23
|
-
|
24
18
|
end
|
25
19
|
|
26
20
|
end
|
@@ -27,6 +27,13 @@ module ClientForPoslynx
|
|
27
27
|
attr_element_mapping attribute: :receipt, element: 'Receipt', numbered_lines: 'Receipt%d'
|
28
28
|
attr_element_mapping attribute: :customer_receipt, element: 'ReceiptCustomer', numbered_lines: 'Receipt%d'
|
29
29
|
|
30
|
+
def signature=(value)
|
31
|
+
if value =~ /^<!\[CDATA\[(.*)\]\]>$/
|
32
|
+
@signature = $1
|
33
|
+
else
|
34
|
+
@signature = value
|
35
|
+
end
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
39
|
end
|
@@ -3,14 +3,4 @@
|
|
3
3
|
# Require this file to load experimental features that
|
4
4
|
# are not yet expected to be fully usable.
|
5
5
|
|
6
|
-
#
|
7
|
-
# here because it is only used by SignatureImage.
|
8
|
-
require "client_for_poslynx/bit_sequence"
|
9
|
-
|
10
|
-
# SignatureImage currently only supports the legacy
|
11
|
-
# Hypercom/Equinox signature data format, which is useful
|
12
|
-
# to approximately 0% of POSLynx users. It has also not
|
13
|
-
# been tested with real data produced by a payment terminal,
|
14
|
-
# so it is possible that some understandings about the
|
15
|
-
# format are incorrect.
|
16
|
-
require "client_for_poslynx/signature_image"
|
6
|
+
# No experimental features at this time.
|
@@ -12,8 +12,6 @@ module ClientForPoslynx
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class Client
|
15
|
-
attr_accessor :client_mac_for_examples
|
16
|
-
|
17
15
|
def config
|
18
16
|
@config ||= Config.new
|
19
17
|
end
|
@@ -95,13 +93,13 @@ module ClientForPoslynx
|
|
95
93
|
end
|
96
94
|
|
97
95
|
def assign_common_example_request_attrs_to(request)
|
98
|
-
request.client_mac = client_mac_for_examples if client_mac_for_examples
|
96
|
+
request.client_mac = config.client_mac_for_examples if config.client_mac_for_examples
|
99
97
|
end
|
100
98
|
|
101
99
|
end
|
102
100
|
|
103
101
|
class Config
|
104
|
-
attr_accessor :host, :port
|
102
|
+
attr_accessor :host, :port, :client_mac_for_examples
|
105
103
|
end
|
106
104
|
|
107
105
|
end
|
@@ -7,16 +7,16 @@ module ClientForPoslynx
|
|
7
7
|
DELTA_BITS_LONG = 6
|
8
8
|
BIT_SEQUENCE_LENGTH = 1 + DELTA_BITS_LONG * 2
|
9
9
|
|
10
|
-
def self.first_in_bit_sequence(bit_seq)
|
10
|
+
def self.first_in_bit_sequence(bit_seq, format=nil)
|
11
11
|
bit_seq.first_bit_digit == '0' &&
|
12
12
|
bit_seq.length >= BIT_SEQUENCE_LENGTH
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.parse_from_bit_sequence!(bit_seq)
|
15
|
+
def self.parse_from_bit_sequence!(bit_seq, format=nil)
|
16
16
|
bit_seq.shift 1
|
17
17
|
dx_bit_seq = bit_seq.shift( DELTA_BITS_LONG )
|
18
18
|
dy_bit_seq = bit_seq.shift( DELTA_BITS_LONG )
|
19
|
-
new( dx_bit_seq.
|
19
|
+
new( dx_bit_seq.as_signed, dy_bit_seq.as_signed )
|
20
20
|
end
|
21
21
|
|
22
22
|
attr_reader :dx, :dy
|
@@ -31,10 +31,10 @@ module ClientForPoslynx
|
|
31
31
|
return dx == other.dx && dy == other.dy
|
32
32
|
end
|
33
33
|
|
34
|
-
def to_bit_sequence
|
34
|
+
def to_bit_sequence(serialization_format=nil)
|
35
35
|
bit_seq = ClientForPoslynx::BitSequence / '0'
|
36
|
-
bit_seq << ClientForPoslynx::BitSequence.
|
37
|
-
bit_seq << ClientForPoslynx::BitSequence.
|
36
|
+
bit_seq << ClientForPoslynx::BitSequence.from_signed( dx, DELTA_BITS_LONG )
|
37
|
+
bit_seq << ClientForPoslynx::BitSequence.from_signed( dy, DELTA_BITS_LONG )
|
38
38
|
end
|
39
39
|
|
40
40
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ClientForPoslynx
|
2
|
+
class SignatureImage
|
3
|
+
|
4
|
+
class Metrics <
|
5
|
+
Struct.new(
|
6
|
+
|
7
|
+
# [x,y] scaled resolution
|
8
|
+
:resolution,
|
9
|
+
|
10
|
+
# [x,y] pysical size in dekamicrometers
|
11
|
+
# 1 dekamicrometer = 10 micrometers or 0.01 millimeters
|
12
|
+
:size_in_dum,
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -4,19 +4,19 @@ module ClientForPoslynx
|
|
4
4
|
class SignatureImage
|
5
5
|
|
6
6
|
class Move
|
7
|
-
X_BITS_LONG = 10
|
8
|
-
Y_BITS_LONG = 7
|
9
|
-
BIT_SEQUENCE_LENGTH = 1 + X_BITS_LONG + Y_BITS_LONG
|
7
|
+
X_BITS_LONG = { legacy: 10, enhanced_narrow: 10, enhanced_wide: 11 }
|
8
|
+
Y_BITS_LONG = { legacy: 7, enhanced_narrow: 10, enhanced_wide: 10 }
|
10
9
|
|
11
|
-
def self.first_in_bit_sequence(bit_seq)
|
10
|
+
def self.first_in_bit_sequence(bit_seq, format=:legacy)
|
11
|
+
bit_sequence_length = 1 + X_BITS_LONG[format] + Y_BITS_LONG[format]
|
12
12
|
bit_seq.first_bit_digit == '1' &&
|
13
|
-
bit_seq.length >=
|
13
|
+
bit_seq.length >= bit_sequence_length
|
14
14
|
end
|
15
15
|
|
16
|
-
def self.parse_from_bit_sequence!(bit_seq)
|
16
|
+
def self.parse_from_bit_sequence!(bit_seq, format=:legacy)
|
17
17
|
bit_seq.shift 1
|
18
|
-
x_bit_seq = bit_seq.shift( X_BITS_LONG )
|
19
|
-
y_bit_seq = bit_seq.shift( Y_BITS_LONG )
|
18
|
+
x_bit_seq = bit_seq.shift( X_BITS_LONG[format] )
|
19
|
+
y_bit_seq = bit_seq.shift( Y_BITS_LONG[format] )
|
20
20
|
new( x_bit_seq.as_unsigned, y_bit_seq.as_unsigned )
|
21
21
|
end
|
22
22
|
|
@@ -32,10 +32,10 @@ module ClientForPoslynx
|
|
32
32
|
return x == other.x && y == other.y
|
33
33
|
end
|
34
34
|
|
35
|
-
def to_bit_sequence
|
35
|
+
def to_bit_sequence(format=:legacy)
|
36
36
|
bit_seq = ClientForPoslynx::BitSequence / '1'
|
37
|
-
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( x, X_BITS_LONG )
|
38
|
-
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( y, Y_BITS_LONG )
|
37
|
+
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( x, X_BITS_LONG[format] )
|
38
|
+
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( y, Y_BITS_LONG[format] )
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -38,9 +38,10 @@ module ClientForPoslynx
|
|
38
38
|
private
|
39
39
|
|
40
40
|
def apply_document_characteristics
|
41
|
-
|
42
|
-
svg_element['
|
43
|
-
svg_element['
|
41
|
+
metrics = signature_image.metrics || SignatureImage::Metrics.new([6717, 1343], [640, 128])
|
42
|
+
svg_element['width' ] = '%fmm' % ( metrics.size_in_dum[0] * 0.01 )
|
43
|
+
svg_element['height' ] = '%fmm' % ( metrics.size_in_dum[1] * 0.01 )
|
44
|
+
svg_element['viewBox' ] = '0 0 %d %d' % metrics.resolution
|
44
45
|
svg_element['preserveAspectRatio'] = 'none'
|
45
46
|
end
|
46
47
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require_relative 'signature_image/metrics'
|
3
4
|
require_relative 'signature_image/move'
|
4
5
|
require_relative 'signature_image/draw'
|
5
6
|
require_relative 'signature_image/to_svg_converter'
|
@@ -11,30 +12,59 @@ module ClientForPoslynx
|
|
11
12
|
class << self
|
12
13
|
|
13
14
|
def deserialize(serialized_data)
|
14
|
-
packed_binary =
|
15
|
+
packed_binary = base64_decode( serialized_data )
|
15
16
|
bit_seq = ClientForPoslynx::BitSequence.from_packed_bits( packed_binary )
|
16
17
|
|
17
18
|
sig_image = new
|
19
|
+
|
20
|
+
if bit_seq.first_bit_digit == '0' then
|
21
|
+
leader_seq = bit_seq.shift( 16 )
|
22
|
+
header_content_length_bytes = leader_seq.as_unsigned
|
23
|
+
if header_content_length_bytes < 8 then
|
24
|
+
# TODO: Should have an exception class for this error.
|
25
|
+
raise "Expected header content length to be >= 8, but got #{header_content_length}."
|
26
|
+
end
|
27
|
+
if header_content_length_bytes > 255 then
|
28
|
+
# TODO: Should have an exception class for this error.
|
29
|
+
byte_0_bit_digits = leader_seq.to_bit_digits[0..7]
|
30
|
+
raise "Expected first byte of leader to be zero, but got #{byte_0_bit_digits}."
|
31
|
+
end
|
32
|
+
header_content_seq = bit_seq.shift( header_content_length_bytes * 8 )
|
33
|
+
x_scaled_res = header_content_seq.shift(16).as_unsigned
|
34
|
+
y_scaled_res = header_content_seq.shift(16).as_unsigned
|
35
|
+
x_phys_size = header_content_seq.shift(16).as_unsigned
|
36
|
+
y_phys_size = header_content_seq.shift(16).as_unsigned
|
37
|
+
sig_image.metrics = SignatureImage::Metrics.new(
|
38
|
+
[ x_scaled_res, y_scaled_res ],
|
39
|
+
[ x_phys_size, y_phys_size ],
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
format = sig_image.serialization_format
|
44
|
+
|
18
45
|
step_types = [ SignatureImage::Move, SignatureImage::Draw ]
|
19
46
|
while true
|
20
|
-
step_type = step_types.detect{ |st| st.first_in_bit_sequence( bit_seq ) }
|
47
|
+
step_type = step_types.detect{ |st| st.first_in_bit_sequence( bit_seq, format ) }
|
21
48
|
break if step_type.nil?
|
22
|
-
step = step_type.parse_from_bit_sequence!( bit_seq )
|
49
|
+
step = step_type.parse_from_bit_sequence!( bit_seq, format )
|
23
50
|
sig_image << step
|
24
51
|
end
|
25
52
|
|
26
53
|
sig_image
|
27
54
|
end
|
28
55
|
|
29
|
-
def
|
30
|
-
|
56
|
+
def base64_decode(encoded)
|
57
|
+
encoded.unpack('m').first
|
31
58
|
end
|
32
59
|
|
33
60
|
end
|
34
61
|
|
62
|
+
attr_accessor :metrics
|
63
|
+
|
35
64
|
def ==(other)
|
36
65
|
return false unless self.class === other
|
37
|
-
|
66
|
+
metrics == other.metrics &&
|
67
|
+
sequence == other.sequence
|
38
68
|
end
|
39
69
|
|
40
70
|
def move(*args)
|
@@ -66,15 +96,34 @@ module ClientForPoslynx
|
|
66
96
|
groups
|
67
97
|
end
|
68
98
|
|
69
|
-
def
|
99
|
+
def serialize
|
70
100
|
unless Move === sequence.first
|
71
101
|
raise 'Must have an initial move-type step in order to serialize'
|
72
102
|
end
|
73
103
|
bit_seq = ClientForPoslynx::BitSequence.new_empty
|
104
|
+
case serialization_format
|
105
|
+
when :enhanced_narrow, :enhanced_wide
|
106
|
+
bit_seq << ClientForPoslynx::BitSequence / '00000000'
|
107
|
+
bit_seq << ClientForPoslynx::BitSequence / '00001000'
|
108
|
+
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( metrics.resolution[0], 16 )
|
109
|
+
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( metrics.resolution[1], 16 )
|
110
|
+
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( metrics.size_in_dum[0], 16 )
|
111
|
+
bit_seq << ClientForPoslynx::BitSequence.from_unsigned( metrics.size_in_dum[1], 16 )
|
112
|
+
end
|
74
113
|
sequence.each do |step|
|
75
|
-
bit_seq << step.to_bit_sequence
|
114
|
+
bit_seq << step.to_bit_sequence( serialization_format )
|
115
|
+
end
|
116
|
+
bit_seq.base64_encode
|
117
|
+
end
|
118
|
+
|
119
|
+
def serialization_format
|
120
|
+
if metrics.nil?
|
121
|
+
:legacy
|
122
|
+
else
|
123
|
+
metrics.resolution[0] > 1024 ?
|
124
|
+
:enhanced_wide :
|
125
|
+
:enhanced_narrow
|
76
126
|
end
|
77
|
-
bit_seq.uuencode
|
78
127
|
end
|
79
128
|
|
80
129
|
protected
|
data/lib/client_for_poslynx.rb
CHANGED
@@ -69,7 +69,7 @@ module ClientForPoslynx
|
|
69
69
|
expect( taken ).to eq( expected_taken )
|
70
70
|
end
|
71
71
|
|
72
|
-
it "can have another bit sequence unshifted onto its
|
72
|
+
it "can have another bit sequence unshifted onto its front" do
|
73
73
|
bit_target = klass / '000111000'
|
74
74
|
bit_target.unshift klass / '111000111'
|
75
75
|
|
@@ -89,17 +89,17 @@ module ClientForPoslynx
|
|
89
89
|
raise_exception( klass::TooManyBitsLong, /\b64\b/ )
|
90
90
|
end
|
91
91
|
|
92
|
-
it "can be (big-endian) interpreted as
|
93
|
-
expect( ( klass / '000'
|
94
|
-
expect( ( klass / '0111000011110000'
|
95
|
-
expect( ( klass / '
|
96
|
-
expect( ( klass / ('
|
92
|
+
it "can be (big-endian) interpreted as a 2s-complement signed integer" do
|
93
|
+
expect( ( klass / '000' ).as_signed ).to eq( 0 )
|
94
|
+
expect( ( klass / '0111000011110000' ).as_signed ).to eq( 0x70F0 )
|
95
|
+
expect( ( klass / '1000111100010000' ).as_signed ).to eq( - 0x70F0 )
|
96
|
+
expect( ( klass / ('11110000' * 8) ).as_signed ).to eq( - 0x0F0F0F0F0F0F0F10 )
|
97
97
|
end
|
98
98
|
|
99
|
-
it "fails to be interpreted as
|
100
|
-
bit_seq = klass / ( '0' + '11110000' * 8
|
101
|
-
expect{ bit_seq.
|
102
|
-
to raise_exception( klass::TooManyBitsLong, /\
|
99
|
+
it "fails to be interpreted as 2s complement if longer than 64 bits" do
|
100
|
+
bit_seq = klass / ( '0' + '11110000' * 8 )
|
101
|
+
expect{ bit_seq.as_signed }.
|
102
|
+
to raise_exception( klass::TooManyBitsLong, /\b64\b/ )
|
103
103
|
end
|
104
104
|
|
105
105
|
it "can be constructed as the big-endian representation of an unsigned integer" do
|
@@ -108,13 +108,6 @@ module ClientForPoslynx
|
|
108
108
|
expect( klass.from_unsigned( (2 ** 64) - 1, 64 ) ).to eq( klass / ( '1' * 64 ) )
|
109
109
|
end
|
110
110
|
|
111
|
-
it "can be constructed as the sign-bit and big-endian magnitude representation of an integer" do
|
112
|
-
expect( klass.from_sign_and_magnitude_of( 0, 10 ) ).to eq( klass / ( '0' * 10 ) )
|
113
|
-
expect( klass.from_sign_and_magnitude_of( 0x23, 8 ) ).to eq( klass / ( '00100011' ) )
|
114
|
-
expect( klass.from_sign_and_magnitude_of( - 0x23, 8 ) ).to eq( klass / ( '10100011' ) )
|
115
|
-
expect( klass.from_sign_and_magnitude_of( -(2 ** 64) + 1, 65 ) ).to eq( klass / ( '1' * 65 ) )
|
116
|
-
end
|
117
|
-
|
118
111
|
it "fails to be constructed as a longer than 64-bit representation of an unsigned number" do
|
119
112
|
expect{ klass.from_unsigned(0x23, 65) }.
|
120
113
|
to raise_exception( klass::TooManyBitsLong, /\b64\b/ )
|
@@ -130,16 +123,38 @@ module ClientForPoslynx
|
|
130
123
|
to raise_exception( klass::NumberOutOfBounds )
|
131
124
|
end
|
132
125
|
|
133
|
-
it "can be
|
134
|
-
|
126
|
+
it "can be constructed as the big-endian, 2's complement representation of a signed integer" do
|
127
|
+
expect( klass.from_signed( 0, 9 ) ).to eq( klass / ( '0' * 9 ) )
|
128
|
+
expect( klass.from_signed( -0x23, 7 ) ).to eq( klass / ( '1011101' ) )
|
129
|
+
expect( klass.from_signed( -1, 4 ) ).to eq( klass / ( '1111' ) )
|
130
|
+
expect( klass.from_signed( -(2 ** 63), 64 ) ).to eq( klass / ( '1' + '0' * 63 ) )
|
131
|
+
end
|
132
|
+
|
133
|
+
it "fails to be constructed as a longer than 64-bit representation of a signed number" do
|
134
|
+
expect{ klass.from_signed(0x23, 65) }.
|
135
|
+
to raise_exception( klass::TooManyBitsLong, /\b64\b/ )
|
136
|
+
end
|
137
|
+
|
138
|
+
it "fails to be constructed as a an under-sized representation a negative signed number" do
|
139
|
+
expect{ klass.from_signed(-0x23, 6) }.
|
140
|
+
to raise_exception( klass::NumberOutOfBounds )
|
141
|
+
end
|
142
|
+
|
143
|
+
it "fails to be constructed as an under-sized representation of a positive signed number" do
|
144
|
+
expect{ klass.from_signed(0x23, 6) }.
|
145
|
+
to raise_exception( klass::NumberOutOfBounds )
|
146
|
+
end
|
147
|
+
|
148
|
+
it "can be build by unpacking bits from a base-64 encoded string" do
|
149
|
+
actual = klass.from_base64( "MjIyMjIy" )
|
135
150
|
expected = klass ^ "\x32" * 6
|
136
151
|
|
137
152
|
expect( actual ).to eq( expected )
|
138
153
|
end
|
139
154
|
|
140
|
-
it "can be packed to a
|
155
|
+
it "can be packed to a base-64 string" do
|
141
156
|
bit_seq = klass ^ "\x32" * 6
|
142
|
-
expect( bit_seq.
|
157
|
+
expect( bit_seq.base64_encode ).to eq( "MjIyMjIy" )
|
143
158
|
end
|
144
159
|
|
145
160
|
end
|
@@ -6,6 +6,17 @@ module ClientForPoslynx
|
|
6
6
|
|
7
7
|
it_behaves_like "a data object"
|
8
8
|
|
9
|
+
# At least one revision of the POSLynx returns signature
|
10
|
+
# data surrounded by <[CDATA[...]]> which is obviously
|
11
|
+
# supposed to be CDATA encoding in XML. Since the angle
|
12
|
+
# brackets are esacped, however, the element contains the
|
13
|
+
# CDATA-encoded XML as its text value instead of the
|
14
|
+
# intended content.
|
15
|
+
it "repairs malformed signature image CDATA" do
|
16
|
+
subject.signature = "<![CDATA[ABC123]]>"
|
17
|
+
expect( subject.signature ).to eq( 'ABC123' )
|
18
|
+
end
|
19
|
+
|
9
20
|
it "Serializes to a PLResponse XML document for a CCSALE response" do
|
10
21
|
expected_xml = "<PLResponse><Command>CCSALE</Command></PLResponse>\n"
|
11
22
|
|
@@ -8,43 +8,82 @@ module ClientForPoslynx
|
|
8
8
|
|
9
9
|
def build_example_image
|
10
10
|
described_class.new.tap { |si|
|
11
|
-
si.move
|
12
|
-
si.draw
|
13
|
-
si.draw
|
14
|
-
si.draw
|
15
|
-
si.draw
|
16
|
-
si.draw
|
17
|
-
si.draw
|
18
|
-
si.
|
11
|
+
si.move 20, 120
|
12
|
+
si.draw 10, -30
|
13
|
+
si.draw 10, -30
|
14
|
+
si.draw 10, -30
|
15
|
+
si.draw 10, 30
|
16
|
+
si.draw 10, 30
|
17
|
+
si.draw 10, 30
|
18
|
+
si.move 35, 75
|
19
|
+
si.draw 30, -1
|
19
20
|
}
|
20
21
|
end
|
21
22
|
|
22
|
-
let( :
|
23
|
-
BitSequence.from_bit_digits(
|
23
|
+
let( :legacy_bit_sequence ) {
|
24
|
+
BitSequence.from_bit_digits( legacy_bit_digit_sequence )
|
24
25
|
}
|
25
26
|
|
26
|
-
let( :
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
'
|
37
|
-
'0' + '000000' + '111110' + # draw 0, -30
|
38
|
-
'0' + '000000' + '111110' + # draw 0, -30
|
39
|
-
'0' + '000000' + '111110' + # draw 0, -30
|
40
|
-
'0' + '000000' + '110100' + # draw 0, -20
|
41
|
-
'0' + '011110' + '011110' + # draw 30, 30
|
42
|
-
'0' + '111001' + '011001' + # draw -25, 25
|
43
|
-
'0' + '000000' + '100010' + # draw 0, -2
|
44
|
-
'000' # remaining bits in last byte
|
27
|
+
let( :legacy_bit_digit_sequence ) {
|
28
|
+
'1' + '0000010100' + '1111000' + # move 20, 120 (10-bit, 7-bit)
|
29
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
30
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
31
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
32
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
33
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
34
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
35
|
+
'1' + '0000100011' + '1001011' + # move 35, 75 64+8+2+1
|
36
|
+
'0' + '011110' + '111111' + # draw 30, -1
|
37
|
+
'0' # remaining bit in last byte
|
45
38
|
}
|
46
39
|
|
47
|
-
|
40
|
+
let( :enhanced_narrow_bit_sequence ) {
|
41
|
+
BitSequence.from_bit_digits( enhanced_narrow_bit_digit_sequence )
|
42
|
+
}
|
43
|
+
|
44
|
+
let( :enhanced_narrow_bit_digit_sequence ) {
|
45
|
+
'00000000' + # 1st byte all 0s: Indicates enhanced format.
|
46
|
+
'00001000' + # Header content length: 8 bytes
|
47
|
+
'0000010000000000' + # X scaled resolution: 1024 (maximum to be treated as narrow)
|
48
|
+
'0000000110000000' + # Y scaled resolution: 384
|
49
|
+
'0001111101000000' + # X physical size in 0.01 mm units: 8000
|
50
|
+
'0000101110111000' + # Y physical size in 0.01 mm units: 3000
|
51
|
+
'1' + '0000010100' + '0001111000' + # move 20, 120 (10-bit, 10-bit)
|
52
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
53
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
54
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
55
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
56
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
57
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
58
|
+
'1' + '0000100011' + '0001001011' + # move 35, 75
|
59
|
+
'0' + '011110' + '111111' + # draw 30, -1
|
60
|
+
'000' # remaining bits in last byte
|
61
|
+
}
|
62
|
+
|
63
|
+
let( :enhanced_wide_bit_sequence ) {
|
64
|
+
BitSequence.from_bit_digits( enhanced_wide_bit_digit_sequence )
|
65
|
+
}
|
66
|
+
|
67
|
+
let( :enhanced_wide_bit_digit_sequence ) {
|
68
|
+
'00000000' + # 1st byte all 0s: Indicates enhanced format.
|
69
|
+
'00001000' + # Header content length: 8 bytes
|
70
|
+
'0000010000000001' + # X scaled resolution: 1025 (minimum to be treated as wide)
|
71
|
+
'0000000110011010' + # Y scaled resolution: 410
|
72
|
+
'0001111101000000' + # X physical size in 0.01 mm units: 8000
|
73
|
+
'0000110010000000' + # Y physical size in 0.01 mm units: 3200
|
74
|
+
'1' + '00000010100' + '0001111000' + # move 20, 120 (11-bit, 10-bit)
|
75
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
76
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
77
|
+
'0' + '001010' + '100010' + # draw 10, -30
|
78
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
79
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
80
|
+
'0' + '001010' + '011110' + # draw 10, 30
|
81
|
+
'1' + '00000100011' + '0001001011' + # move 35, 75
|
82
|
+
'0' + '011110' + '111111' + # draw 30, -1
|
83
|
+
'0' # remaining bit in last byte
|
84
|
+
}
|
85
|
+
|
86
|
+
it "is unequal to another instance with a different sequence of steps and no metrics" do
|
48
87
|
subject = build_example_image
|
49
88
|
|
50
89
|
other_sig = described_class.new
|
@@ -54,35 +93,129 @@ module ClientForPoslynx
|
|
54
93
|
expect( subject ).not_to eq( other_sig )
|
55
94
|
end
|
56
95
|
|
57
|
-
it "is
|
96
|
+
it "is unequal to another instance with a different sequence of steps and same metrics" do
|
97
|
+
subject = build_example_image
|
98
|
+
subject.metrics = SignatureImage::Metrics.new([1000, 250], [6080, 1520])
|
99
|
+
|
100
|
+
other_sig = described_class.new
|
101
|
+
other_sig.metrics = SignatureImage::Metrics.new([1000, 250], [6080, 1520])
|
102
|
+
other_sig.move 10, 120
|
103
|
+
other_sig.draw 0, -29
|
104
|
+
|
105
|
+
expect( subject ).not_to eq( other_sig )
|
106
|
+
end
|
107
|
+
|
108
|
+
it "is unequal to another instance with the same sequence of steps and different metrics" do
|
109
|
+
subject = build_example_image
|
110
|
+
subject.metrics = SignatureImage::Metrics.new([1000, 250], [6080, 1520])
|
111
|
+
|
112
|
+
other_sig = build_example_image
|
113
|
+
other_sig.metrics = SignatureImage::Metrics.new([999, 250], [6080, 1520])
|
114
|
+
|
115
|
+
expect( subject ).not_to eq( other_sig )
|
116
|
+
end
|
117
|
+
|
118
|
+
it "is equal to another instance with the same sequence of steps and no metrics" do
|
58
119
|
subject = build_example_image
|
59
120
|
other_sig = build_example_image
|
60
121
|
|
61
122
|
expect( subject ).to eq( other_sig )
|
62
123
|
end
|
63
124
|
|
64
|
-
|
65
|
-
subject
|
125
|
+
it "is equal to another instance with the same sequence of steps and same metrics" do
|
126
|
+
subject = build_example_image
|
127
|
+
subject.metrics = SignatureImage::Metrics.new([1000, 250], [6080, 1520])
|
66
128
|
|
67
|
-
|
68
|
-
|
69
|
-
|
129
|
+
other_sig = build_example_image
|
130
|
+
other_sig.metrics = SignatureImage::Metrics.new([1000, 250], [6080, 1520])
|
131
|
+
|
132
|
+
expect( subject ).to eq( other_sig )
|
133
|
+
end
|
134
|
+
|
135
|
+
context "legacy serialized format" do
|
136
|
+
context "serializing" do
|
137
|
+
subject{ build_example_image }
|
138
|
+
|
139
|
+
it "serializes data" do
|
140
|
+
actual_serialized = subject.serialize
|
141
|
+
actual_bit_sequence = BitSequence.from_base64( actual_serialized )
|
70
142
|
|
71
|
-
|
143
|
+
expect( actual_bit_sequence ).to eq( legacy_bit_sequence )
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "deserializing" do
|
148
|
+
subject{ described_class.new(serialized_data) }
|
149
|
+
let( :serialized_data ) {
|
150
|
+
legacy_bit_sequence.base64_encode
|
151
|
+
}
|
152
|
+
|
153
|
+
it "deserializes data" do
|
154
|
+
actual = described_class.deserialize( serialized_data )
|
155
|
+
expected = build_example_image
|
156
|
+
|
157
|
+
expect( actual ).to eq( expected )
|
158
|
+
end
|
72
159
|
end
|
73
160
|
end
|
74
161
|
|
75
|
-
context "
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
162
|
+
context "enhanced format with narrow resolution" do
|
163
|
+
context "serializing" do
|
164
|
+
subject{ build_example_image.tap{ |img|
|
165
|
+
img.metrics = SignatureImage::Metrics.new([1024,384], [8000,3000])
|
166
|
+
} }
|
167
|
+
|
168
|
+
it "serializes data" do
|
169
|
+
actual_serialized = subject.serialize
|
170
|
+
actual_bit_sequence = BitSequence.from_base64( actual_serialized )
|
171
|
+
|
172
|
+
expect( actual_bit_sequence ).to eq( enhanced_narrow_bit_sequence )
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "deserializing" do
|
177
|
+
subject{ described_class.new(serialized_data) }
|
178
|
+
let( :serialized_data ) {
|
179
|
+
enhanced_narrow_bit_sequence.base64_encode
|
180
|
+
}
|
181
|
+
|
182
|
+
it "deserializes data" do
|
183
|
+
actual = described_class.deserialize( serialized_data )
|
184
|
+
expected = build_example_image
|
185
|
+
expected.metrics = SignatureImage::Metrics.new([1024,384], [8000,3000])
|
186
|
+
|
187
|
+
expect( actual ).to eq( expected )
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "enhanced format with wide resolution" do
|
193
|
+
context "serializing" do
|
194
|
+
subject{ build_example_image.tap{ |img|
|
195
|
+
img.metrics = SignatureImage::Metrics.new([1025,410], [8000,3200])
|
196
|
+
} }
|
197
|
+
|
198
|
+
it "serializes data" do
|
199
|
+
actual_serialized = subject.serialize
|
200
|
+
actual_bit_sequence = BitSequence.from_base64( actual_serialized )
|
201
|
+
|
202
|
+
expect( actual_bit_sequence ).to eq( enhanced_wide_bit_sequence )
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context "deserializing" do
|
207
|
+
subject{ described_class.new(serialized_data) }
|
208
|
+
let( :serialized_data ) {
|
209
|
+
enhanced_wide_bit_sequence.base64_encode
|
210
|
+
}
|
80
211
|
|
81
|
-
|
82
|
-
|
83
|
-
|
212
|
+
it "deserializes data" do
|
213
|
+
actual = described_class.deserialize( serialized_data )
|
214
|
+
expected = build_example_image
|
215
|
+
expected.metrics = SignatureImage::Metrics.new([1025,410], [8000,3200])
|
84
216
|
|
85
|
-
|
217
|
+
expect( actual ).to eq( expected )
|
218
|
+
end
|
86
219
|
end
|
87
220
|
end
|
88
221
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: client_for_poslynx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Jorgensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -86,7 +86,6 @@ files:
|
|
86
86
|
- bin/fake_pos_terminal
|
87
87
|
- bin/poslynx_client_console
|
88
88
|
- client_for_poslynx.gemspec
|
89
|
-
- foo.svg
|
90
89
|
- lib/client_for_poslynx.rb
|
91
90
|
- lib/client_for_poslynx/bit_sequence.rb
|
92
91
|
- lib/client_for_poslynx/data.rb
|
@@ -135,6 +134,7 @@ files:
|
|
135
134
|
- lib/client_for_poslynx/message_handling/xml_extractor.rb
|
136
135
|
- lib/client_for_poslynx/signature_image.rb
|
137
136
|
- lib/client_for_poslynx/signature_image/draw.rb
|
137
|
+
- lib/client_for_poslynx/signature_image/metrics.rb
|
138
138
|
- lib/client_for_poslynx/signature_image/move.rb
|
139
139
|
- lib/client_for_poslynx/signature_image/to_svg_converter.rb
|
140
140
|
- lib/client_for_poslynx/version.rb
|
data/foo.svg
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
width="67.17mm" height="13.434mm"
|
3
|
-
viewBox="0 0 640 128"
|
4
|
-
preserveAspectRatio='none'
|
5
|
-
xmlns="http://www.w3.org/2000/svg"
|
6
|
-
>
|
7
|
-
|
8
|
-
<path d='M 40,10 l 0,30 0,30 -5,5 -3,1 -3,-1 -5,-5
|
9
|
-
M 24,10 l 30,0
|
10
|
-
M 65,40 l 10,0 6,4 4,6 0,15 -4,6 -6,4 -10,0 -6,-4 -4,-6 0,-15, 4,-6
|
11
|
-
M 93,40 l 14,28 5,10
|
12
|
-
M 130,40 l -15,30 -15,30 M 160,50 l 0,0'
|
13
|
-
stroke='black'
|
14
|
-
stroke-width='1mm'
|
15
|
-
stroke-linejoin='round'
|
16
|
-
stroke-linecap='square'
|
17
|
-
fill='none'
|
18
|
-
/>
|
19
|
-
|
20
|
-
</svg>
|