rubrowser 2.5.0 → 2.9.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
  SHA256:
3
- metadata.gz: e67fd969c9155da49e88d2cc1fd703ac364064841a3800ad03c70bc7c922bfc7
4
- data.tar.gz: 478c3f44d920a685109f24630e17658f3854adc3db675596baa285e4ec8e4538
3
+ metadata.gz: 42ce16c03f4558e78873eb558f1c516e5ce9cad721b951d9f7ecdf31c14c3cc8
4
+ data.tar.gz: 5c39ffdef3e17fc6a13ee5a2ac12007983111686a557faa7c45143f9009527d1
5
5
  SHA512:
6
- metadata.gz: 454bcb581e7fa255cce469d2b82f4321aa0d9f2cf127d2439a99ab437836028587d05a75214b224e1930c971c8b93739aa85838f1a3588658c3909c9d7c84d50
7
- data.tar.gz: 5281d603a1ab859d8609fb05a04ecb63b923beb65977e89ce628a8e6716d17c817eae2ec43e53496f377d348aced37f923374022cf9b5540191157a332bc0f25
6
+ metadata.gz: dbbe9eb3162ec5570ef422675937c174852e16efd7fef2e761cb618cd53b932887dc8e9607ce521bd6a4fe3cb8d2ebf821b9f77ad3abb4361fbddc8afd015e35
7
+ data.tar.gz: bf19b719776bf0c35c60dc250fef2ce29225f2b7158632c19b0c2b1bbba5aec18d31b8e227d33443f89d278c3f84f995e06d399187dc3fa283b17e0b9d1ee45c
@@ -5,3 +5,7 @@ Style/Documentation:
5
5
  Enabled: false
6
6
  Style/FrozenStringLiteralComment:
7
7
  Enabled: false
8
+ Style/GlobalVars:
9
+ Enabled: false
10
+ Metrics/BlockLength:
11
+ Enabled: false
data/.rubrowser CHANGED
@@ -1 +1 @@
1
- [{"id":"Rubrowser::Data","x":905.0088057752334,"y":437.04147016200284},{"id":"Rubrowser","x":712.6220053486966,"y":770.3251873644217},{"id":"Rubrowser::Formatter::JSON","x":1114.4368770370438,"y":560.0312580369882},{"id":"Rubrowser::Formatter","x":1113.6584254066838,"y":601.6487084046246},{"id":"Graph","x":1115.7752854976002,"y":436.6211350242928},{"id":"Rubrowser::Parser::Definition::Base","x":-8.218934126737395,"y":322.74585638398685},{"id":"Rubrowser::Parser::Definition","x":-191.1839782278871,"y":318.6377197576412},{"id":"Rubrowser::Parser","x":713.688310910547,"y":660.9646559993857},{"id":"Rubrowser::Parser::Definition::Class","x":186.15033111747857,"y":246.30753307276427},{"id":"Rubrowser::Parser::Definition::Module","x":188.36911863082037,"y":324.35744429623855},{"id":"Rubrowser::Parser::Directory","x":786.9998045114313,"y":239.74214301898786},{"id":"Rubrowser::Parser::Factory","x":788.0050388528484,"y":325.70343641742613},{"id":"Rubrowser::Parser::File::Builder","x":506.8969046429671,"y":189.48025894394402},{"id":"Rubrowser::Parser::File","x":505.82216034587793,"y":322.6733725221146},{"id":"Rubrowser::Parser::Relation::Base","x":185.12905462589924,"y":402.5519743127113},{"id":"Rubrowser::Parser::Relation","x":187.0097719718301,"y":461.8654698954514},{"id":"Rubrowser::Renderer","x":905.2158605930458,"y":560.8807631671766}]
1
+ [{"id":"A","x":3145.151252107328,"y":1255.7202242818169},{"id":"B","x":3041.815436574058,"y":1133.5156582815155},{"id":"C","x":3199.274701857475,"y":1105.1153162475819},{"id":"ClassWithOneClassDependency","x":1557.2872222716092,"y":-43.47687773940923},{"id":"ModuleWithNoRelations","x":1306.9528557451522,"y":1102.2650375990502},{"id":"ClassWithOneIncludedMixin","x":1498.1264029065396,"y":1151.463703990889},{"id":"ClassWithOneExtendedMixin","x":1505.8925222231119,"y":1066.3427953527182},{"id":"ModuleWithOneClassDependency","x":1506.2730755201367,"y":108.22508398850451},{"id":"ClassWithNoRelations","x":1400.4239271808685,"y":-11.760907506717134},{"id":"Rubrowser::Data","x":905.0088057752334,"y":437.04147016200284},{"id":"Rubrowser","x":712.6220053486966,"y":770.3251873644217},{"id":"Rubrowser::Trace","x":197.20494882540459,"y":735.0751347963624},{"id":"Rubrowser::Monitor","x":430.7305845891392,"y":680.3256207864202},{"id":"Graph","x":1115.7752854976002,"y":436.6211350242928},{"id":"Rubrowser::Connection","x":4.873283667279907,"y":680.4067753374231},{"id":"Rubrowser::Channel","x":1366.414402671432,"y":185.96446885474367},{"id":"Rubrowser::Renderer","x":905.2158605930458,"y":560.8807631671766},{"id":"Rubrowser::Server","x":208.96464998862217,"y":631.2323207047698},{"id":"Rubrowser::Formatter::JSON","x":1114.4368770370438,"y":560.0312580369882},{"id":"Rubrowser::Formatter","x":1113.6584254066838,"y":601.6487084046246},{"id":"Rubrowser::Parser::Definition::Module","x":188.36911863082037,"y":324.35744429623855},{"id":"Rubrowser::Parser::Definition","x":-191.1839782278871,"y":318.6377197576412},{"id":"Rubrowser::Parser","x":713.688310910547,"y":660.9646559993857},{"id":"Rubrowser::Parser::Definition::Base","x":-8.218934126737395,"y":322.74585638398685},{"id":"Rubrowser::Parser::Definition::Class","x":186.15033111747857,"y":246.30753307276427},{"id":"Rubrowser::Parser::Relation::Base","x":185.12905462589924,"y":402.5519743127113},{"id":"Rubrowser::Parser::Relation","x":187.0097719718301,"y":461.8654698954514},{"id":"Rubrowser::Parser::Factory","x":788.0050388528484,"y":325.70343641742613},{"id":"Rubrowser::Parser::File::Builder","x":506.8969046429671,"y":189.48025894394402},{"id":"Rubrowser::Parser::File","x":505.82216034587793,"y":322.6733725221146},{"id":"Rubrowser::Parser::Directory","x":786.9998045114313,"y":239.74214301898786}]
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - 2.3
5
+ - 2.4
6
+ - 2.5
@@ -1,55 +1,71 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubrowser (2.5.0)
5
- parser (~> 2.3, >= 2.3.0)
4
+ rubrowser (2.9.0)
5
+ litecable
6
+ parser
7
+ puma
8
+ websocket
6
9
 
