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