neuron-client 0.2.6 → 0.3.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.
- data/README.md +11 -8
- data/lib/neuron-client/api.rb +5 -0
- data/lib/neuron-client/model/ad.rb +142 -0
- data/lib/neuron-client/model/ad_calculations.rb +325 -0
- data/lib/neuron-client/model/ad_zone.rb +45 -0
- data/lib/neuron-client/model/base.rb +233 -18
- data/lib/neuron-client/model/blocked_referer.rb +20 -0
- data/lib/neuron-client/model/blocked_user_agent.rb +21 -0
- data/lib/neuron-client/model/geo_target.rb +36 -0
- data/lib/neuron-client/model/pixel.rb +22 -0
- data/lib/neuron-client/model/report.rb +35 -0
- data/lib/neuron-client/model/s3_file.rb +30 -0
- data/lib/neuron-client/model/zone.rb +64 -0
- data/lib/neuron-client/model/zone_calculations.rb +37 -0
- data/lib/neuron-client/schema/ad.rb +406 -0
- data/lib/neuron-client/schema/ad_zone.rb +49 -0
- data/lib/neuron-client/schema/blocked_referer.rb +52 -0
- data/lib/neuron-client/schema/blocked_user_agent.rb +64 -0
- data/lib/neuron-client/schema/common.rb +220 -0
- data/lib/neuron-client/schema/event.rb +17 -0
- data/lib/neuron-client/schema/geo_target.rb +33 -0
- data/lib/neuron-client/schema/pixel.rb +39 -0
- data/lib/neuron-client/schema/report.rb +59 -0
- data/lib/neuron-client/schema/s3_file.rb +87 -0
- data/lib/neuron-client/schema/zone.rb +214 -0
- data/lib/neuron-client/version.rb +1 -1
- data/lib/neuron-client.rb +24 -59
- data/neuron-client.gemspec +3 -0
- data/spec/lib/admin_connection_spec.rb +234 -0
- data/spec/lib/api_spec.rb +41 -63
- data/spec/lib/model/ad_calculations_spec.rb +1146 -0
- data/spec/lib/model/ad_spec.rb +253 -0
- data/spec/lib/model/ad_zone_spec.rb +15 -0
- data/spec/lib/model/base_spec.rb +5 -83
- data/spec/lib/model/blocked_referer_spec.rb +36 -0
- data/spec/lib/model/blocked_user_agent_spec.rb +36 -0
- data/spec/lib/model/geo_target_spec.rb +28 -0
- data/spec/lib/model/pixel_spec.rb +36 -0
- data/spec/lib/model/report_spec.rb +17 -0
- data/spec/lib/{s3_file_spec.rb → model/s3_file_spec.rb} +6 -5
- data/spec/lib/model/zone_calculations_spec.rb +49 -0
- data/spec/lib/model/zone_spec.rb +155 -0
- data/spec/lib/schema/ad_spec.rb +515 -0
- data/spec/lib/schema/ad_zone_spec.rb +149 -0
- data/spec/lib/schema/blocked_referer_spec.rb +136 -0
- data/spec/lib/schema/blocked_user_agent_spec.rb +147 -0
- data/spec/lib/schema/geo_target_spec.rb +92 -0
- data/spec/lib/schema/pixel_spec.rb +125 -0
- data/spec/lib/schema/report_spec.rb +129 -0
- data/spec/lib/schema/s3_file_spec.rb +164 -0
- data/spec/lib/schema/zone_spec.rb +243 -0
- data/spec/spec_helper.rb +2 -1
- metadata +141 -121
- data/lib/neuron-client/model/admin/ad.rb +0 -22
- data/lib/neuron-client/model/admin/ad_zone.rb +0 -15
- data/lib/neuron-client/model/admin/base.rb +0 -91
- data/lib/neuron-client/model/admin/blocked_referer.rb +0 -12
- data/lib/neuron-client/model/admin/blocked_user_agent.rb +0 -12
- data/lib/neuron-client/model/admin/geo_target.rb +0 -16
- data/lib/neuron-client/model/admin/pixel.rb +0 -12
- data/lib/neuron-client/model/admin/report.rb +0 -15
- data/lib/neuron-client/model/admin/s3_file.rb +0 -12
- data/lib/neuron-client/model/admin/zone.rb +0 -15
- data/lib/neuron-client/model/common/ad.rb +0 -42
- data/lib/neuron-client/model/common/ad_calculations.rb +0 -329
- data/lib/neuron-client/model/common/ad_zone.rb +0 -17
- data/lib/neuron-client/model/common/base.rb +0 -67
- data/lib/neuron-client/model/common/blocked_referer.rb +0 -16
- data/lib/neuron-client/model/common/blocked_user_agent.rb +0 -16
- data/lib/neuron-client/model/common/geo_target.rb +0 -16
- data/lib/neuron-client/model/common/pixel.rb +0 -18
- data/lib/neuron-client/model/common/report.rb +0 -21
- data/lib/neuron-client/model/common/s3_file.rb +0 -16
- data/lib/neuron-client/model/common/zone.rb +0 -22
- data/lib/neuron-client/model/common/zone_calculations.rb +0 -41
- data/lib/neuron-client/model/membase/ad.rb +0 -49
- data/lib/neuron-client/model/membase/ad_zone.rb +0 -11
- data/lib/neuron-client/model/membase/blocked_referer.rb +0 -20
- data/lib/neuron-client/model/membase/blocked_user_agent.rb +0 -20
- data/lib/neuron-client/model/membase/geo_target.rb +0 -11
- data/lib/neuron-client/model/membase/pixel.rb +0 -22
- data/lib/neuron-client/model/membase/report.rb +0 -11
- data/lib/neuron-client/model/membase/s3_file.rb +0 -11
- data/lib/neuron-client/model/membase/zone.rb +0 -30
- data/lib/neuron-client/model/models.rb +0 -15
- data/spec/lib/model/admin/ad_spec.rb +0 -34
- data/spec/lib/model/admin/ad_zone_spec.rb +0 -19
- data/spec/lib/model/admin/base_spec.rb +0 -11
- data/spec/lib/model/admin/blocked_referer_spec.rb +0 -11
- data/spec/lib/model/admin/blocked_user_agent_spec.rb +0 -11
- data/spec/lib/model/admin/geo_target_spec.rb +0 -30
- data/spec/lib/model/admin/report_spec.rb +0 -21
- data/spec/lib/model/admin/s3_spec.rb +0 -11
- data/spec/lib/model/admin/zone_spec.rb +0 -21
- data/spec/lib/model/common/ad_calculations_spec.rb +0 -1151
- data/spec/lib/model/common/ad_spec.rb +0 -11
- data/spec/lib/model/common/ad_zone_spec.rb +0 -11
- data/spec/lib/model/common/base_spec.rb +0 -11
- data/spec/lib/model/common/blocked_referer_spec.rb +0 -11
- data/spec/lib/model/common/blocked_user_agent_spec.rb +0 -11
- data/spec/lib/model/common/geo_target_spec.rb +0 -11
- data/spec/lib/model/common/report_spec.rb +0 -11
- data/spec/lib/model/common/s3_spec.rb +0 -11
- data/spec/lib/model/common/zone_calculations_spec.rb +0 -54
- data/spec/lib/model/common/zone_spec.rb +0 -11
- data/spec/lib/model/membase/ad_spec.rb +0 -54
- data/spec/lib/model/membase/ad_zone_spec.rb +0 -11
- data/spec/lib/model/membase/base_spec.rb +0 -11
- data/spec/lib/model/membase/blocked_referer_spec.rb +0 -34
- data/spec/lib/model/membase/blocked_user_agent_spec.rb +0 -34
- data/spec/lib/model/membase/geo_target_spec.rb +0 -11
- data/spec/lib/model/membase/pixel_spec.rb +0 -34
- data/spec/lib/model/membase/report_spec.rb +0 -11
- data/spec/lib/model/membase/s3_spec.rb +0 -11
- data/spec/lib/model/membase/zone_spec.rb +0 -32
- data/spec/lib/old_spec.rb +0 -437
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
module AdCalculations
|
|
6
|
-
# This module expects the following methods to be defined:
|
|
7
|
-
# start_datetime (Time, String, or nil)
|
|
8
|
-
# end_datetime (Time, String, or nil)
|
|
9
|
-
# time_zone (String)
|
|
10
|
-
# day_partitions (String, or nil, length = 7*24, matches /^[TF]+$/)
|
|
11
|
-
# daily_cap (FixNum, or nil)
|
|
12
|
-
# overall_cap (FixNum, or nil)
|
|
13
|
-
# ideal_impressions_per_hour (Number, or nil)
|
|
14
|
-
# total_impressed (Integer, >= 0)
|
|
15
|
-
# today_impressed (Integer, >= 0)
|
|
16
|
-
|
|
17
|
-
def active?
|
|
18
|
-
calculate_active?(Time.now, total_impressed, today_impressed)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def pressure
|
|
22
|
-
calculate_pressure(Time.now, total_impressed, today_impressed)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def calculate_active?(time, total, today)
|
|
26
|
-
time = time.in_time_zone(time_zone)
|
|
27
|
-
return false unless within_date_range?(time)
|
|
28
|
-
return false if partitioned? && !partitioned_hour?(time)
|
|
29
|
-
!cap_met?(total, today)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Set the optional "active" parameter to true or false if you already know
|
|
33
|
-
def calculate_pressure(time, total, today, active=nil)
|
|
34
|
-
return nil if active == false
|
|
35
|
-
return nil unless active || calculate_active?(time,total,today)
|
|
36
|
-
time = time.in_time_zone(time_zone)
|
|
37
|
-
if daily_capped?
|
|
38
|
-
if daily_cap_precludes_overall_cap?(time,total,today)
|
|
39
|
-
calculate_overall_pressure(time, total)
|
|
40
|
-
else
|
|
41
|
-
calculate_today_pressure(time, today)
|
|
42
|
-
end
|
|
43
|
-
elsif overall_pressure_exists?
|
|
44
|
-
calculate_overall_pressure(time, total)
|
|
45
|
-
else
|
|
46
|
-
(ideal_impressions_per_hour || 1.0).to_f
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
def in_ad_time_zone(time)
|
|
53
|
-
if time.present?
|
|
54
|
-
(time.is_a?(String) ? Time.parse(time) : time).in_time_zone(time_zone)
|
|
55
|
-
end
|
|
56
|
-
rescue
|
|
57
|
-
nil
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def start_in_time_zone
|
|
61
|
-
in_ad_time_zone(start_datetime)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def end_in_time_zone
|
|
65
|
-
in_ad_time_zone(end_datetime)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def daily_capped?
|
|
69
|
-
!daily_cap.nil? && daily_cap >= 0
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def overall_capped?
|
|
73
|
-
!overall_cap.nil? && overall_cap >= 0
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def overall_pressure_exists?
|
|
77
|
-
overall_capped? && end_datetime.present?
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def partitioned?
|
|
81
|
-
!day_partitions.nil? && day_partitions.length == 24*7
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def within_date_range?(time)
|
|
85
|
-
return false if start_datetime.present? && time < start_in_time_zone
|
|
86
|
-
return false if end_datetime.present? && time >= end_in_time_zone
|
|
87
|
-
true
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Assume time is in the time zone of the ad.
|
|
91
|
-
# Doesn't worry about whether or not the time is in the ad's date range.
|
|
92
|
-
# Assumes ad is partitioned.
|
|
93
|
-
def partitioned_hour?(time)
|
|
94
|
-
day_partitions.at((time.wday * 24) + time.hour) == 'T'
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Assume time is in the time zone of the ad.
|
|
98
|
-
# Doesn't worry about whether or not the time is in the ad's date range.
|
|
99
|
-
# Assumes ad is partitioned.
|
|
100
|
-
# Returns true if there is any active partition the day of the given time.
|
|
101
|
-
def partitioned_day?(time)
|
|
102
|
-
day_partitions[(time.wday) * 24, 24].include?('T')
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# Assumes time is in the time zone of the ad.
|
|
106
|
-
# Doesn't worry about date range or day partitions.
|
|
107
|
-
def cap_met?(total_impressed, today_impressed)
|
|
108
|
-
return true if daily_capped? && (daily_cap <= today_impressed)
|
|
109
|
-
return true if overall_capped? && (overall_cap <= total_impressed)
|
|
110
|
-
false
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Assumes time is in time_zone of the ad.
|
|
114
|
-
# Returns true if there's no way we can hit the overall cap
|
|
115
|
-
# without busting the daily cap.
|
|
116
|
-
def daily_cap_precludes_overall_cap?(time,total_impressed,today_impressed)
|
|
117
|
-
return false unless daily_capped? && overall_capped?
|
|
118
|
-
return false unless self.end_datetime.present?
|
|
119
|
-
a = remaining_impressions_via_daily_cap(time, today_impressed)
|
|
120
|
-
b = remaining_impressions_via_overall_cap(total_impressed)
|
|
121
|
-
a < b
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def remaining_impressions_via_overall_cap(total_impressed)
|
|
125
|
-
[overall_cap - total_impressed, 0].max
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def remaining_impressions_today(today_impressed)
|
|
129
|
-
[daily_cap - today_impressed, 0].max
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def remaining_impressions_via_daily_cap(time, today_impressed)
|
|
133
|
-
days = remaining_days(time) - 1 # exclude today
|
|
134
|
-
daily_cap * days + remaining_impressions_today(today_impressed)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# Assumes time is in time_zone of the ad.
|
|
138
|
-
# Assume daily_cap is present.
|
|
139
|
-
def calculate_today_pressure(time, today_impressed)
|
|
140
|
-
hours = remaining_hours_today(time)
|
|
141
|
-
if hours <= 0
|
|
142
|
-
0.0
|
|
143
|
-
else
|
|
144
|
-
impressions = remaining_impressions_today(today_impressed)
|
|
145
|
-
2 * impressions / hours.to_f
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Assumes time is in time_zone of the ad.
|
|
150
|
-
# Assume overall_cap is present.
|
|
151
|
-
# Assume end_datetime is present.
|
|
152
|
-
def calculate_overall_pressure(time, total_impressed)
|
|
153
|
-
hours = remaining_hours(time)
|
|
154
|
-
if hours <= 0
|
|
155
|
-
0.0
|
|
156
|
-
else
|
|
157
|
-
impressions = remaining_impressions_via_overall_cap(total_impressed)
|
|
158
|
-
impressions / hours.to_f
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# remaining_days : the total integer number of days that an ad will run
|
|
163
|
-
# (even for part of the day) between now and the
|
|
164
|
-
# end_datetime.
|
|
165
|
-
# Assume all dates/times are in the time_zone of the ad.
|
|
166
|
-
# Assume end_datetime is present.
|
|
167
|
-
def remaining_days(time)
|
|
168
|
-
ending = end_in_time_zone
|
|
169
|
-
beginning = [time, start_in_time_zone].compact.max
|
|
170
|
-
return 0 unless beginning < ending
|
|
171
|
-
if partitioned?
|
|
172
|
-
end_of_beginning_week = beginning_of_week(beginning) + 7.days
|
|
173
|
-
beginning_of_end_week = beginning_of_week(ending)
|
|
174
|
-
|
|
175
|
-
if end_of_beginning_week < beginning_of_end_week
|
|
176
|
-
head_days = partitioned_days(beginning, end_of_beginning_week)
|
|
177
|
-
tail_days = partitioned_days(beginning_of_end_week, ending)
|
|
178
|
-
whole_weeks = (beginning_of_end_week-end_of_beginning_week) / 7.days
|
|
179
|
-
head_days + (whole_weeks * days_per_week) + tail_days
|
|
180
|
-
else
|
|
181
|
-
partitioned_days(beginning, ending)
|
|
182
|
-
end
|
|
183
|
-
else
|
|
184
|
-
(ending.beginning_of_day.to_datetime -
|
|
185
|
-
beginning.beginning_of_day.to_datetime) + 1
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# remaining_hours : the total number of hours that an ad will run from now
|
|
190
|
-
# to the end_datetime, taking day parting into account.
|
|
191
|
-
# Assume all dates/times are in the time_zone of the ad.
|
|
192
|
-
def remaining_hours(time)
|
|
193
|
-
ending = end_in_time_zone
|
|
194
|
-
beginning = [time, start_in_time_zone].compact.max
|
|
195
|
-
return 0 unless beginning < ending
|
|
196
|
-
if partitioned?
|
|
197
|
-
|
|
198
|
-
end_of_beginning_week = beginning_of_week(beginning) + 7.days
|
|
199
|
-
beginning_of_end_week = beginning_of_week(ending)
|
|
200
|
-
|
|
201
|
-
if end_of_beginning_week < beginning_of_end_week
|
|
202
|
-
head_hours = partitioned_hours(beginning, end_of_beginning_week)
|
|
203
|
-
tail_hours = partitioned_hours(beginning_of_end_week, ending)
|
|
204
|
-
whole_weeks = (beginning_of_end_week-end_of_beginning_week) / 7.days
|
|
205
|
-
head_hours + (whole_weeks * hours_per_week) + tail_hours
|
|
206
|
-
else
|
|
207
|
-
partitioned_hours(beginning, ending)
|
|
208
|
-
end
|
|
209
|
-
else
|
|
210
|
-
actual_hours(beginning, ending)
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
# remaining_hours_today : the total number of hours that an ad will run
|
|
215
|
-
# between now and the end of the day, taking day
|
|
216
|
-
# parting into account.
|
|
217
|
-
# Assume all dates/times are in the time_zone of the ad.
|
|
218
|
-
def remaining_hours_today(time)
|
|
219
|
-
beginning = [time, start_in_time_zone].compact.max
|
|
220
|
-
ending = [time.beginning_of_day + 1.day, end_in_time_zone].compact.min
|
|
221
|
-
return 0 unless beginning < ending
|
|
222
|
-
if partitioned?
|
|
223
|
-
partitioned_hours(beginning, ending)
|
|
224
|
-
else
|
|
225
|
-
actual_hours(beginning, ending)
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# Assume time is in the time_zone of the ad.
|
|
230
|
-
# Assume a week begins on Sunday.
|
|
231
|
-
def beginning_of_week(time)
|
|
232
|
-
recent_monday = time.monday
|
|
233
|
-
sunday_before_recent_monday = recent_monday - 1.day
|
|
234
|
-
if (time - sunday_before_recent_monday) < 7.days
|
|
235
|
-
sunday_before_recent_monday
|
|
236
|
-
else
|
|
237
|
-
sunday_before_recent_monday + 7.days
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def beginning_of_hour(time)
|
|
242
|
-
time.change(:min => 0, :sec => 0, :usec => 0)
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
# Assume beginning and ending are in the ad's time_zone.
|
|
246
|
-
# Assume beginning and ending are within the ad's date range.
|
|
247
|
-
# Assume ad is partitioned.
|
|
248
|
-
def partitioned_hours(beginning, ending)
|
|
249
|
-
return 0 unless beginning < ending
|
|
250
|
-
total = 0.0
|
|
251
|
-
this_hour = beginning_of_hour(beginning)
|
|
252
|
-
last_hour = beginning_of_hour(ending)
|
|
253
|
-
if this_hour.to_i == last_hour.to_i
|
|
254
|
-
if partitioned_hour?(this_hour)
|
|
255
|
-
total = actual_hours(beginning, ending)
|
|
256
|
-
end
|
|
257
|
-
else
|
|
258
|
-
next_hour = this_hour + 1.hour
|
|
259
|
-
if partitioned_hour?(this_hour)
|
|
260
|
-
total += actual_hours(beginning, next_hour)
|
|
261
|
-
end
|
|
262
|
-
each_hour(next_hour, last_hour) do |hour|
|
|
263
|
-
total += 1 if partitioned_hour?(hour)
|
|
264
|
-
end
|
|
265
|
-
if partitioned_hour?(last_hour)
|
|
266
|
-
total += actual_hours(last_hour, ending)
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
total
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
# Assume beginning and ending are in the ad's time_zone.
|
|
273
|
-
# Assume beginning and ending are within the ad's date range.
|
|
274
|
-
# Assume ad is partitioned.
|
|
275
|
-
# Assume beginning and ending are within a week of each other.
|
|
276
|
-
# Computes integer number of days where any part of the day is active.
|
|
277
|
-
def partitioned_days(beginning, ending)
|
|
278
|
-
return 0 unless beginning < ending
|
|
279
|
-
|
|
280
|
-
end_of_beginning_day = beginning.beginning_of_day + 1.day
|
|
281
|
-
beginning_of_end_day = ending.beginning_of_day
|
|
282
|
-
|
|
283
|
-
if end_of_beginning_day < beginning_of_end_day
|
|
284
|
-
days = 0
|
|
285
|
-
days += 1 if partitioned_hours(beginning, end_of_beginning_day) > 0
|
|
286
|
-
days += 1 if partitioned_hours(beginning_of_end_day, ending) > 0
|
|
287
|
-
each_day(end_of_beginning_day, beginning_of_end_day) do |day|
|
|
288
|
-
days += 1 if partitioned_day?(day)
|
|
289
|
-
end
|
|
290
|
-
days
|
|
291
|
-
else
|
|
292
|
-
(partitioned_hours(beginning,ending) > 0) ? 1 : 0
|
|
293
|
-
end
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def each_day(beginning, ending)
|
|
297
|
-
time = beginning.clone
|
|
298
|
-
while (time < ending)
|
|
299
|
-
yield time
|
|
300
|
-
time += 1.day
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def each_hour(beginning, ending)
|
|
305
|
-
time = beginning.clone
|
|
306
|
-
while(time < ending)
|
|
307
|
-
yield time
|
|
308
|
-
time += 1.hour
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
def actual_hours(beginning, ending)
|
|
313
|
-
(ending.to_f - beginning.to_f) / 3600
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
# Assumes ad is partitioned.
|
|
317
|
-
def days_per_week
|
|
318
|
-
(0..6).map{|d| day_partitions[d*24,24].include?('T') ? 1 : 0 }.sum
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
# Assumes ad is partitioned.
|
|
322
|
-
def hours_per_week
|
|
323
|
-
day_partitions.count("T")
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class AdZone
|
|
6
|
-
include Base
|
|
7
|
-
|
|
8
|
-
resource_name("ad_zone")
|
|
9
|
-
resources_name("ad_zones")
|
|
10
|
-
|
|
11
|
-
attr_accessor :ad_id, :zone_id, :priority, :weight,
|
|
12
|
-
:created_at, :updated_at
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
module Base
|
|
6
|
-
def initialize(attrs=nil)
|
|
7
|
-
(attrs || {}).each do |k,v|
|
|
8
|
-
next if k.to_s == 'id' && self.class.remote_id != 'id'
|
|
9
|
-
k = 'id' if k.to_s == self.class.remote_id
|
|
10
|
-
self.send("#{k}=", v) if self.respond_to?("#{k}=")
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.included(base)
|
|
15
|
-
base.send(:attr_accessor, :id)
|
|
16
|
-
base.extend(ClassMethods)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
module ClassMethods
|
|
20
|
-
def api
|
|
21
|
-
class_name_to_load = superclass.name.split('::').last
|
|
22
|
-
Neuron::Client::Model.const_get(class_name_to_load).api
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def connection
|
|
26
|
-
api.connection
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def attr_accessor(*vars)
|
|
30
|
-
@attributes ||= []
|
|
31
|
-
@attributes += vars
|
|
32
|
-
super(*vars)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def attributes
|
|
36
|
-
@attributes
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def resource_name(res=nil)
|
|
40
|
-
if res
|
|
41
|
-
@resource_name = res.to_s
|
|
42
|
-
end
|
|
43
|
-
@resource_name
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def resources_name(res=nil)
|
|
47
|
-
if res
|
|
48
|
-
@resources_name = res.to_s.downcase
|
|
49
|
-
end
|
|
50
|
-
if @resources_name.nil? && !@resource_name.nil?
|
|
51
|
-
@resources_name = "#{@resource_name}s"
|
|
52
|
-
end
|
|
53
|
-
@resources_name
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def remote_id(remote_id=nil)
|
|
57
|
-
if remote_id
|
|
58
|
-
@remote_id = remote_id.to_s
|
|
59
|
-
end
|
|
60
|
-
@remote_id || 'id'
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class BlockedReferer
|
|
6
|
-
include Base
|
|
7
|
-
|
|
8
|
-
resource_name("blocked_referer")
|
|
9
|
-
resources_name("blocked_referers")
|
|
10
|
-
|
|
11
|
-
attr_accessor :referer, :reversed_referer, :created_at, :updated_at
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class BlockedUserAgent
|
|
6
|
-
include Base
|
|
7
|
-
|
|
8
|
-
resource_name("blocked_user_agent")
|
|
9
|
-
resources_name("blocked_user_agents")
|
|
10
|
-
|
|
11
|
-
attr_accessor :user_agent, :description, :created_at, :updated_at
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class GeoTarget
|
|
6
|
-
include Base
|
|
7
|
-
|
|
8
|
-
resource_name("geo_target")
|
|
9
|
-
resources_name("geo_targets")
|
|
10
|
-
|
|
11
|
-
attr_accessor :geo_type, :full_name, :name, :abbreviation, :updated_at
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class Report
|
|
6
|
-
include Base
|
|
7
|
-
|
|
8
|
-
resource_name("report")
|
|
9
|
-
resources_name("reports")
|
|
10
|
-
|
|
11
|
-
attr_accessor :errors
|
|
12
|
-
attr_accessor :template, :parameters, :state
|
|
13
|
-
|
|
14
|
-
def status
|
|
15
|
-
@state
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class S3File
|
|
6
|
-
include Base
|
|
7
|
-
|
|
8
|
-
resource_name("s3_file")
|
|
9
|
-
resources_name("s3_files")
|
|
10
|
-
|
|
11
|
-
attr_accessor :bucket, :filename, :purpose, :filesize, :created_at, :updated_at
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
class Zone
|
|
6
|
-
include Base
|
|
7
|
-
include ZoneCalculations
|
|
8
|
-
|
|
9
|
-
resource_name("zone")
|
|
10
|
-
resources_name("zones")
|
|
11
|
-
|
|
12
|
-
attr_accessor :slug, :response_type, :template_slug, :parameters,
|
|
13
|
-
:created_at, :updated_at, :ad_links
|
|
14
|
-
|
|
15
|
-
def find_ad(ad_id)
|
|
16
|
-
Neuron::Client::Model::Ad.find(ad_id)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Common
|
|
5
|
-
module ZoneCalculations
|
|
6
|
-
# This module expects the following methods to be defined:
|
|
7
|
-
#
|
|
8
|
-
# ad_links (Hash, keys are ad IDs, values are a sub-hash: {'priority' => p, 'weight' => w})
|
|
9
|
-
# find_ad(ad_id) (nil, or an object that responds to :active? and :pressure)
|
|
10
|
-
|
|
11
|
-
def ads_by_priority
|
|
12
|
-
calculate_ads_by_priority
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def calculate_ads_by_priority
|
|
16
|
-
entries = {}
|
|
17
|
-
ad_links.each do |ad_id, link|
|
|
18
|
-
next unless ad = find_ad(ad_id)
|
|
19
|
-
next unless ad.active?
|
|
20
|
-
weight = link['weight'].to_f
|
|
21
|
-
priority = link['priority'].to_f
|
|
22
|
-
entries[priority] ||= []
|
|
23
|
-
entries[priority] << [ad_id, weighted_pressure(weight, ad.pressure)]
|
|
24
|
-
end
|
|
25
|
-
entries.sort_by do |priority, entry|
|
|
26
|
-
priority
|
|
27
|
-
end.map do |priority, entry|
|
|
28
|
-
entry.sort_by(&:first)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def weighted_pressure(weight, pressure)
|
|
35
|
-
[( [weight, 0.0].max * [pressure, 1.0].max ), 1.0].max.to_f
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Membase
|
|
5
|
-
class Ad < Common::Ad
|
|
6
|
-
|
|
7
|
-
ACTIVE_TTL = 60 #seconds
|
|
8
|
-
PRESSURE_TTL = 60 #seconds
|
|
9
|
-
|
|
10
|
-
def total_impressed
|
|
11
|
-
key = "count_delivery_ad_#{self.id}"
|
|
12
|
-
self.class.connection.get(key,1).to_f
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def today_impressed
|
|
16
|
-
now_adjusted_for_ad_time_zone = Time.now.in_time_zone(self.time_zone)
|
|
17
|
-
formatted_date = now_adjusted_for_ad_time_zone.strftime('%Y%m%d') # format to YYYYMMDD
|
|
18
|
-
key = "count_delivery_#{formatted_date}_ad_#{self.id}"
|
|
19
|
-
self.class.connection.get(key,1).to_f
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def active?
|
|
23
|
-
self.class.connection.fetch("Ad:#{id}:active", ACTIVE_TTL) do
|
|
24
|
-
calculate_active?(Time.now, total_impressed, today_impressed)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def pressure
|
|
29
|
-
self.class.connection.fetch("Ad:#{id}:pressure", PRESSURE_TTL) do
|
|
30
|
-
calculate_pressure(Time.now, total_impressed, today_impressed)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
class << self
|
|
35
|
-
def find(id)
|
|
36
|
-
self.connection.local_cache.fetch("Neuron::Client::Model::Ad:#{id}") do
|
|
37
|
-
ad = nil
|
|
38
|
-
membase_key = "Ad:#{id}"
|
|
39
|
-
cached_json = self.connection.get(membase_key)
|
|
40
|
-
ad = self.new(Yajl.load(cached_json)[superclass.resource_name]) if cached_json.present?
|
|
41
|
-
ad
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Membase
|
|
5
|
-
class BlockedReferer < Common::BlockedReferer
|
|
6
|
-
class << self
|
|
7
|
-
def all
|
|
8
|
-
self.connection.local_cache.fetch("Neuron::Client::Model::BlockedReferer:all") do
|
|
9
|
-
blocked_referers = []
|
|
10
|
-
cached_json = self.connection.get('blocked_referers')
|
|
11
|
-
blocked_referers = Yajl.load(cached_json).collect{|item| self.new(item[superclass.resource_name])} if cached_json.present?
|
|
12
|
-
blocked_referers
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module Neuron
|
|
2
|
-
module Client
|
|
3
|
-
module Model
|
|
4
|
-
module Membase
|
|
5
|
-
class BlockedUserAgent < Common::BlockedUserAgent
|
|
6
|
-
class << self
|
|
7
|
-
def all
|
|
8
|
-
self.connection.local_cache.fetch("Neuron::Client::Model::BlockedUserAgent:all") do
|
|
9
|
-
blocked_user_agents = []
|
|
10
|
-
cached_json = self.connection.get('blocked_user_agents')
|
|
11
|
-
blocked_user_agents = Yajl.load(cached_json).collect{|item| self.new(item[superclass.resource_name])} if cached_json.present?
|
|
12
|
-
blocked_user_agents
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|