7
10
  GEM
8
11
  remote: https://rubygems.org/
9
12
  specs:
10
- ast (2.2.0)
11
- byebug (9.0.6)
12
- diff-lcs (1.3)
13
- parallel (1.12.0)
14
- parser (2.4.0.0)
15
- ast (~> 2.2)
16
- powerpack (0.1.1)
17
- rainbow (2.2.2)
18
- rake
19
- rake (10.4.2)
20
- rspec (3.6.0)
21
- rspec-core (~> 3.6.0)
22
- rspec-expectations (~> 3.6.0)
23
- rspec-mocks (~> 3.6.0)
24
- rspec-core (3.6.0)
25
- rspec-support (~> 3.6.0)
26
- rspec-expectations (3.6.0)
13
+ anyway_config (2.0.6)
14
+ ruby-next-core (>= 0.8.0)
15
+ ast (2.4.1)
16
+ byebug (11.1.3)
17
+ diff-lcs (1.4.4)
18
+ litecable (0.7.0)
19
+ anyway_config (>= 1.0)
20
+ nio4r (2.5.2)
21
+ parallel (1.19.2)
22
+ parser (2.7.1.4)
23
+ ast (~> 2.4.1)
24
+ puma (4.3.5)
25
+ nio4r (~> 2.0)
26
+ rainbow (3.0.0)
27
+ rake (13.0.1)
28
+ regexp_parser (1.7.1)
29
+ rexml (3.2.4)
30
+ rspec (3.9.0)
31
+ rspec-core (~> 3.9.0)
32
+ rspec-expectations (~> 3.9.0)
33
+ rspec-mocks (~> 3.9.0)
34
+ rspec-core (3.9.2)
35
+ rspec-support (~> 3.9.3)
36
+ rspec-expectations (3.9.2)
27
37
  diff-lcs (>= 1.2.0, < 2.0)
28
- rspec-support (~> 3.6.0)
29
- rspec-mocks (3.6.0)
38
+ rspec-support (~> 3.9.0)
39
+ rspec-mocks (3.9.1)
30
40
  diff-lcs (>= 1.2.0, < 2.0)
31
- rspec-support (~> 3.6.0)
32
- rspec-support (3.6.0)
33
- rubocop (0.49.1)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-support (3.9.3)
43
+ rubocop (0.88.0)
34
44
  parallel (~> 1.10)
