vchain_client 1.0.24 → 1.0.25

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
  SHA1:
3
- metadata.gz: 45eab3023d999ff109e6276094ad539f90b58cd5
4
- data.tar.gz: 5ba7df0e979f407888885065f52c7b806407411f
3
+ metadata.gz: 594cda89ecd48d65fe70e8ab692af24962232ff0
4
+ data.tar.gz: 5f20fe475e378bf2380c9ee1d069052d9139772a
5
5
  SHA512:
6
- metadata.gz: 0e15a53253f36814cd6c59f7b59109dfcc9f052a23678d686b88be16c6676a8cd4aba8f1537d007bb565febbfdd94b7caae15261be1d540656a7f7f353638feb
7
- data.tar.gz: 1769eb0e95bfb74529ad4dfe569d3d8b7c91e34efeb492c24b79f193470a3db3ee05f50691343e39ad32bf3e48458234ef9b0730e1bb2db701adc172d66781ee
6
+ metadata.gz: 4d62fc662be3b9200c587ade4e9307fb2ef4bf5e72d84b4fe2a0d122233cbd79258e8bbd6be4bc6005da44563e1b27e00dd9c0caf21f0b75b6a3e235799e9374
7
+ data.tar.gz: 514bb2f17cc0de35fbb6247a43f5976a92b606b34a895a06c01886edf95c52a4304c320b1f21974f82ed17865eb542af696b068a4811d8f260e3604048f42d87
@@ -0,0 +1,11 @@
1
+ module VChainClient
2
+
3
+ class DecisionAlgorithm
4
+
5
+ def make_decision(sent_document, res, validated_data_points)
6
+ return nil
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,477 @@
1
+ module VChainClient
2
+
3
+ class VectorBasedDecisionAlgorithm < VChainClient::DecisionAlgorithm
4
+
5
+ @log = nil
6
+
7
+ @config = nil
8
+
9
+ CREDENTIALS_FIELD_WEIGHT = 1
10
+ NON_CREDENTIALS_FIELD_WEIGHT = 1
11
+ PROBABILITY_THRESHOLD = 80
12
+
13
+ def initialize(app_config)
14
+ @config = app_config
15
+
16
+ @log = Log4r::Logger["vchain_client"]
17
+ end
18
+
19
+ def get_vector_weight(vector, credentials_fields)
20
+ vector_weight = 0
21
+
22
+ vector.each { |field_hash, values|
23
+ field = values[1]
24
+
25
+ if field_hash != "names_parts"
26
+ weight = values[2]
27
+
28
+ if credentials_fields.include?(field)
29
+ vector_weight += weight * CREDENTIALS_FIELD_WEIGHT
30
+ else
31
+ vector_weight += weight * NON_CREDENTIALS_FIELD_WEIGHT
32
+ end
33
+ end
34
+ }
35
+
36
+ return vector_weight
37
+ end
38
+
39
+ def make_decision(sent_document, res, validated_data_points)
40
+
41
+ sent_type_credentials_fields = VChainClient::Client.get_credentials_fields(sent_document["type"])
42
+
43
+ # total_response_weight = 0
44
+ #
45
+ # sent_document_fully_hashed = VChainClient::Client.full_hash(sent_document)
46
+ #
47
+ # sent_type_credentials_fields_hashed = []
48
+ # sent_type_credentials_fields.each { |credentials_field|
49
+ # sent_type_credentials_fields_hashed.push(Digest::SHA512.hexdigest(credentials_field))
50
+ # }
51
+ #
52
+ # validated_data_points.each { |data_point_hash, validated_data_point|
53
+ # validated_data_point.each { |field_hashed, weight|
54
+ #
55
+ # if sent_document_fully_hashed.key?(field_hashed) || sent_type_credentials_fields_hashed.include?(field_hashed)
56
+ #
57
+ # if sent_type_credentials_fields_hashed.include?(field_hashed)
58
+ # total_response_weight += weight * CREDENTIALS_FIELD_WEIGHT
59
+ # else
60
+ # total_response_weight += weight * NON_CREDENTIALS_FIELD_WEIGHT
61
+ # end
62
+ #
63
+ # end
64
+ # }
65
+ # }
66
+
67
+ # 1. cut non-input fields, rebuild doc_hashes
68
+ # 2. build vectors out of cut documents
69
+
70
+ cut_res_docs = []
71
+
72
+ vectors = []
73
+
74
+ res["docs"].each { |res_doc|
75
+
76
+ cut_doc = {}
77
+ vector = {}
78
+
79
+ names_parts = {}
80
+ if res_doc.key?("names_parts")
81
+ names_parts = res_doc["names_parts"]
82
+
83
+ res_doc.delete("names_parts")
84
+ end
85
+
86
+ full_doc_hash = VChainClient::Client.get_doc_hash(res_doc)
87
+
88
+ res_doc.each { |res_doc_field, res_doc_value|
89
+ if sent_document.key?(res_doc_field) || sent_type_credentials_fields.include?(res_doc_field)
90
+ cut_doc[res_doc_field] = res_doc_value
91
+
92
+ vector[Digest::SHA512.hexdigest(res_doc_field)] = [res_doc_value, res_doc_field, 0]
93
+ end
94
+ }
95
+
96
+ cut_doc["doc_hash"] = VChainClient::Client.get_doc_hash(cut_doc)
97
+
98
+ cut_doc["full_doc_hash"] = full_doc_hash
99
+
100
+ hashed_full_doc_hash = Digest::SHA512.hexdigest(full_doc_hash);
101
+
102
+ if validated_data_points.key?(hashed_full_doc_hash)
103
+ data_points = validated_data_points[hashed_full_doc_hash]
104
+
105
+ data_points.each { |data_point_field, data_point_value|
106
+ if vector.key?(data_point_field)
107
+ vector[data_point_field][2] += data_point_value
108
+ end
109
+ }
110
+ end
111
+
112
+ if !names_parts.empty?
113
+ cut_doc["names_parts"] = names_parts
114
+ vector["names_parts"] = names_parts
115
+ end
116
+
117
+ vectors.push(vector)
118
+
119
+ cut_res_docs.push(cut_doc)
120
+ }
121
+
122
+ res["docs"] = cut_res_docs
123
+
124
+
125
+ # 3. combine vectors part 1 - marking => absorb smaller, merge equal
126
+ for i in 0..(vectors.length - 1)
127
+
128
+ vector_i = vectors[i]
129
+
130
+ for j in i+1..(vectors.length - 1)
131
+
132
+ if j >= vectors.length
133
+ break
134
+ end
135
+
136
+ vector_j = vectors[j]
137
+
138
+ i_is_less_j = false
139
+ j_is_less_i = false
140
+
141
+ need_to_combine = true
142
+
143
+ vector_i.each { |vector_i_hashed_field, vector_i_values|
144
+ if vector_i_hashed_field != "names_parts" && vector_i_hashed_field != "resolutions"
145
+ if !vector_j.key?(vector_i_hashed_field)
146
+ j_is_less_i = true
147
+ else
148
+ vector_j_values = vector_j[vector_i_hashed_field]
149
+ if vector_i_values[0] != vector_j_values[0]
150
+ need_to_combine = false
151
+ break
152
+ end
153
+ end
154
+ end
155
+ }
156
+
157
+ vector_j.each { |vector_j_hashed_field, vector_j_values|
158
+ if vector_j_hashed_field != "names_parts" && vector_j_hashed_field != "resolutions"
159
+ if !vector_i.key?(vector_j_hashed_field)
160
+ i_is_less_j = true
161
+ else
162
+ vector_i_values = vector_i[vector_j_hashed_field]
163
+ if vector_j_values[0] != vector_i_values[0]
164
+ need_to_combine = false
165
+ break
166
+ end
167
+ end
168
+ end
169
+ }
170
+
171
+ if need_to_combine
172
+ if i_is_less_j && j_is_less_i
173
+ # differs, no need to combine
174
+
175
+ elsif i_is_less_j && !j_is_less_i
176
+ # combine i to j
177
+ if !vectors[i].key?("resolutions")
178
+ vectors[i]["resolutions"] = []
179
+ end
180
+ if !vectors[j].key?("resolutions")
181
+ vectors[j]["resolutions"] = []
182
+ end
183
+ vectors[i]["resolutions"].push(["combine_to", j])
184
+ vectors[j]["resolutions"].push(["absorb", i])
185
+
186
+ elsif !i_is_less_j && j_is_less_i
187
+ # combine j to i
188
+ if !vectors[i].key?("resolutions")
189
+ vectors[i]["resolutions"] = []
190
+ end
191
+ if !vectors[j].key?("resolutions")
192
+ vectors[j]["resolutions"] = []
193
+ end
194
+ vectors[j]["resolutions"].push(["combine_to", i])
195
+ vectors[i]["resolutions"].push(["absorb", j])
196
+
197
+ else
198
+ # equals, combine j to i and delete j
199
+ if !vectors[i].key?("resolutions")
200
+ vectors[i]["resolutions"] = []
201
+ end
202
+ if !vectors[j].key?("resolutions")
203
+ vectors[j]["resolutions"] = []
204
+ end
205
+ vectors[j]["resolutions"].push(["combine_to", i])
206
+ vectors[i]["resolutions"].push(["absorb", j])
207
+
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ # 4. combine vectors part 2 - resolutions execution => absorb smaller, merge equal
214
+ vectors_to_remove = []
215
+
216
+ for i in 0..(vectors.length-1)
217
+
218
+ vector_i = vectors[i]
219
+
220
+ if vector_i.key?("resolutions")
221
+
222
+ need_to_delete = false
223
+
224
+ vector_i["resolutions"].each { |resolution|
225
+
226
+ resolution_type = resolution[0]
227
+
228
+ if resolution_type == "combine_to"
229
+
230
+ vector_i["resolutions"].each { |resolution_b|
231
+
232
+ if resolution_b[0] == "absorb"
233
+ if !vectors[resolution[1]].key?("resolutions")
234
+ vectors[resolution[1]]["resolutions"] = []
235
+ end
236
+
237
+ # check for dublicates
238
+ need_to_add = true
239
+
240
+ vectors[resolution[1]]["resolutions"].each { |resolution_c|
241
+ if resolution_c[0] == resolution_b[0] && resolution_c[1] == resolution_b[1]
242
+ need_to_add = false
243
+ break
244
+ end
245
+ }
246
+
247
+ if need_to_add
248
+ vectors[resolution[1]]["resolutions"].push(resolution_b)
249
+ end
250
+ end
251
+ }
252
+
253
+ need_to_delete = true
254
+ end
255
+ }
256
+
257
+ if need_to_delete
258
+ vectors_to_remove.push(i)
259
+ end
260
+ end
261
+ end
262
+
263
+ for i in 0..(vectors.length - 1)
264
+
265
+ vector_i = vectors[i]
266
+
267
+ if vector_i.key?("resolutions")
268
+ if !vectors_to_remove.include?(i)
269
+
270
+ vector_i["resolutions"].each { |resolution|
271
+
272
+ if resolution[0] == "absorb"
273
+ vector_j = vectors[resolution[1]]
274
+
275
+ vector_j.each { |vector_j_hashed_field, vector_j_values|
276
+ if vector_j_hashed_field != "names_parts" && vector_j_hashed_field != "resolutions"
277
+ vectors[i][vector_j_hashed_field][2] += vector_j_values[2]
278
+ end
279
+ }
280
+ end
281
+
282
+ }
283
+
284
+ vectors[i].delete("resolutions")
285
+
286
+ end
287
+ end
288
+ end
289
+
290
+ # remove marked vectors
291
+ vectors_removed_number = 0
292
+ vectors_to_remove.each { |index|
293
+ vectors.delete_at(index - vectors_removed_number)
294
+ vectors_removed_number += 1
295
+ }
296
+
297
+ total_response_weight = 0
298
+
299
+ vectors.each { |vector|
300
+
301
+ vector_weight = self.get_vector_weight(vector, sent_type_credentials_fields)
302
+
303
+ total_response_weight += vector_weight
304
+ }
305
+
306
+ vectors.each { |vector|
307
+
308
+ vector_weight = self.get_vector_weight(vector, sent_type_credentials_fields)
309
+ vector_probability = (vector_weight / total_response_weight) * 100
310
+
311
+ if vector_probability > PROBABILITY_THRESHOLD
312
+
313
+ compare_document = sent_document.clone
314
+ compare_document.delete("names")
315
+
316
+ # let's compare found vector with sent_document
317
+ diff_fields = []
318
+ validated = {}
319
+
320
+ # flip vector
321
+ vector_fliped = {}
322
+
323
+ vector.each { |hashed_vector_field, vector_values|
324
+ if hashed_vector_field != "names_parts"
325
+ vector_fliped[vector_values[1]] = vector_values[2]
326
+ end
327
+ }
328
+
329
+ # all fields except of names
330
+ compare_document.each { |compare_field, compared_value_hashed|
331
+
332
+ compare_field_hashed = Digest::SHA512.hexdigest(compare_field)
333
+
334
+ if vector.key?(compare_field_hashed)
335
+
336
+ vector_values = vector[compare_field_hashed]
337
+
338
+ if sent_document[vector_values[1]] != vector_values[0]
339
+
340
+ diff_fields.push(compare_field)
341
+
342
+ else
343
+
344
+ validated[compare_field] = {
345
+ "validations_weight" => vector_values[2]
346
+ }
347
+
348
+ end
349
+
350
+ else
351
+
352
+ validated[compare_field] = {
353
+ "validations_weight" => 0
354
+ }
355
+
356
+ end
357
+ }
358
+
359
+ # names
360
+
361
+ if vector.key?("names_parts")
362
+ if vector["names_parts"].key?("surname")
363
+
364
+ validated["surname"] = {
365
+ "vector_values" => vector["names_parts"]["surname"],
366
+ "validations_weight" => vector_fliped["surname"]
367
+ }
368
+
369
+ else
370
+ diff_fields.push("surname")
371
+ end
372
+ else
373
+ diff_fields.push("surname")
374
+ end
375
+
376
+ if vector.key?("names_parts")
377
+ if vector["names_parts"].key?("given_names")
378
+
379
+ validated["given_names"] = {
380
+ "vector_values" => vector["names_parts"]["given_names"],
381
+ "validations_weight" => vector_fliped["given_names"]
382
+ }
383
+
384
+ else
385
+ diff_fields.push("given_names")
386
+ end
387
+ else
388
+ diff_fields.push("given_names")
389
+ end
390
+
391
+ if diff_fields.length == 0
392
+ return {
393
+ "decision_made" => true,
394
+ "decision" => "MATCH",
395
+ "validations" => validated
396
+ }
397
+ end
398
+
399
+ return {
400
+ "decision_made" => true,
401
+ "decision" => "POSSIBLE_MISTAKES",
402
+ "possible_mistakes" => diff_fields,
403
+ "validations" => validated
404
+ }
405
+
406
+ end
407
+ }
408
+
409
+ # prepare for output
410
+
411
+ vectors_fliped = []
412
+
413
+ for i in 0..(vectors.length - 1)
414
+
415
+ vector_fliped = {}
416
+
417
+ vectors[i].each { |hashed_vector_field, vector_values|
418
+
419
+ if hashed_vector_field != "names_parts"
420
+ val = "same"
421
+ if sent_document[vector_values[1]] != vector_values[0]
422
+ val = "different"
423
+ end
424
+ vector_fliped[vector_values[1]] = [val, vector_values[2]]
425
+ else
426
+ vector_fliped[hashed_vector_field] = vector_values
427
+ end
428
+ }
429
+
430
+ vector_raw_surname = ""
431
+ if vector_fliped.key?("names_parts")
432
+ if vector_fliped["names_parts"].key?("surname")
433
+ sep = ""
434
+ vector_fliped["names_parts"]["surname"].each { |surname_part|
435
+ vector_raw_surname += sep + surname_part
436
+ sep = " "
437
+ }
438
+ else
439
+ vector_raw_surname = "different"
440
+ end
441
+ else
442
+ vector_raw_surname = "different"
443
+ end
444
+
445
+ vector_raw_given_names = ""
446
+ if vector_fliped.key?("names_parts")
447
+ if vector_fliped["names_parts"].key?("given_names")
448
+ sep = ""
449
+ vector_fliped["names_parts"]["given_names"].each { |given_names_part|
450
+ vector_raw_given_names += sep + given_names_part
451
+ sep = " "
452
+ }
453
+ else
454
+ vector_raw_given_names = "different"
455
+ end
456
+ else
457
+ vector_raw_given_names = "different"
458
+ end
459
+
460
+ vector_fliped["surname"] = [vector_raw_surname, vector_fliped["surname"][1]]
461
+ vector_fliped["given_names"] = [vector_raw_given_names, vector_fliped["given_names"][1]]
462
+
463
+ vector_fliped.delete("names_parts")
464
+
465
+ vectors_fliped.push(vector_fliped)
466
+
467
+ end
468
+
469
+ return {
470
+ "decision_made" => false,
471
+ "vectors" => vectors_fliped
472
+ }
473
+ end
474
+
475
+ end
476
+
477
+ end
data/lib/vchain_client.rb CHANGED
@@ -15,6 +15,8 @@ module VChainClient
15
15
  require 'vchain_client/blockchain_connection'
