wackamole 0.0.1
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.
- data/.bnsignore +16 -0
- data/.gitignore +2 -0
- data/History.txt +4 -0
- data/README.rdoc +88 -0
- data/Rakefile +42 -0
- data/aa.rb +25 -0
- data/aaa.txt +13 -0
- data/bin/wackamole +77 -0
- data/lib/app.rb +63 -0
- data/lib/controllers/dashboard.rb +30 -0
- data/lib/controllers/features.rb +41 -0
- data/lib/controllers/logs.rb +49 -0
- data/lib/controllers/mission.rb +27 -0
- data/lib/controllers/users.rb +41 -0
- data/lib/helpers/dashboard_helper.rb +32 -0
- data/lib/helpers/features_helper.rb +13 -0
- data/lib/helpers/flash_helper.rb +16 -0
- data/lib/helpers/logs_helper.rb +116 -0
- data/lib/helpers/main_helper.rb +182 -0
- data/lib/helpers/mission_helper.rb +59 -0
- data/lib/helpers/rails_helper.rb +7 -0
- data/lib/wackamole.rb +47 -0
- data/lib/wackamole/core_ext/date_time.rb +8 -0
- data/lib/wackamole/core_ext/time.rb +9 -0
- data/lib/wackamole/models/control.rb +132 -0
- data/lib/wackamole/models/feature.rb +74 -0
- data/lib/wackamole/models/log.rb +45 -0
- data/lib/wackamole/models/mission.rb +164 -0
- data/lib/wackamole/models/mole_info.rb +94 -0
- data/lib/wackamole/models/search_filter.rb +192 -0
- data/lib/wackamole/models/user.rb +46 -0
- data/public/favicon.ico +0 -0
- data/public/images/.DS_Store +0 -0
- data/public/images/browsers/.DS_Store +0 -0
- data/public/images/browsers/MSIE 6.png +0 -0
- data/public/images/browsers/MSIE 8.0 +0 -0
- data/public/images/browsers/MSIE 8.0.png +0 -0
- data/public/images/browsers/chrome.png +0 -0
- data/public/images/browsers/firefox.png +0 -0
- data/public/images/browsers/ie 6.0.png +0 -0
- data/public/images/browsers/ie6.jpg +0 -0
- data/public/images/browsers/ie7.jpg +0 -0
- data/public/images/browsers/ie7.png +0 -0
- data/public/images/browsers/msie 6.0.png +0 -0
- data/public/images/browsers/msie 7.0.png +0 -0
- data/public/images/browsers/opera.jpg +0 -0
- data/public/images/browsers/opera.png +0 -0
- data/public/images/browsers/safari.jpg +0 -0
- data/public/images/browsers/safari.png +0 -0
- data/public/images/browsers/unknown_browser.png +0 -0
- data/public/images/close.png +0 -0
- data/public/images/error.png +0 -0
- data/public/images/fade.png +0 -0
- data/public/images/fault_big.png +0 -0
- data/public/images/fault_small.png +0 -0
- data/public/images/feature.png +0 -0
- data/public/images/h300.png +0 -0
- data/public/images/hori_large.png +0 -0
- data/public/images/info_big.png +0 -0
- data/public/images/info_small.png +0 -0
- data/public/images/loading.gif +0 -0
- data/public/images/loading1.gif +0 -0
- data/public/images/mole_error.png +0 -0
- data/public/images/more.gif +0 -0
- data/public/images/next.png +0 -0
- data/public/images/perf_big.png +0 -0
- data/public/images/perf_small.png +0 -0
- data/public/images/powered_by.png +0 -0
- data/public/images/prev.png +0 -0
- data/public/images/row_fade.png +0 -0
- data/public/images/search.png +0 -0
- data/public/images/small_logo.png +0 -0
- data/public/images/spaceball.gif +0 -0
- data/public/images/tick.png +0 -0
- data/public/images/users.png +0 -0
- data/public/images/wackamole_logo.png +0 -0
- data/public/javascripts/.DS_Store +0 -0
- data/public/javascripts/application.js +28 -0
- data/public/javascripts/g.dot.min.js +7 -0
- data/public/javascripts/g.raphael.min.js +7 -0
- data/public/javascripts/jit.js +9052 -0
- data/public/javascripts/jit.min.js +1 -0
- data/public/javascripts/jquery-ui.js +188 -0
- data/public/javascripts/jquery.example.js +160 -0
- data/public/javascripts/jquery.js +19 -0
- data/public/javascripts/jquery.tools.min.js +38 -0
- data/public/javascripts/jquery_ba-url.js +9 -0
- data/public/javascripts/jquery_min.js +19 -0
- data/public/javascripts/jquery_ui_min.js +298 -0
- data/public/javascripts/raphael.min.js +7 -0
- data/public/stylesheets/tabs-slideshow.css +95 -0
- data/public/stylesheets/wackamole.css +684 -0
- data/spec/config/bogus_test.yml +3 -0
- data/spec/config/test.yml +3 -0
- data/spec/core_ext/date_time_spec.rb +8 -0
- data/spec/core_ext/time_spec.rb +12 -0
- data/spec/data/fixtures.rb +92 -0
- data/spec/models/control_spec.rb +98 -0
- data/spec/models/feature_spec.rb +52 -0
- data/spec/models/log_spec.rb +43 -0
- data/spec/models/mission_spec.rb +225 -0
- data/spec/models/moled_info_spec.rb +30 -0
- data/spec/models/search_filter_spec.rb +151 -0
- data/spec/models/user_spec.rb +44 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/wackamole_spec.rb +20 -0
- data/tasks/bones.rake +20 -0
- data/tasks/fixtures.rake +13 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +32 -0
- data/tasks/rdoc.rake +54 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +290 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +46 -0
- data/views/dashboard/_report.erb +118 -0
- data/views/dashboard/index.erb +4 -0
- data/views/dashboard/refresh_js.erb +3 -0
- data/views/features/_rows.erb +26 -0
- data/views/features/filter.js.erb +2 -0
- data/views/features/index.erb +24 -0
- data/views/features/index.js.erb +2 -0
- data/views/layout.erb +47 -0
- data/views/logs/_array.erb +12 -0
- data/views/logs/_hash.erb +14 -0
- data/views/logs/_rows.erb +65 -0
- data/views/logs/filter.js.erb +4 -0
- data/views/logs/index.erb +13 -0
- data/views/logs/index.js.erb +2 -0
- data/views/logs/show.erb +66 -0
- data/views/mission/_report.erb +49 -0
- data/views/mission/index.erb +7 -0
- data/views/mission/refresh_js.erb +3 -0
- data/views/shared/_filter.erb +63 -0
- data/views/shared/_flash.erb +3 -0
- data/views/shared/_search.erb +25 -0
- data/views/shared/_timestamp.erb +1 -0
- data/views/shared/_wait.erb +1 -0
- data/views/shared/flash.js.erb +10 -0
- data/views/users/_rows.erb +26 -0
- data/views/users/filter.js.erb +4 -0
- data/views/users/index.erb +24 -0
- data/views/users/index.js.erb +2 -0
- metadata +347 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
|
|
3
|
+
module Wackamole
|
|
4
|
+
class MoledInfo
|
|
5
|
+
|
|
6
|
+
def self.logs_cltn() Wackamole::Control.collection( 'logs' ) ; end
|
|
7
|
+
def self.users_cltn() Wackamole::Control.collection( 'users' ); end
|
|
8
|
+
def self.features_cltn() Wackamole::Control.collection( 'features' ); end
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# Collect various data points to power up dashboard
|
|
12
|
+
# TODO - PERF - try just using cursor vs to_a
|
|
13
|
+
def self.collect_dashboard_info( now )
|
|
14
|
+
info = {}
|
|
15
|
+
day_logs = logs_cltn.find( { :did => now.to_date_id.to_s }, :fields => [:typ, :fid, :tid, :did, :uid] ).to_a
|
|
16
|
+
|
|
17
|
+
# Fetch user count for this hour
|
|
18
|
+
users = day_logs.inject( Set.new ) do |set,log|
|
|
19
|
+
set << log['uid'] if log['tid'] =~ /^#{"%02d" % now.hour}/
|
|
20
|
+
set
|
|
21
|
+
end
|
|
22
|
+
info[:total_users] = users_cltn.count
|
|
23
|
+
info[:user_load] = users.size
|
|
24
|
+
|
|
25
|
+
# Fetch features for this hour
|
|
26
|
+
features = day_logs.inject( Set.new ) do |set,log|
|
|
27
|
+
set << log['fid'].to_s if log['tid'] =~ /^#{"%02d" % now.hour}/
|
|
28
|
+
set
|
|
29
|
+
end
|
|
30
|
+
info[:total_features] = features_cltn.count
|
|
31
|
+
info[:feature_load] = features.size
|
|
32
|
+
|
|
33
|
+
info[:perf_load] = day_logs.inject(0) do |count,log|
|
|
34
|
+
if log['tid'] =~ /^#{"%02d" % now.hour}/
|
|
35
|
+
count += (log['typ'] == Rackamole.perf ? 1 : 0 )
|
|
36
|
+
end
|
|
37
|
+
count
|
|
38
|
+
end
|
|
39
|
+
info[:fault_load] = day_logs.inject(0) do |count,log|
|
|
40
|
+
if log['tid'] =~ /^#{"%02d" % now.hour}/
|
|
41
|
+
count += (log['typ'] == Rackamole.fault ? 1 : 0 )
|
|
42
|
+
end
|
|
43
|
+
count
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Count all logs per hourly time period
|
|
47
|
+
times = (0...24).to_a
|
|
48
|
+
time_info = times.inject(OrderedHash.new) { |res,time| res[time] = { :user => 0, :feature => 0, :perf => 0, :fault => 0 };res }
|
|
49
|
+
user_per_hour = {}
|
|
50
|
+
day_logs.each do |log|
|
|
51
|
+
date_tokens = log['did'].match( /(\d{4})(\d{2})(\d{2})/ ).captures
|
|
52
|
+
time_tokens = log['tid'].match( /(\d{2})(\d{2})(\d{2})/ ).captures
|
|
53
|
+
utc = Time.utc( date_tokens[0], date_tokens[1], date_tokens[2], time_tokens[0], time_tokens[1], time_tokens[2] )
|
|
54
|
+
time = utc.getlocal.hour
|
|
55
|
+
if user_per_hour[time]
|
|
56
|
+
unless user_per_hour[time].include? log['uid']
|
|
57
|
+
time_info[time][:user] += 1
|
|
58
|
+
user_per_hour[time] << log['uid']
|
|
59
|
+
end
|
|
60
|
+
else
|
|
61
|
+
user_per_hour[time] = [ log['uid'] ]
|
|
62
|
+
time_info[time][:user] += 1
|
|
63
|
+
end
|
|
64
|
+
case log['typ']
|
|
65
|
+
when Rackamole.feature : time_info[time][:feature] += 1 if features.add?( log['fid'])
|
|
66
|
+
when Rackamole.perf : time_info[time][:perf] += 1
|
|
67
|
+
when Rackamole.fault : time_info[time][:fault] += 1
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# BOZO !! LAME ASS...
|
|
72
|
+
info[:user_series] = []
|
|
73
|
+
info[:fault_series] = []
|
|
74
|
+
info[:perf_series] = []
|
|
75
|
+
info[:feature_series] = []
|
|
76
|
+
time_info.values.map do |hash|
|
|
77
|
+
info[:user_series] << hash[:user]
|
|
78
|
+
info[:fault_series] << hash[:fault]
|
|
79
|
+
info[:perf_series] << hash[:perf]
|
|
80
|
+
info[:feature_series] << hash[:feature]
|
|
81
|
+
end
|
|
82
|
+
info
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# ===========================================================================
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
# -------------------------------------------------------------------------
|
|
89
|
+
# Makes sure we have some indexes set
|
|
90
|
+
# BOZO !! Create script to set these up ?
|
|
91
|
+
def self.ensure_indexes
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
require 'chronic'
|
|
2
|
+
|
|
3
|
+
module Wackamole
|
|
4
|
+
class SearchFilter
|
|
5
|
+
|
|
6
|
+
attr_accessor :time_frame, :feature_id, :type, :browser_type, :search_terms
|
|
7
|
+
|
|
8
|
+
# ---------------------------------------------------------------------------
|
|
9
|
+
# Ctor
|
|
10
|
+
def initialize
|
|
11
|
+
reset!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Reset filter to defaults
|
|
16
|
+
def reset!
|
|
17
|
+
@feature_id = -1
|
|
18
|
+
@time_frame = SearchFilter.time_frames.first
|
|
19
|
+
@browser_type = SearchFilter.browser_types.first
|
|
20
|
+
@type = SearchFilter.mole_types.first
|
|
21
|
+
@search_terms = ""
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Available browsers
|
|
26
|
+
def self.browser_types
|
|
27
|
+
@browsers ||= [ 'All', 'Unknown', 'Firefox', 'Safari', 'MSIE 8.0', 'MSIE 7.0', 'MSIE 6.0', 'Opera', 'Chrome' ]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Available time frames
|
|
32
|
+
def self.time_frames
|
|
33
|
+
@time_frames ||= ['today', '2 days', '1 week', '2 weeks', '1 month', '3 months', '6 months', '1 year' ]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Collection of mole types
|
|
38
|
+
def self.mole_types
|
|
39
|
+
@types ||= %w[All Feature Perf Fault]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
# Find all features
|
|
44
|
+
def features
|
|
45
|
+
features = Feature.features_cltn.find().to_a
|
|
46
|
+
features = features.map { |f| [context_for(f), f['_id']] }
|
|
47
|
+
features.sort! { |a,b| a.first <=> b.first }
|
|
48
|
+
features.insert( 0, ["All", -1] )
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
# Retrieves feature context
|
|
53
|
+
def context_for( f )
|
|
54
|
+
return "#{f['ctl']}##{f['act']}" if f['ctl']
|
|
55
|
+
f['ctx']
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
# Fetch filter start date id
|
|
60
|
+
def from_date_id
|
|
61
|
+
start = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
|
|
62
|
+
start.to_date_id
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# fetch time series from time frame
|
|
67
|
+
def time_ids
|
|
68
|
+
now = Time.now
|
|
69
|
+
start = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
|
|
70
|
+
corpus_end = DateTime.new( now.year, now.month, now.day )
|
|
71
|
+
corpus_start = DateTime.new( start.year, start.month, start.day )
|
|
72
|
+
|
|
73
|
+
calc_date = corpus_start
|
|
74
|
+
time_series = []
|
|
75
|
+
while calc_date <= corpus_end do
|
|
76
|
+
time_series << calc_date.to_date_id
|
|
77
|
+
calc_date += 1
|
|
78
|
+
end
|
|
79
|
+
time_series
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
# fetch time series from time frame
|
|
84
|
+
def time_series
|
|
85
|
+
now = Time.now
|
|
86
|
+
start = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
|
|
87
|
+
corpus_end = DateTime.new( now.year, now.month, now.day )
|
|
88
|
+
corpus_start = DateTime.new( start.year, start.month, start.day )
|
|
89
|
+
|
|
90
|
+
calc_date = corpus_start
|
|
91
|
+
time_series = []
|
|
92
|
+
while calc_date <= corpus_end do
|
|
93
|
+
time_series << calc_date.strftime( "%Y-%m-%d" )
|
|
94
|
+
calc_date += 1
|
|
95
|
+
end
|
|
96
|
+
time_series
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
# Populate filter from request params
|
|
101
|
+
def from_options( options )
|
|
102
|
+
return unless options
|
|
103
|
+
options.each_pair do |k,v|
|
|
104
|
+
# value = k.index( /_id$/) ? v.to_i : v
|
|
105
|
+
self.send( "#{k}=", v )
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Spews filter conditions
|
|
111
|
+
def to_conds
|
|
112
|
+
conds = {}
|
|
113
|
+
|
|
114
|
+
# filter mole_types
|
|
115
|
+
if type != 'All'
|
|
116
|
+
conds[:typ] = map_mole_type( type )
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if browser_type != 'All'
|
|
120
|
+
conds[:bro] = browser_type
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# filter mole_features
|
|
124
|
+
unless feature_id.to_s == "-1"
|
|
125
|
+
conds[:fid] = Mongo::ObjectID.from_string( feature_id )
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# filter by date
|
|
129
|
+
time = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
|
|
130
|
+
conds[:did] = { '$gte' => time.to_date_id.to_s }
|
|
131
|
+
|
|
132
|
+
unless search_terms.empty?
|
|
133
|
+
tokens = search_terms.split( ":" ).collect{ |c| c.strip }
|
|
134
|
+
key = tokens.shift
|
|
135
|
+
if key
|
|
136
|
+
if key == "user"
|
|
137
|
+
users = Wackamole::User.users_cltn.find( { :una => Regexp.new( tokens.first ) }, :fields => ['_id'] )
|
|
138
|
+
conds[field_map( key )] = { '$in' => users.collect{ |u| u['_id'] } }
|
|
139
|
+
elsif tokens.size == 2
|
|
140
|
+
conds["#{field_map(key)}.#{tokens.first}"] = Regexp.new( tokens.last )
|
|
141
|
+
elsif tokens.size == 1
|
|
142
|
+
conds[field_map(key)] = Regexp.new( tokens.first )
|
|
143
|
+
else
|
|
144
|
+
raise "Unable to evaluate search terms"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
conds
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# ===========================================================================
|
|
152
|
+
private
|
|
153
|
+
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
# Search filter key name map
|
|
156
|
+
def field_map( key )
|
|
157
|
+
case key.to_sym
|
|
158
|
+
when :user : :uid
|
|
159
|
+
when :method : :met
|
|
160
|
+
when :host : :hos
|
|
161
|
+
when :session : :ses
|
|
162
|
+
when :params : :par
|
|
163
|
+
else key
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Map named type to fixnum value
|
|
168
|
+
def map_mole_type( type )
|
|
169
|
+
case type
|
|
170
|
+
when 'Feature'
|
|
171
|
+
Rackamole.feature
|
|
172
|
+
when 'Perf'
|
|
173
|
+
Rackamole.perf
|
|
174
|
+
when 'Fault'
|
|
175
|
+
Rackamole.fault
|
|
176
|
+
else
|
|
177
|
+
raise "Invalid mole type `#{type}"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# ---------------------------------------------------------------------------
|
|
182
|
+
# Zeroed out now
|
|
183
|
+
def now
|
|
184
|
+
to_zero_hour( Time.now )
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Zeros out time info
|
|
188
|
+
def to_zero_hour( time )
|
|
189
|
+
Time.gm( time.year, time.month, time.day, 0, 0, 0 )
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'will_paginate/collection'
|
|
2
|
+
|
|
3
|
+
module Wackamole
|
|
4
|
+
class User
|
|
5
|
+
|
|
6
|
+
def self.logs_cltn() Wackamole::Control.collection( 'logs' ) ; end
|
|
7
|
+
def self.users_cltn() Wackamole::Control.collection( 'users' ); end
|
|
8
|
+
|
|
9
|
+
# Pagination size
|
|
10
|
+
def self.default_page_size() @page_size ||= 20; end
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
# Find all users matching criteria and returns pagination collection
|
|
14
|
+
def self.paginate_tops( conds, page=1, page_size=default_page_size )
|
|
15
|
+
tops = logs_cltn.group( [:uid], conds, { :count => 0 }, 'function(obj,prev) { prev.count += 1}', true )
|
|
16
|
+
users = []
|
|
17
|
+
tops.sort{ |a,b| b['count'] <=> a['count'] }.each do |row|
|
|
18
|
+
users << { :uid => row['uid'], :total => row['count'].to_i, :details => [] }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
WillPaginate::Collection.create( page, page_size, users.size ) do |pager|
|
|
22
|
+
offset = (page-1)*page_size
|
|
23
|
+
result = users[offset...(offset+page_size)]
|
|
24
|
+
result.each do |u|
|
|
25
|
+
user = users_cltn.find_one( u[:uid] ) #, :fields => [:una] )
|
|
26
|
+
raise "Unable to find user with id `#{u[:uid].inspect}" unless user
|
|
27
|
+
u[:name] = user['una']
|
|
28
|
+
end
|
|
29
|
+
pager.replace( result )
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Make sure indexes are setup for users
|
|
35
|
+
def self.ensure_indexes!
|
|
36
|
+
indexes = users_cltn.index_information
|
|
37
|
+
created_count = 0
|
|
38
|
+
|
|
39
|
+
unless indexes.has_key?( :una )
|
|
40
|
+
users_cltn.create_index( :una )
|
|
41
|
+
created_count += 1
|
|
42
|
+
end
|
|
43
|
+
created_count
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/public/favicon.ico
ADDED
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function truncate(str, limit)
|
|
2
|
+
{
|
|
3
|
+
var bits, i;
|
|
4
|
+
bits = str.split('');
|
|
5
|
+
if (bits.length > limit) {
|
|
6
|
+
for (i = bits.length - 1; i > -1; --i) {
|
|
7
|
+
if (i > limit) {
|
|
8
|
+
bits.length = i;
|
|
9
|
+
}
|
|
10
|
+
else if (' ' === bits[i]) {
|
|
11
|
+
bits.length = i;
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
bits.push('...');
|
|
16
|
+
}
|
|
17
|
+
return bits.join('');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
function blee( url )
|
|
22
|
+
{
|
|
23
|
+
if( url == "/explore")
|
|
24
|
+
window.location = url;
|
|
25
|
+
else
|
|
26
|
+
$.ajax( {url: url, dataType: 'script', method: 'GET'} );
|
|
27
|
+
return false;
|
|
28
|
+
}
|