saikuro_treemap 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/MIT-LICENSE.txt +21 -0
- data/README.textile +65 -0
- data/Rakefile +62 -0
- data/lib/saikuro_treemap/ccn_node.rb +76 -0
- data/lib/saikuro_treemap/parser.rb +162 -0
- data/lib/saikuro_treemap.rb +74 -0
- data/saikuro_treemap.gemspec +37 -0
- data/templates/css/treemap.css +33 -0
- data/templates/js/jit-min.js +27 -0
- data/templates/js/jit.js +16675 -0
- data/templates/js/saikuro-render.js +48 -0
- data/templates/saikuro.html.erb +27 -0
- data/test/ccn_node_test.rb +96 -0
- data/test/test_helper.rb +4 -0
- metadata +107 -0
data/.gitignore
ADDED
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 ThoughtWorks, Inc. (http://thoughtworks.com)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
h2. Saikuro Treemap Generator
|
2
|
+
|
3
|
+
This gem generates a "treemap":http://en.wikipedia.org/wiki/Treemapping
|
4
|
+
showing the complexity of ruby code on which it is run. It uses
|
5
|
+
"Saikuro":http://saikuro.rubyforge.org/ under the covers to analyze ruby
|
6
|
+
code complexity.
|
7
|
+
|
8
|
+
The size of blocks in the treemap is representative of the size of the
|
9
|
+
code element represented by that block. The color of the block indicates
|
10
|
+
complexity of that particular code element. Green is good, red is bad,
|
11
|
+
blue is somewhere in between.
|
12
|
+
|
13
|
+
Small evenly distributed blocks which are green in color is indicative of
|
14
|
+
good code.
|
15
|
+
|
16
|
+
h2. Usage
|
17
|
+
|
18
|
+
We clearly need to make the gem install a bit easier, but for now:
|
19
|
+
|
20
|
+
* checkout this repos from github
|
21
|
+
* build the saikuro_treemap gem...
|
22
|
+
* >rake gem
|
23
|
+
* install saikuro_treemap gem...
|
24
|
+
* >sudo gem install saikuro_treemap
|
25
|
+
* add a rake task like below to your project, adjusting :code_dirs for your project:
|
26
|
+
|
27
|
+
<pre>
|
28
|
+
require 'saikuro_treemap'
|
29
|
+
|
30
|
+
namespace :metrics do
|
31
|
+
desc 'generate ccn treemap'
|
32
|
+
task :ccn_treemap do
|
33
|
+
SaikuroTreemap.generate_treemap :code_dirs => ['lib']
|
34
|
+
`open reports/saikuro_treemap.html`
|
35
|
+
end
|
36
|
+
end
|
37
|
+
</pre>
|
38
|
+
|
39
|
+
* run the task to see the treemap in your browser
|
40
|
+
|
41
|
+
h2. License
|
42
|
+
|
43
|
+
Saikuro Treemap Generator is MIT Licensed
|
44
|
+
|
45
|
+
The MIT License
|
46
|
+
|
47
|
+
Copyright (c) 2010 ThoughtWorks, Inc. (http://thoughtworks.com)
|
48
|
+
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
50
|
+
of this software and associated documentation files (the "Software"), to deal
|
51
|
+
in the Software without restriction, including without limitation the rights
|
52
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
53
|
+
copies of the Software, and to permit persons to whom the Software is
|
54
|
+
furnished to do so, subject to the following conditions:
|
55
|
+
|
56
|
+
The above copyright notice and this permission notice shall be included in
|
57
|
+
all copies or substantial portions of the Software.
|
58
|
+
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
60
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
61
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
62
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
63
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
64
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
65
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
$: << 'lib'
|
5
|
+
require 'saikuro_treemap'
|
6
|
+
|
7
|
+
namespace :metrics do
|
8
|
+
desc 'generate ccn treemap'
|
9
|
+
task :ccn_treemap do
|
10
|
+
SaikuroTreemap.generate_treemap :code_dirs => ['lib']
|
11
|
+
`open reports/saikuro_treemap.html`
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'rubygems'
|
17
|
+
rescue LoadError
|
18
|
+
# Too bad.
|
19
|
+
else
|
20
|
+
task "saikuro_treemap.gemspec" do
|
21
|
+
spec = Gem::Specification.new do |s|
|
22
|
+
s.name = "saikuro_treemap"
|
23
|
+
s.version = 0.1
|
24
|
+
s.platform = Gem::Platform::RUBY
|
25
|
+
s.summary = "Generate CCN Treemap based on saikuro analysis"
|
26
|
+
|
27
|
+
s.description = <<-EOF
|
28
|
+
Generate CCN Treemap based on saikuro analysis
|
29
|
+
EOF
|
30
|
+
s.add_dependency 'json'
|
31
|
+
s.add_dependency 'Saikuro'
|
32
|
+
|
33
|
+
s.files = `git ls-files`.split("\n") + %w(saikuro_treemap.gemspec)
|
34
|
+
s.bindir = 'bin'
|
35
|
+
s.require_path = 'lib'
|
36
|
+
s.has_rdoc = false
|
37
|
+
s.extra_rdoc_files = ['README.textile']
|
38
|
+
s.test_files = Dir['test/{test,spec}_*.rb']
|
39
|
+
|
40
|
+
s.author = 'ThoughtWorks Studios'
|
41
|
+
s.email = 'studios@thoughtworks.com'
|
42
|
+
s.homepage = 'http://github.com/ThoughtWorksStudios/saikuro_treemap'
|
43
|
+
s.rubyforge_project = 'saikuro_treemap'
|
44
|
+
end
|
45
|
+
|
46
|
+
File.open("saikuro_treemap.gemspec", "w") { |f| f << spec.to_ruby }
|
47
|
+
end
|
48
|
+
|
49
|
+
task :gem => ["saikuro_treemap.gemspec"] do
|
50
|
+
sh "gem build saikuro_treemap.gemspec"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
task :test do
|
55
|
+
Rake::TestTask.new do |t|
|
56
|
+
t.libs << "test"
|
57
|
+
t.test_files = FileList['test/*test.rb']
|
58
|
+
t.verbose = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
task :default => :test
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module SaikuroTreemap
|
2
|
+
class CCNNode
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
def initialize(path, complexity=0, lines=0)
|
6
|
+
@path = path
|
7
|
+
@children = []
|
8
|
+
@complexity = complexity
|
9
|
+
@lines = lines
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_child(child)
|
13
|
+
@children << child
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_node(*pathes)
|
17
|
+
return self if pathes.join("::") == @path
|
18
|
+
return self if pathes.empty?
|
19
|
+
|
20
|
+
# Eumerable#find is buggy for recursive calls!
|
21
|
+
@children.each do |child|
|
22
|
+
if r = child.find_node(pathes)
|
23
|
+
return r
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_nodes(*pathes)
|
30
|
+
pathes.each_with_index {|_, i| find_or_create_node(*pathes[0..i]) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_json(*args)
|
34
|
+
hash = { 'name' => compact_name, 'id' => @path, 'children' => @children }
|
35
|
+
data = {}
|
36
|
+
data['complexity'] = @complexity if @complexity != 0
|
37
|
+
data['lines'] = @lines if @lines != 0
|
38
|
+
data['$area'] = area if area != 0
|
39
|
+
data['$color'] = color if area != 0
|
40
|
+
hash['data'] = data
|
41
|
+
hash.to_json(*args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def area
|
45
|
+
return @lines if leaf?
|
46
|
+
@children.inject(0) {|sum, child| sum + child.area }
|
47
|
+
end
|
48
|
+
|
49
|
+
def color
|
50
|
+
return "#101010" unless leaf?
|
51
|
+
return "#AE0000" if @complexity >= 10
|
52
|
+
return "#006500" if @complexity < 5
|
53
|
+
return "#4545C2"
|
54
|
+
end
|
55
|
+
|
56
|
+
def leaf?
|
57
|
+
return @children.empty?
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def compact_name
|
63
|
+
return '' if @path !~ /\S/
|
64
|
+
@path.split('::').last.split('#').last
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_or_create_node(*pathes)
|
68
|
+
find_node(*pathes) || create_node(*pathes)
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_node(*pathes)
|
72
|
+
parent = find_node(*pathes[0..-2])
|
73
|
+
parent.add_child(CCNNode.new(pathes.join("::")))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# almost all of code in this file is from metric_fu
|
2
|
+
# http://metric-fu.rubyforge.org/
|
3
|
+
module SaikuroTreemap
|
4
|
+
module Parser
|
5
|
+
def self.parse(saikuro_out_dir)
|
6
|
+
files = Dir[File.join(saikuro_out_dir, "/**/*.html")].collect do |path|
|
7
|
+
SFile.new(path) if SFile.is_valid_text_file?(path)
|
8
|
+
end
|
9
|
+
|
10
|
+
files.compact!
|
11
|
+
|
12
|
+
files = files.sort_by do |file|
|
13
|
+
file.elements.
|
14
|
+
max {|a,b| a.complexity.to_i <=> b.complexity.to_i}.
|
15
|
+
complexity.to_i
|
16
|
+
end.reverse
|
17
|
+
|
18
|
+
files.each do |file|
|
19
|
+
file.elements.each do |element|
|
20
|
+
element.defs.each do |defn|
|
21
|
+
defn.name = "#{element.name}##{defn.name}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
files.collect(&:to_h)
|
27
|
+
end
|
28
|
+
|
29
|
+
class SFile
|
30
|
+
attr_reader :elements
|
31
|
+
|
32
|
+
def initialize(path)
|
33
|
+
@path = path
|
34
|
+
@file_handle = File.open(@path, "r")
|
35
|
+
@elements = []
|
36
|
+
get_elements
|
37
|
+
ensure
|
38
|
+
@file_handle.close if @file_handle
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.is_valid_text_file?(path)
|
42
|
+
File.open(path, "r") do |f|
|
43
|
+
if f.eof? || !f.readline.match(/--/)
|
44
|
+
return false
|
45
|
+
else
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def filename
|
52
|
+
File.basename(@path, '_cyclo.html')
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_h
|
56
|
+
merge_classes
|
57
|
+
{:classes => @elements}
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_elements
|
61
|
+
begin
|
62
|
+
while (line = @file_handle.readline) do
|
63
|
+
return [] if line.nil? || line !~ /\S/
|
64
|
+
element ||= nil
|
65
|
+
if line.match /START/
|
66
|
+
unless element.nil?
|
67
|
+
@elements << element
|
68
|
+
element = nil
|
69
|
+
end
|
70
|
+
line = @file_handle.readline
|
71
|
+
element = ParsingElement.new(line)
|
72
|
+
elsif line.match /END/
|
73
|
+
@elements << element if element
|
74
|
+
element = nil
|
75
|
+
else
|
76
|
+
element << line if element
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue EOFError
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def merge_classes
|
86
|
+
new_elements = []
|
87
|
+
get_class_names.each do |target_class|
|
88
|
+
elements = @elements.find_all {|el| el.name == target_class }
|
89
|
+
complexity = 0
|
90
|
+
lines = 0
|
91
|
+
defns = []
|
92
|
+
elements.each do |el|
|
93
|
+
complexity += el.complexity.to_i
|
94
|
+
lines += el.lines.to_i
|
95
|
+
defns << el.defs
|
96
|
+
end
|
97
|
+
|
98
|
+
new_element = {:class_name => target_class,
|
99
|
+
:complexity => complexity,
|
100
|
+
:lines => lines,
|
101
|
+
:methods => defns.flatten.map {|d| d.to_h}}
|
102
|
+
new_element[:methods] = new_element[:methods].
|
103
|
+
sort_by {|x| x[:complexity] }.
|
104
|
+
reverse
|
105
|
+
|
106
|
+
new_elements << new_element
|
107
|
+
end
|
108
|
+
@elements = new_elements if new_elements
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_class_names
|
112
|
+
class_names = []
|
113
|
+
@elements.each do |element|
|
114
|
+
unless class_names.include?(element.name)
|
115
|
+
class_names << element.name
|
116
|
+
end
|
117
|
+
end
|
118
|
+
class_names
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
class ParsingElement
|
125
|
+
TYPE_REGEX=/Type:(.*) Name/
|
126
|
+
NAME_REGEX=/Name:(.*) Complexity/
|
127
|
+
COMPLEXITY_REGEX=/Complexity:(.*) Lines/
|
128
|
+
LINES_REGEX=/Lines:(.*)/
|
129
|
+
|
130
|
+
attr_reader :complexity, :lines, :defs, :element_type
|
131
|
+
attr_accessor :name
|
132
|
+
|
133
|
+
def initialize(line)
|
134
|
+
@line = line
|
135
|
+
@element_type = line.match(TYPE_REGEX)[1].strip
|
136
|
+
@name = line.match(NAME_REGEX)[1].strip
|
137
|
+
@complexity = line.match(COMPLEXITY_REGEX)[1].strip
|
138
|
+
@lines = line.match(LINES_REGEX)[1].strip
|
139
|
+
@defs = []
|
140
|
+
end
|
141
|
+
|
142
|
+
def <<(line)
|
143
|
+
@defs << ParsingElement.new(line)
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_h
|
147
|
+
base = {:name => @name, :complexity => @complexity.to_i, :lines => @lines.to_i}
|
148
|
+
unless @defs.empty?
|
149
|
+
defs = @defs.map do |my_def|
|
150
|
+
my_def = my_def.to_h
|
151
|
+
my_def.delete(:defs)
|
152
|
+
my_def
|
153
|
+
end
|
154
|
+
base[:defs] = defs
|
155
|
+
end
|
156
|
+
return base
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'json'
|
3
|
+
require 'erb'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
require 'saikuro_treemap/parser'
|
7
|
+
require 'saikuro_treemap/ccn_node'
|
8
|
+
|
9
|
+
module SaikuroTreemap
|
10
|
+
|
11
|
+
DEFAULT_CONFIG = {
|
12
|
+
:code_dirs => ['app/controllers', 'app/models', 'app/helpers' 'lib'],
|
13
|
+
:output_file => 'reports/saikuro_treemap.html',
|
14
|
+
:saikuro_args => [
|
15
|
+
"--warn_cyclo 5",
|
16
|
+
"--error_cyclo 7",
|
17
|
+
"--formater text",
|
18
|
+
"--cyclo --filter_cyclo 0"]
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.generate_treemap(config={})
|
22
|
+
temp_dir = 'tmp/saikuro'
|
23
|
+
|
24
|
+
config = DEFAULT_CONFIG.merge(config)
|
25
|
+
|
26
|
+
config[:saikuro_args] << "--output_directory #{temp_dir}"
|
27
|
+
|
28
|
+
options_string = config[:saikuro_args] + config[:code_dirs].collect { |dir| "--input_directory '#{dir}'" }
|
29
|
+
|
30
|
+
|
31
|
+
rm_rf temp_dir
|
32
|
+
sh %{saikuro #{options_string.join(' ')}} do |ok, response|
|
33
|
+
unless ok
|
34
|
+
puts "Saikuro failed with exit status: #{response.exitstatus}"
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
saikuro_files = Parser.parse(temp_dir)
|
40
|
+
|
41
|
+
@ccn_node = create_ccn_root_node(saikuro_files)
|
42
|
+
FileUtils.mkdir_p(File.dirname(config[:output_file]))
|
43
|
+
|
44
|
+
File.open(config[:output_file], 'w') do |f|
|
45
|
+
f << ERB.new(File.read(template('saikuro.html.erb'))).result(binding)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.create_ccn_root_node(saikuro_files)
|
50
|
+
root_node = CCNNode.new('')
|
51
|
+
saikuro_files.each do |f|
|
52
|
+
f[:classes].each do |c|
|
53
|
+
class_node_name = c[:class_name]
|
54
|
+
namespaces = class_node_name.split("::")[0..-2]
|
55
|
+
root_node.create_nodes(*namespaces)
|
56
|
+
parent = root_node.find_node(*namespaces)
|
57
|
+
class_node = CCNNode.new(class_node_name, c[:complexity], c[:lines])
|
58
|
+
parent.add_child(class_node)
|
59
|
+
|
60
|
+
c[:methods].each do |m|
|
61
|
+
class_node.add_child(CCNNode.new(m[:name], m[:complexity], m[:lines]))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
root_node
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.template(file)
|
70
|
+
File.expand_path("../../templates/#{file}", __FILE__)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{saikuro_treemap}
|
5
|
+
s.version = "0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["ThoughtWorks Studios"]
|
9
|
+
s.date = %q{2010-07-16}
|
10
|
+
s.description = %q{ Generate CCN Treemap based on saikuro analysis
|
11
|
+
}
|
12
|
+
s.email = %q{studios@thoughtworks.com}
|
13
|
+
s.extra_rdoc_files = ["README.textile"]
|
14
|
+
s.files = [".gitignore", "MIT-LICENSE.txt", "README.textile", "Rakefile", "lib/saikuro_treemap.rb", "lib/saikuro_treemap/ccn_node.rb", "lib/saikuro_treemap/parser.rb", "saikuro_treemap.gemspec", "templates/css/treemap.css", "templates/js/jit-min.js", "templates/js/jit.js", "templates/js/saikuro-render.js", "templates/saikuro.html.erb", "test/ccn_node_test.rb", "test/test_helper.rb"]
|
15
|
+
s.homepage = %q{http://github.com/ThoughtWorksStudios/saikuro_treemap}
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{saikuro_treemap}
|
18
|
+
s.rubygems_version = %q{1.3.7}
|
19
|
+
s.summary = %q{Generate CCN Treemap based on saikuro analysis}
|
20
|
+
s.test_files = ["test/test_helper.rb"]
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 3
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
28
|
+
s.add_runtime_dependency(%q<Saikuro>, [">= 0"])
|
29
|
+
else
|
30
|
+
s.add_dependency(%q<json>, [">= 0"])
|
31
|
+
s.add_dependency(%q<Saikuro>, [">= 0"])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<json>, [">= 0"])
|
35
|
+
s.add_dependency(%q<Saikuro>, [">= 0"])
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
html, body {
|
2
|
+
margin:0;
|
3
|
+
padding:0;
|
4
|
+
font-family: "Lucida Grande", Verdana;
|
5
|
+
font-size: 0.9em;
|
6
|
+
background-color:#F2F2F2;
|
7
|
+
}
|
8
|
+
|
9
|
+
.node {
|
10
|
+
color:#FFFFFF;
|
11
|
+
overflow:hidden;
|
12
|
+
cursor:pointer;
|
13
|
+
}
|
14
|
+
|
15
|
+
#infovis {
|
16
|
+
text-align: center;
|
17
|
+
position:relative;
|
18
|
+
width:90%;
|
19
|
+
height:900px;
|
20
|
+
margin:auto;
|
21
|
+
overflow:hidden;
|
22
|
+
}
|
23
|
+
|
24
|
+
.tip {
|
25
|
+
color: #fff;
|
26
|
+
width: auto;
|
27
|
+
background-color: black;
|
28
|
+
opacity:0.9;
|
29
|
+
filter:alpha(opacity=90);
|
30
|
+
font-size:10px;
|
31
|
+
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
|
32
|
+
padding:7px;
|
33
|
+
}
|