aws_security_viz 0.2.5.pre.alpha.pre.34 → 1.0.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -1
  3. data/README.md +122 -81
  4. data/exe/aws_security_viz +4 -40
  5. data/lib/aws_security_viz/aws_config.rb +80 -0
  6. data/lib/aws_security_viz/cli.rb +151 -0
  7. data/lib/aws_security_viz/cli_guard.rb +39 -0
  8. data/lib/aws_security_viz/directed_graph.rb +72 -0
  9. data/lib/aws_security_viz/ec2/security_groups.rb +74 -0
  10. data/lib/aws_security_viz/exclusions.rb +18 -0
  11. data/lib/aws_security_viz/export/html/viewer.html +222 -0
  12. data/lib/aws_security_viz/graph.rb +93 -0
  13. data/lib/aws_security_viz/graph_filter.rb +20 -0
  14. data/lib/aws_security_viz/logging.rb +18 -0
  15. data/lib/aws_security_viz/model.rb +87 -0
  16. data/lib/aws_security_viz/obfuscation.rb +45 -0
  17. data/lib/{opts.yml.sample → aws_security_viz/opts.yml.sample} +2 -0
  18. data/lib/aws_security_viz/port_label.rb +44 -0
  19. data/lib/aws_security_viz/provider/ec2.rb +84 -0
  20. data/lib/aws_security_viz/provider/json.rb +17 -0
  21. data/lib/aws_security_viz/renderer/all.rb +49 -0
  22. data/lib/aws_security_viz/renderer/graphviz.rb +119 -0
  23. data/lib/aws_security_viz/renderer/html.rb +46 -0
  24. data/lib/aws_security_viz/renderer/json.rb +29 -0
  25. data/lib/aws_security_viz/renderer/mermaid.rb +105 -0
  26. data/lib/aws_security_viz/risk.rb +18 -0
  27. data/lib/aws_security_viz/vendor/cytoscape/LICENSE +19 -0
  28. data/lib/aws_security_viz/vendor/cytoscape/README.md +15 -0
  29. data/lib/aws_security_viz/vendor/cytoscape/cytoscape.min.js +31 -0
  30. data/lib/aws_security_viz/version.rb +5 -0
  31. data/lib/aws_security_viz.rb +44 -37
  32. metadata +39 -232
  33. data/.dockerignore +0 -7
  34. data/.editorconfig +0 -17
  35. data/.github/dependabot.yml +0 -15
  36. data/.github/workflows/ruby.yml +0 -34
  37. data/.github/workflows/rubygem.yml +0 -29
  38. data/.github/workflows/rubygem_release.yml +0 -27
  39. data/.gitignore +0 -43
  40. data/.tool-versions +0 -1
  41. data/CODE_OF_CONDUCT.md +0 -46
  42. data/Dockerfile +0 -9
  43. data/Gemfile +0 -3
  44. data/Rakefile +0 -15
  45. data/Vagrantfile +0 -18
  46. data/aws_security_viz.gemspec +0 -40
  47. data/config/boot.rb +0 -4
  48. data/images/sample.png +0 -0
  49. data/lib/aws_config.rb +0 -44
  50. data/lib/color_picker.rb +0 -245
  51. data/lib/debug/parse_log.rb +0 -26
  52. data/lib/debug_graph.rb +0 -29
  53. data/lib/ec2/ip_permission.rb +0 -35
  54. data/lib/ec2/security_groups.rb +0 -78
  55. data/lib/ec2/traffic.rb +0 -32
  56. data/lib/exclusions.rb +0 -14
  57. data/lib/export/html/navigator.html +0 -84
  58. data/lib/export/html/view.html +0 -163
  59. data/lib/graph.rb +0 -45
  60. data/lib/graph_filter.rb +0 -38
  61. data/lib/provider/ec2.rb +0 -105
  62. data/lib/provider/json.rb +0 -104
  63. data/lib/renderer/all.rb +0 -18
  64. data/lib/renderer/graphviz.rb +0 -37
  65. data/lib/renderer/json.rb +0 -23
  66. data/lib/renderer/navigator.rb +0 -33
  67. data/lib/version.rb +0 -3
  68. data/spec/color_picker_spec.rb +0 -20
  69. data/spec/graph_filter_spec.rb +0 -85
  70. data/spec/integration/aws_expected.json +0 -1
  71. data/spec/integration/dummy.dot +0 -50
  72. data/spec/integration/dummy.json +0 -64
  73. data/spec/integration/expected.json +0 -1
  74. data/spec/integration/navigator.json +0 -1
  75. data/spec/integration/visualize_aws_spec.rb +0 -96
  76. data/spec/spec_helper.rb +0 -36
  77. data/spec/visualize_aws_spec.rb +0 -194