35
- parser (>= 2.3.3.1, < 3.0)
36
- powerpack (~> 0.1)
37
- rainbow (>= 1.99.1, < 3.0)
45
+ parser (>= 2.7.1.1)
46
+ rainbow (>= 2.2.2, < 4.0)
47
+ regexp_parser (>= 1.7)
48
+ rexml
49
+ rubocop-ast (>= 0.1.0, < 1.0)
38
50
  ruby-progressbar (~> 1.7)
39
- unicode-display_width (~> 1.0, >= 1.0.1)
40
- ruby-progressbar (1.8.1)
41
- unicode-display_width (1.3.0)
51
+ unicode-display_width (>= 1.4.0, < 2.0)
52
+ rubocop-ast (0.3.0)
53
+ parser (>= 2.7.1.4)
54
+ ruby-next-core (0.9.2)
55
+ ruby-progressbar (1.10.1)
56
+ unicode-display_width (1.7.0)
57
+ websocket (1.2.8)
42
58
 
43
59
  PLATFORMS
44
60
  ruby
45
61
 
46
62
  DEPENDENCIES
47
- bundler (~> 1.14)
63
+ bundler
48
64
  byebug
49
- rake (~> 10.0)
65
+ rake
50
66
  rspec
51
67
  rubocop
52
68
  rubrowser!
53
69
 
54
70
  BUNDLED WITH
55
- 1.16.1
71
+ 2.1.4
@@ -12,20 +12,34 @@ options = {
12
12
  }
13
13
 
14
14
  OptionParser.new do |opts|
15
- opts.banner = "Usage: #{__FILE__} [options] [file] ..."
16
-
17
- opts.on('-oFILE', '--output=FILE', 'output file page, if not specified output will be written to stdout') do |output|
18
- options[:output] = output
19
- end
20
-
21
- opts.on('-lFILE', '--layout=FILE', 'layout file to apply on the resulting graph') do |layout|
22
- options[:layout] = layout
23
- end
15
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] [file] ..."
16
+
17
+ opts.on(
18
+ '-oFILE',
19
+ '--output=FILE',
20
+ 'output file page, if not specified output will be written to stdout'
21
+ ) { |output| options[:output] = output }
22
+
23
+ opts.on(
24
+ '-lFILE',
25
+ '--layout=FILE',
26
+ 'layout file to apply on the resulting graph'
27
+ ) { |layout| options[:layout] = layout }
28
+
29
+ opts.on(
30
+ '-sSERVER:PORT',
31
+ '--server=SERVER:PORT',
32
+ 'rubrowser server for execution monitoring'
33
+ ) { |server| options[:server] = server }
24
34
 
25
35
  opts.on('-T', '--no-toolbox', 'Don\'t display toolbox on the page') do
26
36
  options[:toolbox] = false
27
37
  end
28
38
 
39
+ opts.on('-j', '--json', 'Do export data as JSON instead of HTML') do
40
+ options[:json] = true
41
+ end
42
+
29
43
  opts.on('-v', '--version', 'Print Rubrowser version') do
30
44
  puts "Rubrowser #{Rubrowser::VERSION}"
31
45
  exit
@@ -1,4 +1,5 @@
1
1
  require 'rubrowser/version'
2
+ require 'rubrowser/monitor'
2
3
 
3
4
  module Rubrowser
4
5
  end
@@ -0,0 +1,9 @@
1
+ module Rubrowser
2
+ class Channel < LiteCable::Channel::Base
3
+ identifier :classes
4
+
5
+ def subscribed
6
+ stream_from 'classes'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ require 'rubrowser/channel'
2
+
3
+ module Rubrowser
4
+ class Connection < LiteCable::Connection::Base
5
+ identified_by :id
6
+
7
+ def connect
8
+ @id = rand(100_000)
9
+ self.class.initiate_reader
10
+ end
11
+
12
+ def self.initiate_reader
13
+ @reader ||= Thread.new do
14
+ $rd.each_line do |line|
15
+ LiteCable.broadcast('classes', message: line.strip)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubrowser/trace'
2
+ require 'rubrowser/server'
3
+
4
+ module Rubrowser
5
+ module Monitor
6
+ module_function
7
+
8
+ def run(path: '', port: 8080)
9
+ $rd, $wr = IO.pipe
10
+
11
+ if fork
12
+ $rd.close
13
+ Trace.new(path: path).run
14
+ else
15
+ $wr.close
16
+ Server.new(port: port).run
17
+ exit
18
+ end
19
+ end
20
+ end
21
+ end
@@ -12,20 +12,26 @@ module Rubrowser
12
12
  end
13
13
 
14
14
  def call
15
- output.write(erb(:index))
15
+ if @json
16
+ output.write(data)
17
+ else
18
+ output.write(erb(:index))
19
+ end
16
20
  end
17
21
 
18
22
  private
19
23
 
20
24
  include ERB::Util
21
25
 
22
- attr_reader :files, :output
26
+ attr_reader :files, :output, :server
23
27
 