16
16
  require 'vchain_client/signatures'
17
17
  require 'vchain_client/blockstack_client'
18
+ require 'vchain_client/decision_algos/decision_algorithm.rb'
19
+ require 'vchain_client/decision_algos/vector_based_decision_algorithm.rb'
18
20
 
19
21
  FIELD_TYPE_TRAVEL_DOCUMENT = "travel_document"
20
22
  FIELD_TYPE_TEST_DOCUMENT = "test_document"
@@ -24,7 +26,7 @@ module VChainClient
24
26
 
25
27
  DATA_POINT_VERSION = "1"
26
28
 
27
- CLIENT_LIB_VERSION = "1.0.24"
29
+ CLIENT_LIB_VERSION = "1.0.25"
28
30
 
29
31
  @config = nil
30
32
  @log = nil
@@ -35,7 +37,7 @@ module VChainClient
35
37
  @log = Log4r::Logger["vchain_client"]
36
38
  end
37
39
 
38
- def hash(arr)
40
+ def self.hash_doc(arr)
39
41
  arr.each { |k, v|
40
42
  if k != "names_parts"
41
43
  if k != "surname" && k != "given_names"
@@ -47,11 +49,11 @@ module VChainClient
47
49
  }
48
50
  end
49
51
 
50
- def full_hash(arr)
52
+ def self.full_hash(arr)
51
53
  output = {}
