fnordmetric 0.5.9 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -277,6 +277,23 @@ FnordMetric.namespace :myapp do
277
277
 
278
278
  end
279
279
 
280
+ FnordMetric.server_configuration = {
281
+ :redis_url => "redis://localhost:6379",
282
+ :redis_prefix => "fnordmetric",
283
+ :inbound_stream => ["0.0.0.0", "1339"],
284
+ :start_worker => true,
285
+ :print_stats => 3,
286
+
287
+ # events that aren't processed after 2 min get dropped
288
+ :event_queue_ttl => 120,
289
+
290
+ # event data is kept for one month
291
+ :event_data_ttl => 3600*24*30,
292
+
293
+ # session data is kept for one month
294
+ :session_data_ttl => 3600*24*30
295
+ }
296
+
280
297
  FnordMetric.standalone
281
298
  ```
282
299
 
@@ -288,6 +305,8 @@ Contributors
288
305
  + Marco Borromeo (http://github.com/mborromeo)
289
306
  + Leo Lou (http://github.com/l4u)
290
307
  + Andy Lindeman (http://github.com/alindeman)
308
+ + Jurriaan Pruis (http://github.com/jurriaan)
309
+ + Kacper Bielecki (http://github.com/kazjote)
291
310
 
292
311
  To contribute, please fork this repository, make your changes and run the specs, commit them to your github repository and send me a pull request.
293
312
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.9
1
+ 0.6.0
data/doc/ulm_stats.rb CHANGED
@@ -615,6 +615,24 @@ FnordMetric.namespace :ulm do
615
615
 
616
616
  end
617
617
 
618
+ FnordMetric.server_configuration = {
619
+ :redis_url => "redis://localhost:6379",
620
+ :redis_prefix => "fnordmetric",
621
+ :inbound_stream => ["0.0.0.0", "1337"],
622
+ :web_interface => ["0.0.0.0", "4242"],
623
+ :start_worker => true,
624
+ :print_stats => 3,
625
+
626
+ # events that aren't processed after 2 min get dropped
627
+ :event_queue_ttl => 120,
628
+
629
+ # event data is kept for one month
630
+ :event_data_ttl => 3600*24*30,
631
+
632
+ # session data is kept for one month
633
+ :session_data_ttl => 3600*24*30
634
+ }
635
+
618
636
  #task :setup do
619
637
  # @fm_opts = {:web_interface => ["0.0.0.0", "2323"]} if ENV['DEV']
620
638
  #end
data/fnordmetric.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "fnordmetric"
8
- s.version = "0.5.9"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Paul Asmuth"]
12
- s.date = "2012-01-04"
12
+ s.date = "2012-01-11"
13
13
  s.description = "FnordMetric is a Ruby Event-Tracking gem on steroids"
14
14
  s.email = "paul@paulasmuth.com"
15
15
  s.extra_rdoc_files = [
data/lib/fnordmetric.rb CHANGED
@@ -15,6 +15,10 @@ module FnordMetric
15
15
  def self.namespace(key=nil, &block)
16
16
  @@namespaces[key] = block
17
17
  end
18
+
19
+ def self.server_configuration=(configuration)
20
+ @@server_configuration = configuration
21
+ end
18
22
 
19
23
  def self.default_options(opts)
20
24
 
@@ -90,7 +94,8 @@ module FnordMetric
90
94
  puts(msg); exit!
91
95
  end
92
96
 
93
- def self.run(opts={})
97
+ def self.run
98
+ opts = (defined?(@@server_configuration) && @@server_configuration) || {}
94
99
  start_em(opts)
95
100
  rescue Exception => e
96
101
  log "!!! eventmachine died, restarting... #{e.message}"
@@ -97,6 +97,8 @@ class FnordMetric::App < Sinatra::Base
97
97
 
98
98
  events = if params[:type]
99
99
  current_namespace.events(:by_type, :type => params[:type])
100
+ elsif params[:session_key]
101
+ current_namespace.events(:by_session_key, :session_key => params[:session_key])
100
102
  else
101
103
  find_opts = { :limit => 100 }
102
104
  find_opts.merge!(:since => params[:since].to_i+1) if params[:since]
@@ -1,78 +1,86 @@
1
- class FnordMetric::Event
1
+ module FnordMetric
2
+ class Event
2
3
 
3
- attr_accessor :time, :type, :event_id
4
+ attr_accessor :time, :type, :event_id
4
5
 
5
- #def self.track!(event_type, event_data)
6
- #end
6
+ #def self.track!(event_type, event_data)
7
+ #end
7
8
 
8
- def self.all(opts)
9
- range_opts = { :withscores => true }
10
- range_opts.merge!(:limit => [0,opts[:limit]]) if opts[:limit]
11
- opts[:redis].zrevrangebyscore(
12
- "#{opts[:namespace_prefix]}-timeline",
13
- '+inf', opts[:since]||'0',
14
- range_opts
15
- ).in_groups_of(2).map do |event_id, ts|
16
- next if event_id.blank?
17
- find(event_id, opts).tap{ |e| e.time = ts }
9
+ def self.all(opts)
10
+ range_opts = { :withscores => true }
11
+ range_opts.merge!(:limit => [0,opts[:limit]]) if opts[:limit]
12
+ opts[:redis].zrevrangebyscore(
13
+ "#{opts[:namespace_prefix]}-timeline",
14
+ '+inf', opts[:since]||'0',
15
+ range_opts
16
+ ).in_groups_of(2).map do |event_id, ts|
17
+ next if event_id.blank?
18
+ find(event_id, opts).tap{ |e| e.time = ts }
19
+ end
18
20
  end
19
- end
20
21
 
21
- def self.by_type(_type, opts)
22
- opts[:redis].lrange(
23
- "#{opts[:namespace_prefix]}-type-#{_type}",
24
- 0, 200).map do |event_id|
25
- next if event_id.blank?
26
- find(event_id, opts).tap{ |e| }
22
+ def self.by_type(_type, opts)
23
+ opts[:redis].lrange(
24
+ "#{opts[:namespace_prefix]}-type-#{_type}",
25
+ 0, 200).map do |event_id|
26
+ next if event_id.blank?
27
+ find(event_id, opts).tap{ |e| }
28
+ end
27
29
  end
28
- end
29
30
 
30
- def self.find(event_id, opts)
31
- self.new(event_id, opts).tap do |event|
32
- event.fetch!
31
+ def self.by_session_key(_session_key, opts)
32
+ session = Session.find(_session_key, opts)
33
+ session.fetch_event_ids!(200).reject(&:blank?).map do |event_id|
34
+ find(event_id, opts)
35
+ end
33
36
  end
34
- end
35
37
 
36
- def initialize(event_id, opts)
37
- @opts = opts
38
- @event_id = event_id
39
- end
38
+ def self.find(event_id, opts)
39
+ self.new(event_id, opts).tap do |event|
40
+ event.fetch!
41
+ end
42
+ end
40
43
 
41
- def fetch!
42
- @data = JSON.parse(fetch_json).tap do |event|
43
- @type = event.delete("_type")
44
+ def initialize(event_id, opts)
45
+ @opts = opts
46
+ @event_id = event_id
44
47
  end
45
- end
46
48
 
47
- def fetch_json
48
- @opts[:redis].get(redis_key) || "{}"
49
- end
49
+ def fetch!
50
+ @data = JSON.parse(fetch_json).tap do |event|
51
+ @type = event.delete("_type")
52
+ end
53
+ end
50
54
 
51
- def redis_key
52
- [@opts[:redis_prefix], :event, @event_id].join("-")
53
- end
55
+ def fetch_json
56
+ @opts[:redis].get(redis_key) || "{}"
57
+ end
54
58
 
55
- def session_key
56
- @data["_session"] ? Digest::MD5.hexdigest(@data["_session"]) : nil
57
- end
59
+ def redis_key
60
+ [@opts[:redis_prefix], :event, @event_id].join("-")
61
+ end
58
62
 
59
- def id
60
- @event_id
61
- end
62
-
63
- def data(key=nil)
64
- key ? @data[key.to_s] : @data
65
- end
63
+ def session_key
64
+ @data["_session"] ? Digest::MD5.hexdigest(@data["_session"]) : nil
65
+ end
66
66
 
67
- alias :[] :data
67
+ def id
68
+ @event_id
69
+ end
70
+
71
+ def data(key=nil)
72
+ key ? @data[key.to_s] : @data
73
+ end
68
74
 
69
- def to_json
70
- @data.merge!(
71
- :_type => @type,
72
- :_session_key => session_key,
73
- :_eid => @event_id,
74
- :_time => @time
75
- )
76
- end
75
+ alias :[] :data
77
76
 
78
- end
77
+ def to_json
78
+ @data.merge!(
79
+ :_type => @type,
80
+ :_session_key => session_key,
81
+ :_eid => @event_id,
82
+ :_time => @time
83
+ )
84
+ end
85
+ end
86
+ end
@@ -1,3 +1,4 @@
1
+ require 'securerandom'
1
2
  class FnordMetric::InboundStream < EventMachine::Connection
2
3
 
3
4
  @@opts = nil
@@ -43,7 +44,7 @@ class FnordMetric::InboundStream < EventMachine::Connection
43
44
  end
44
45
 
45
46
  def get_next_uuid
46
- rand(9999999999999999999).to_s # FIXME
47
+ SecureRandom.uuid
47
48
  end
48
49
 
49
50
  def close_connection?
@@ -77,6 +77,7 @@ class FnordMetric::Namespace
77
77
  def events(_ids, opts={})
78
78
  return FnordMetric::Event.all(extend_opts(opts)) if _ids == :all
79
79
  return FnordMetric::Event.by_type(opts.delete(:type), extend_opts(opts)) if _ids == :by_type
80
+ return FnordMetric::Event.by_session_key(opts.delete(:session_key), extend_opts(opts)) if _ids == :by_session_key
80
81
  end
81
82
 
82
83
  def method_missing(m, *args, &block)
@@ -89,6 +89,7 @@ class FnordMetric::Session
89
89
 
90
90
  def add_event(event)
91
91
  @redis.zadd(redis_key(:events), event[:_time], event[:_eid])
92
+
92
93
  add_data(:_picture, event[:url]) if event[:_type] == "_set_picture"
93
94
  add_data(:_name, event[:name]) if event[:_type] == "_set_name"
94
95
  add_event_data(event) if event[:_type] == "_set_data"
@@ -125,7 +126,7 @@ class FnordMetric::Session
125
126
 
126
127
  def fetch_event_ids!(since=-1)
127
128
  # FIXME: use WITHSCORE to get the timestamps and return event objects
128
- @event_ids = @redis.zrange(redis_key(:events), 0, since)
129
+ @event_ids = @redis.zrevrange(redis_key(:events), 0, since)
129
130
  end
130
131
 
131
- end
132
+ end
data/pub/fnordmetric.css CHANGED
@@ -107,11 +107,14 @@ text-shadow: 1px 0px 2px rgba(255, 255, 255, 1);
107
107
 
108
108
 
109
109
  ul.session_list{ list-style-type:none; margin:0; padding:9px 16px 0 11px; }
110
- ul.session_list li{ color:#0A0A0A; margin-bottom:10px; height:18px; overflow:hidden; line-height:18px; padding:4px; }
110
+ ul.session_list li{ color:#0A0A0A; height:32px; overflow:hidden; line-height:18px; padding:4px; }
111
111
  ul.session_list li:hover{ background:#eee; cursor:pointer; }
112
+ ul.session_list li input{ float: left; margin-right: 7px; }
112
113
  ul.session_list li .picture{ height:18px; width:18px; float:left; background:#333; overflow:hidden; }
113
114
  ul.session_list li .name{ float:left; width:120px; overflow:hidden; margin-left:10px; font-size:12px; }
114
115
  ul.session_list li .time{ float:right; width:40px; overflow:hidden; text-align:right; font-size:10px; }
116
+ ul.session_list li .history{ float:right; color:#999; font-size:10px; line-height: 12px;}
117
+ ul.session_list li .history:hover{ color:#333; text-decoration:underline; }
115
118
 
116
119
  .sessions_feed{ min-width:300px; min-height:100px; float:left; }
117
120
  .sessions_feed ul.feed_inner{ margin:5px 15px; min-height:100px; padding:0px; }
@@ -139,4 +142,4 @@ ul.event_type_list li .history:hover{ color:#333; text-decoration:underline; }
139
142
  height: 0;
140
143
  }
141
144
 
142
- .highcharts-series circle{ stroke-width:1px; }
145
+ .highcharts-series circle{ stroke-width:1px; }
data/pub/fnordmetric.js CHANGED
@@ -78,9 +78,15 @@ var FnordMetric = (function(){
78
78
  }
79
79
  }
80
80
 
81
+ function formatPercentValue(value){
82
+ return value + '%';
83
+ }
84
+
81
85
  function formatGaugeValue(gauge_key, value){
82
86
  if(gauge_key.slice(0,8) === '__time__'){
83
87
  return formatTimeValue(value);
88
+ } else if(gauge_key.slice(0,11) === '__percent__'){
89
+ return formatPercentValue(value);
84
90
  } else {
85
91
  return formatValue(value);
86
92
  }
@@ -733,7 +739,7 @@ var FnordMetric = (function(){
733
739
  ).append(listElem);
734
740
 
735
741
  var eventsPolledUntil = false;
736
- var eventsFilter = [];
742
+ var eventsFilter = {uncheckedTypes: [], checkedSessions: []};
737
743
  var sessionData = {};
738
744
  var pollRunning = true;
739
745
 
@@ -771,10 +777,11 @@ var FnordMetric = (function(){
771
777
  });
772
778
  };
773
779
 
774
- function loadEventHistory(event_type){
780
+ function loadEventHistory(params){
775
781
  feedInnerElem.html('');
776
782
  $.ajax({
777
- url: FnordMetric.p + '/' + currentNamespace+'/events?type='+event_type,
783
+ url: FnordMetric.p + '/' + currentNamespace+'/events',
784
+ data: params,
778
785
  success: function(_data, _status){
779
786
  var data = JSON.parse(_data).events;
780
787
  for(var n=data.length; n >= 0; n--){
@@ -807,14 +814,19 @@ var FnordMetric = (function(){
807
814
  });
808
815
  };
809
816
 
817
+ function setCheckboxesCheckedState(types_state, sessions_state) {
818
+ $('.event_type_list .event_type input').attr('checked', types_state);
819
+ $('.session_list .session input').attr('checked', sessions_state);
820
+ }
821
+
810
822
  function addEventType(type, display){
811
823
  typeListElem.append(
812
824
  $('<li class="event_type"></li>').append(
813
825
  $('<span class="history"></span>').html('history')
814
826
  .click(function(){
815
- $('.event_type_list .event_type input').attr('checked', false);
827
+ setCheckboxesCheckedState(true, true);
816
828
  $('input', $(this).parent()).attr('checked', true);
817
- updateEventFilter(); loadEventHistory(type);
829
+ updateEventFilter(); loadEventHistory({type: type});
818
830
  })
819
831
  ).append(
820
832
  $('<input type="checkbox" />').attr('checked', true)
@@ -832,7 +844,15 @@ var FnordMetric = (function(){
832
844
  _unchecked_types.push($(v).attr('rel'));
833
845
  }
834
846
  });
835
- eventsFilter = _unchecked_types;
847
+ eventsFilter.uncheckedTypes = _unchecked_types;
848
+
849
+ var _checked_sessions = [];
850
+ $('ul.session_list li.session').each(function(i,v){
851
+ if($('input', v).attr('checked')){
852
+ _checked_sessions.push($(v).data().session);
853
+ }
854
+ });
855
+ eventsFilter.checkedSessions = _checked_sessions;
836
856
  }
837
857
 
838
858
  function doEventsPoll(){
@@ -848,18 +868,40 @@ var FnordMetric = (function(){
848
868
  return (function(_data, _status){
849
869
  var data = JSON.parse(_data)
850
870
  var events = data.events;
851
- var timout = 1000;
871
+ var timeout = 1000;
852
872
  var maxevents = 200;
873
+ var passesFiltering = function(event_data) {
874
+ var passes_type_filtering = false;
875
+ var passes_session_filtering = false;
876
+ if(eventsFilter.uncheckedTypes.indexOf(event_data._type) == -1) {
877
+ if(parseInt(v._time)<=eventsPolledUntil) {
878
+ passes_type_filtering = true;
879
+ }
880
+ }
881
+ if(!passes_type_filtering) return false;
882
+
883
+ if(eventsFilter.checkedSessions.length == 0){
884
+ return true; // No filter set - show all events
885
+ } else {
886
+ if(event_data._session_key){
887
+ if(eventsFilter.checkedSessions.indexOf(event_data._session_key) >= 0){
888
+ return true; // Filter set and match
889
+ } else {
890
+ return false; // Filter set but no match
891
+ }
892
+ } else {
893
+ return false; // Filter set but event is not associated with session
894
+ }
895
+ }
896
+ }
897
+
853
898
  if(events.length > 0){
854
- timeout = 200;
855
899
  eventsPolledUntil = parseInt(events[0]._time)-1;
856
900
  }
857
901
  for(var n=events.length-1; n >= 0; n--){
858
902
  var v = events[n];
859
- if(eventsFilter.indexOf(v._type) == -1){
860
- if(parseInt(v._time)<=eventsPolledUntil){
861
- renderEvent(v);
862
- }
903
+ if(passesFiltering(v)) {
904
+ renderEvent(v);
863
905
  }
864
906
  };
865
907
  var elems = $("p", feedInnerElem);
@@ -867,13 +909,17 @@ var FnordMetric = (function(){
867
909
  $(elems[n]).remove();
868
910
  }
869
911
  if(pollRunning){
870
- window.setTimeout(doEventsPoll(), timout);
912
+ window.setTimeout(doEventsPoll(), timeout);
871
913
  }
872
914
  });
873
915
  };
874
916
 
875
917
  function updateSession(session_data){
876
- sessionData[session_data.session_key] = session_data;
918
+ var session_key = session_data.session_key;
919
+ if(!sessionData[session_key]){
920
+ updateEventFilter()
921
+ }
922
+ sessionData[session_key] = session_data;
877
923
  renderSession(session_data);
878
924
  }
879
925
 
@@ -913,11 +959,20 @@ var FnordMetric = (function(){
913
959
 
914
960
  listElem.append(
915
961
  $('<li class="session"></li>').append(
962
+ $('<input type="checkbox" />').click(function(){ updateEventFilter(); })
963
+ ).append(
916
964
  $('<div class="picture"></div>').html(session_picture)
917
965
  ).append(
918
966
  $('<span class="name"></span>').html(session_name)
919
967
  ).append(
920
968
  $('<span class="time"></span>').html(session_time)
969
+ ).append(
970
+ $('<span class="history"></span>').html('history')
971
+ .click(function(){
972
+ setCheckboxesCheckedState(true, false);
973
+ $('input', $(this).parent()).attr('checked', true);
974
+ updateEventFilter(); loadEventHistory({session_key: session_data["session_key"]});
975
+ })
921
976
  ).attr('data-session', session_data["session_key"])
922
977
  );
923
978
 
data/spec/app_spec.rb CHANGED
@@ -334,6 +334,38 @@ describe "app" do
334
334
  JSON.parse(last_response.body)["events"].length.should == 1
335
335
  end
336
336
 
337
+ it "should render all events for a single session key" do
338
+ @namespace.ready!(@redis_wrap).announce(
339
+ :_time => @now,
340
+ :_session => "max_session",
341
+ :_eid => "124234"
342
+ )
343
+ @namespace.ready!(@redis_wrap).announce(
344
+ :_time => @now,
345
+ :_session => "kate_session",
346
+ :_eid => "12235234"
347
+ )
348
+ @namespace.ready!(@redis_wrap).announce(
349
+ :_time => @now,
350
+ :_session => "kate_session",
351
+ :_eid => "124234234"
352
+ )
353
+ @namespace.ready!(@redis_wrap).announce(
354
+ :_time => @now,
355
+ :_eid => "124234234"
356
+ )
357
+ max_session_key = Digest::MD5.hexdigest "max_session"
358
+ kate_session_key = Digest::MD5.hexdigest "kate_session"
359
+
360
+ get "/foospace/events?session_key=#{max_session_key}"
361
+ events = JSON.parse(last_response.body)["events"]
362
+ events.length.should == 1
363
+
364
+ get "/foospace/events?session_key=#{kate_session_key}"
365
+ events = JSON.parse(last_response.body)["events"]
366
+ events.length.should == 2
367
+ end
368
+
337
369
  it "should render a list of event types" do
338
370
  @namespace.ready!(@redis_wrap).announce(
339
371
  :_type => "fn0rd",
@@ -449,4 +481,4 @@ describe "app" do
449
481
 
450
482
  end
451
483
 
452
- end
484
+ end
data/spec/event_spec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require ::File.expand_path('../spec_helper.rb', __FILE__)
2
+ require 'irb'
2
3
 
3
4
  describe FnordMetric::Event do
4
5
 
@@ -116,6 +117,48 @@ describe FnordMetric::Event do
116
117
  Event.by_type('f00bar', @opts).length.should == 1
117
118
  end
118
119
 
120
+ describe "looking by session_key" do
121
+ let(:namespace) do
122
+ options = {:redis_prefix => "fnordmetric-test", :session_data_ttl => 1}
123
+ Namespace.new(:ns123, options)
124
+ end
125
+
126
+ let(:events_data) do
127
+ [[1, "max_session"], [2, "kate_session"], [3, "kate_session"], [12345678, nil]]
128
+ end
129
+
130
+ let(:kate_session_key) { Digest::MD5.hexdigest "kate_session" }
131
+ let(:events) { Event.by_session_key kate_session_key, @opts }
132
+
133
+ before do
134
+ created_events_data.each do |(event_id, session)|
135
+ event_data = { :_time => @now + event_id, :_eid => event_id }
136
+ event_data[:_session] = session if session
137
+ namespace.ready!(@redis_wrap).announce event_data
138
+ end
139
+ end
140
+
141
+ context "when events are added in ascending time order" do
142
+ let(:created_events_data) { events_data }
143
+
144
+ it "should find correct events" do
145
+ ["2","3"].each {|id| events.map(&:id).should include(id) }
146
+ end
147
+
148
+ it "should have correct order" do
149
+ events.map(&:id).should == ["3","2"]
150
+ end
151
+ end
152
+
153
+ context "when events are added in descending time order" do
154
+ let(:created_events_data) { events_data.reverse }
155
+
156
+ it "should have correct order" do
157
+ events.map(&:id).should == ["3","2"]
158
+ end
159
+ end
160
+ end
161
+
119
162
  def create_event(event_id, event_data)
120
163
  @redis_wrap.zadd(@timeline, event_data.delete(:_time), event_id)
121
164
  @redis.set("fnordmetric-test-event-#{event_id}", event_data.to_json)
@@ -124,4 +167,4 @@ describe FnordMetric::Event do
124
167
  end
125
168
 
126
169
 
127
- end
170
+ end
data/spec/session_spec.rb CHANGED
@@ -212,8 +212,8 @@ describe FnordMetric::Session do
212
212
  @redis_wrap.zadd("#{@namespace}-session-#{sesshash}-events", @now, "fnord")
213
213
  sess = Session.find(sesshash, @opts)
214
214
  sess.fetch_event_ids!
215
- sess.event_ids[0].should == "fnord"
216
- sess.event_ids[1].should == "shmoo"
215
+ sess.event_ids.should include("shmoo")
216
+ sess.event_ids.should include("fnord")
217
217
  end
218
218
 
219
219
  def create_session(sesskey, sesstime, sessdata)
@@ -228,4 +228,4 @@ describe FnordMetric::Session do
228
228
  end
229
229
 
230
230
 
231
- end
231
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fnordmetric
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.9
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-04 00:00:00.000000000 Z
12
+ date: 2012-01-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bson_ext
16
- requirement: &70308910325440 !ruby/object:Gem::Requirement
16
+ requirement: &70186955498840 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.4.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70308910325440
24
+ version_requirements: *70186955498840
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sinatra
27
- requirement: &70308910324960 !ruby/object:Gem::Requirement
27
+ requirement: &70186955498360 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.2.6
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70308910324960
35
+ version_requirements: *70186955498360
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: redis
38
- requirement: &70308910324480 !ruby/object:Gem::Requirement
38
+ requirement: &70186955497820 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.2.2
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70308910324480
46
+ version_requirements: *70186955497820
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: eventmachine
49
- requirement: &70308910324000 !ruby/object:Gem::Requirement
49
+ requirement: &70186955497320 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70308910324000
57
+ version_requirements: *70186955497320
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: em-hiredis
60
- requirement: &70308910323480 !ruby/object:Gem::Requirement
60
+ requirement: &70186955496720 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70308910323480
68
+ version_requirements: *70186955496720
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: json
71
- requirement: &70308910322980 !ruby/object:Gem::Requirement
71
+ requirement: &70186955496080 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *70308910322980
79
+ version_requirements: *70186955496080
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: i18n
82
- requirement: &70308910322360 !ruby/object:Gem::Requirement
82
+ requirement: &70186955495200 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *70308910322360
90
+ version_requirements: *70186955495200
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: haml
93
- requirement: &70308910321760 !ruby/object:Gem::Requirement
93
+ requirement: &70186955494700 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *70308910321760
101
+ version_requirements: *70186955494700
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rack
104
- requirement: &70308910321100 !ruby/object:Gem::Requirement
104
+ requirement: &70186955494200 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :runtime
111
111
  prerelease: false
112
- version_requirements: *70308910321100
112
+ version_requirements: *70186955494200
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rack-test
115
- requirement: &70308910320340 !ruby/object:Gem::Requirement
115
+ requirement: &70186955490620 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :runtime
122
122
  prerelease: false
123
- version_requirements: *70308910320340
123
+ version_requirements: *70186955490620
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: yajl-ruby
126
- requirement: &70308910319860 !ruby/object:Gem::Requirement
126
+ requirement: &70186955490140 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: '0'
132
132
  type: :runtime
133
133
  prerelease: false
134
- version_requirements: *70308910319860
134
+ version_requirements: *70186955490140
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: thin
137
- requirement: &70308910319200 !ruby/object:Gem::Requirement
137
+ requirement: &70186955489620 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ! '>='
@@ -142,10 +142,10 @@ dependencies:
142
142
  version: '0'
143
143
  type: :runtime
144
144
  prerelease: false
145
- version_requirements: *70308910319200
145
+ version_requirements: *70186955489620
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: activesupport
148
- requirement: &70308910312620 !ruby/object:Gem::Requirement
148
+ requirement: &70186955489120 !ruby/object:Gem::Requirement
149
149
  none: false
150
150
  requirements:
151
151
  - - ! '>='
@@ -153,10 +153,10 @@ dependencies:
153
153
  version: '0'
154
154
  type: :runtime
155
155
  prerelease: false
156
- version_requirements: *70308910312620
156
+ version_requirements: *70186955489120
157
157
  - !ruby/object:Gem::Dependency
158
158
  name: delorean
159
- requirement: &70308910312100 !ruby/object:Gem::Requirement
159
+ requirement: &70186955488640 !ruby/object:Gem::Requirement
160
160
  none: false
161
161
  requirements:
162
162
  - - ! '>='
@@ -164,10 +164,10 @@ dependencies:
164
164
  version: '0'
165
165
  type: :development
166
166
  prerelease: false
167
- version_requirements: *70308910312100
167
+ version_requirements: *70186955488640
168
168
  - !ruby/object:Gem::Dependency
169
169
  name: rspec
170
- requirement: &70308910311600 !ruby/object:Gem::Requirement
170
+ requirement: &70186955488160 !ruby/object:Gem::Requirement
171
171
  none: false
172
172
  requirements:
173
173
  - - ~>
@@ -175,10 +175,10 @@ dependencies:
175
175
  version: 2.6.0
176
176
  type: :development
177
177
  prerelease: false
178
- version_requirements: *70308910311600
178
+ version_requirements: *70186955488160
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: shoulda
181
- requirement: &70308910311120 !ruby/object:Gem::Requirement
181
+ requirement: &70186955487680 !ruby/object:Gem::Requirement
182
182
  none: false
183
183
  requirements:
184
184
  - - ! '>='
@@ -186,10 +186,10 @@ dependencies:
186
186
  version: '0'
187
187
  type: :development
188
188
  prerelease: false
189
- version_requirements: *70308910311120
189
+ version_requirements: *70186955487680
190
190
  - !ruby/object:Gem::Dependency
191
191
  name: bundler
192
- requirement: &70308910310640 !ruby/object:Gem::Requirement
192
+ requirement: &70186955487140 !ruby/object:Gem::Requirement
193
193
  none: false
194
194
  requirements:
195
195
  - - ~>
@@ -197,10 +197,10 @@ dependencies:
197
197
  version: 1.0.0
198
198
  type: :development
199
199
  prerelease: false
200
- version_requirements: *70308910310640
200
+ version_requirements: *70186955487140
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: jeweler
203
- requirement: &70308910310160 !ruby/object:Gem::Requirement
203
+ requirement: &70186955486600 !ruby/object:Gem::Requirement
204
204
  none: false
205
205
  requirements:
206
206
  - - ~>
@@ -208,7 +208,7 @@ dependencies:
208
208
  version: 1.5.2
209
209
  type: :development
210
210
  prerelease: false
211
- version_requirements: *70308910310160
211
+ version_requirements: *70186955486600
212
212
  description: FnordMetric is a Ruby Event-Tracking gem on steroids
213
213
  email: paul@paulasmuth.com
214
214
  executables: []