data/Rakefile DELETED
@@ -1,15 +0,0 @@
1
- require 'bundler/gem_tasks'
2
- require 'rspec/core/rake_task'
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- namespace :docker do
7
- task :login do
8
- sh 'echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin'
9
- end
10
- desc "push to dockerhub"
11
- task :push => :login do
12
- sh 'docker build -t anay/aws-security-viz .'
13
- sh 'docker push anay/aws-security-viz'
14
- end
15
- end
data/Vagrantfile DELETED
@@ -1,18 +0,0 @@
1
- # -*- mode: ruby -*-
2
- # vi: set ft=ruby :
3
-
4
- Vagrant.configure(2) do |config|
5
- config.vm.box = "ubuntu/vivid64"
6
- config.vm.provision "shell", inline: <<-SHELL
7
- apt-get -y update
8
- apt-get -y install git ruby-dev ruby graphviz libxml2-dev g++ zlib1g-dev
9
- SHELL
10
-
11
- config.vm.provision "shell", privileged: false, inline: <<-SHELL
12
- git clone https://github.com/anaynayak/aws-security-viz.git
13
- cd aws-security-viz
14
- sudo gem install bundler
15
- bundle install
16
- # bundle exec ruby lib/visualize_aws.rb -a your_aws_key -s your_aws_secret_key -f viz.svg --color=true
17
- SHELL
18
- end
@@ -1,40 +0,0 @@
1
- lib = File.expand_path('../lib', __FILE__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'version'
4
-
5
- Gem::Specification.new do |s|
6
- s.name = 'aws_security_viz'
7
- s.version = AwsSecurityViz::VERSION
8
- s.version = "#{s.version}-alpha-#{ENV['ALPHA_BUILD_NUMBER']}" if ENV['ALPHA_BUILD_NUMBER']
9
- s.date = Time.now.strftime('%Y-%m-%d')
10
- s.summary = 'Visualize your aws security groups'
11
- s.description = 'Provides a quick mechanism to visualize your EC2 security groups in multiple formats'
12
- s.authors = ['Anay Nayak']
13
- s.email = 'anayak007+rubygems@gmail.com'
14
- s.files = %w(lib config)
15
- s.homepage = 'https://github.com/anaynayak/aws-security-viz'
16
- s.license = 'MIT'
17
- s.bindir = 'exe'
18
-
19
- s.files = `git ls-files -z`.split("\x0")
20
- s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
22
- s.require_paths = ['lib']
23
-
24
- s.add_development_dependency 'rake', '>= 12.0.0', '~> 13.0'
25
- s.add_development_dependency 'rspec', '~> 3.5', '>= 3.5.0'
26
- if ENV["COVERAGE"]
27
- s.add_development_dependency "simplecov"
28
- end
29
- s.add_runtime_dependency 'rexml', '~> 3.2', '>= 3.2.2'
30
- s.add_runtime_dependency 'graphviz', '~> 1.1', '>= 1.1.0'
31
- s.add_runtime_dependency 'optimist', '>= 3.0', '< 3.3'
32
- s.add_runtime_dependency 'organic_hash', '~> 1.0', '>= 1.0.2'
33
- s.add_runtime_dependency 'rgl', '>= 0.5.3', '< 0.7.0'
34
- s.add_runtime_dependency 'webrick', '>= 1.8.1', '< 1.10.0'
35
- s.add_runtime_dependency 'aws-sdk-ec2', '>= 1.65', '< 1.499'
36
- s.add_runtime_dependency 'base64', '~> 0.2.0'
37
-
38
- s.required_ruby_version = '>= 3.0.0'
39
- end
40
-
data/config/boot.rb DELETED
@@ -1,4 +0,0 @@
1
- require 'bundler'
2
- Bundler.setup
3
-
4
- Dir["./lib/**/*.rb"].each { |f| require f }
data/images/sample.png DELETED
Binary file
data/lib/aws_config.rb DELETED
@@ -1,44 +0,0 @@
1
- require 'yaml'
2
-
3
- class AwsConfig
4
- def initialize(opts={})
5
- @opts = opts
6
- end
7
-
8
- def exclusions
9
- @exclusions ||=Exclusions.new(@opts[:exclude])
10
- end
11
-
12
- def egress?
13
- @opts.key?(:egress) ? @opts[:egress] : true
14
- end
15
-
16
- def groups
17
- @opts[:groups] || {}
18
- end
19
-
20
- def format
21
- @opts[:format] || 'dot'
22
- end
23
-
24
- def debug?
25
- @opts[:debug] || false
26
- end
27
-
28
- def obfuscate?
29
- @opts[:obfuscate] || false
30
- end
31
-
32
- def self.load(file)
33
- config_opts = File.exist?(file) ? YAML.load_file(file) : {}
34
- AwsConfig.new(config_opts)
35
- end
36
-
37
- def merge(opts)
38
- AwsConfig.new(@opts.merge!(opts))
39
- end
40
-
41
- def self.write(file)
42
- FileUtils.cp(File.expand_path('../opts.yml.sample', __FILE__), file)
43
- end
44
- end
data/lib/color_picker.rb DELETED
@@ -1,245 +0,0 @@
1
- class ColorPicker
2
- def initialize(colored)
3
- @picker = colored ? NodeColors.new : DefaultColors.new
4
- end
5
- def color(index, ingress)
6
- @picker.color(index, ingress)
7
- end
8
- class NodeColors
9
- def color(index, ingress)
10
- ColorPicker::COLORS[index % ColorPicker::COLORS.length]
11
- end
12
- end
13
- class DefaultColors
14
- def color(index, ingress)
15
- ingress ? :blue : :red
16
- end
17
- end
18
-
19
- COLORS = %w(
20
- #00004c
21
- #000080
22
- #0000fb
23
- #003a52
24
- #0040cd
25
- #0050b2
26
- #005390
27
- #007800
28
- #007eff
29
- #0096D8
30
- #009917
31
- #00B4AB
32
- #00a6a6
33
- #00cafe
34
- #012456
35
- #0298c3
36
- #02f88c
37
- #04133b
38
- #0579aa
39
- #078193
40
- #0aa0ff
41
- #0db7ed
42
- #0e60e3
43
- #101F1F
44
- #118f9e
45
- #120F14
46
- #14253c
47
- #178600
48
- #185619
49
- #198CE7
50
- #199f4b
51
- #1C3552
52
- #1D222D
53
- #1F1F1F
54
- #1ac620
55
- #1e4aec
56
- #22228f
57
- #244776
58
- #28431f
59
- #2ACCA8
60
- #2F2530
61
- #2b7489
62
- #2c3e50
63
- #302B6D
64
- #315665
65
- #341708
66
- #348a34
67
- #3572A5
68
- #358a5b
69
- #375eab
70
- #37775b
71
- #3A4E3A
72
- #3D6117
73
- #3F3F3F
74
- #3F85AF
75
- #3ac486
76
- #3be133
77
- #3d3c6e
78
- #3d9970
79
- #3fb68b
80
- #403a40
81
- #40d47e
82
- #427819
83
- #42f1f4
84
- #438eff
85
- #447265
86
- #44a51c
87
- #46390b
88
- #499886
89
- #4A76B8
90
- #4B6BEF
91
- #4B6C4B
92
- #4C3023
93
- #4F5D95
94
- #4d41b1
95
- #5232e7
96
- #555555
97
- #563d7c
98
- #596706
99
- #5A8164
100
- #5B2063
101
- #5a6986
102
- #5c7611
103
- #5e5086
104
- #60B5CC
105
- #62A8D6
106
- #636746
107
- #646464
108
- #64C800
109
- #64b970
110
- #652B81
111
- #6594b9
112
- #6600cc
113
- #665a4e
114
- #6866fb
115
- #6E4C13
116
- #6a40fd
117
- #6c616e
118
- #6e4a7e
119
- #701516
120
- #7055b5
121
- #74283c
122
- #747faa
123
- #7582D1
124
- #776791
125
- #7790B2
126
- #77d9fb
127
- #79aa7a
128
- #7b9db4
129
- #7e7eff
130
- #7fa2a7
131
- #800000
132
- #814CCC
133
- #82937f
134
- #843179
135
- #878787
136
- #87AED7
137
- #882B0F
138
- #88562A
139
- #88ccff
140
- #89e051
141
- #8a1267
142
- #8dc63f
143
- #8f0f8d
144
- #8f14e9
145
- #8fb200
146
- #913960
147
- #945db7
148
- #946d57
149
- #94B0C7
150
- #990000
151
- #999999
152
- #99DA07
153
- #9DC3FF
154
- #9EEDFF
155
- #9d5200
156
- #A0AA87
157
- #AA6746
158
- #B0CE4E
159
- #B34936
160
- #B5314C
161
- #B83998
162
- #B9D9FF
163
- #C1F12E
164
- #C76F5B
165
- #C7D7DC
166
- #DA5B0B
167
- #DAE1C2
168
- #DBCA00
169
- #E3F171
170
- #E4E6F3
171
- #E6EFBB
172
- #E8274B
173
- #EB8CEB
174
- #F18E33
175
- #FEFE00
176
- #FF5000
177
- #FFF4F3
178
- #a270ba
179
- #a3522f
180
- #a54c4d
181
- #a78649
182
- #a9188d
183
- #a957b0
184
- #aa2afe
185
- #adb2cb
186
- #b07219
187
- #b0b77e
188
- #b2011d
189
- #b2b7f8
190
- #b30000
191
- #b7e1f4
192
- #b845fc
193
- #ba595e
194
- #c065db
195
- #c22d40
196
- #c4a79c
197
- #c7a938
198
- #c9df40
199
- #cabbff
200
- #cc0000
201
- #cc0088
202
- #cc9900
203
- #cca760
204
- #ccccff
205
- #ccce35
206
- #cd6400
207
- #cdd0e3
208
- #cf142b
209
- #d4bec1
210
- #d80074
211
- #da291c
212
- #dad8d8
213
- #db5855
214
- #db901e
215
- #dbb284
216
- #dc566d
217
- #dce200
218
- #dea584
219
- #df7900
220
- #dfa535
221
- #e16737
222
- #e34c26
223
- #e4cc98
224
- #e69f56
225
- #ecdebe
226
- #ed2cd6
227
- #f0a9f0
228
- #f1e05a
229
- #f34b7d
230
- #f3ca0a
231
- #f50000
232
- #f7ede0
233
- #f97732
234
- #fab738
235
- #fb855d
236
- #fbe5cd
237
- #fcd7de
238
- #ff0c5a
239
- #ff2b2b
240
- #ff6375
241
- #ff7f7f
242
- #ffac45
243
- #fffaa0
244
- )
245
- end
@@ -1,26 +0,0 @@
1
- require_relative '../graph.rb'
2
- require 'organic_hash'
3
-
4
- @oh = OrganicHash.new
5
-
6
- def h(s)
7
- @oh.hash(s)
8
- end
9
-
10
-
11
- def debug
12
- g = Graph.new
13
- File.readlines('debug-output.log').map do |l|
14
- type, left, right = l.split(/\W+/)
15
- if type=="node"
16
- g.add_node(h(left), {})
17
- elsif type=="edge"
18
- g.add_edge(h(left), h(right), {})
19
- end
20
- end
21
- g.output(:svg => 'test.svg', :use => 'sfdp')
22
- end
23
-
24
- if __FILE__ == $0
25
- debug
26
- end
data/lib/debug_graph.rb DELETED
@@ -1,29 +0,0 @@
1
- require 'digest'
2
- require_relative 'graph'
3
-
4
- class DebugGraph
5
- def initialize(config)
6
- @g = Graph.new(config)
7
- end
8
-
9
- def add_node(name, opts)
10
- @g.add_node(h(name), opts) if name
11
- end
12
-
13
- def add_edge(from, to, opts)
14
- @g.add_edge(h(from), h(to), opts.update(label: h(opts[:label])))
15
- end
16
-
17
- def filter(source, destination)
18
- @g.filter(source, destination)
19
- end
20
-
21
- def output(renderer)
22
- @g.output(renderer)
23
- end
24
-
25
- private
26
- def h(msg)
27
- Digest::SHA256.hexdigest msg
28
- end
29
- end
@@ -1,35 +0,0 @@
1
- require_relative 'traffic.rb'
2
-
3
- class IpPermission
4
- def initialize(group, ip, ingress, exclusions)
5
- @group = group
6
- @ip = ip
7
- @ingress = ingress
8
- @exclusions = exclusions
9
- end
10
-
11
- def traffic
12
- cidr_traffic + group_traffic
13
- end
14
-
15
- private
16
- def port_range
17
- @ip.protocol == '-1' ? '*' : [@ip.from, @ip.to].uniq.join('-') + '/' + @ip.protocol
18
- end
19
-
20
- def cidr_traffic
21
- @ip.ip_ranges
22
- .select { |range| !@exclusions.match(range)}
23
- .collect { |range|
24
- Traffic.new(@ingress, range.cidr_ip, @group.name, port_range)
25
- }
26
- end
27
-
28
- def group_traffic
29
- @ip.groups
30
- .select { |gp| !@exclusions.match(gp.name)}
31
- .collect { |gp|
32
- Traffic.new(@ingress, gp.name, @group.name, port_range)
33
- }
34
- end
35
- end
@@ -1,78 +0,0 @@
1
- require 'set'
2
- require 'forwardable'
3
- require_relative 'ip_permission.rb'
4
-
5
- class SecurityGroups
6
- include Enumerable
7
-
8
- def initialize(provider, config)
9
- @groups = provider.security_groups
10
- @config = config
11
- end
12
-
13
- def each(&block)
14
- groups = @groups.select { |sg| !@config.exclusions.match(sg.name) }
15
- groups.each { |group|
16
- if block_given?
17
- block.call SecurityGroup.new(@groups, group, @config)
18
- else
19
- yield SecurityGroup.new(@groups, group, @config)
20
- end
21
- }
22
- end
23
-
24
- def size
25
- @groups.size
26
- end
27
- end
28
-
29
- class SecurityGroup
30
- extend Forwardable
31
-
32
- def_delegators :@group, :name, :vpc_id, :group_id
33
-
34
- def initialize(all_groups, group, config)
35
- @all_groups = all_groups
36
- @group = group
37
- @config = config
38
- end
39
-
40
- def permissions
41
- ingress_permissions = @group.ip_permissions.collect { |ip|
42
- IpPermission.new(@group, ip, true, @config.exclusions)
43
- }
44
- return ingress_permissions unless @config.egress?
45
- egress_permissions = @group.ip_permissions_egress.collect { |ip|
46
- IpPermission.new(@group, ip, false, @config.exclusions)
47
- }
48
- ingress_permissions + egress_permissions
49
- end
50
-
51
- def traffic
52
- all_traffic = permissions.collect { |permission|
53
- permission.traffic
54
- }.flatten.uniq
55
- CidrGroupMapping.new(@all_groups, @config.groups).map(all_traffic)
56
- end
57
- end
58
-
59
- class CidrGroupMapping
60
- def initialize(all_groups, user_groups)
61
- @all_groups = all_groups
62
- @user_groups = user_groups
63
- end
64
-
65
- def map(all_traffic)
66
- traffic = all_traffic.collect { |traffic|
67
- traffic.copy(mapping(traffic.from), mapping(traffic.to))
68
- }
69
- traffic.uniq.group_by {|t| [t.from, t.to, t.ingress]}.collect {|k,v| Traffic.grouped(v)}.uniq
70
- end
71
-
72
- private
73
- def mapping(val)
74
- group = @all_groups.find { |g| g.group_id == val }
75
- name = group.nil? ? val : group.name
76
- @user_groups[name] ? @user_groups[name] : name
77
- end
78
- end
data/lib/ec2/traffic.rb DELETED
@@ -1,32 +0,0 @@
1
- class Traffic
2
- attr_accessor :from, :to, :port_range, :ingress
3
-
4
- def initialize(ingress, from, to, port_range)
5
- @ingress = ingress
6
- @from = from
7
- @to = to
8
- @port_range = port_range
9
- end
10
-
11
- def copy(from, to)
12
- Traffic.new(@ingress, from, to, @port_range)
13
- end
14
-
15
- def eql?(other)
16
- if @ingress == other.ingress
17
- @from == other.from && @to == other.to && @port_range == other.port_range
18
- else
19
- @from == other.to && @to == other.from && @port_range == other.port_range
20
- end
21
- end
22
-
23
- def hash
24
- @from.hash + @to.hash + @port_range.hash
25
- end
26
-
27
- def self.grouped(traffic_list)
28
- t = traffic_list.first
29
- port_range = traffic_list.collect(&:port_range).uniq.join(',')
30
- Traffic.new(t.ingress, t.from, t.to, port_range)
31
- end
32
- end
data/lib/exclusions.rb DELETED
@@ -1,14 +0,0 @@
1
- class Exclusions
2
- attr_reader :patterns
3
-
4
- def initialize(patterns)
5
- @patterns = patterns.map {|p| /#{p}/} unless patterns.nil?
6
- end
7
-
8
- def match(str)
9
- return false if patterns.nil?
10
- patterns.any? { |p|
11
- p.match(str)
12
- }
13
- end
14
- end
@@ -1,84 +0,0 @@
1
- <html>
2
-
3
- <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
- <title>GraphNavigator</title>
6
- <script type="text/javascript" src="https://rawcdn.githack.com/grapheco/InteractiveGraph/0.3.2/dist/igraph/interactive-graph.min.js"></script>
7
- <link type="text/css" rel="stylesheet" href="https://rawcdn.githack.com/grapheco/InteractiveGraph/0.3.2/dist/igraph/interactive-graph.min.css">
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
9
- crossorigin="anonymous"></script>
10
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" integrity="sha256-p6xU9YulB7E2Ic62/PX+h59ayb3PBJ0WFTEQxq0EjHw="
11
- crossorigin="anonymous" />
12
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha256-KM512VNnjElC30ehFwehXjx1YCHPiQkOPmqnrWtpccM="
13
- crossorigin="anonymous"></script>
14
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
15
- integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
16
- <style type="text/css">
17
- body {
18
- margin: 0px;
19
- font-size: 14px;
20
- }
21
-
22
- #graphArea {
23
- height: 100%;
24
- border: 1px solid lightgray;
25
- }
26
- </style>
27
-
28
- </head>
29
-
30
- <body>
31
- <div style="height:100%">
32
- <div id="graphArea"></div>
33
- </div>
34
- <!--all UI controls-->
35
- <div>
36
- <!--toolbar-->
37
- <div class="toolbarPanel igraph-dockable igraph-draggable" igraph-control-role="ToolbarCtrl"
38
- igraph-dock-position="B:-6,0">
39
- <div class="toolbar"></div>
40
- </div>
41
- <!--info box-->
42
- <div class="infoPanel igraph-dockable igraph-draggable" igraph-control-role="InfoBoxCtrl" igraph-dock-position="A:10,200">
43
- <div>
44
- <div class="infoPanel1"></div>
45
- <div class="infoPanel2"><span align="center" class="fa fa-close fa-lg btnCloseInfoPanel"></span></div>
46
- </div>
47
- <div class="infoBox"></div>
48
- </div>
49
- <!--search box-->
50
- <div class="searchPanel igraph-dockable igraph-draggable" igraph-control-role="SearchBoxCtrl"
51
- igraph-dock-position="A:10,20">
52
- <div class="searchPanel1">
53
- <input class="igraph-searchbox" type="text" size="16" placeholder="input keyword">
54
- </div>
55
- <div class="searchPanel2 igraph-searchbox-image">
56
- <span align="center" class="fa fa-photo fa-lg" />
57
- </div>
58
- </div>
59
- <!--status bar-->
60
- <div class="statusPanel igraph-dockable" igraph-control-role="StatusBarCtrl" igraph-dock-position="C:-100,0">
61
- <div class="statusBar"></div>
62
- </div>
63
- <!--image upload box-->
64
- <div class="imageUploadPanel" igraph-control-role="ImageUploadCtrl"></div>
65
- <div class="ResultListPanel igraph-dockable igraph-draggable" igraph-control-role="ResultListCtrl" igraph-dock-position="A:10,70"></div>
66
- </div>
67
- <script type="text/javascript">
68
- function load() {
69
- var file = location.hash.replace(/^#/, '/');
70
- if (!file) {
71
- $('#error').dialog('open');
72
- return;
73
- } else {
74
- $('#error').dialog('close');
75
- }
76
- var app = new igraph.GraphNavigator(document.getElementById('graphArea'), 'LIGHT');
77
- app.loadGson(file);
78
- }
79
- $(window).on('hashchange', load);
80
- load();
81
- </script>
82
- </body>
83
-
84
- </html>