24
28
  def initialize(options)
25
29
  @output = output_file(options[:output])
26
30
  @layout = options[:layout]
31
+ @server = options[:server]
27
32
  @files = options[:files]
28
33
  @toolbox = options[:toolbox]
34
+ @json = !!options[:json]
29
35
  end
30
36
 
31
37
  def output_file(path)
@@ -0,0 +1,43 @@
1
+ require 'lite_cable'
2
+ require 'lite_cable/server'
3
+ require 'puma/configuration'
4
+ require 'puma/launcher'
5
+ require 'rubrowser/connection'
6
+
7
+ module Rubrowser
8
+ class Server
9
+ def initialize(port: 8080)
10
+ @port = port
11
+ end
12
+
13
+ def run
14
+ launcher.run
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :port
20
+
21
+ def launcher
22
+ @launcher ||= Puma::Launcher.new(conf)
23
+ end
24
+
25
+ def conf
26
+ @conf ||= Puma::Configuration.new do |user_config|
27
+ user_config.threads(1, 1)
28
+ user_config.workers 1
29
+ user_config.port port
30
+ user_config.app(rack_app)
31
+ end
32
+ end
33
+
34
+ def rack_app
35
+ @app ||= Rack::Builder.new do
36
+ map '/' do
37
+ use LiteCable::Server::Middleware, connection_class: Connection
38
+ run(proc { |_| [200, { 'Content-Type' => 'text/plain' }, ['OK']] })
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module Rubrowser
2
+ class Trace
3
+ def initialize(path: '')
4
+ @path = path
5
+ end
6
+
7
+ def run
8
+ trace_point.enable
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :path
14
+
15
+ def trace_point
16
+ @trace_point ||= TracePoint.new(:call) do |tp|
17
+ $wr.puts tp.defined_class if tp.path.start_with?(path)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Rubrowser
2
- VERSION = '2.5.0'.freeze
2
+ VERSION = '2.9.0'.freeze
3
3
  end
@@ -4,18 +4,19 @@ html, body, .dependency_graph, .dependency_graph svg{
4
4
  padding: 0px;
5
5
  margin: 0px;
6
6
  font-size: 13px;
7
+ overflow: hidden;
7
8
  }
8
9
 
9
10
  .link {
10
- fill: none;
11
- stroke: #666;
12
- stroke-width: 1.5px;
11
+ fill: none;
12
+ stroke: #666;
13
+ stroke-width: 1.5px;
13
14
  }
14
15
 
15
16
  circle {
16
- fill: #fff;
17
- stroke: #333;
18
- stroke-width: 1.5px;
17
+ fill: #fff;
18
+ stroke: #333;
19
+ stroke-width: 1.5px;
19
20
  }
20
21
 
