classbench 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +2 -0
- data/LICENSE.txt +1 -1
- data/NOTES.txt +26 -0
- data/README.rdoc +8 -1
- data/VERSION +1 -1
- data/bin/classbench +41 -0
- data/classbench.gemspec +11 -3
- data/lib/classbench/analyser.rb +55 -0
- data/lib/classbench/rule.rb +13 -0
- data/lib/classbench/trie.rb +157 -23
- data/lib/classbench/trie_node.rb +8 -0
- data/lib/classbench.rb +28 -8
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da83ac14c9b94a4a716e107bdb45cc191a690c8b
|
4
|
+
data.tar.gz: 80baca1f165b53d3ddb4c6f03eb17266b4fec88b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab085c658086d665d2b16ce1c7c7e60d6c5275f2290e661b4afc125f61a2d8f45fcb79119265cdb0db8911d5779fd36103ff10866c0734ee4b95b4760c1ae917
|
7
|
+
data.tar.gz: b2ca90c9cb9ca99f107623d989bcd40ac5cf258eb6e0524029f504aae0a1979a3b34d72f90aa33be6e57f2bd1fbb205899f12f6e2ed74154b558ecae4135e557
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -5,6 +5,7 @@ GEM
|
|
5
5
|
builder (3.2.2)
|
6
6
|
descendants_tracker (0.0.4)
|
7
7
|
thread_safe (~> 0.3, >= 0.3.1)
|
8
|
+
docopt (0.5.0)
|
8
9
|
faraday (0.9.1)
|
9
10
|
multipart-post (>= 1.2, < 3)
|
10
11
|
git (1.2.9.1)
|
@@ -50,5 +51,6 @@ PLATFORMS
|
|
50
51
|
|
51
52
|
DEPENDENCIES
|
52
53
|
bundler
|
54
|
+
docopt
|
53
55
|
jeweler
|
54
56
|
rdoc
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2015 Adam
|
3
|
+
Copyright (c) 2015 Adam Lučanský, Gianni Antichi, Jiri Matousek
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/NOTES.txt
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
1. Extract parameters from the original set and write them into a
|
2
|
+
seed file in a ClassBench-like format (i.e. ClassBench can understand this
|
3
|
+
format but the file also contains statistics not relevant for ClassBench).
|
4
|
+
Parser should be able to extract parameters from rule sets in an OpenFlow
|
5
|
+
format, other formats are not necessary. Extracted parameters are as follow:
|
6
|
+
1. original ClassBench parameters
|
7
|
+
2. probabilities for different rule types (rules with no
|
8
|
+
OF-defined header fields are omitted)
|
9
|
+
3. parameters for generation of OF-specific header fields
|
10
|
+
1. ingress port
|
11
|
+
2. vendor part of MAC addresses
|
12
|
+
3. Ethernet type
|
13
|
+
4. 3 leftmost bits of IP TOS/DSCP
|
14
|
+
2. Use ClassBench for generation of the given number of rules.
|
15
|
+
Each rule will containing all 5-tuple header fields (this is ClassBench's
|
16
|
+
feature).
|
17
|
+
3. For each generated rule
|
18
|
+
1. determine its OF type
|
19
|
+
2. remove 5-tuple header fields that ARE NOT defined by the OF type
|
20
|
+
3. add OF-specific header fields that ARE defined by the OF type
|
21
|
+
1. if the field is ingress port, Ethernet type or IP protocol,
|
22
|
+
use specified dependencies (see shared Google document) to constrain a set
|
23
|
+
of possible values for this field
|
24
|
+
2. generate value for the OF-specific header field in a
|
25
|
+
specified way (see shared Google document)
|
26
|
+
4. Label all the header fields by the corresponding OF name
|
data/README.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
1
|
== Classbench
|
2
2
|
|
3
|
-
Utility for generation of firewall/OpenFlow rules based on original
|
3
|
+
Utility for generation of firewall/OpenFlow rules based on original {(no longer maintained) Classbench}[http://www.arl.wustl.edu/classbench/].
|
4
|
+
|
5
|
+
=== Requirements
|
6
|
+
* Ruby 1.9.3+
|
7
|
+
* RubyGems
|
8
|
+
|
9
|
+
=== Installation
|
10
|
+
gem install classbench
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/bin/classbench
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Library loader
|
4
|
+
if File.exists?("../lib/classbench.rb")
|
5
|
+
load("../lib/classbench.rb") # Devel
|
6
|
+
STDERR.puts "Loading development library..."
|
7
|
+
else
|
8
|
+
require "classbench" # Live
|
9
|
+
end
|
10
|
+
|
11
|
+
require "pp"
|
12
|
+
require "docopt"
|
13
|
+
doc = <<DOCOPT
|
14
|
+
Classbench utility
|
15
|
+
Firewall/openflow rule generator.
|
16
|
+
|
17
|
+
Usage:
|
18
|
+
#{__FILE__} analyse openflow FILE
|
19
|
+
#{__FILE__} -h | --help
|
20
|
+
#{__FILE__} --version
|
21
|
+
|
22
|
+
Options:
|
23
|
+
-h --help Show this screen.
|
24
|
+
--version Show version.
|
25
|
+
|
26
|
+
DOCOPT
|
27
|
+
|
28
|
+
begin
|
29
|
+
opts = Docopt::docopt(doc)
|
30
|
+
if opts["analyse"]
|
31
|
+
if opts["openflow"]
|
32
|
+
Classbench::analyse(opts["FILE"])
|
33
|
+
else # prefixes
|
34
|
+
raise "Not implemented yet."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# TODO: --version
|
38
|
+
|
39
|
+
rescue Docopt::Exit => e
|
40
|
+
STDERR.puts e.message
|
41
|
+
end
|
data/classbench.gemspec
CHANGED
@@ -2,18 +2,19 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: classbench 0.0
|
5
|
+
# stub: classbench 0.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "classbench"
|
9
|
-
s.version = "0.0
|
9
|
+
s.version = "0.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Adam Lucansky", "Gianni Antichi", "Jiri Matousek"]
|
14
|
-
s.date = "2015-06-
|
14
|
+
s.date = "2015-06-29"
|
15
15
|
s.description = "Statistical generation of firewall/OpenFLOW rules based on seed file (IN DEVELOPMENT)"
|
16
16
|
s.email = "adamlucansky@gmail.com"
|
17
|
+
s.executables = ["classbench"]
|
17
18
|
s.extra_rdoc_files = [
|
18
19
|
"LICENSE.txt",
|
19
20
|
"README.rdoc"
|
@@ -23,11 +24,15 @@ Gem::Specification.new do |s|
|
|
23
24
|
"Gemfile",
|
24
25
|
"Gemfile.lock",
|
25
26
|
"LICENSE.txt",
|
27
|
+
"NOTES.txt",
|
26
28
|
"README.rdoc",
|
27
29
|
"Rakefile",
|
28
30
|
"VERSION",
|
31
|
+
"bin/classbench",
|
29
32
|
"classbench.gemspec",
|
30
33
|
"lib/classbench.rb",
|
34
|
+
"lib/classbench/analyser.rb",
|
35
|
+
"lib/classbench/rule.rb",
|
31
36
|
"lib/classbench/trie.rb",
|
32
37
|
"lib/classbench/trie_node.rb",
|
33
38
|
"test/helper.rb",
|
@@ -43,15 +48,18 @@ Gem::Specification.new do |s|
|
|
43
48
|
s.specification_version = 4
|
44
49
|
|
45
50
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_runtime_dependency(%q<docopt>, [">= 0"])
|
46
52
|
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
47
53
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
48
54
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
49
55
|
else
|
56
|
+
s.add_dependency(%q<docopt>, [">= 0"])
|
50
57
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
51
58
|
s.add_dependency(%q<bundler>, [">= 0"])
|
52
59
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
53
60
|
end
|
54
61
|
else
|
62
|
+
s.add_dependency(%q<docopt>, [">= 0"])
|
55
63
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
56
64
|
s.add_dependency(%q<bundler>, [">= 0"])
|
57
65
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "base64"
|
2
|
+
|
3
|
+
module Classbench
|
4
|
+
class Analyser
|
5
|
+
INTERESTING_ATTRIBUTES = ["dl_dst", "dl_src", "dl_type", "dl_vlan", "dl_vlan_pcp",
|
6
|
+
"eth_type", "in_port",
|
7
|
+
"nw_dst", "nw_proto", "nw_src", "nw_tos",
|
8
|
+
"tp_dst", "tp_src"]
|
9
|
+
|
10
|
+
attr_accessor :rules
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
self.rules ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_openflow(lines)
|
17
|
+
lines.split("\n").each do |line|
|
18
|
+
# Array of arrays ... [["dl_dst", "fa:16:3e:91:c3:01", ","], ["nw_src", "255.255.255.255", ","],
|
19
|
+
attributes = line.scan(/([a-z_\-]+)=([A-Za-z0-9\-_:\.\/]+)(,|\w)?/).
|
20
|
+
keep_if {|a| INTERESTING_ATTRIBUTES.include?(a.first) }
|
21
|
+
|
22
|
+
next if attributes.empty?
|
23
|
+
|
24
|
+
rule = {}
|
25
|
+
attributes.each do |attr|
|
26
|
+
if INTERESTING_ATTRIBUTES.include? attr.first
|
27
|
+
rule[attr.first] = attr[1]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
self.rules << Rule.new(rule)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate_seed
|
35
|
+
# acl3_seed
|
36
|
+
seed3 = "LXNjYWxlCjI0MDAKIwotcHJvdHMKMAkwLjA0OTE2NjY3CTEuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAKMQkwLjA0MTY2NjY3CTEuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAKNgkwLjY0OTk5OTk4CTAuMDAxMjgyMDUJMC4xNDU1MTI4MgkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMTQyOTQ4NzIJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC43MTAyNTY0MAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAKMTcJMC4yNTg3NDk5OQkwLjAwMTYxMDMxCTAuMTcwNjkyNDMJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjA2NzYzMjg1CTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuNzU2ODQzODEJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAzMjIwNjEJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCjg5CTAuMDAwNDE2NjcJMS4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAkwLjAwMDAwMDAwCTAuMDAwMDAwMDAJMC4wMDAwMDAwMAojCi1mbGFncwowCTB4MDAwMC8weDAwMDAsMS4wMDAwMDAwMAkKMQkweDAwMDAvMHgwMDAwLDEuMDAwMDAwMDAJCjYJMHgwMDAwLzB4MDIwMCwwLjAwMDY0MTAzCTB4MTAwMC8weDEwMDAsMC4wMDA2NDEwMwkweDAwMDAvMHgwMDAwLDAuOTk4NzE3OTYJCjE3CTB4MDAwMC8weDAwMDAsMS4wMDAwMDAwMAkKODkJMHgwMDAwLzB4MDAwMCwxLjAwMDAwMDAwCQojCi1leHRyYQowCiMKLXNwYXIKIwotc3BlbQowLjUwMDAwMDAwCTUzOjUzCjAuNTAwMDAwMDAJNDAwMDo0MDAwCiMKLWRwYXIKMC4yMjY0MTUxMAkyMDoyMQowLjA4Njc5MjQ1CTIwMTA6MjAxMQowLjA3OTI0NTI4CTEzNzoxMzgKMC4wNjAzNzczNgk0MDExOjQwMTQKMC4wNTI4MzAxOQkyMjAxNDoyMjAyOQowLjA0NTI4MzAyCTMxMDY6MzEwOAowLjA0NTI4MzAyCTE2MToxNjIKMC4wMzc3MzU4NQkzMDAwOjMwMTAKMC4wMzc3MzU4NQk0MTIwOjUxMjAKMC4wMzM5NjIyNgkzMjA2OjMyMTYKMC4wMzM5NjIyNgkzMTEwOjMxMTIKMC4wMzM5NjIyNgkzMTAwOjMxMDEKMC4wMzAxODg2OAk0MTAwOjQxMTAKMC4wMjI2NDE1MQkzMzQzMzozMzU1MwowLjAyMjY0MTUxCTI5MzAwOjI5MzAxCjAuMDIyNjQxNTEJMjEwNjoyMTA5CjAuMDE1MDk0MzQJMjAwMDoyMDAxCjAuMDE1MDk0MzQJNTAwMDo1MDEwCjAuMDExMzIwNzUJODM5Ojg0OAowLjAxMTMyMDc1CTc3NzA6Nzc3MQowLjAxMTMyMDc1CTY2NjQ6NjY2NQowLjAwNzU0NzE3CTcwMDA6NzAwMQowLjAwNzU0NzE3CTg5OTE6ODk5MwowLjAwMzc3MzU4CTQ0NDo0NDUKMC4wMDM3NzM1OAkxMTAyMToxMTAyMwowLjAwMzc3MzU4CTMyMDAwOjMyMDIwCjAuMDAzNzczNTgJNTQzMTo1NDMyCjAuMDAzNzczNTgJMTIzNDU6MTIzNDYKMC4wMDM3NzM1OAk4MDYwOjgwNzkKMC4wMDM3NzM1OAk4Mzk6OTA5CjAuMDAzNzczNTgJMjAwMDE6NjU1MzUKMC4wMDM3NzM1OAk4MDo4MQowLjAwMzc3MzU4CTg2MDo5MDkKMC4wMDM3NzM1OAkyMjAwOjIyOTkKMC4wMDM3NzM1OAk3MDUwOjczMDAKMC4wMDM3NzM1OAk1MDAwOjUwMDEKIwotZHBlbQowLjA5Njk1ODE4CTUxNDo1MTQKMC4wNzY2NzkzNAk4MDo4MAowLjA1NDQ5OTM3CTI1OjI1CjAuMDUyNTk4MjMJMTIzOjEyMwowLjA1MTk2NDUxCTY5OjY5CjAuMDQ0MzU5OTUJNTM6NTMKMC4wNDExOTEzOAkzMDE1OjMwMTUKMC4wMjkxNTA4Mgk1MTkwOjUxOTAKMC4wMjg1MTcxMQkzMTA2OjMxMDYKMC4wMjA5MTI1NQkxNjI6MTYyCjAuMDE5NjQ1MTIJMjkzMDE6MjkzMDEKMC4wMTY0NzY1NQk4MDgwOjgwODAKMC4wMTU4NDI4NAk0NDM6NDQzCjAuMDE1ODQyODQJMTYxOjE2MQowLjAxNTIwOTEzCTk5OTM6OTk5MwowLjAxMzMwNzk4CTQyOjQyCjAuMDEzMzA3OTgJMTcwMToxNzAxCjAuMDEzMzA3OTgJMTM5OjEzOQowLjAxMzMwNzk4CTEzNToxMzUKMC4wMTE0MDY4NAkzNzozNwowLjAxMTQwNjg0CTQ0NDQ6NDQ0NAowLjAxMTQwNjg0CTUwNTA6NTA1MAowLjAwOTUwNTcwCTQwMDE6NDAwMQowLjAwOTUwNTcwCTMzMDA6MzMwMAowLjAwODg3MTk5CTExMTE6MTExMQowLjAwODIzODI4CTIzNDU6MjM0NQowLjAwNzYwNDU2CTMzMDE6MzMwMQowLjAwNzYwNDU2CTUwMDA6NTAwMAowLjAwNzYwNDU2CTIwMDEwOjIwMDEwCjAuMDA3NjA0NTYJOTAwMDo5MDAwCjAuMDA3NjA0NTYJMjM0NDoyMzQ0CjAuMDA3NjA0NTYJMzMxOjMzMQowLjAwNjMzNzE0CTUwMTU6NTAxNQowLjAwNjMzNzE0CTM0NTY6MzQ1NgowLjAwNjMzNzE0CTQzMjE6NDMyMQowLjAwNjMzNzE0CTIzOjIzCjAuMDA2MzM3MTQJNTU2NjY6NTU2NjYKMC4wMDU3MDM0MgkxNDMzOjE0MzMKMC4wMDU3MDM0MgkzMjAwOjMyMDAKMC4wMDU3MDM0MgkzMDMwOjMwMzAKMC4wMDU3MDM0MgkzMTE0OjMxMTQKMC4wMDU3MDM0MgkyMzE0OjIzMTQKMC4wMDU3MDM0MgkzMTE2OjMxMTYKMC4wMDU3MDM0MgkzMzUwOjMzNTAKMC4wMDU3MDM0MgkyMDUwMDoyMDUwMAowLjAwNTcwMzQyCTUxMDA6NTEwMAowLjAwNTcwMzQyCTQxMDY6NDEwNgowLjAwNTA2OTcxCTE4MjU6MTgyNQowLjAwNTA2OTcxCTU0NDA6NTQ0MAowLjAwNTA2OTcxCTIwMzAwOjIwMzAwCjAuMDA0NDM2MDAJNzQ5Ojc0OQowLjAwNDQzNjAwCTMzMzM6MzMzMwowLjAwNDQzNjAwCTc2MTo3NjEKMC4wMDQ0MzYwMAkyMDAzMDoyMDAzMAowLjAwNDQzNjAwCTE0MzoxNDMKMC4wMDM4MDIyOAkxODEyOjE4MTIKMC4wMDM4MDIyOAk1NzE5OjU3MTkKMC4wMDM4MDIyOAk1NzA4OjU3MDgKMC4wMDM4MDIyOAk1NzQxOjU3NDEKMC4wMDM4MDIyOAk1NzMwOjU3MzAKMC4wMDMxNjg1NwkzMDEwOjMwMTAKMC4wMDMxNjg1Nwk1NTU1OjU1NTUKMC4wMDMxNjg1NwkzMTAxOjMxMDEKMC4wMDI1MzQ4NQkzMzM3OjMzMzcKMC4wMDI1MzQ4NQkxNTM0OjE1MzQKMC4wMDI1MzQ4NQkxNzgwOjE3ODAKMC4wMDI1MzQ4NQk3MDAwOjcwMDAKMC4wMDI1MzQ4NQkzMDAwOjMwMDAKMC4wMDI1MzQ4NQk3MTEzOjcxMTMKMC4wMDI1MzQ4NQk1NzAwOjU3MDAKMC4wMDI1MzQ4NQkzMzQwOjMzNDAKMC4wMDE5MDExNAkzMTExOjMxMTEKMC4wMDE5MDExNAk1MDAxOjUwMDEKMC4wMDE5MDExNAkxMTM6MTEzCjAuMDAxOTAxMTQJNTExMjo1MTEyCjAuMDAxOTAxMTQJNTE1MDA6NTE1MDAKMC4wMDE5MDExNAkzMDIxMDozMDIxMAowLjAwMTkwMTE0CTMzNDozMzQKMC4wMDE5MDExNAkxMTk6MTE5CjAuMDAxOTAxMTQJMzA3NzozMDc3CjAuMDAxMjY3NDMJODkwMDo4OTAwCjAuMDAxMjY3NDMJOTA6OTAKMC4wMDEyNjc0Mwk0NTU1OjQ1NTUKMC4wMDEyNjc0MwkzMDAxOjMwMDEKMC4wMDEyNjc0Mwk1MTc3MDo1MTc3MAowLjAwMTI2NzQzCTg3Mjo4NzIKMC4wMDEyNjc0Mwk2NjAwOjY2MDAKMC4wMDEyNjc0MwkxMTE6MTExCjAuMDAxMjY3NDMJNjAwMDo2MDAwCjAuMDAxMjY3NDMJNTAxMDo1MDEwCjAuMDAxMjY3NDMJMzAwNTozMDA1CjAuMDAxMjY3NDMJMzAwNDozMDA0CjAuMDAxMjY3NDMJMjAwMDA6MjAwMDAKMC4wMDEyNjc0MwkzMDA4OjMwMDgKMC4wMDEyNjc0MwkwOjAKMC4wMDEyNjc0Mwk3NTA6NzUwCjAuMDAxMjY3NDMJMzgzOjM4MwowLjAwMTI2NzQzCTk0NDM6OTQ0MwowLjAwMTI2NzQzCTU5MDI6NTkwMgowLjAwMTI2NzQzCTM4MjozODIKMC4wMDEyNjc0MwkzMTA4OjMxMDgKMC4wMDA2MzM3MQkyMDU1NToyMDU1NQowLjAwMDYzMzcxCTI1MDI3OjI1MDI3CjAuMDAwNjMzNzEJMzAwMDA6MzAwMDAKMC4wMDA2MzM3MQkyNTE0NDoyNTE0NAowLjAwMDYzMzcxCTI4NTI6Mjg1MgowLjAwMDYzMzcxCTE4OTkyOjE4OTkyCjAuMDAwNjMzNzEJMjg1MzoyODUzCjAuMDAwNjMzNzEJMjg2MjoyODYyCjAuMDAwNjMzNzEJNTAwMDA6NTAwMDAKMC4wMDA2MzM3MQkyMjAwMDoyMjAwMAowLjAwMDYzMzcxCTI1MDI1OjI1MDI1CjAuMDAwNjMzNzEJMTkwMDA6MTkwMDAKMC4wMDA2MzM3MQkyMDQ5OjIwNDkKMC4wMDA2MzM3MQk0NDQzOjQ0NDMKMC4wMDA2MzM3MQk4MDQ0OjgwNDQKMC4wMDA2MzM3MQk1MTc1Mjo1MTc1MgowLjAwMDYzMzcxCTMxMzM3OjMxMzM3CjAuMDAwNjMzNzEJMjg2MzoyODYzCjAuMDAwNjMzNzEJMjI6MjIKMC4wMDA2MzM3MQkzMzM0OjMzMzQKMC4wMDA2MzM3MQkxMjE6MTIxCjAuMDAwNjMzNzEJNDQzOTo0NDM5CjAuMDAwNjMzNzEJNTAyMDo1MDIwCjAuMDAwNjMzNzEJMjEyMToyMTIxCjAuMDAwNjMzNzEJNTQzOjU0MwowLjAwMDYzMzcxCTU0NDo1NDQKMC4wMDA2MzM3MQk3MTQxOjcxNDEKMC4wMDA2MzM3MQk4MzU4OjgzNTgKMC4wMDA2MzM3MQkzMjA2OjMyMDYKMC4wMDA2MzM3MQkxMTA6MTEwCjAuMDAwNjMzNzEJMTk3MToxOTcxCjAuMDAwNjMzNzEJMTUyMToxNTIxCjAuMDAwNjMzNzEJNDc0Nzo0NzQ3CjAuMDAwNjMzNzEJMTk3MjoxOTcyCjAuMDAwNjMzNzEJMTAyNToxMDI1CjAuMDAwNjMzNzEJNTQ1OjU0NQowLjAwMDYzMzcxCTQ0NjQ1OjQ0NjQ1CjAuMDAwNjMzNzEJNTE2Njo1MTY2CjAuMDAwNjMzNzEJNTE2MDo1MTYwCjAuMDAwNjMzNzEJNTE3Mzo1MTczCjAuMDAwNjMzNzEJNTE3MDo1MTcwCjAuMDAwNjMzNzEJNTE1NDo1MTU0CjAuMDAwNjMzNzEJNTE0OTo1MTQ5CjAuMDAwNjMzNzEJNTE1ODo1MTU4CjAuMDAwNjMzNzEJMTk4MDoxOTgwCjAuMDAwNjMzNzEJNTcwOjU3MAowLjAwMDYzMzcxCTczNTg6NzM1OAowLjAwMDYzMzcxCTQ0Njo0NDYKMC4wMDA2MzM3MQk1ODEwOjU4MTAKMC4wMDA2MzM3MQk1MDM1OjUwMzUKMC4wMDA2MzM3MQk2MDAxOjYwMDEKIwotd2Nfd2MKMCwwLjAyNzAyNzAzCTAsMS4wMDAwMDAwMAoxMywwLjAxMzUxMzUxCTEzLDEuMDAwMDAwMDAKMTQsMC4wMDQ1MDQ1MAkxNCwxLjAwMDAwMDAwCjE1LDAuMDA0NTA0NTAJMTUsMS4wMDAwMDAwMAoxNiwwLjAwNDUwNDUwCTE2LDEuMDAwMDAwMDAKMTcsMC4wMDQ1MDQ1MAkxNywxLjAwMDAwMDAwCjIwLDAuMDA0NTA0NTAJMCwxLjAwMDAwMDAwCjI0LDAuMDcyMDcyMDcJMCwwLjkzNzUwMDAwCTI0LDAuMDYyNTAwMDAKMjgsMC4wMDQ1MDQ1MAkwLDEuMDAwMDAwMDAKMzIsMC4xMzA2MzA2MwkwLDAuODk2NTUxNzMJMzIsMC4xMDM0NDgyOAo0NSwwLjEzNTEzNTEzCTEzLDEuMDAwMDAwMDAKNDYsMC4wNDUwNDUwNAkxNCwxLjAwMDAwMDAwCjQ3LDAuMDQ5NTQ5NTUJMTUsMC45MDkwOTA5NAkyMywwLjA5MDkwOTA5CjQ4LDAuMDkwMDkwMDkJMTYsMS4wMDAwMDAwMAo1MSwwLjA0NTA0NTA0CTE5LDEuMDAwMDAwMDAKNTYsMC4xNzU2NzU2OAkyNCwxLjAwMDAwMDAwCjU4LDAuMDEzNTEzNTEJMjcsMS4wMDAwMDAwMAo1OSwwLjEzNTEzNTEzCTI3LDEuMDAwMDAwMDAKNjIsMC4wMzE1MzE1MwkzMCwxLjAwMDAwMDAwCjY0LDAuMDA5MDA5MDEJMzIsMS4wMDAwMDAwMAojCi13Y19oaQowLDAuMDAzMDAzMDAJMCwxLjAwMDAwMDAwCjI0LDAuMDE4MDE4MDIJMCwwLjgzMzMzMzMxCTI0LDAuMTY2NjY2NjcKMjYsMC4wMDMwMDMwMAkwLDEuMDAwMDAwMDAKMjcsMC4wMTgwMTgwMgkwLDAuMzMzMzMzMzQJMjcsMC42NjY2NjY2OQozMSwwLjAwMzAwMzAwCTAsMS4wMDAwMDAwMAozMiwwLjE0NzE0NzE1CTAsMC45Mzg3NzU1NAkzMiwwLjA2MTIyNDQ5CjQ4LDAuMDEyMDEyMDEJMTYsMS4wMDAwMDAwMAo0OSwwLjAwNjAwNjAxCTE3LDEuMDAwMDAwMDAKNTEsMC4wMDYwMDYwMQkxOSwxLjAwMDAwMDAwCjUyLDAuMDA2MDA2MDEJMjAsMS4wMDAwMDAwMAo1NCwwLjAwNjAwNjAxCTIyLDEuMDAwMDAwMDAKNTUsMC4wNDUwNDUwNAkyMywxLjAwMDAwMDAwCjU2LDAuMTY4MTY4MTcJMjQsMC45MTA3MTQyNwkyNSwwLjAzNTcxNDI5CTMyLDAuMDUzNTcxNDMKNTcsMC4wNDIwNDIwNAkyNSwwLjcxNDI4NTczCTI2LDAuMjg1NzE0MzAKNTgsMC4wNjMwNjMwNgkyNiwwLjcxNDI4NTczCTI3LDAuMjg1NzE0MzAKNTksMC4wNjkwNjkwNwkyNywwLjk1NjUyMTc1CTMyLDAuMDQzNDc4MjYKNjIsMC4wMTUwMTUwMgkzMCwwLjgwMDAwMDAxCTMxLDAuMjAwMDAwMDAKNjMsMC4wMDkwMDkwMQkzMiwxLjAwMDAwMDAwCjY0LDAuMzYwMzYwMzUJMzIsMS4wMDAwMDAwMAojCi1oaV93YwojCi1oaV9oaQojCi13Y19sbwojCi1sb193YwojCi1oaV9sbwojCi1sb19oaQojCi1sb19sbwojCi13Y19hcgowLDAuMDAzNzczNTgJMCwxLjAwMDAwMDAwCjgsMC4wMDM3NzM1OAk4LDEuMDAwMDAwMDAKMTIsMC4wMDc1NDcxNwkxMiwxLjAwMDAwMDAwCjE2LDAuMDE4ODY3OTIJMTYsMS4wMDAwMDAwMAoxOSwwLjAwMzc3MzU4CTE5LDEuMDAwMDAwMDAKMjEsMC4wNDE1MDk0MwkyMSwxLjAwMDAwMDAwCjIzLDAuMDQ1MjgzMDIJMjMsMS4wMDAwMDAwMAoyNCwwLjEwOTQzMzk2CTI0LDEuMDAwMDAwMDAKMjcsMC4wMDM3NzM1OAkyNywxLjAwMDAwMDAwCjMxLDAuMDAzNzczNTgJMCwxLjAwMDAwMDAwCjMyLDAuMDMzOTYyMjYJMCwxLjAwMDAwMDAwCjQ1LDAuMDExMzIwNzUJMTMsMS4wMDAwMDAwMAo0NiwwLjAwMzc3MzU4CTE0LDEuMDAwMDAwMDAKNDcsMC4wMDM3NzM1OAkxNSwxLjAwMDAwMDAwCjQ4LDAuMDIyNjQxNTEJMTYsMS4wMDAwMDAwMAo0OSwwLjAwNzU0NzE3CTE3LDEuMDAwMDAwMDAKNTEsMC4wMDc1NDcxNwkxOSwxLjAwMDAwMDAwCjUyLDAuMDAzNzczNTgJMjAsMS4wMDAwMDAwMAo1MywwLjAxODg2NzkyCTIxLDAuMjAwMDAwMDAJMjYsMC4yMDAwMDAwMAkyNywwLjYwMDAwMDAyCjU0LDAuMDYwMzc3MzYJMjIsMC4wNjI1MDAwMAkyNywwLjkzNzUwMDAwCjU1LDAuMDQxNTA5NDMJMjMsMS4wMDAwMDAwMAo1NiwwLjEwOTQzMzk2CTI0LDAuOTY1NTE3MjIJMjUsMC4wMzQ0ODI3Ngo1NywwLjAzMzk2MjI2CTI1LDAuNjY2NjY2NjkJMjYsMC4zMzMzMzMzNAo1OCwwLjA1NjYwMzc3CTI2LDAuODAwMDAwMDEJMjcsMC4yMDAwMDAwMAo1OSwwLjAzMDE4ODY4CTI3LDAuODc1MDAwMDAJMzIsMC4xMjUwMDAwMAo2MCwwLjAwMzc3MzU4CTI5LDEuMDAwMDAwMDAKNjEsMC4wMTEzMjA3NQkyOSwwLjY2NjY2NjY5CTMwLDAuMzMzMzMzMzQKNjIsMC4wMTg4Njc5MgkzMCwwLjIwMDAwMDAwCTMxLDAuODAwMDAwMDEKNjMsMC4wMzAxODg2OAkzMSwwLjM3NTAwMDAwCTMyLDAuNjI1MDAwMDAKNjQsMC4yNDkwNTY2MQkzMiwxLjAwMDAwMDAwCiMKLWFyX3djCiMKLWhpX2FyCiMKLWFyX2hpCiMKLXdjX2VtCjAsMC4wMDI1MzQ4NQkwLDEuMDAwMDAwMDAKMjEsMC4wMTE0MDY4NAkyMSwxLjAwMDAwMDAwCjIzLDAuMDEyNjc0MjcJMjMsMS4wMDAwMDAwMAoyNCwwLjAzMTA1MTk3CTI0LDEuMDAwMDAwMDAKMjYsMC4wMDA2MzM3MQkyNiwxLjAwMDAwMDAwCjI3LDAuMDAzMTY4NTcJMCwwLjgwMDAwMDAxCTI3LDAuMjAwMDAwMDAKMjksMC4wMDA2MzM3MQkwLDEuMDAwMDAwMDAKMzIsMC4wNjE0NzAyMQkwLDAuODc2Mjg4NjUJMTYsMC4xMDMwOTI3OAkzMiwwLjAyMDYxODU2CjM5LDAuMDAxMjY3NDMJMTIsMS4wMDAwMDAwMAo0MCwwLjAwODg3MTk5CTEzLDEuMDAwMDAwMDAKNDEsMC4wMDU3MDM0MgkxMywwLjU1NTU1NTU4CTE0LDAuNDQ0NDQ0NDUKNDIsMC4wMDUwNjk3MQkxMiwwLjI1MDAwMDAwCTE0LDAuMTI1MDAwMDAJMTUsMC42MjUwMDAwMAo0MywwLjAwNzYwNDU2CTE1LDAuMTY2NjY2NjcJMTYsMC44MzMzMzMzMQo0NCwwLjAxMDc3MzEzCTEyLDAuOTQxMTc2NDcJMTYsMC4wNTg4MjM1Mwo0NiwwLjAwMjUzNDg1CTE2LDAuNTAwMDAwMDAJMTksMC41MDAwMDAwMAo0NywwLjAwMTkwMTE0CTIwLDEuMDAwMDAwMDAKNDgsMC4wNTUxMzMwOAkxNiwwLjk4ODUwNTcyCTIwLDAuMDExNDk0MjUKNDksMC4wMDY5NzA4NQkxNywwLjE4MTgxODE5CTIyLDAuMjcyNzI3MjgJMjcsMC41NDU0NTQ1Ngo1MCwwLjAxMDEzOTQyCTIyLDAuMDYyNTAwMDAJMjMsMC45Mzc1MDAwMAo1MSwwLjA0ODE2MjIzCTE5LDAuMzU1MjYzMTQJMjMsMC4wNjU3ODk0OAkyNCwwLjQyMTA1MjYzCTI3LDAuMTU3ODk0NzMKNTIsMC4wMDk1MDU3MAkyMCwwLjEzMzMzMzM0CTI0LDAuNzMzMzMzMzUJMjYsMC4xMzMzMzMzNAo1MywwLjAzMjMxOTM5CTIxLDAuNDkwMTk2MDgJMjYsMC4wOTgwMzkyMgkyNywwLjQxMTc2NDcxCjU0LDAuMDU3MDM0MjIJMjIsMC4wNTU1NTU1NgkyMywwLjAxMTExMTExCTI3LDAuOTMzMzMzMzQKNTUsMC4wMzM1ODY4MgkyMywwLjkyNDUyODMwCTI0LDAuMDc1NDcxNzAKNTYsMC4xMDcwOTc1OQkyNCwwLjk3NjMzMTM1CTI1LDAuMDIzNjY4NjQKNTcsMC4wMTgzNzc2OQkyNSwwLjY4OTY1NTE4CTI2LDAuMjc1ODYyMDcJMjcsMC4wMzQ0ODI3Ngo1OCwwLjA2MTQ3MDIxCTI2LDAuODU1NjcwMDkJMjcsMC4xMDMwOTI3OAkyOSwwLjA0MTIzNzExCjU5LDAuMDQ4Nzk1OTUJMjcsMC43OTIyMDc3OAkyOSwwLjAyNTk3NDAzCTMyLDAuMTgxODE4MTkKNjAsMC4wMzIzMTkzOQkyOCwwLjY4NjI3NDUzCTI5LDAuMTk2MDc4NDMJMzEsMC4wMzkyMTU2OQkzMiwwLjA3ODQzMTM4CjYxLDAuMDI0NzE0ODMJMjksMC44OTc0MzU5MAkzMSwwLjEwMjU2NDEwCjYyLDAuMDAyNTM0ODUJMzAsMC43NTAwMDAwMAkzMiwwLjI1MDAwMDAwCjYzLDAuMDE4Mzc3NjkJMzEsMC44OTY1NTE3MwkzMiwwLjEwMzQ0ODI4CjY0LDAuMjY2MTU5NjgJMzIsMS4wMDAwMDAwMAojCi1lbV93YwojCi1oaV9lbQojCi1lbV9oaQowLDAuNTAwMDAwMDAJMCwxLjAwMDAwMDAwCjY0LDAuNTAwMDAwMDAJMzIsMS4wMDAwMDAwMAojCi1sb19hcgojCi1hcl9sbwojCi1sb19lbQojCi1lbV9sbwojCi1hcl9hcgojCi1hcl9lbQojCi1lbV9hcgojCi1lbV9lbQojCi1zbmVzdAo2CiMKLXNza2V3CjAJMC4wMDAwMDAwMAkxLjAwMDAwMDAwCTAuMTI1ODU2MTYKMQkwLjAwMDAwMDAwCTEuMDAwMDAwMDAJMC43NDM4ODA4NwoyCTAuMDAwMDAwMDAJMS4wMDAwMDAwMAkwLjc1MTA4NDgwCjMJMC41MDAwMDAwMAkwLjUwMDAwMDAwCTAuMzcxMjYzMzMKNAkwLjQxNjY2NjY2CTAuNTgzMzMzMzEJMC44MjAzMDk5NAo1CTAuNjg0MjEwNTQJMC4zMTU3ODk0NgkwLjkzNDQ2MjEzCjYJMC44MDAwMDAwMQkwLjIwMDAwMDAwCTAuOTUzOTQxMzUKNwkwLjg5OTk5OTk4CTAuMTAwMDAwMDAJMC45MzM0MjA0Mgo4CTAuODQ4NDg0ODcJMC4xNTE1MTUxNgkwLjc1NzQzMzE4CjkJMC44OTQ3MzY4MwkwLjEwNTI2MzE2CTAuNjkyNzU5MDQKMTAJMC44ODA5NTIzNgkwLjExOTA0NzYyCTAuMzEwNzY4NzUKMTEJMS4wMDAwMDAwMAkwLjAwMDAwMDAwCTEuMDAwMDAwMDAKMTIJMC45NTY1MjE3NQkwLjA0MzQ3ODI2CTAuNjc1MDAwMDEKMTMJMS4wMDAwMDAwMAkwLjAwMDAwMDAwCTEuMDAwMDAwMDAKMTQJMS4wMDAwMDAwMAkwLjAwMDAwMDAwCTEuMDAwMDAwMDAKMTUJMS4wMDAwMDAwMAkwLjAwMDAwMDAwCTEuMDAwMDAwMDAKMTYJMC44MTM5NTM0NgkwLjE4NjA0NjUxCTAuNjAzOTA0NjAKMTcJMC44NjI3NDUxMQkwLjEzNzI1NDkxCTAuNTkwNTQ2NTUKMTgJMC44MTAzNDQ4MgkwLjE4OTY1NTE3CTAuNzE5NTU1NjIKMTkJMC43ODI2MDg2OQkwLjIxNzM5MTMwCTAuNjY2ODUzNzMKMjAJMC44MjE0Mjg2MAkwLjE3ODU3MTQzCTAuNTYwMTU3MjQKMjEJMC44MjY1MzA2NAkwLjE3MzQ2OTM4CTAuNTY3MDUwMTYKMjIJMC43NzE5Mjk4MAkwLjIyODA3MDE4CTAuNDg4NzIzMDEKMjMJMC44NTQ5NjE4MQkwLjE0NTAzODE3CTAuNTg0Njk4MjAKMjQJMC44Mjc1ODYyMwkwLjE3MjQxMzgxCTAuNjI1MzgyNjAKMjUJMC43OTg1MDc0NQkwLjIwMTQ5MjUzCTAuNDIxNTUxNTkKMjYJMC44NTQxNjY2OQkwLjE0NTgzMzM0CTAuNTI4NDExOTgKMjcJMC44ODU5MDYwNAkwLjExNDA5Mzk1CTAuNDgzNzI4MTQKMjgJMC44NzU3NzY0MQkwLjEyNDIyMzYwCTAuNDU4OTU4MzMKMjkJMC44NDQ4Mjc1OQkwLjE1NTE3MjQyCTAuMzY3MjI3NzkKMzAJMC44NDM0MzQzMwkwLjE1NjU2NTY1CTAuMjExOTgxNTYKMzEJMC44NTU4MTM5OAkwLjE0NDE4NjA1CTAuMjA3NTM2MzEKMzIJMC4wMDAwMDAwMAkxLjAwMDAwMDAwCTAuMjA3NTM2MzEKIwotZG5lc3QKNAojCi1kc2tldwowCTAuMDAwMDAwMDAJMS4wMDAwMDAwMAkwLjU3MDA0NTIzCjEJMC4wMDAwMDAwMAkxLjAwMDAwMDAwCTAuNzQzMTA3NjgKMgkwLjAwMDAwMDAwCTEuMDAwMDAwMDAJMC41NjAxODM4OAozCTAuMzc1MDAwMDAJMC42MjUwMDAwMAkwLjY5MjY3Njc4CjQJMC42OTIzMDc3MQkwLjMwNzY5MjMyCTAuODY5ODEyMjUKNQkwLjgyMzUyOTQyCTAuMTc2NDcwNTkJMC42Njk1MTk0OAo2CTAuOTQ5OTk5OTkJMC4wNTAwMDAwMAkwLjI5NDExNzYzCjcJMC45NTIzODA5NgkwLjA0NzYxOTA1CTAuODQ3ODI2MTIKOAkwLjgxODE4MTgxCTAuMTgxODE4MTkJMC41MzE0MDcwMAo5CTAuODg0NjE1MzYJMC4xMTUzODQ2MgkwLjU5NzI4MzkwCjEwCTAuODk2NTUxNzMJMC4xMDM0NDgyOAkwLjkzNTAxODM2CjExCTAuOTY4NzUwMDAJMC4wMzEyNTAwMAkwLjExMTExMTEwCjEyCTAuOTY5Njk3MDAJMC4wMzAzMDMwMwkwLjgwMDAwMDAxCjEzCTEuMDAwMDAwMDAJMC4wMDAwMDAwMAkxLjAwMDAwMDAwCjE0CTEuMDAwMDAwMDAJMC4wMDAwMDAwMAkxLjAwMDAwMDAwCjE1CTEuMDAwMDAwMDAJMC4wMDAwMDAwMAkxLjAwMDAwMDAwCjE2CTAuNjE3NjQ3MDUJMC4zODIzNTI5NQkwLjU5ODc2MTE0CjE3CTAuNzg3MjM0MDcJMC4yMTI3NjU5NgkwLjcyOTg5OTQ3CjE4CTAuNjg0MjEwNTQJMC4zMTU3ODk0NgkwLjU3NjU3MzI1CjE5CTAuODAwMDAwMDEJMC4yMDAwMDAwMAkwLjUzMDU1NDEyCjIwCTAuNzMwMzM3MDgJMC4yNjk2NjI5NQkwLjY2ODUyMDkzCjIxCTAuNzY5OTExNTMJMC4yMzAwODg1MAkwLjU3MjM1MDc0CjIyCTAuODA4ODIzNTMJMC4xOTExNzY0NgkwLjUzNzI5MTQxCjIzCTAuODY0MTk3NTUJMC4xMzU4MDI0NgkwLjU4MTc2MTQ4CjI0CTAuNzc5ODc0MjEJMC4yMjAxMjU3OAkwLjU4NDU2MzAyCjI1CTAuODg2NTk3OTMJMC4xMTM0MDIwNgkwLjUxMjQ1MTA1CjI2CTAuODU1ODEzOTgJMC4xNDQxODYwNQkwLjYxMjEyODg1CjI3CTAuODI4MzI2MTcJMC4xNzE2NzM4MAkwLjU1MzIyNzg0CjI4CTAuODIxNTYxMzQJMC4xNzg0Mzg2NgkwLjM3NjM3MzMyCjI5CTAuODY5MDA5NTUJMC4xMzA5OTA0MgkwLjQyOTg4Njc5CjMwCTAuODQ3NzAxMTMJMC4xNTIyOTg4NQkwLjI1MzY5OTQyCjMxCTAuOTI2MjA4NjcJMC4wNzM3OTEzNQkwLjI4NjMzMDA0CjMyCTAuMDAwMDAwMDAJMS4wMDAwMDAwMAkwLjI4NjMzMDA0CiMKLXBjb3JyCjEJMC40NjkwMTMzOQoyCTAuMjkxNzU0NzUKMwkwLjUyMTczOTEzCjQJMC4wMjA4MzMzMwo1CTAuNjY2NjY2NjkKNgkwLjAwMDAwMDAwCjcJMC4wMDAwMDAwMAo4CTAuMDAwMDAwMDAKOQkwLjAwMDAwMDAwCjEwCTAuMDAwMDAwMDAKMTEJMC4wMDAwMDAwMAoxMgkwLjAwMDAwMDAwCjEzCTAuMDAwMDAwMDAKMTQJMC4wMDAwMDAwMAoxNQkwLjAwMDAwMDAwCjE2CTAuMDAwMDAwMDAKMTcJMC4wMDAwMDAwMAoxOAkwLjAwMDAwMDAwCjE5CTAuMDAwMDAwMDAKMjAJMC4wMDAwMDAwMAoyMQkwLjAwMDAwMDAwCjIyCTAuMDAwMDAwMDAKMjMJMC4wMDAwMDAwMAoyNAkwLjAwMDAwMDAwCjI1CTAuMDAwMDAwMDAKMjYJMC4wMDAwMDAwMAoyNwkwLjAwMDAwMDAwCjI4CTAuMDAwMDAwMDAKMjkJMC4wMDAwMDAwMAozMAkwLjAwMDAwMDAwCjMxCTAuMDAwMDAwMDAKMzIJMC4wMDAwMDAwMAojCg=="
|
37
|
+
Base64.strict_decode64(seed3)
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_rule
|
41
|
+
random_rule = rules[rand(rules.size)]
|
42
|
+
random_rule.fields
|
43
|
+
|
44
|
+
#1. determine its OF type
|
45
|
+
#2. remove 5-tuple header fields that ARE NOT defined by the OF type
|
46
|
+
#3. add OF-specific header fields that ARE defined by the OF type
|
47
|
+
# 1. if the field is ingress port, Ethernet type or IP protocol,
|
48
|
+
# use specified dependencies (see shared Google document) to constrain a set
|
49
|
+
# of possible values for this field
|
50
|
+
# 2. generate value for the OF-specific header field in a
|
51
|
+
# specified way (see shared Google document)
|
52
|
+
#4. Label all the header fields by the corresponding OF name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/classbench/trie.rb
CHANGED
@@ -1,40 +1,74 @@
|
|
1
1
|
module Classbench
|
2
|
+
DEFAULT_DEPTH = 32
|
2
3
|
|
3
4
|
# Structure representing trie statistics proposed in the ClassBench tool.
|
4
5
|
#
|
5
6
|
# Array members store statistics defined separately for each level of the
|
6
7
|
# trie. Prefix nesting is defined for the whole trie.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
class ClassbenchStats
|
9
|
+
# (float[]) number of prefixes (not prefix nodes) with given length
|
10
|
+
attr_accessor :prefix_lengths
|
11
|
+
|
12
|
+
# (float[]) probability of node with only one child (from all non-leaf nodes),
|
13
|
+
attr_accessor :branching_one_child
|
14
|
+
|
15
|
+
# (float[]) probability of node with two children (from all non-leaf nodes)
|
16
|
+
attr_accessor :branching_two_children
|
17
|
+
|
18
|
+
# (float[]) average relative weight ratio of lighter vs heavier subtree (nodes with two children only)
|
19
|
+
attr_accessor :skew
|
20
|
+
|
21
|
+
# (int) maximum number of prefix nodes on an arbitrary path in the trie
|
22
|
+
attr_accessor :prefix_nesting
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
preinitialized_hash = Hash[*(0..DEFAULT_DEPTH).flat_map { |k, v| [k , 0.0] }]
|
26
|
+
|
27
|
+
self.prefix_lengths = preinitialized_hash.dup
|
28
|
+
self.branching_one_child = preinitialized_hash.dup
|
29
|
+
self.branching_two_children = preinitialized_hash.dup
|
30
|
+
self.skew = preinitialized_hash.dup
|
31
|
+
self.prefix_nesting = 0
|
32
|
+
end
|
33
|
+
end
|
18
34
|
|
19
35
|
|
20
36
|
# Structure representing statistics related to trie nodes.
|
21
37
|
#
|
22
38
|
# All the statistics are stored separately for each level of the trie.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
39
|
+
class NodeStats
|
40
|
+
attr_accessor :leaf # (int[]) number of leaf nodes
|
41
|
+
attr_accessor :one_child # (int[]) number of nodes with one child only
|
42
|
+
attr_accessor :two_children # (int[]) number of nodes with both children
|
43
|
+
attr_accessor :prefix # (int[]) number of prefix nodes (not prefixes)
|
44
|
+
attr_accessor :non_prefix # (int[]) number of non-prefix nodes
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
preinitialized_hash = Hash[*(0..DEFAULT_DEPTH).flat_map { |k, v| [k , 0] }]
|
48
|
+
|
49
|
+
self.leaf = preinitialized_hash.dup;
|
50
|
+
self.one_child = preinitialized_hash.dup;
|
51
|
+
self.two_children = preinitialized_hash.dup;
|
52
|
+
self.prefix = preinitialized_hash.dup;
|
53
|
+
self.non_prefix = preinitialized_hash.dup;
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Class representing statistics related to the trie.
|
32
58
|
#
|
33
59
|
# Statistics are divided into two groups:
|
34
60
|
# 1) statistics proposed in ClassBench tool and
|
35
61
|
# 2) statistics related to trie nodes.
|
36
62
|
#
|
37
|
-
|
63
|
+
class TrieStats
|
64
|
+
attr_accessor :classbench
|
65
|
+
attr_accessor :nodes
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
self.classbench = ClassbenchStats.new
|
69
|
+
self.nodes = NodeStats.new
|
70
|
+
end
|
71
|
+
end
|
38
72
|
|
39
73
|
# Class for representation of a n-ary prefix tree - trie.
|
40
74
|
class Trie
|
@@ -70,10 +104,35 @@ module Classbench
|
|
70
104
|
current_node.increment_prefixes
|
71
105
|
end
|
72
106
|
|
107
|
+
def self.get_prefix_nesting(node)
|
108
|
+
if node # non-empty subtree
|
109
|
+
# get prefix nesting from successor nodes
|
110
|
+
zero_nesting = get_prefix_nesting(node.subtree["0"])
|
111
|
+
one_nesting = get_prefix_nesting(node.subtree["1"])
|
112
|
+
# will this node increase prefix nesting?
|
113
|
+
if node.prefixes_count > 0 # this is a prefix node
|
114
|
+
is_prefix = 1
|
115
|
+
else
|
116
|
+
is_prefix = 0
|
117
|
+
end
|
118
|
+
|
119
|
+
# return maximum of successors' nesting, possibly incremented
|
120
|
+
if zero_nesting > one_nesting
|
121
|
+
return zero_nesting + is_prefix
|
122
|
+
else
|
123
|
+
return one_nesting + is_prefix
|
124
|
+
end
|
125
|
+
else # empty subtree
|
126
|
+
return 0
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
73
130
|
# Erase not implemented/neccessary
|
74
131
|
|
75
132
|
def get_stats
|
76
|
-
|
133
|
+
stats = TrieStats.new
|
134
|
+
|
135
|
+
return stats if not root
|
77
136
|
root.compute_weights
|
78
137
|
|
79
138
|
level = root.level
|
@@ -86,7 +145,82 @@ module Classbench
|
|
86
145
|
node.subtree.each do |char, subnode|
|
87
146
|
que << subnode
|
88
147
|
end
|
148
|
+
|
149
|
+
# level change - finish statistics computation for the previous level
|
150
|
+
if node.level != level
|
151
|
+
# auxiliary variables
|
152
|
+
one_child = stats.nodes.one_child[level];
|
153
|
+
two_children = stats.nodes.two_children[level];
|
154
|
+
sum = one_child + two_children;
|
155
|
+
# branching_one_child and branching_two_children
|
156
|
+
if sum != 0
|
157
|
+
stats.classbench.branching_one_child[level] =
|
158
|
+
one_child.to_f / sum;
|
159
|
+
stats.classbench.branching_two_children[level] =
|
160
|
+
two_children.to_f / sum;
|
161
|
+
end
|
162
|
+
# skew
|
163
|
+
if two_children != 0
|
164
|
+
stats.classbench.skew[level] /= two_children.to_f;
|
165
|
+
end
|
166
|
+
# increment the level counter
|
167
|
+
level += 1;
|
168
|
+
end
|
169
|
+
|
170
|
+
# trie node visit - classbench statistics
|
171
|
+
stats.classbench.prefix_lengths[level] += node.prefixes_count;
|
172
|
+
if node.subtree["0"] and node.subtree["1"] # skew is defined
|
173
|
+
if node.zero_weight > node.one_weight # lighter 1-subtree
|
174
|
+
skew = 1 - (node.one_weight.to_f / node.zero_weight);
|
175
|
+
else # lighter 0-subtree
|
176
|
+
skew = 1 - (node.zero_weight.to_f / node.one_weight);
|
177
|
+
end
|
178
|
+
stats.classbench.skew[level] += skew;
|
179
|
+
end
|
180
|
+
|
181
|
+
# trie node visit - nodes statistics
|
182
|
+
if node.subtree["0"].nil?
|
183
|
+
if node.subtree["1"].nil? # leaf node
|
184
|
+
stats.nodes.leaf[level] += 1
|
185
|
+
else # one child node
|
186
|
+
stats.nodes.one_child[level] += 1
|
187
|
+
end
|
188
|
+
else # node->zero != NULL
|
189
|
+
if node.subtree["1"] # two child node
|
190
|
+
stats.nodes.two_children[level] += 1
|
191
|
+
else # one child node
|
192
|
+
stats.nodes.one_child[level] += 1
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
if node.prefixes_count > 0 # prefix node
|
197
|
+
stats.nodes.prefix[level] += 1
|
198
|
+
else # non-prefix node
|
199
|
+
stats.nodes.non_prefix[level] += 1
|
200
|
+
end
|
201
|
+
|
202
|
+
end # end of while BFS
|
203
|
+
|
204
|
+
# finish statistics computation for the last level
|
205
|
+
# auxiliary variables
|
206
|
+
one_child = stats.nodes.one_child[level]
|
207
|
+
two_children = stats.nodes.two_children[level]
|
208
|
+
sum = one_child + two_children
|
209
|
+
# branching_one_child and branching_two_children
|
210
|
+
if sum != 0
|
211
|
+
stats.classbench.branching_one_child[level] =
|
212
|
+
one_child.to_f / sum
|
213
|
+
stats.classbench.branching_two_children[level] =
|
214
|
+
two_children.to_f / sum
|
89
215
|
end
|
90
|
-
|
216
|
+
# skew
|
217
|
+
if two_children != 0
|
218
|
+
stats.classbench.skew[level] /= two_children.to_f
|
219
|
+
end
|
220
|
+
# compute prefix nesting
|
221
|
+
stats.classbench.prefix_nesting = Trie.get_prefix_nesting(root)
|
222
|
+
|
223
|
+
return stats
|
224
|
+
end # end of get_stats
|
91
225
|
end
|
92
226
|
end
|
data/lib/classbench/trie_node.rb
CHANGED
data/lib/classbench.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'classbench/trie'
|
2
|
+
require_relative 'classbench/trie_node'
|
3
|
+
require_relative 'classbench/analyser'
|
4
|
+
require_relative 'classbench/rule'
|
5
|
+
require 'ip' # ruby-ip gem
|
4
6
|
require 'pp'
|
5
7
|
|
6
8
|
module Classbench
|
@@ -10,17 +12,35 @@ module Classbench
|
|
10
12
|
(0...len).map { [0,1][rand(2)]}.join
|
11
13
|
end
|
12
14
|
|
15
|
+
def self.ip_to_binary_string(ip)
|
16
|
+
ip = IP.new(ip)
|
17
|
+
ip.to_b.to_s[0,ip.pfxlen]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.load_prefixes_from_file(filename)
|
21
|
+
t = Trie.new
|
22
|
+
|
23
|
+
prefixes = File.readlines(filename).map(&:chomp)
|
24
|
+
prefixes.each do |pfx|
|
25
|
+
t.insert ip_to_binary_string(pfx)
|
26
|
+
end
|
27
|
+
t
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.analyse(filename)
|
31
|
+
analyser = Analyser.new
|
32
|
+
analyser.parse_openflow(File.read(filename))
|
33
|
+
100.times { p analyser.generate }
|
34
|
+
end
|
35
|
+
|
13
36
|
def self.hi
|
14
37
|
t = Trie.new
|
15
38
|
#2.times { t.insert "101" }
|
16
39
|
#3.times { t.insert "100" }
|
17
|
-
|
40
|
+
100_000.times { t.insert generate_prefix }
|
18
41
|
puts "Stats"
|
19
|
-
t.get_stats
|
42
|
+
pp t.get_stats
|
20
43
|
|
21
44
|
puts "Done"
|
22
|
-
|
23
|
-
|
24
|
-
|
25
45
|
end
|
26
46
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: classbench
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Lucansky
|
@@ -10,8 +10,22 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-06-
|
13
|
+
date: 2015-06-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: docopt
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
15
29
|
- !ruby/object:Gem::Dependency
|
16
30
|
name: rdoc
|
17
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -57,7 +71,8 @@ dependencies:
|
|
57
71
|
description: Statistical generation of firewall/OpenFLOW rules based on seed file
|
58
72
|
(IN DEVELOPMENT)
|
59
73
|
email: adamlucansky@gmail.com
|
60
|
-
executables:
|
74
|
+
executables:
|
75
|
+
- classbench
|
61
76
|
extensions: []
|
62
77
|
extra_rdoc_files:
|
63
78
|
- LICENSE.txt
|
@@ -67,11 +82,15 @@ files:
|
|
67
82
|
- Gemfile
|
68
83
|
- Gemfile.lock
|
69
84
|
- LICENSE.txt
|
85
|
+
- NOTES.txt
|
70
86
|
- README.rdoc
|
71
87
|
- Rakefile
|
72
88
|
- VERSION
|
89
|
+
- bin/classbench
|
73
90
|
- classbench.gemspec
|
74
91
|
- lib/classbench.rb
|
92
|
+
- lib/classbench/analyser.rb
|
93
|
+
- lib/classbench/rule.rb
|
75
94
|
- lib/classbench/trie.rb
|
76
95
|
- lib/classbench/trie_node.rb
|
77
96
|
- test/helper.rb
|