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 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