vchain_client 1.0.24 → 1.0.25

Sign up to get free protection for your applications and to get access to all the features.
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: