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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0476c25d8f3928d4d671593eb0008199838443a1
4
- data.tar.gz: af9f48ef68198ea312cf5bf2c7e7f7264df1ddee
3
+ metadata.gz: da83ac14c9b94a4a716e107bdb45cc191a690c8b
4
+ data.tar.gz: 80baca1f165b53d3ddb4c6f03eb17266b4fec88b
5
5
  SHA512:
6
- metadata.gz: 7df7583555c764b29b9a3b2bfa496fe58f20350b22f449d83bda3a09242c4eea79b2361306a301781cd32904be09ae2de8b34ebfb9dc8c04938cb7bb5e93431a
7
- data.tar.gz: 470d1129f07c85f2db6081a419db550cd9ff096aa5879748b2fade35e80b189424df2165b302de5f441aceb984b23ce892514d815b0edc24da1e368c987c6c7a
6
+ metadata.gz: ab085c658086d665d2b16ce1c7c7e60d6c5275f2290e661b4afc125f61a2d8f45fcb79119265cdb0db8911d5779fd36103ff10866c0734ee4b95b4760c1ae917
7
+ data.tar.gz: b2ca90c9cb9ca99f107623d989bcd40ac5cf258eb6e0524029f504aae0a1979a3b34d72f90aa33be6e57f2bd1fbb205899f12f6e2ed74154b558ecae4135e557
data/Gemfile CHANGED
@@ -9,3 +9,5 @@ group :development do
9
9
  gem "jeweler" #, "~> 2.0", '>= 2.0.1'
10
10
  # gem "simplecov"
11
11
  end
12
+
13
+ gem "docopt"
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 Lučanský (xlucan01)
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 [(no longer maintained) Classbench](http://www.arl.wustl.edu/classbench/).
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.5
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 ruby lib
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.5"
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-21"
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
@@ -0,0 +1,13 @@
1
+ module Classbench
2
+ class Rule
3
+ attr_accessor :attributes
4
+
5
+ def initialize(attrs)
6
+ self.attributes = attrs
7
+ end
8
+
9
+ def fields
10
+ attributes.keys
11
+ end
12
+ end
13
+ end
@@ -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
- Struct.new("ClassbenchStats",
8
- # (float[]) number of prefixes (not prefix nodes) with given length
9
- :prefix_lengths,
10
- # (float[]) probability of node with only one child (from all non-leaf nodes),
11
- :branching_one_child,
12
- # (float[]) probability of node with two children (from all non-leaf nodes)
13
- :branching_two_children,
14
- # (float[]) average relative weight ratio of lighter vs heavier subtree (nodes with two children only)
15
- :skew,
16
- # (int) maximum number of prefix nodes on an arbitrary path in the trie
17
- :prefix_nesting)
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
- Struct.new("NodeStats",
24
- :leaf, # (int[]) number of leaf nodes
25
- :one_child, # (int[]) number of nodes with one child only
26
- :two_children, # (int[]) number of nodes with both children
27
- :prefix, # (int[]) number of prefix nodes (not prefixes)
28
- :non_prefix # (int[]) number of non-prefix nodes
29
- )
30
-
31
- # Structure representing statistics related to the trie.
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
- Struct.new("TrieStats", :classbench_stats, :node_stats)
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
- return if not root
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
- end
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
@@ -28,4 +28,12 @@ class TrieNode
28
28
  def increment_prefixes
29
29
  self.prefixes_count += 1
30
30
  end
31
+
32
+ def zero_weight
33
+ subtree_weights["0"]
34
+ end
35
+
36
+ def one_weight
37
+ subtree_weights["1"]
38
+ end
31
39
  end
data/lib/classbench.rb CHANGED
@@ -1,6 +1,8 @@
1
- require 'classbench/trie'
2
- require 'classbench/trie_node'
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
- 500_000.times { t.insert generate_prefix }
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.5
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-21 00:00:00.000000000 Z
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