21
22
  .circular {
@@ -23,13 +24,13 @@ circle {
23
24
  }
24
25
 
25
26
  .fixed circle {
26
- stroke-width: 3px;
27
+ stroke-width: 3px;
27
28
  }
28
29
 
29
30
  text {
30
- font: 10px sans-serif;
31
- pointer-events: none;
32
- text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
31
+ font: 10px sans-serif;
32
+ pointer-events: none;
33
+ text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
33
34
  }
34
35
 
35
36
  text.type{
@@ -44,6 +45,11 @@ text.type{
44
45
  display: none;
45
46
  }
46
47
 
48
+ .running circle{
49
+ stroke: #18b738;
50
+ fill: #7dea93;
51
+ }
52
+
47
53
  .highlighted,
48
54
  .highlighted_by_namespace,
49
55
  .highlighted_by_path,
@@ -83,3 +89,24 @@ ul, ol{
83
89
  padding-left: 0px;
84
90
  overflow: auto;
85
91
  }
92
+
93
+ #information_panel{
94
+ position: fixed;
95
+ bottom: 0px;
96
+ left: 0px;
97
+ height: 5rem;
98
+ background: rgba(255,255,255,0.8);
99
+ width: 100%;
100
+ margin-left: 250px;
101
+ padding-right: 250px;
102
+ }
103
+
104
+ #information_panel div{
105
+ margin: 1rem;
106
+ display: inline-block;
107
+ }
108
+
109
+ #information_panel:hover{
110
+ height: 33%;
111
+ overflow: auto;
112
+ }
@@ -0,0 +1,613 @@
1
+ (function() {
2
+ var slice = [].slice;
3
+
4
+ this.ActionCable = {
5
+ INTERNAL: {
6
+ "message_types": {
7
+ "welcome": "welcome",
8
+ "ping": "ping",
9
+ "confirmation": "confirm_subscription",
10
+ "rejection": "reject_subscription"
11
+ },
12
+ "default_mount_path": "/cable",
13
+ "protocols": ["actioncable-v1-json", "actioncable-unsupported"]
14
+ },
15
+ WebSocket: window.WebSocket,
16
+ logger: window.console,
17
+ createConsumer: function(url) {
18
+ var ref;
19
+ if (url == null) {
20
+ url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path;
21
+ }
22
+ return new ActionCable.Consumer(this.createWebSocketURL(url));
23
+ },
24
+ getConfig: function(name) {
25
+ var element;
26
+ element = document.head.querySelector("meta[name='action-cable-" + name + "']");
27
+ return element != null ? element.getAttribute("content") : void 0;
28
+ },
29
+ createWebSocketURL: function(url) {
30
+ var a;
31
+ if (url && !/^wss?:/i.test(url)) {
32
+ a = document.createElement("a");
33
+ a.href = url;
34
+ a.href = a.href;
35
+ a.protocol = a.protocol.replace("http", "ws");
36
+ return a.href;
37
+ } else {
38
+ return url;
39
+ }
40
+ },
41
+ startDebugging: function() {
42
+ return this.debugging = true;
43
+ },
44
+ stopDebugging: function() {
45
+ return this.debugging = null;
46
+ },
47
+ log: function() {
48
+ var messages, ref;
49
+ messages = 1 <= arguments.length ? slice.call(arguments, 0) : [];
50
+ if (this.debugging) {
51
+ messages.push(Date.now());
52
+ return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages)));
53
+ }
54
+ }
55
+ };
56
+
57
+ }).call(this);
58
+ (function() {
59
+ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
60
+
61
+ ActionCable.ConnectionMonitor = (function() {
62
+ var clamp, now, secondsSince;
63
+
64
+ ConnectionMonitor.pollInterval = {
65
+ min: 3,
66
+ max: 30
67
+ };
68
+
69
+ ConnectionMonitor.staleThreshold = 6;
70
+
71
+ function ConnectionMonitor(connection) {
72
+ this.connection = connection;
73
+ this.visibilityDidChange = bind(this.visibilityDidChange, this);
74
+ this.reconnectAttempts = 0;
75
+ }
76
+
77
+ ConnectionMonitor.prototype.start = function() {
78
+ if (!this.isRunning()) {
79
+ this.startedAt = now();
80
+ delete this.stoppedAt;
81
+ this.startPolling();
82
+ document.addEventListener("visibilitychange", this.visibilityDidChange);
83
+ return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms");
84
+ }
85
+ };
86
+
87
+ ConnectionMonitor.prototype.stop = function() {
88
+ if (this.isRunning()) {
89
+ this.stoppedAt = now();
90
+ this.stopPolling();
91
+ document.removeEventListener("visibilitychange", this.visibilityDidChange);
92
+ return ActionCable.log("ConnectionMonitor stopped");
93
+ }
94
+ };
95
+
96
+ ConnectionMonitor.prototype.isRunning = function() {
97
+ return (this.startedAt != null) && (this.stoppedAt == null);
98
+ };
99
+
100
+ ConnectionMonitor.prototype.recordPing = function() {
101
+ return this.pingedAt = now();
102
+ };
103
+
104
+ ConnectionMonitor.prototype.recordConnect = function() {
105
+ this.reconnectAttempts = 0;
106
+ this.recordPing();
107
+ delete this.disconnectedAt;
108
+ return ActionCable.log("ConnectionMonitor recorded connect");
109
+ };
110
+
111
+ ConnectionMonitor.prototype.recordDisconnect = function() {
112
+ this.disconnectedAt = now();
113
+ return ActionCable.log("ConnectionMonitor recorded disconnect");
114
+ };
115
+
116
+ ConnectionMonitor.prototype.startPolling = function() {
117
+ this.stopPolling();
118
+ return this.poll();
119
+ };
120
+
121
+ ConnectionMonitor.prototype.stopPolling = function() {
122
+ return clearTimeout(this.pollTimeout);
123
+ };
124
+
125
+ ConnectionMonitor.prototype.poll = function() {
126
+ return this.pollTimeout = setTimeout((function(_this) {
127
+ return function() {
128
+ _this.reconnectIfStale();
129
+ return _this.poll();
130
+ };
131
+ })(this), this.getPollInterval());
132
+ };
133
+
134
+ ConnectionMonitor.prototype.getPollInterval = function() {
135
+ var interval, max, min, ref;
136
+ ref = this.constructor.pollInterval, min = ref.min, max = ref.max;
137
+ interval = 5 * Math.log(this.reconnectAttempts + 1);
138
+ return Math.round(clamp(interval, min, max) * 1000);
139
+ };
140
+
141
+ ConnectionMonitor.prototype.reconnectIfStale = function() {
142
+ if (this.connectionIsStale()) {
143
+ ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s");
144
+ this.reconnectAttempts++;
145
+ if (this.disconnectedRecently()) {
146
+ return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect");
147
+ } else {
148
+ ActionCable.log("ConnectionMonitor reopening");
149
+ return this.connection.reopen();
150
+ }
151
+ }
152
+ };
153
+
154
+ ConnectionMonitor.prototype.connectionIsStale = function() {
155
+ var ref;
156
+ return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold;
157
+ };
158
+
159
+ ConnectionMonitor.prototype.disconnectedRecently = function() {
160
+ return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;
161
+ };
162
+
163
+ ConnectionMonitor.prototype.visibilityDidChange = function() {
164
+ if (document.visibilityState === "visible") {
165
+ return setTimeout((function(_this) {
166
+ return function() {
167
+ if (_this.connectionIsStale() || !_this.connection.isOpen()) {
168
+ ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState);
169
+ return _this.connection.reopen();
170
+ }
171
+ };
172
+ })(this), 200);
173
+ }
174
+ };
175
+
176
+ now = function() {
177
+ return new Date().getTime();
178
+ };
179
+
180
+ secondsSince = function(time) {
181
+ return (now() - time) / 1000;
182
+ };
183
+
184
+ clamp = function(number, min, max) {
185
+ return Math.max(min, Math.min(max, number));
186
+ };
187
+
188
+ return ConnectionMonitor;
189
+
190
+ })();
191
+
192
+ }).call(this);
193
+ (function() {
194
+ var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol,
195
+ slice = [].slice,
196
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
197
+ indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
198
+
199
+ ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols;
200
+
201
+ supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++];
202
+
203
+ ActionCable.Connection = (function() {
204
+ Connection.reopenDelay = 500;
205
+
206
+ function Connection(consumer) {
207
+ this.consumer = consumer;
208
+ this.open = bind(this.open, this);
209
+ this.subscriptions = this.consumer.subscriptions;
210
+ this.monitor = new ActionCable.ConnectionMonitor(this);
211
+ this.disconnected = true;
212
+ }
213
+
214
+ Connection.prototype.send = function(data) {
215
+ if (this.isOpen()) {
216
+ this.webSocket.send(JSON.stringify(data));
217
+ return true;
218
+ } else {
219
+ return false;
220
+ }
221
+ };
222
+
223
+ Connection.prototype.open = function() {
224
+ if (this.isActive()) {
225
+ ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState()));
226
+ return false;
227
+ } else {
228
+ ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols);
229
+ if (this.webSocket != null) {
230
+ this.uninstallEventHandlers();
231
+ }
232
+ this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols);
233
+ this.installEventHandlers();
234
+ this.monitor.start();
235
+ return true;
236
+ }
237
+ };
238
+
239
+ Connection.prototype.close = function(arg) {
240
+ var allowReconnect, ref1;
241
+ allowReconnect = (arg != null ? arg : {
242
+ allowReconnect: true
243
+ }).allowReconnect;
244
+ if (!allowReconnect) {
245
+ this.monitor.stop();
246
+ }
247
+ if (this.isActive()) {
248
+ return (ref1 = this.webSocket) != null ? ref1.close() : void 0;
249
+ }
250
+ };
251
+
252
+ Connection.prototype.reopen = function() {
253
+ var error;
254
+ ActionCable.log("Reopening WebSocket, current state is " + (this.getState()));
255
+ if (this.isActive()) {
256
+ try {
257
+ return this.close();
258
+ } catch (error1) {
259
+ error = error1;
260
+ return ActionCable.log("Failed to reopen WebSocket", error);
261
+ } finally {
262
+ ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms");
263
+ setTimeout(this.open, this.constructor.reopenDelay);
264
+ }
265
+ } else {
266
+ return this.open();
267
+ }
268
+ };
269
+
270
+ Connection.prototype.getProtocol = function() {
271
+ var ref1;
272
+ return (ref1 = this.webSocket) != null ? ref1.protocol : void 0;
273
+ };
274
+
275
+ Connection.prototype.isOpen = function() {
276
+ return this.isState("open");
277
+ };
278
+
279
+ Connection.prototype.isActive = function() {
280
+ return this.isState("open", "connecting");
281
+ };
282
+
283
+ Connection.prototype.isProtocolSupported = function() {
284
+ var ref1;
285
+ return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0;
286
+ };
287
+
288
+ Connection.prototype.isState = function() {
289
+ var ref1, states;
290
+ states = 1 <= arguments.length ? slice.call(arguments, 0) : [];
291
+ return ref1 = this.getState(), indexOf.call(states, ref1) >= 0;
292
+ };
293
+
294
+ Connection.prototype.getState = function() {
295
+ var ref1, state, value;
296
+ for (state in WebSocket) {
297
+ value = WebSocket[state];
298
+ if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) {
299
+ return state.toLowerCase();
300
+ }
301
+ }
302
+ return null;
303
+ };
304
+
305
+ Connection.prototype.installEventHandlers = function() {
306
+ var eventName, handler;
307
+ for (eventName in this.events) {
308
+ handler = this.events[eventName].bind(this);
309
+ this.webSocket["on" + eventName] = handler;
310
+ }
311
+ };
312
+
313
+ Connection.prototype.uninstallEventHandlers = function() {
314
+ var eventName;
315
+ for (eventName in this.events) {
316
+ this.webSocket["on" + eventName] = function() {};
317
+ }
318
+ };
319
+
320
+ Connection.prototype.events = {
321
+ message: function(event) {
322
+ var identifier, message, ref1, type;
323
+ if (!this.isProtocolSupported()) {
324
+ return;
325
+ }
326
+ ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type;
327
+ switch (type) {
328
+ case message_types.welcome:
329
+ this.monitor.recordConnect();
330
+ return this.subscriptions.reload();
331
+ case message_types.ping:
332
+ return this.monitor.recordPing();
333
+ case message_types.confirmation:
334
+ return this.subscriptions.notify(identifier, "connected");
335
+ case message_types.rejection:
336
+ return this.subscriptions.reject(identifier);
337
+ default:
338
+ return this.subscriptions.notify(identifier, "received", message);
339
+ }
340
+ },
341
+ open: function() {
342
+ ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol");
343
+ this.disconnected = false;
344
+ if (!this.isProtocolSupported()) {
345
+ ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.");
346
+ return this.close({
347
+ allowReconnect: false
348
+ });
349
+ }
350
+ },
351
+ close: function(event) {
352
+ ActionCable.log("WebSocket onclose event");
353
+ if (this.disconnected) {
354
+ return;
355
+ }
356
+ this.disconnected = true;
357
+ this.monitor.recordDisconnect();
358
+ return this.subscriptions.notifyAll("disconnected", {
359
+ willAttemptReconnect: this.monitor.isRunning()
360
+ });
361
+ },
362
+ error: function() {
363
+ return ActionCable.log("WebSocket onerror event");
364
+ }
365
+ };
366
+
367
+ return Connection;
368
+
369
+ })();
370
+
371
+ }).call(this);
372
+ (function() {
373
+ var slice = [].slice;
374
+
375
+ ActionCable.Subscriptions = (function() {
376
+ function Subscriptions(consumer) {
377
+ this.consumer = consumer;
378
+ this.subscriptions = [];
379
+ }
380
+
381
+ Subscriptions.prototype.create = function(channelName, mixin) {
382
+ var channel, params, subscription;
383
+ channel = channelName;
384
+ params = typeof channel === "object" ? channel : {
385
+ channel: channel
386
+ };
387
+ subscription = new ActionCable.Subscription(this.consumer, params, mixin);
388
+ return this.add(subscription);
389
+ };
390
+
391
+ Subscriptions.prototype.add = function(subscription) {
392
+ this.subscriptions.push(subscription);
393
+ this.consumer.ensureActiveConnection();
394
+ this.notify(subscription, "initialized");
395
+ this.sendCommand(subscription, "subscribe");
396
+ return subscription;
397
+ };
398
+
399
+ Subscriptions.prototype.remove = function(subscription) {
400
+ this.forget(subscription);
401
+ if (!this.findAll(subscription.identifier).length) {
402
+ this.sendCommand(subscription, "unsubscribe");
403
+ }
404
+ return subscription;
405
+ };
406
+
407
+ Subscriptions.prototype.reject = function(identifier) {
408
+ var i, len, ref, results, subscription;
409
+ ref = this.findAll(identifier);
410
+ results = [];
411
+ for (i = 0, len = ref.length; i < len; i++) {
412
+ subscription = ref[i];
413
+ this.forget(subscription);
414
+ this.notify(subscription, "rejected");
415
+ results.push(subscription);
416
+ }
417
+ return results;
418
+ };
419
+
420
+ Subscriptions.prototype.forget = function(subscription) {
421
+ var s;
422
+ this.subscriptions = (function() {
423
+ var i, len, ref, results;
424
+ ref = this.subscriptions;
425
+ results = [];
426
+ for (i = 0, len = ref.length; i < len; i++) {
427
+ s = ref[i];
428
+ if (s !== subscription) {
429
+ results.push(s);
430
+ }
431
+ }
432
+ return results;
433
+ }).call(this);
434
+ return subscription;
435
+ };
436
+
437
+ Subscriptions.prototype.findAll = function(identifier) {
438
+ var i, len, ref, results, s;
439
+ ref = this.subscriptions;
440
+ results = [];
441
+ for (i = 0, len = ref.length; i < len; i++) {
442
+ s = ref[i];
443
+ if (s.identifier === identifier) {
444
+ results.push(s);
445
+ }
446
+ }
447
+ return results;
448
+ };
449
+
450
+ Subscriptions.prototype.reload = function() {
451
+ var i, len, ref, results, subscription;
452
+ ref = this.subscriptions;
453
+ results = [];
454
+ for (i = 0, len = ref.length; i < len; i++) {
455
+ subscription = ref[i];
456
+ results.push(this.sendCommand(subscription, "subscribe"));
457
+ }
458
+ return results;
459
+ };
460
+
461
+ Subscriptions.prototype.notifyAll = function() {
462
+ var args, callbackName, i, len, ref, results, subscription;
463
+ callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
464
+ ref = this.subscriptions;
465
+ results = [];
466
+ for (i = 0, len = ref.length; i < len; i++) {
467
+ subscription = ref[i];
468
+ results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args))));
469
+ }
470
+ return results;
471
+ };
472
+
473
+ Subscriptions.prototype.notify = function() {
474
+ var args, callbackName, i, len, results, subscription, subscriptions;
475
+ subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
476
+ if (typeof subscription === "string") {
477
+ subscriptions = this.findAll(subscription);
478
+ } else {
479
+ subscriptions = [subscription];
480
+ }
481
+ results = [];
482
+ for (i = 0, len = subscriptions.length; i < len; i++) {
483
+ subscription = subscriptions[i];
484
+ results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0);
485
+ }
486
+ return results;
487
+ };
488
+
489
+ Subscriptions.prototype.sendCommand = function(subscription, command) {
490
+ var identifier;
491
+ identifier = subscription.identifier;
492
+ return this.consumer.send({
493
+ command: command,
494
+ identifier: identifier
495
+ });
496
+ };
497
+
498
+ return Subscriptions;
499
+
500
+ })();
501
+
502
+ }).call(this);
503
+ (function() {
504
+ ActionCable.Subscription = (function() {
505
+ var extend;
506
+
507
+ function Subscription(consumer, params, mixin) {
508
+ this.consumer = consumer;
509
+ if (params == null) {
510
+ params = {};
511
+ }
512
+ this.identifier = JSON.stringify(params);
513
+ extend(this, mixin);
514
+ }
515
+
516
+ Subscription.prototype.perform = function(action, data) {
517
+ if (data == null) {
518
+ data = {};
519
+ }
520
+ data.action = action;
521
+ return this.send(data);
522
+ };
523
+
524
+ Subscription.prototype.send = function(data) {
525
+ return this.consumer.send({
526
+ command: "message",
527
+ identifier: this.identifier,
528
+ data: JSON.stringify(data)
529
+ });
530
+ };
531
+
532
+ Subscription.prototype.unsubscribe = function() {
533
+ return this.consumer.subscriptions.remove(this);
534
+ };
535
+
536
+ extend = function(object, properties) {
537
+ var key, value;
538
+ if (properties != null) {
539
+ for (key in properties) {
540
+ value = properties[key];
541
+ object[key] = value;
542
+ }
543
+ }
544
+ return object;
545
+ };
546
+
547
+ return Subscription;
548
+
549
+ })();
550
+
551
+ }).call(this);
552
+ (function() {
553
+ ActionCable.Consumer = (function() {
554
+ function Consumer(url) {
555
+ this.url = url;
556
+ this.subscriptions = new ActionCable.Subscriptions(this);
557
+ this.connection = new ActionCable.Connection(this);
558
+ }
559
+
560
+ Consumer.prototype.send = function(data) {
561
+ return this.connection.send(data);
562
+ };
563
+
564
+ Consumer.prototype.connect = function() {
565
+ return this.connection.open();
566
+ };
567
+
568
+ Consumer.prototype.disconnect = function() {
569
+ return this.connection.close({
570
+ allowReconnect: false
571
+ });
572
+ };
573
+
574
+ Consumer.prototype.ensureActiveConnection = function() {
575
+ if (!this.connection.isActive()) {
576
+ return this.connection.open();
577
+ }
578
+ };
579
+
580
+ return Consumer;
581
+
582
+ })();
583
+
584
+ }).call(this);
585
+
586
+ var glowing = {}
587
+ function glow(cls) {
588
+ if (!glowing[cls]) {
589
+ var node = rubrowser.node.filter(function(d){
590
+ return d.id == cls;
591
+ });
592
+
593
+ if (node.size() > 0){
594
+ node.classed("running", true);
595
+ glowing[cls] = true;
596
+ setTimeout(function(){
597
+ glowing[cls] = false;
598
+ node.classed("running", false);
599
+ }, 2000)
600
+ }
601
+ }
602
+ }
603
+
604
+ var cable = ActionCable.createConsumer(server)
605
+ cable.ensureActiveConnection()
606
+ var channel = cable.subscriptions.create(
607
+ "classes",
608
+ {
609
+ received: function(data){
610
+ glow(data.message);
611
+ }
612
+ }
613
+ )