52
54
 
53
55
  arr.each { |k, v|
54
- if k != "names_parts"
56
+ if k != "names_parts" && k != "names"
55
57
  if k != "doc_hash"
56
58
  output[Digest::SHA512.hexdigest(k)] = Digest::SHA512.hexdigest(v)
57
59
  else
@@ -63,7 +65,7 @@ module VChainClient
63
65
  return output
64
66
  end
65
67
 
66
- def cut(arr)
68
+ def self.cut(arr)
67
69
  arr.each { |k, v|
68
70
  if arr["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
69
71
  if k == "type" || k == "country_code" || k == "number" || k == "surname" || k == "given_names" || k == "birthdate" || k == "nationality" || k == "sex" || k == "birthplace" || k == "issue_date" || k == "expiry_date" || k == "authority"
@@ -83,7 +85,7 @@ module VChainClient
83
85
  }
84
86
  end
85
87
 
86
- def get_doc_hash(arr)
88
+ def self.get_doc_hash(arr)
87
89
  if arr["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
88
90
 
89
91
  what_to_hash = ""
@@ -117,7 +119,7 @@ module VChainClient
117
119
  end
118
120
  end
119
121
 
120
- def get_credentials_fields(type)
122
+ def self.get_credentials_fields(type)
121
123
  if type == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
122
124
  return ["type", "number", "given_names", "surname", "birthdate"]
123
125
 
@@ -133,7 +135,7 @@ module VChainClient
133
135
  return nil
134
136
  end
135
137
 
136
- def get_similar_credential_sets(type)
138
+ def self.get_similar_credential_sets(type)
137
139
  if type == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
138
140
  output = []
139
141
  output.push(["type", "number", "surname", "birthdate"])
@@ -161,7 +163,7 @@ module VChainClient
161
163
  return nil
162
164
  end
163
165
 
164
- def get_credentials_hash(document)
166
+ def self.get_credentials_hash(document)
165
167
  if document["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
166
168
  what_to_hash = document["type"] + document["number"] + document["given_names"] + document["surname"] + document["birthdate"]
167
169
 
@@ -265,14 +267,14 @@ module VChainClient
265
267
  raw_document["given_names"] = hashed_given_names
266
268
  raw_document["surname"] = hashed_surname
267
269
 
268
- out_document = self.hash(raw_document)
270
+ out_document = VChainClient::Client.hash_doc(raw_document)
269
271
 
270
- out_document = self.cut(out_document)
272
+ out_document = VChainClient::Client.cut(out_document)
271
273
 
272
- doc_hash = self.get_doc_hash(out_document)
274
+ doc_hash = VChainClient::Client.get_doc_hash(out_document)
273
275
  out_document["doc_hash"] = doc_hash
274
276
 
275
- credentials_hash = self.get_credentials_hash(out_document)
277
+ credentials_hash = VChainClient::Client.get_credentials_hash(out_document)
276
278
  out_document["credentials_hash"] = credentials_hash
277
279
 
278
280
  if weight > 1
@@ -533,14 +535,14 @@ module VChainClient
533
535
 
534
536
  document["given_names"] = hashed_given_names
535
537
  document["surname"] = hashed_surname
536
-
537
- document = self.hash(document)
538
538
 
539
- document = self.cut(document)
539
+ document = VChainClient::Client.hash_doc(document)
540
+
541
+ document = VChainClient::Client.cut(document)
540
542
 
541
- doc_hash = self.get_doc_hash(document)
543
+ doc_hash = VChainClient::Client.get_doc_hash(document)
542
544
 
543
- credentials_hash = self.get_credentials_hash(document)
545
+ credentials_hash = VChainClient::Client.get_credentials_hash(document)
544
546
 
545
547
  if weight > 1
546
548
 
@@ -741,9 +743,9 @@ module VChainClient
741
743
  raw_document.delete("names")
742
744
  end
743
745
 
744
- out_document = self.hash(raw_document)
746
+ out_document = VChainClient::Client.hash_doc(raw_document)
745
747
 
746
- out_document = self.cut(out_document)
748
+ out_document = VChainClient::Client.cut(out_document)
747
749
 
748
750
  if out_document["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
749
751
  out_document["names"] = []
@@ -761,7 +763,7 @@ module VChainClient
761
763
  return output
762
764
  end
763
765
 
764
- def check(input, is_already_hashed = false)
766
+ def check(input, is_already_hashed = false, preffered_decision_algo = nil)
765
767
 
766
768
  client_id = @config["client_id"]
767
769
 
@@ -776,12 +778,10 @@ module VChainClient
776
778
  end
777
779
 
778
780
  if (!is_already_hashed)
779
- document = self.hash(document)
781
+ document = VChainClient::Client.hash_doc(document)
780
782
  end
781
783
 
782
- document = self.cut(document)
783
-
784
- names_index = {}
784
+ document = VChainClient::Client.cut(document)
785
785
 
786
786
  if document["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
787
787
  document["names"] = []
@@ -792,8 +792,7 @@ module VChainClient
792
792
  if (!is_already_hashed)
793
793
  name_hash = Digest::SHA512.hexdigest(name.downcase)
794
794
  end
795
-
796
- names_index[name_hash] = name
795
+
797
796
  document["names"].push(name_hash)
798
797
  }
799
798
  end
@@ -878,313 +877,32 @@ module VChainClient
878
877
 
879
878
  return {
880
879
  "status" => "success",
881
- "result" => "NO_DATA"
880
+ "result" => {
881
+ "decision_made" => true,
882
+ "decision" => "NO_DATA"
883
+ }
882
884
  }
883
885
 
884
886
  end
885
887
 
886
888
  #
887
- # analyse
889
+ # decision
888
890
  #
889
891
 
890
- sent_type_credentials_fields = self.get_credentials_fields(sent_document["type"])
891
-
892
-
893
- # 1. cut non-input fields, rebuild doc_hashes
894
- # 2. build vectors out of cut documents
895
-
896
- cut_res_docs = []
897
-
898
- vectors = []
899
-
900
- res["docs"].each { |res_doc|
901
-
902
- cut_doc = {}
903
- vector = {}
904
-
905
- names_parts = {}
906
- if res_doc.key?("names_parts")
907
- names_parts = res_doc["names_parts"]
908
-
909
- res_doc.delete("names_parts")
910
- end
911
-
912
- full_doc_hash = self.get_doc_hash(res_doc)
913
-
914
- res_doc.each { |res_doc_field, res_doc_value|
915
- if sent_document.key?(res_doc_field) || sent_type_credentials_fields.include?(res_doc_field)
916
- cut_doc[res_doc_field] = res_doc_value
917
-
918
- vector[Digest::SHA512.hexdigest(res_doc_field)] = [res_doc_value, res_doc_field, 0]
919
- end
920
- }
921
-
922
- cut_doc["doc_hash"] = self.get_doc_hash(cut_doc)
923
-
924
- cut_doc["full_doc_hash"] = full_doc_hash
925
-
926
- hashed_full_doc_hash = Digest::SHA512.hexdigest(full_doc_hash);
927
-
928
- if validated_data_points.key?(hashed_full_doc_hash)
929
- data_points = validated_data_points[hashed_full_doc_hash]
930
-
931
- data_points.each { |data_point_field, data_point_value|
932
- if vector.key?(data_point_field)
933
- vector[data_point_field][2] += data_point_value
934
- end
935
- }
936
- end
937
-
938
- if !names_parts.empty?
939
- cut_doc["names_parts"] = names_parts
940
- vector["names_parts"] = names_parts
941
- end
942
-
943
- vectors.push(vector)
944
-
945
- cut_res_docs.push(cut_doc)
946
- }
947
-
948
- res["docs"] = cut_res_docs
949
-
950
-
951
- # 3. combine vectors part 1 - marking => absorb smaller, merge equal
952
- for i in 0..(vectors.length - 1)
953
-
954
- vector_i = vectors[i]
955
-
956
- for j in i+1..(vectors.length - 1)
957
-
958
- if j >= vectors.length
959
- break
960
- end
961
-
962
- vector_j = vectors[j]
963
-
964
- i_is_less_j = false
965
- j_is_less_i = false
966
-
967
- need_to_combine = true
968
-
969
- vector_i.each { |vector_i_hashed_field, vector_i_values|
970
- if vector_i_hashed_field != "names_parts" && vector_i_hashed_field != "resolutions"
971
- if !vector_j.key?(vector_i_hashed_field)
972
- j_is_less_i = true
973
- else
974
- vector_j_values = vector_j[vector_i_hashed_field]
975
- if vector_i_values[0] != vector_j_values[0]
976
- need_to_combine = false
977
- break
978
- end
979
- end
980
- end
981
- }
982
-
983
- vector_j.each { |vector_j_hashed_field, vector_j_values|
984
- if vector_j_hashed_field != "names_parts" && vector_j_hashed_field != "resolutions"
985
- if !vector_i.key?(vector_j_hashed_field)
986
- i_is_less_j = true
987
- else
988
- vector_i_values = vector_i[vector_j_hashed_field]
989
- if vector_j_values[0] != vector_i_values[0]
990
- need_to_combine = false
991
- break
992
- end
993
- end
994
- end
995
- }
996
-
997
- if need_to_combine
998
- if i_is_less_j && j_is_less_i
999
- # differs, no need to combine
1000
-
1001
- elsif i_is_less_j && !j_is_less_i
1002
- # combine i to j
1003
- if !vectors[i].key?("resolutions")
1004
- vectors[i]["resolutions"] = []
1005
- end
1006
- if !vectors[j].key?("resolutions")
1007
- vectors[j]["resolutions"] = []
1008
- end
1009
- vectors[i]["resolutions"].push(["combine_to", j])
1010
- vectors[j]["resolutions"].push(["absorb", i])
1011
-
1012
- elsif !i_is_less_j && j_is_less_i
1013
- # combine j to i
1014
- if !vectors[i].key?("resolutions")
1015
- vectors[i]["resolutions"] = []
1016
- end
1017
- if !vectors[j].key?("resolutions")
1018
- vectors[j]["resolutions"] = []
1019
- end
1020
- vectors[j]["resolutions"].push(["combine_to", i])
1021
- vectors[i]["resolutions"].push(["absorb", j])
1022
-
1023
- else
1024
- # equals, combine j to i and delete j
1025
- if !vectors[i].key?("resolutions")
1026
- vectors[i]["resolutions"] = []
1027
- end
1028
- if !vectors[j].key?("resolutions")
1029
- vectors[j]["resolutions"] = []
1030
- end
1031
- vectors[j]["resolutions"].push(["combine_to", i])
1032
- vectors[i]["resolutions"].push(["absorb", j])
1033
-
1034
- end
1035
- end
1036
- end
1037
- end
1038
-
1039
- # 4. combine vectors part 2 - resolutions execution => absorb smaller, merge equal
1040
- vectors_to_remove = []
1041
-
1042
- for i in 0..(vectors.length-1)
1043
-
1044
- vector_i = vectors[i]
1045
-
1046
- if vector_i.key?("resolutions")
1047
-
1048
- need_to_delete = false
1049
-
1050
- vector_i["resolutions"].each { |resolution|
1051
-
1052
- resolution_type = resolution[0]
1053
-
1054
- if resolution_type == "combine_to"
1055
-
1056
- vector_i["resolutions"].each { |resolution_b|
1057
-
1058
- if resolution_b[0] == "absorb"
1059
- if !vectors[resolution[1]].key?("resolutions")
1060
- vectors[resolution[1]]["resolutions"] = []
1061
- end
1062
-
1063
- # check for dublicates
1064
- need_to_add = true
1065
-
1066
- vectors[resolution[1]]["resolutions"].each { |resolution_c|
1067
- if resolution_c[0] == resolution_b[0] && resolution_c[1] == resolution_b[1]
1068
- need_to_add = false
1069
- break
1070
- end
1071
- }
1072
-
1073
- if need_to_add
1074
- vectors[resolution[1]]["resolutions"].push(resolution_b)
1075
- end
1076
- end
1077
- }
1078
-
1079
- need_to_delete = true
1080
- end
1081
- }
1082
-
1083
- if need_to_delete
1084
- vectors_to_remove.push(i)
1085
- end
1086
- end
1087
- end
1088
-
1089
- for i in 0..(vectors.length - 1)
1090
-
1091
- vector_i = vectors[i]
1092
-
1093
- if vector_i.key?("resolutions")
1094
- if !vectors_to_remove.include?(i)
1095
-
1096
- vector_i["resolutions"].each { |resolution|
1097
-
1098
- if resolution[0] == "absorb"
1099
- vector_j = vectors[resolution[1]]
1100
-
1101
- vector_j.each { |vector_j_hashed_field, vector_j_values|
1102
- if vector_j_hashed_field != "names_parts" && vector_j_hashed_field != "resolutions"
1103
- vectors[i][vector_j_hashed_field][2] += vector_j_values[2]
1104
- end
1105
- }
1106
- end
1107
-
1108
- }
892
+ decisionAlgo = nil
1109
893
 
1110
- vectors[i].delete("resolutions")
1111
-
1112
- end
1113
- end
894
+ if preffered_decision_algo == nil
895
+ # falling to default algo
896
+ decisionAlgo = VChainClient::VectorBasedDecisionAlgorithm.new(@config)
1114
897
  end
1115
898
 
1116
- # remove marked vectors
1117
- vectors_removed_number = 0
1118
- vectors_to_remove.each { |index|
1119
- vectors.delete_at(index - vectors_removed_number)
1120
- vectors_removed_number += 1
1121
- }
1122
-
1123
- # prepare for output
1124
-
1125
- vectors_fliped = []
1126
-
1127
- for i in 0..(vectors.length - 1)
1128
-
1129
- vector_fliped = {}
1130
-
1131
- vectors[i].each { |hashed_vector_field, vector_values|
1132
-
1133
- if hashed_vector_field != "names_parts"
1134
- val = "same"
1135
- if sent_document[vector_values[1]] != vector_values[0]
1136
- val = "different"
1137
- end
1138
- vector_fliped[vector_values[1]] = [val, vector_values[2]]
1139
- else
1140
- vector_fliped[hashed_vector_field] = vector_values
1141
- end
1142
- }
1143
-
1144
- vector_raw_surname = ""
1145
- if vector_fliped.key?("names_parts")
1146
- if vector_fliped["names_parts"].key?("surname")
1147
- sep = ""
1148
- vector_fliped["names_parts"]["surname"].each { |surname_part|
1149
- vector_raw_surname += sep + names_index[surname_part]
1150
- sep = " "
1151
- }
1152
- else
1153
- vector_raw_surname = "different"
1154
- end
1155
- else
1156
- vector_raw_surname = "different"
1157
- end
1158
-
1159
- vector_raw_given_names = ""
1160
- if vector_fliped.key?("names_parts")
1161
- if vector_fliped["names_parts"].key?("given_names")
1162
- sep = ""
1163
- vector_fliped["names_parts"]["given_names"].each { |given_names_part|
1164
- vector_raw_given_names += sep + names_index[given_names_part]
1165
- sep = " "
1166
- }
1167
- else
1168
- vector_raw_given_names = "different"
1169
- end
1170
- else
1171
- vector_raw_given_names = "different"
1172
- end
1173
-
1174
- vector_fliped["surname"] = [vector_raw_surname, vector_fliped["surname"][1]]
1175
- vector_fliped["given_names"] = [vector_raw_given_names, vector_fliped["given_names"][1]]
1176
-
1177
- vector_fliped.delete("names_parts")
1178
-
1179
- vectors_fliped.push(vector_fliped)
1180
-
1181
- end
899
+ decision = decisionAlgo.make_decision(sent_document, res, validated_data_points)
1182
900
 
1183
901
  # result output
1184
902
 
1185
903
  return {
1186
- "status" => "success",
1187
- "vectors" => vectors_fliped
904
+ "status" => "success",
905
+ "result" => decision
1188
906
  }
1189
907
 
1190
908
  end
@@ -1203,8 +921,8 @@ module VChainClient
1203
921
  documents_index = {}
1204
922
 
1205
923
  documents.each { |document|
1206
- hashed_doc = self.full_hash(document)
1207
- hashed_doc["original_doc_hash"] = self.get_doc_hash(document)
924
+ hashed_doc = VChainClient::Client.full_hash(document)
925
+ hashed_doc["original_doc_hash"] = VChainClient::Client.get_doc_hash(document)
1208
926
  documents_index[hashed_doc["doc_hash"]] = hashed_doc
1209
927
  }
1210
928
 
@@ -1715,7 +1433,8 @@ module VChainClient
1715
1433
  output[data_point["doc_hash"]][data_point["field_hash"]] = 0
1716
1434
  end
1717
1435
 
1718
- output[data_point["doc_hash"]][data_point["field_hash"]] += 1
1436
+ # add weight coming from the data_point
1437
+ output[data_point["doc_hash"]][data_point["field_hash"]] += (1 * data_point["weight"].to_f)
1719
1438
  }
1720
1439
 
1721
1440
  return output
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vchain_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.24
4
+ version: 1.0.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksandr Gorelik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-05 00:00:00.000000000 Z
11
+ date: 2017-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: log4r
@@ -84,6 +84,8 @@ files:
84
84
  - lib/vchain_client/blockchain_connection.rb
85
85
  - lib/vchain_client/blockcypher_blockchain_adapter.rb
86
86
  - lib/vchain_client/blockstack_client.rb
87
+ - lib/vchain_client/decision_algos/decision_algorithm.rb
88
+ - lib/vchain_client/decision_algos/vector_based_decision_algorithm.rb
87
89
  - lib/vchain_client/signatures.rb
88
90
  homepage: http://rubygems.org/gems/vchain_client
89
91
  licenses: