society 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,54 +0,0 @@
1
- require 'json'
2
-
3
- module Society
4
- module Formatter
5
- module Graph
6
- class JSON
7
-
8
- def initialize(graph)
9
- @graph = graph
10
- end
11
-
12
- def to_json
13
- to_hash.to_json
14
- end
15
-
16
- def to_hash
17
- {
18
- nodes: node_names.map { |name| { name: name } },
19
- edges: named_edges.map do |edge|
20
- {
21
- from: node_names.index(edge.from),
22
- to: node_names.index(edge.to)
23
- }
24
- end,
25
- clusters: clusters_of_indices
26
- }
27
- end
28
-
29
- private
30
-
31
- attr_reader :graph
32
-
33
- def node_names
34
- @node_names ||= graph.nodes.map(&:full_name).uniq
35
- end
36
-
37
- def named_edges
38
- @named_edges ||= graph.edges.map { |edge| Edge.new(from: edge.from.full_name, to: edge.to.full_name) }
39
- end
40
-
41
- def clusters_of_indices
42
- Society::Clusterer.new.cluster(graph_of_names).map do |cluster|
43
- cluster.map { |name| node_names.index(name) }
44
- end
45
- end
46
-
47
- def graph_of_names
48
- ObjectGraph.new(nodes: node_names, edges: named_edges)
49
- end
50
-
51
- end
52
- end
53
- end
54
- end
@@ -1,60 +0,0 @@
1
- module Society
2
-
3
- class ReferenceProcessor
4
-
5
- attr_reader :classes, :references, :unresolved_references
6
-
7
- def initialize(classes)
8
- @classes = classes
9
- @references = []
10
- @unresolved_references = []
11
- process
12
- end
13
-
14
- private
15
-
16
- def process
17
- classes.each do |klass|
18
- klass.constants.each do |const|
19
- if assigned_constant(const, klass)
20
- next
21
- elsif target = perfect_match_for(const)
22
- @references << Edge.new(from: klass,
23
- to: target,
24
- meta: {
25
- type: :perfect,
26
- entity: const})
27
- elsif target = partial_match_for(const)
28
- @references << Edge.new(from: klass,
29
- to: target,
30
- meta: {
31
- type: :partial,
32
- entity: const})
33
- else
34
- @unresolved_references << { class: klass,
35
- target_name: const.full_name,
36
- constant: const }
37
- end
38
- end
39
- end
40
- end
41
-
42
- def perfect_match_for(const)
43
- classes.detect { |klass| klass.full_name == const.name }
44
- end
45
-
46
- def partial_match_for(const)
47
- partial_matches = classes.select do |klass|
48
- klass.full_name.include? const.full_name
49
- end
50
- partial_matches.first if partial_matches.size == 1
51
- end
52
-
53
- def assigned_constant(const, klass)
54
- klass.constant_assignments.map(&:name).include? const.name
55
- end
56
-
57
- end
58
-
59
- end
60
-
data/society_graph.json DELETED
@@ -1 +0,0 @@
1
- {"nodes":[{"name":"Account"},{"name":"Attachment"},{"name":"Attempt"},{"name":"Auth"},{"name":"Certificate"},{"name":"Collection"},{"name":"CollectionEnrollment"},{"name":"CollectionGroupEnrollment"},{"name":"CollectionItem"},{"name":"ConcreteConfig"},{"name":"CourseTemplate"},{"name":"CustomField"},{"name":"EnrollingMembership"},{"name":"Enrollment"},{"name":"Group"},{"name":"GroupEnrollment"},{"name":"ImportObject"},{"name":"LearnerCourse"},{"name":"LearnerCustomFieldValue"},{"name":"LearnerFile"},{"name":"LearnerLibraryCourse"},{"name":"LearnerLiveCourse"},{"name":"LearnerSlide"},{"name":"LiveCourse"},{"name":"LiveCourseEnrollment"},{"name":"LiveCourseEnrollmentSource"},{"name":"LiveCourseGroupEnrollment"},{"name":"LiveCourseSession"},{"name":"LiveCourseSessionRegistration"},{"name":"Manager"},{"name":"Membership"},{"name":"MembershipBuilder"},{"name":"NotifiableEnrollment"},{"name":"NotifiableLiveCourseEnrollment"},{"name":"NotifiableLiveCourseSessionRegistration"},{"name":"Notification"},{"name":"NotificationProfile"},{"name":"PasswordToken"},{"name":"Presence"},{"name":"QuestionAnswer"},{"name":"QuestionHash"},{"name":"QuestionResponse"},{"name":"RequestHost"},{"name":"Rule"},{"name":"RulesAttributesNormalizer"},{"name":"SessionToken"},{"name":"Slide"},{"name":"User"},{"name":"Account::Config"},{"name":"Attempt::NullFurthestSlide"},{"name":"Auth::Basic"},{"name":"Auth::CAS"},{"name":"GroupEnrollment::StatisticsCalculator"},{"name":"QuestionHash::Factoid"},{"name":"QuestionHash::Factoid::MultipleChoiceQuestion"},{"name":"QuestionHash::Factoid::Statement"},{"name":"QuestionHash::Factoid::TrueFalseQuestion"},{"name":"QuestionHash::Glossary"},{"name":"QuestionHash::Glossary::MultipleChoiceQuestion"},{"name":"QuestionHash::Glossary::TrueFalseQuestion"},{"name":"QuestionHash::OrderedList"},{"name":"QuestionHash::OrderedList::MultipleChoiceQuestion"},{"name":"QuestionHash::OrderedList::ReorderQuestion"},{"name":"Rule::InvalidPredicate"},{"name":"RulesAttributesNormalizer::FieldRules"},{"name":"Notifications::AuthorCourseDigest"},{"name":"Notifications::CourseAssignedNotificationBuilder"},{"name":"Notifications::CourseDigest"},{"name":"Notifications::LearnerCourseDigest"},{"name":"Notifications::LiveCourseInvitationNotificationBuilder"},{"name":"Notifications::LiveCourseNotificationBuilder"},{"name":"Notifications::LiveCourseRegisteredForSessionNotificationBuilder"},{"name":"Notifications::LiveCourseSessionNotificationBuilder"},{"name":"Notifications::LiveCourseUnregisteredFromCanceledSessionNotificationBuilder"},{"name":"Notifications::LiveCourseUnregisteredFromSessionNotificationBuilder"},{"name":"Notifications::LiveCourseUnregisteredFromUnattendedSessionNotificationBuilder"},{"name":"Notifications::ManagerCourseDigest"},{"name":"Notifications::NotificationBuilder"},{"name":"Notifications::TimeUntilSessionNotificationBuilder"},{"name":"Reports::CourseStatusReport"},{"name":"Reports::PassRateReport"},{"name":"Reports::ScoreDistributionReport"},{"name":"Scorm::Activity"},{"name":"Scorm::Attempt"},{"name":"Scorm::CourseUploadResponse"},{"name":"Scorm::CourseUploadStatusResponse"},{"name":"Scorm::Enrollment"},{"name":"Scorm::RegistrationListResponse"},{"name":"Scorm::RegistrationResponse"},{"name":"Search::CustomFieldValueSearch"},{"name":"Search::EnrollableSearch"}],"edges":[{"from":0,"to":36},{"from":1,"to":46},{"from":2,"to":46},{"from":2,"to":46},{"from":2,"to":13},{"from":2,"to":41},{"from":5,"to":8},{"from":5,"to":6},{"from":5,"to":7},{"from":6,"to":5},{"from":6,"to":47},{"from":7,"to":5},{"from":7,"to":14},{"from":8,"to":5},{"from":8,"to":10},{"from":10,"to":47},{"from":10,"to":8},{"from":10,"to":15},{"from":10,"to":46},{"from":11,"to":18},{"from":11,"to":43},{"from":13,"to":10},{"from":13,"to":47},{"from":13,"to":2},{"from":13,"to":2},{"from":14,"to":30},{"from":14,"to":15},{"from":14,"to":26},{"from":14,"to":43},{"from":14,"to":7},{"from":15,"to":14},{"from":15,"to":10},{"from":16,"to":47},{"from":18,"to":47},{"from":18,"to":11},{"from":23,"to":47},{"from":23,"to":24},{"from":23,"to":27},{"from":23,"to":26},{"from":24,"to":47},{"from":24,"to":23},{"from":24,"to":25},{"from":24,"to":28},{"from":25,"to":24},{"from":26,"to":23},{"from":26,"to":14},{"from":27,"to":23},{"from":27,"to":28},{"from":28,"to":47},{"from":28,"to":27},{"from":28,"to":24},{"from":29,"to":47},{"from":29,"to":47},{"from":30,"to":14},{"from":30,"to":47},{"from":36,"to":0},{"from":41,"to":2},{"from":41,"to":46},{"from":43,"to":14},{"from":43,"to":11},{"from":45,"to":47},{"from":46,"to":10},{"from":46,"to":41},{"from":46,"to":1},{"from":47,"to":13},{"from":47,"to":10},{"from":47,"to":6},{"from":47,"to":24},{"from":47,"to":28},{"from":47,"to":23},{"from":47,"to":45},{"from":47,"to":30},{"from":47,"to":18},{"from":47,"to":29},{"from":47,"to":29},{"from":5,"to":10},{"from":5,"to":47},{"from":5,"to":14},{"from":10,"to":5},{"from":10,"to":14},{"from":11,"to":47},{"from":13,"to":46},{"from":14,"to":10},{"from":14,"to":23},{"from":14,"to":47},{"from":14,"to":5},{"from":23,"to":47},{"from":24,"to":14},{"from":24,"to":27},{"from":27,"to":47},{"from":47,"to":10},{"from":47,"to":23},{"from":47,"to":14},{"from":47,"to":11},{"from":47,"to":47},{"from":47,"to":47},{"from":0,"to":0},{"from":0,"to":3},{"from":0,"to":48},{"from":0,"to":36},{"from":2,"to":49},{"from":2,"to":22},{"from":2,"to":41},{"from":5,"to":13},{"from":5,"to":10},{"from":6,"to":13},{"from":6,"to":2},{"from":10,"to":46},{"from":12,"to":30},{"from":12,"to":30},{"from":13,"to":46},{"from":13,"to":47},{"from":14,"to":10},{"from":14,"to":14},{"from":14,"to":47},{"from":27,"to":78},{"from":27,"to":78},{"from":27,"to":78},{"from":28,"to":78},{"from":31,"to":30},{"from":31,"to":30},{"from":31,"to":30},{"from":32,"to":86},{"from":32,"to":66},{"from":32,"to":66},{"from":33,"to":69},{"from":33,"to":69},{"from":34,"to":71},{"from":34,"to":78},{"from":34,"to":78},{"from":37,"to":78},{"from":37,"to":78},{"from":37,"to":47},{"from":37,"to":37},{"from":40,"to":40},{"from":40,"to":40},{"from":40,"to":55},{"from":40,"to":40},{"from":40,"to":40},{"from":40,"to":40},{"from":40,"to":40},{"from":41,"to":40},{"from":43,"to":63},{"from":45,"to":45},{"from":47,"to":47},{"from":47,"to":47},{"from":47,"to":5},{"from":47,"to":10},{"from":47,"to":14},{"from":47,"to":23},{"from":53,"to":40},{"from":54,"to":40},{"from":53,"to":40},{"from":56,"to":40},{"from":53,"to":55},{"from":57,"to":40},{"from":58,"to":40},{"from":57,"to":40},{"from":59,"to":40},{"from":60,"to":40},{"from":61,"to":40},{"from":60,"to":40},{"from":62,"to":40},{"from":77,"to":35},{"from":82,"to":82},{"from":82,"to":82},{"from":83,"to":83},{"from":83,"to":83},{"from":83,"to":78},{"from":86,"to":83},{"from":86,"to":83},{"from":90,"to":47},{"from":90,"to":14}]}
@@ -1,174 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Society::AssociationProcessor do
4
-
5
- describe "#associations" do
6
-
7
- context "`belongs_to`, `has_many`, and `has_many through:` associations" do
8
- let(:code) {
9
- <<-CODE
10
- class Assembly < ActiveRecord::Base
11
- has_many :manifests
12
- has_many :parts, through: :manifests
13
- end
14
-
15
- class Manifest < ActiveRecord::Base
16
- belongs_to :assembly
17
- belongs_to :part
18
- end
19
-
20
- class Part < ActiveRecord::Base
21
- has_many :manifests
22
- has_many :assemblies, through: :manifests
23
- end
24
- CODE
25
- }
26
-
27
- let(:parser) { Society::Parser.for_source(code) }
28
- let(:processor) { Society::AssociationProcessor.new(parser.analyzer.classes) }
29
- let(:assembly) { processor.classes.detect {|c| c.name == "Assembly" } }
30
- let(:manifest) { processor.classes.detect {|c| c.name == "Manifest" } }
31
- let(:part) { processor.classes.detect {|c| c.name == "Part" } }
32
-
33
- it "records `has_many` and `has_many through:` associations" do
34
- assembly_associations = processor.associations.select { |edge| edge.from == assembly }
35
- expect(assembly_associations.map(&:to)).to match_array [manifest, part]
36
-
37
- part_associations = processor.associations.select { |edge| edge.from == part }
38
- expect(part_associations.map(&:to)).to eq [manifest, assembly]
39
- end
40
-
41
- it "records `belongs_to` associations" do
42
- manifest_associations = processor.associations.select { |edge| edge.from == manifest }
43
- expect(manifest_associations.map(&:to)).to match_array [assembly, part]
44
- end
45
- end
46
-
47
- context "associations with `class_name` specified" do
48
- let(:code) {<<-CODE
49
- class Post < ActiveRecord::Base
50
- belongs_to :author, :class_name => "User"
51
- belongs_to :editor, :class_name => "User"
52
- end
53
-
54
- class User < ActiveRecord::Base
55
- has_many :authored_posts, :foreign_key => "author_id", :class_name => "Post"
56
- has_many :edited_posts, :foreign_key => "editor_id", :class_name => "Post"
57
- end
58
- CODE
59
- }
60
- let(:parser) { Society::Parser.for_source(code) }
61
- let(:processor) { Society::AssociationProcessor.new(parser.analyzer.classes) }
62
- let(:user) { processor.classes.detect {|c| c.name == "User" } }
63
- let(:post) { processor.classes.detect {|c| c.name == "Post" } }
64
-
65
- it "records belongs_to's" do
66
- post_associations = processor.associations.select { |edge| edge.from == post }
67
- expect(post_associations.map(&:to)).to match_array [user, user]
68
- end
69
-
70
- it "records has_many's" do
71
- user_associations = processor.associations.select { |edge| edge.from == user }
72
- expect(user_associations.map(&:to)).to match_array [post, post]
73
- end
74
- end
75
-
76
- context "associations with `class_name` or `source` specified" do
77
- let(:code) { <<-CODE
78
- class Post < ActiveRecord::Base
79
- has_many :post_authorings, :foreign_key => :authored_post_id
80
- has_many :authors, :through => :post_authorings, :source => :post_author
81
- belongs_to :editor, :class_name => "User"
82
- end
83
-
84
- class User < ActiveRecord::Base
85
- has_many :post_authorings, :foreign_key => :post_author_id
86
- has_many :authored_posts, :through => :post_authorings
87
- has_many :edited_posts, :foreign_key => :editor_id, :class_name => "Post"
88
- end
89
-
90
- class PostAuthoring < ActiveRecord::Base
91
- belongs_to :post_author, :class_name => "User"
92
- belongs_to :authored_post, :class_name => "Post"
93
- end
94
- CODE
95
- }
96
- let(:parser) { Society::Parser.for_source(code) }
97
- let(:processor) { Society::AssociationProcessor.new(parser.analyzer.classes) }
98
- let(:user) { processor.classes.detect {|c| c.name == "User" } }
99
- let(:post) { processor.classes.detect {|c| c.name == "Post" } }
100
- let(:post_authoring) { processor.classes.detect {|c| c.name == "PostAuthoring" } }
101
-
102
- it "handles `source` and `class_name` correctly" do
103
- post_associations = processor.associations.select { |edge| edge.from == post }
104
- expect(post_associations.map(&:to)).to match_array [post_authoring, user, user]
105
- end
106
-
107
- it "handles `through` and `class_name` correctly" do
108
- user_associations = processor.associations.select { |edge| edge.from == user }
109
- expect(user_associations.map(&:to)).to match_array [post_authoring, post, post]
110
- end
111
-
112
- it "handles `class_name` correctly" do
113
- pa_associations = processor.associations.select { |edge| edge.from == post_authoring }
114
- expect(pa_associations.map(&:to)).to match_array [user, post]
115
- end
116
- end
117
-
118
- context "polymorphic associations" do
119
- let(:code) { <<-CODE
120
- class Picture < ActiveRecord::Base
121
- belongs_to :imageable, polymorphic: true
122
- end
123
-
124
- class Employee < ActiveRecord::Base
125
- has_many :pictures, as: :imageable
126
- end
127
-
128
- class Product < ActiveRecord::Base
129
- has_many :pictures, as: :imageable
130
- end
131
- CODE
132
- }
133
- let(:parser) { Society::Parser.for_source(code) }
134
- let(:processor) { Society::AssociationProcessor.new(parser.analyzer.classes) }
135
- let(:picture) { processor.classes.detect {|c| c.name == "Picture" } }
136
- let(:employee) { processor.classes.detect {|c| c.name == "Employee" } }
137
- let(:product) { processor.classes.detect {|c| c.name == "Product" } }
138
-
139
- it "records the `polymorphic: true` side of the association" do
140
- picture_associations = processor.associations.select { |edge| edge.from == picture }
141
- expect(picture_associations.map(&:to)).to match_array [employee, product]
142
- end
143
-
144
- it "records the `as: :something` side of the asociation" do
145
- employee_associations = processor.associations.select { |edge| edge.from == employee }
146
- expect(employee_associations.map(&:to)).to match_array [picture]
147
-
148
- product_associations = processor.associations.select { |edge| edge.from == product }
149
- expect(product_associations .map(&:to)).to match_array [picture]
150
- end
151
- end
152
-
153
- context "self joins" do
154
- let(:code) {<<-CODE
155
- class Employee < ActiveRecord::Base
156
- has_many :subordinates, class_name: "Employee",
157
- foreign_key: "manager_id"
158
-
159
- belongs_to :manager, class_name: "Employee"
160
- end
161
- CODE
162
- }
163
- let(:parser) { Society::Parser.for_source(code) }
164
- let(:processor) { Society::AssociationProcessor.new(parser.analyzer.classes) }
165
- let(:employee) { processor.classes.detect {|c| c.name == "Employee" } }
166
-
167
- it "records self joins" do
168
- employee_associations = processor.associations.select { |edge| edge.from == employee }
169
- expect(employee_associations.map(&:to)).to match_array [employee, employee]
170
- end
171
- end
172
- end
173
- end
174
-
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
- require_relative 'fixtures/clustering/clusterer_fixtures.rb'
3
-
4
- describe Society::Clusterer do
5
-
6
- describe "#cluster" do
7
- let(:clusterer) { Society::Clusterer.new }
8
-
9
- it "detects clusters" do
10
- clusters = clusterer.cluster(MCL::GRAPH_1).map(&:sort)
11
- expected = MCL::CLUSTERS_1.map(&:sort)
12
- expect(clusters).to match_array(expected)
13
- end
14
-
15
- context "with inflation parameter set to 1.7" do
16
- let(:clusterer) { Society::Clusterer.new(inflation: 1.7) }
17
-
18
- it "detects clusters at coarser granularity" do
19
- clusters = clusterer.cluster(MCL::GRAPH_1).map(&:sort)
20
- expected = MCL::CLUSTERS_1_I17.map(&:sort)
21
- expect(clusters).to match_array(expected)
22
- end
23
- end
24
-
25
- context "with inflation parameter set to 4.0" do
26
- let(:clusterer) { Society::Clusterer.new(inflation: 4.0) }
27
-
28
- it "detects clusters at finer granularity" do
29
- clusters = clusterer.cluster(MCL::GRAPH_1).map(&:sort)
30
- expected = MCL::CLUSTERS_1_I40.map(&:sort)
31
- expect(clusters).to match_array(expected)
32
- end
33
- end
34
- end
35
-
36
- end
37
-
@@ -1,144 +0,0 @@
1
- # Reference results were calculated using the `minimcl` perl script from
2
- # release 14-137 of the MCL-edge library. http://micans.org/mcl
3
-
4
- require 'set'
5
-
6
- module MCL
7
-
8
- def self.graph_from_edges(path)
9
- full_path = File.join(File.dirname(__FILE__), path)
10
- nodes = Set.new
11
- edges = []
12
- edges_with_weights = /(\S+)\s+(\S+)\s+(\S+)/
13
- edges_only = /(\S+)\s+(\S+)/
14
- File.readlines(full_path).each do |line|
15
- if data = line.match(edges_with_weights)
16
- a,b,weight = data[1..-1]
17
- # FIXME: disregarding weight for now -- include it once we have
18
- # weights in Edges
19
- edges << Society::Edge.new(from: a.to_i, to: b.to_i)
20
- nodes << a << b
21
- elsif data = line.match(edges_only)
22
- a,b = data[1..-1]
23
- edges << Society::Edge.new(from: a.to_i, to: b.to_i)
24
- nodes << a << b
25
- end
26
- end
27
- Society::ObjectGraph.new(nodes: nodes.to_a, edges: edges)
28
- end
29
-
30
- GRAPH_1 = graph_from_edges('edges_1.txt')
31
-
32
- CLUSTERS_1 = [
33
- [9, 10, 19, 24, 25, 26, 28, 29, 30, 39, 58, 68, 102, 189, 198, 200],
34
- [46, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139],
35
- [0, 1, 4, 11, 38, 49, 52, 59, 60, 61, 71, 125],
36
- [109, 110, 144, 145, 146, 147, 148, 149],
37
- [81, 121, 122, 184, 185, 188],
38
- [12, 31, 32, 79, 91, 124],
39
- [7, 47, 53, 54, 78, 82],
40
- [33, 83, 96, 113, 119],
41
- [17, 55, 56, 57, 65],
42
- [13, 42, 115, 120],
43
- [14, 15, 27, 190],
44
- [43, 90, 99, 118],
45
- [173, 175, 193],
46
- [88, 116, 117],
47
- [73, 143, 176],
48
- [77, 114, 116],
49
- [20, 69, 103],
50
- [41, 44, 112],
51
- [16, 97, 98],
52
- [3, 23, 126],
53
- [183, 186],
54
- [100, 101],
55
- [107, 108],
56
- [70, 104],
57
- [87, 106],
58
- [86, 105],
59
- [50, 140],
60
- [67, 95],
61
- [85, 94],
62
- [8, 111],
63
- [66, 92],
64
- [2, 84],
65
- [182],
66
- [93]]
67
-
68
- CLUSTERS_1_I17 = [
69
- [8, 9, 10, 13, 14, 15, 17, 19, 20, 24, 25, 26, 27, 28, 29, 30, 39, 41, 42, 43, 44, 55, 56, 57, 58, 65, 68, 69, 93, 102, 103, 111, 112, 115, 120, 189, 190, 198, 200],
70
- [46, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139],
71
- [0, 1, 4, 11, 38, 49, 52, 59, 60, 61, 71, 125],
72
- [33, 83, 90, 96, 99, 113, 118, 119],
73
- [109, 110, 144, 145, 146, 147, 148, 149],
74
- [2, 7, 47, 53, 54, 78, 82, 84],
75
- [70, 86, 87, 104, 105, 106],
76
- [81, 121, 122, 184, 185, 188],
77
- [12, 31, 32, 79, 91, 124],
78
- [73, 143, 173, 176],
79
- [88, 116, 117],
80
- [77, 114, 116],
81
- [16, 97, 98],
82
- [3, 23, 126],
83
- [183, 186],
84
- [100, 101],
85
- [50, 140],
86
- [175, 193],
87
- [107, 108],
88
- [66, 92],
89
- [67, 95],
90
- [85, 94],
91
- [182]]
92
-
93
- CLUSTERS_1_I40 = [
94
- [46, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139],
95
- [10, 28, 29, 30, 39, 58, 146, 198, 200],
96
- [109, 110, 144, 145, 147, 148, 149],
97
- [81, 121, 122, 184, 185, 188],
98
- [7, 47, 53, 54, 78, 82],
99
- [14, 15, 24, 27, 190],
100
- [0, 4, 38, 60, 125],
101
- [13, 42, 115, 120],
102
- [31, 32, 91, 124],
103
- [17, 55, 56, 65],
104
- [73, 143, 176],
105
- [20, 69, 103],
106
- [41, 44, 112],
107
- [33, 83, 113],
108
- [3, 23, 126],
109
- [16, 97, 98],
110
- [175, 193],
111
- [107, 108],
112
- [183, 186],
113
- [100, 101],
114
- [70, 104],
115
- [43, 118],
116
- [68, 102],
117
- [88, 117],
118
- [19, 189],
119
- [50, 140],
120
- [86, 105],
121
- [77, 114],
122
- [87, 106],
123
- [8, 111],
124
- [67, 95],
125
- [25, 26],
126
- [85, 94],
127
- [12, 79],
128
- [11, 49],
129
- [52, 71],
130
- [66, 92],
131
- [2, 84],
132
- [1, 61],
133
- [119],
134
- [173],
135
- [116],
136
- [182],
137
- [57],
138
- [93],
139
- [90],
140
- [99],
141
- [59],
142
- [96],
143
- [9]]
144
- end