fleetpull 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. fleetpull/__init__.py +36 -0
  2. fleetpull/api/__init__.py +32 -0
  3. fleetpull/api/auth_ingress.py +216 -0
  4. fleetpull/api/catalog.py +139 -0
  5. fleetpull/api/fetch.py +229 -0
  6. fleetpull/api/identity.py +90 -0
  7. fleetpull/api/sync.py +735 -0
  8. fleetpull/cli.py +146 -0
  9. fleetpull/config/__init__.py +47 -0
  10. fleetpull/config/base.py +18 -0
  11. fleetpull/config/example.py +90 -0
  12. fleetpull/config/geotab.py +78 -0
  13. fleetpull/config/http.py +32 -0
  14. fleetpull/config/loading.py +195 -0
  15. fleetpull/config/logger.py +139 -0
  16. fleetpull/config/providers.py +520 -0
  17. fleetpull/config/rate_limit.py +50 -0
  18. fleetpull/config/resolution.py +156 -0
  19. fleetpull/config/retry.py +69 -0
  20. fleetpull/config/root.py +157 -0
  21. fleetpull/config/sections.py +146 -0
  22. fleetpull/endpoints/__init__.py +24 -0
  23. fleetpull/endpoints/geotab/__init__.py +12 -0
  24. fleetpull/endpoints/geotab/_requests.py +427 -0
  25. fleetpull/endpoints/geotab/annotation_logs.py +73 -0
  26. fleetpull/endpoints/geotab/audits.py +70 -0
  27. fleetpull/endpoints/geotab/devices.py +79 -0
  28. fleetpull/endpoints/geotab/driver_changes.py +73 -0
  29. fleetpull/endpoints/geotab/duty_status_logs.py +75 -0
  30. fleetpull/endpoints/geotab/dvir_logs.py +76 -0
  31. fleetpull/endpoints/geotab/exception_events.py +119 -0
  32. fleetpull/endpoints/geotab/fault_data.py +72 -0
  33. fleetpull/endpoints/geotab/fill_ups.py +79 -0
  34. fleetpull/endpoints/geotab/fuel_and_energy_used.py +74 -0
  35. fleetpull/endpoints/geotab/fuel_tax_details.py +75 -0
  36. fleetpull/endpoints/geotab/log_records.py +74 -0
  37. fleetpull/endpoints/geotab/media_files.py +74 -0
  38. fleetpull/endpoints/geotab/shipment_logs.py +71 -0
  39. fleetpull/endpoints/geotab/status_data.py +71 -0
  40. fleetpull/endpoints/geotab/text_messages.py +77 -0
  41. fleetpull/endpoints/geotab/trips.py +102 -0
  42. fleetpull/endpoints/geotab/users.py +81 -0
  43. fleetpull/endpoints/motive/__init__.py +12 -0
  44. fleetpull/endpoints/motive/_spec_builders.py +94 -0
  45. fleetpull/endpoints/motive/driver_idle_rollups.py +113 -0
  46. fleetpull/endpoints/motive/driving_periods.py +85 -0
  47. fleetpull/endpoints/motive/groups.py +61 -0
  48. fleetpull/endpoints/motive/idle_events.py +94 -0
  49. fleetpull/endpoints/motive/users.py +64 -0
  50. fleetpull/endpoints/motive/vehicle_locations.py +170 -0
  51. fleetpull/endpoints/motive/vehicle_utilizations.py +122 -0
  52. fleetpull/endpoints/motive/vehicles.py +106 -0
  53. fleetpull/endpoints/registry.py +280 -0
  54. fleetpull/endpoints/samsara/__init__.py +12 -0
  55. fleetpull/endpoints/samsara/_spec_builders.py +202 -0
  56. fleetpull/endpoints/samsara/addresses.py +77 -0
  57. fleetpull/endpoints/samsara/asset_locations.py +217 -0
  58. fleetpull/endpoints/samsara/driver_fuel_energy_reports.py +124 -0
  59. fleetpull/endpoints/samsara/driver_vehicle_assignments.py +211 -0
  60. fleetpull/endpoints/samsara/drivers.py +169 -0
  61. fleetpull/endpoints/samsara/engine_states.py +114 -0
  62. fleetpull/endpoints/samsara/gps_readings.py +113 -0
  63. fleetpull/endpoints/samsara/idling_events.py +195 -0
  64. fleetpull/endpoints/samsara/odometer_readings.py +116 -0
  65. fleetpull/endpoints/samsara/trips.py +217 -0
  66. fleetpull/endpoints/samsara/vehicle_fuel_energy_reports.py +139 -0
  67. fleetpull/endpoints/samsara/vehicles.py +121 -0
  68. fleetpull/endpoints/shared/__init__.py +57 -0
  69. fleetpull/endpoints/shared/base.py +529 -0
  70. fleetpull/endpoints/shared/request_shape.py +227 -0
  71. fleetpull/endpoints/shared/resume.py +74 -0
  72. fleetpull/endpoints/shared/spec_builders.py +59 -0
  73. fleetpull/endpoints/shared/sync_mode.py +159 -0
  74. fleetpull/endpoints/shared/url_paths.py +149 -0
  75. fleetpull/exceptions.py +320 -0
  76. fleetpull/incremental/__init__.py +27 -0
  77. fleetpull/incremental/cursor.py +66 -0
  78. fleetpull/incremental/resolution.py +152 -0
  79. fleetpull/incremental/seed.py +53 -0
  80. fleetpull/incremental/window.py +94 -0
  81. fleetpull/logger/__init__.py +5 -0
  82. fleetpull/logger/setup.py +145 -0
  83. fleetpull/model_contract/__init__.py +6 -0
  84. fleetpull/model_contract/coercions.py +33 -0
  85. fleetpull/model_contract/response.py +45 -0
  86. fleetpull/models/__init__.py +7 -0
  87. fleetpull/models/geotab/__init__.py +166 -0
  88. fleetpull/models/geotab/annotation_log.py +109 -0
  89. fleetpull/models/geotab/audit.py +56 -0
  90. fleetpull/models/geotab/device.py +217 -0
  91. fleetpull/models/geotab/driver_change.py +102 -0
  92. fleetpull/models/geotab/duty_status_log.py +200 -0
  93. fleetpull/models/geotab/dvir_log.py +184 -0
  94. fleetpull/models/geotab/exception_event.py +135 -0
  95. fleetpull/models/geotab/fault_data.py +168 -0
  96. fleetpull/models/geotab/fill_up.py +189 -0
  97. fleetpull/models/geotab/fuel_and_energy_used.py +81 -0
  98. fleetpull/models/geotab/fuel_tax_detail.py +150 -0
  99. fleetpull/models/geotab/log_record.py +68 -0
  100. fleetpull/models/geotab/media_file.py +133 -0
  101. fleetpull/models/geotab/shared.py +221 -0
  102. fleetpull/models/geotab/shipment_log.py +105 -0
  103. fleetpull/models/geotab/status_data.py +108 -0
  104. fleetpull/models/geotab/text_message.py +125 -0
  105. fleetpull/models/geotab/trip.py +162 -0
  106. fleetpull/models/geotab/user.py +187 -0
  107. fleetpull/models/motive/__init__.py +43 -0
  108. fleetpull/models/motive/driver_idle_rollup.py +109 -0
  109. fleetpull/models/motive/driving_period.py +82 -0
  110. fleetpull/models/motive/group.py +49 -0
  111. fleetpull/models/motive/idle_event.py +77 -0
  112. fleetpull/models/motive/shared.py +192 -0
  113. fleetpull/models/motive/user.py +217 -0
  114. fleetpull/models/motive/vehicle.py +162 -0
  115. fleetpull/models/motive/vehicle_location.py +127 -0
  116. fleetpull/models/motive/vehicle_utilization.py +128 -0
  117. fleetpull/models/samsara/__init__.py +108 -0
  118. fleetpull/models/samsara/address.py +149 -0
  119. fleetpull/models/samsara/asset_location.py +131 -0
  120. fleetpull/models/samsara/driver.py +232 -0
  121. fleetpull/models/samsara/driver_fuel_energy_report.py +153 -0
  122. fleetpull/models/samsara/driver_vehicle_assignment.py +168 -0
  123. fleetpull/models/samsara/engine_state.py +92 -0
  124. fleetpull/models/samsara/gps_reading.py +146 -0
  125. fleetpull/models/samsara/idling_event.py +174 -0
  126. fleetpull/models/samsara/odometer_reading.py +90 -0
  127. fleetpull/models/samsara/trip.py +199 -0
  128. fleetpull/models/samsara/vehicle.py +167 -0
  129. fleetpull/models/samsara/vehicle_fuel_energy_report.py +191 -0
  130. fleetpull/network/__init__.py +9 -0
  131. fleetpull/network/auth/__init__.py +15 -0
  132. fleetpull/network/auth/authenticate.py +271 -0
  133. fleetpull/network/auth/manager.py +223 -0
  134. fleetpull/network/auth/models.py +57 -0
  135. fleetpull/network/auth/strategies.py +169 -0
  136. fleetpull/network/classifiers/__init__.py +11 -0
  137. fleetpull/network/classifiers/geotab.py +145 -0
  138. fleetpull/network/classifiers/motive.py +79 -0
  139. fleetpull/network/classifiers/samsara.py +80 -0
  140. fleetpull/network/client/__init__.py +25 -0
  141. fleetpull/network/client/page.py +32 -0
  142. fleetpull/network/client/profile.py +27 -0
  143. fleetpull/network/client/registry.py +103 -0
  144. fleetpull/network/client/registry_base.py +150 -0
  145. fleetpull/network/client/runtime.py +44 -0
  146. fleetpull/network/client/transport.py +381 -0
  147. fleetpull/network/contract/__init__.py +50 -0
  148. fleetpull/network/contract/auth.py +48 -0
  149. fleetpull/network/contract/classifier.py +189 -0
  150. fleetpull/network/contract/envelope_fetcher.py +33 -0
  151. fleetpull/network/contract/envelopes.py +189 -0
  152. fleetpull/network/contract/outcome.py +43 -0
  153. fleetpull/network/contract/page_decoder.py +101 -0
  154. fleetpull/network/contract/request.py +97 -0
  155. fleetpull/network/decoders/__init__.py +40 -0
  156. fleetpull/network/decoders/_window_stamp.py +78 -0
  157. fleetpull/network/decoders/geotab.py +309 -0
  158. fleetpull/network/decoders/motive.py +204 -0
  159. fleetpull/network/decoders/motive_reports.py +114 -0
  160. fleetpull/network/decoders/samsara.py +343 -0
  161. fleetpull/network/decoders/samsara_reports.py +119 -0
  162. fleetpull/network/decoders/single_page.py +55 -0
  163. fleetpull/network/limits/__init__.py +13 -0
  164. fleetpull/network/limits/bucket_math.py +58 -0
  165. fleetpull/network/limits/limiter.py +153 -0
  166. fleetpull/network/limits/registry.py +96 -0
  167. fleetpull/network/posture/__init__.py +6 -0
  168. fleetpull/network/posture/client_options.py +96 -0
  169. fleetpull/network/retry/__init__.py +13 -0
  170. fleetpull/network/retry/decision.py +155 -0
  171. fleetpull/network/tls/__init__.py +5 -0
  172. fleetpull/network/tls/truststore_context.py +35 -0
  173. fleetpull/orchestrator/__init__.py +30 -0
  174. fleetpull/orchestrator/backfill.py +127 -0
  175. fleetpull/orchestrator/batch.py +155 -0
  176. fleetpull/orchestrator/bisection.py +271 -0
  177. fleetpull/orchestrator/drivers.py +350 -0
  178. fleetpull/orchestrator/entry.py +347 -0
  179. fleetpull/orchestrator/executors.py +128 -0
  180. fleetpull/orchestrator/fanout.py +163 -0
  181. fleetpull/orchestrator/feed_drive.py +266 -0
  182. fleetpull/orchestrator/metadata_projection.py +195 -0
  183. fleetpull/orchestrator/outcome.py +53 -0
  184. fleetpull/orchestrator/recording.py +85 -0
  185. fleetpull/orchestrator/resume.py +143 -0
  186. fleetpull/orchestrator/roster_harvest.py +108 -0
  187. fleetpull/orchestrator/roster_refresh.py +363 -0
  188. fleetpull/orchestrator/runner.py +262 -0
  189. fleetpull/orchestrator/shape_resolution.py +221 -0
  190. fleetpull/orchestrator/spine.py +166 -0
  191. fleetpull/orchestrator/streaming.py +153 -0
  192. fleetpull/orchestrator/unit_loop.py +273 -0
  193. fleetpull/orchestrator/watermark_drive.py +455 -0
  194. fleetpull/paths/__init__.py +13 -0
  195. fleetpull/paths/datasets.py +38 -0
  196. fleetpull/paths/partitions.py +41 -0
  197. fleetpull/paths/resolution.py +98 -0
  198. fleetpull/polars_typing/__init__.py +20 -0
  199. fleetpull/py.typed +0 -0
  200. fleetpull/records/__init__.py +19 -0
  201. fleetpull/records/convert.py +53 -0
  202. fleetpull/records/dataframe.py +63 -0
  203. fleetpull/records/event_time.py +70 -0
  204. fleetpull/records/fields.py +190 -0
  205. fleetpull/records/flatten.py +54 -0
  206. fleetpull/records/roster_members.py +74 -0
  207. fleetpull/records/schema.py +73 -0
  208. fleetpull/records/validation.py +62 -0
  209. fleetpull/resources/__init__.py +10 -0
  210. fleetpull/resources/config.example.yaml +222 -0
  211. fleetpull/roster/__init__.py +16 -0
  212. fleetpull/roster/definition.py +46 -0
  213. fleetpull/roster/key.py +40 -0
  214. fleetpull/roster/registry.py +93 -0
  215. fleetpull/state/__init__.py +36 -0
  216. fleetpull/state/cursors.py +417 -0
  217. fleetpull/state/database.py +463 -0
  218. fleetpull/state/migrations.py +430 -0
  219. fleetpull/state/reconcile.py +127 -0
  220. fleetpull/state/rosters.py +159 -0
  221. fleetpull/state/run_ledger.py +572 -0
  222. fleetpull/state/work_units.py +648 -0
  223. fleetpull/storage/__init__.py +30 -0
  224. fleetpull/storage/append.py +187 -0
  225. fleetpull/storage/atomic.py +161 -0
  226. fleetpull/storage/files.py +176 -0
  227. fleetpull/storage/frames.py +98 -0
  228. fleetpull/storage/metadata.py +161 -0
  229. fleetpull/storage/partitioned.py +205 -0
  230. fleetpull/storage/pruning.py +169 -0
  231. fleetpull/storage/read.py +35 -0
  232. fleetpull/storage/result.py +34 -0
  233. fleetpull/storage/single_file.py +130 -0
  234. fleetpull/storage/splitting.py +88 -0
  235. fleetpull/storage/staging.py +178 -0
  236. fleetpull/storage/writers.py +145 -0
  237. fleetpull/timing/__init__.py +21 -0
  238. fleetpull/timing/canon.py +92 -0
  239. fleetpull/timing/clock.py +192 -0
  240. fleetpull/timing/codec.py +122 -0
  241. fleetpull/timing/sleeper.py +65 -0
  242. fleetpull/vocabulary/__init__.py +16 -0
  243. fleetpull/vocabulary/json_types.py +20 -0
  244. fleetpull/vocabulary/provider.py +29 -0
  245. fleetpull/vocabulary/quota_scope.py +47 -0
  246. fleetpull/vocabulary/response_category.py +32 -0
  247. fleetpull-0.1.0.dist-info/METADATA +248 -0
  248. fleetpull-0.1.0.dist-info/RECORD +252 -0
  249. fleetpull-0.1.0.dist-info/WHEEL +5 -0
  250. fleetpull-0.1.0.dist-info/entry_points.txt +2 -0
  251. fleetpull-0.1.0.dist-info/licenses/LICENSE +202 -0
  252. fleetpull-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,121 @@
1
+ # src/fleetpull/endpoints/samsara/vehicles.py
2
+ """The Samsara vehicles binding: a factory composing the vehicles snapshot
3
+ EndpointDefinition from resolved Samsara configuration, plus the
4
+ ``vehicle_ids`` roster the listing feeds.
5
+
6
+ A binding cannot be a module-level constant because its spec-builder
7
+ needs the run's configured base URL, known only after the YAML config
8
+ loads; so the endpoint is a factory taking a validated ``SamsaraConfig``
9
+ and returning the frozen ``EndpointDefinition`` the composition root
10
+ hands to the client (the Motive leaf convention).
11
+
12
+ The cursor walk was proven live before this binding shipped (2026-07-17
13
+ probe session): the advance continued across a real page boundary with
14
+ no overlap or loss, and the terminal page carries ``hasNextPage: false``
15
+ beside an empty-string ``endCursor``. The walk is complete by
16
+ construction -- continuation is explicit on every page and a promised
17
+ continuation without a cursor fails loudly in the decoder -- so no
18
+ completeness check is declared (unlike GeoTab's silently capped ``Get``,
19
+ there is nothing here to silently lose). Success responses carry no
20
+ rate-limit headers (captured 2026-07-17), so the config's self-limiting
21
+ default is the only budget signal.
22
+
23
+ ``VEHICLE_IDS_ROSTER`` is declared here, beside the feeder it describes:
24
+ the roster names this module's endpoint and its frame column, which is
25
+ provider-specific knowledge that belongs in the provider leaf (the
26
+ Motive vehicles precedent). Unlike the endpoint factory it needs no
27
+ config, so it is a frozen constant -- and a public one deliberately:
28
+ ``build_roster_registry`` discovers public module-level
29
+ ``RosterDefinition`` constants in the same walk that finds
30
+ ``build_endpoint``, so declaring the constant IS the registration (no
31
+ hand-maintained list exists to drift). On inactive coverage, honestly:
32
+ the 2026-07-17 capture proves ``/fleet/vehicles`` lists unplugged units
33
+ (the minimal 7-key shape is a gateway-less unit carrying a
34
+ serial-shaped default name), so present-but-inactive vehicles stay
35
+ fanned over; whether Samsara ever delists a removed vehicle was not
36
+ probed, and the eviction hysteresis below is what retires a member the
37
+ listing stops returning.
38
+ """
39
+
40
+ from datetime import timedelta
41
+ from typing import Final
42
+
43
+ from fleetpull.config import SamsaraConfig
44
+ from fleetpull.endpoints.shared import (
45
+ EndpointDefinition,
46
+ SnapshotMode,
47
+ StaticGetSpecBuilder,
48
+ StorageKind,
49
+ )
50
+ from fleetpull.models.samsara import Vehicle
51
+ from fleetpull.network.decoders import SamsaraCursorPageDecoder
52
+ from fleetpull.roster import RosterDefinition, RosterKey
53
+ from fleetpull.vocabulary import Provider, QuotaScope
54
+
55
+ __all__: list[str] = ['VEHICLE_IDS_ROSTER', 'build_endpoint']
56
+
57
+ _VEHICLES_PATH: Final[str] = '/fleet/vehicles'
58
+ _RECORDS_KEY: Final[str] = 'data'
59
+
60
+ # The per-page record count. 512 is Samsara's documented list-endpoint
61
+ # maximum, and the live sweep confirmed it honored exactly (a 608-vehicle
62
+ # fleet returned 512 + 96). A strong candidate for a user config knob.
63
+ _RESULTS_LIMIT: Final[int] = 512
64
+
65
+ # The fleet's membership changes on the order of days, so a daily re-list
66
+ # keeps the roster current without spending a full vehicles listing on
67
+ # every sync (the Motive vehicle_ids policy, re-declared per provider --
68
+ # intentional cross-provider duplication, blast-radius over DRY).
69
+ _VEHICLE_IDS_MAX_AGE: Final[timedelta] = timedelta(days=1)
70
+
71
+ # Eviction hysteresis (DESIGN §3): vehicle ids are permanent, absent-
72
+ # means-empty keys, so eviction is an efficiency lever (stop fanning over
73
+ # vehicles the listing no longer returns), not a correctness one. Three
74
+ # consecutive absent listings tolerate a transient provider omission
75
+ # before dropping a member.
76
+ _VEHICLE_IDS_EVICTION_THRESHOLD: Final[int] = 3
77
+
78
+ # The Samsara vehicle_ids roster: fed by this module's vehicles listing,
79
+ # read by its fan-out consumers -- trips and asset_locations -- which
80
+ # carry only the RosterKey. The
81
+ # source column is the vehicles frame's 'id' (the top-level model field,
82
+ # flattened verbatim) -- a numeric string, mirrored as string.
83
+ VEHICLE_IDS_ROSTER: RosterDefinition = RosterDefinition(
84
+ key=RosterKey(Provider.SAMSARA, 'vehicle_ids'),
85
+ source_endpoint='vehicles',
86
+ source_column='id',
87
+ max_age=_VEHICLE_IDS_MAX_AGE,
88
+ eviction_threshold=_VEHICLE_IDS_EVICTION_THRESHOLD,
89
+ )
90
+
91
+
92
+ def build_endpoint(config: SamsaraConfig) -> EndpointDefinition[Vehicle]:
93
+ """Build the Samsara vehicles snapshot binding.
94
+
95
+ A full-listing snapshot of the fleet's vehicles: no resume, a single
96
+ parquet file, full replacement each run. Records arrive as a
97
+ top-level list under ``data``, walked by explicit cursor pages
98
+ (``limit`` on page one, ``after`` merged thereafter), terminal on
99
+ ``hasNextPage: false``.
100
+
101
+ Args:
102
+ config: The validated Samsara configuration; supplies the base
103
+ URL the spec-builder joins to the vehicles path.
104
+
105
+ Returns:
106
+ The frozen vehicles ``EndpointDefinition``.
107
+ """
108
+ return EndpointDefinition(
109
+ provider=Provider.SAMSARA,
110
+ name='vehicles',
111
+ spec_builder=StaticGetSpecBuilder(
112
+ base_url=config.base_url, path=_VEHICLES_PATH
113
+ ),
114
+ page_decoder=SamsaraCursorPageDecoder(
115
+ records_key=_RECORDS_KEY, results_limit=_RESULTS_LIMIT
116
+ ),
117
+ response_model=Vehicle,
118
+ quota_scope=QuotaScope.SAMSARA,
119
+ storage_kind=StorageKind.SINGLE,
120
+ sync_mode=SnapshotMode(),
121
+ )
@@ -0,0 +1,57 @@
1
+ # src/fleetpull/endpoints/shared/__init__.py
2
+ """Shared endpoints-layer surface: the ``EndpointDefinition`` binding, the
3
+ ``SpecBuilder`` protocol and its provider-agnostic implementations, the
4
+ ``RequestShape`` union (request cardinality), the URL-path renderer for
5
+ fan-out paths, the resume-value type guard, and the sync-mode / storage /
6
+ resume declaration types."""
7
+
8
+ from fleetpull.endpoints.shared.base import (
9
+ CompletenessCheck,
10
+ EndpointDefinition,
11
+ ResumeValue,
12
+ SpecBuilder,
13
+ )
14
+ from fleetpull.endpoints.shared.request_shape import (
15
+ BatchedRosterFanOut,
16
+ BisectedWindowFetch,
17
+ ParamSweep,
18
+ RequestShape,
19
+ RosterFanOut,
20
+ SingleFetch,
21
+ )
22
+ from fleetpull.endpoints.shared.resume import require_date_window, require_feed_resume
23
+ from fleetpull.endpoints.shared.spec_builders import StaticGetSpecBuilder
24
+ from fleetpull.endpoints.shared.sync_mode import (
25
+ FeedMode,
26
+ SnapshotMode,
27
+ StorageKind,
28
+ SyncMode,
29
+ WatermarkMode,
30
+ )
31
+ from fleetpull.endpoints.shared.url_paths import (
32
+ UrlPathTemplateError,
33
+ render_url_path_template,
34
+ )
35
+
36
+ __all__: list[str] = [
37
+ 'BatchedRosterFanOut',
38
+ 'BisectedWindowFetch',
39
+ 'CompletenessCheck',
40
+ 'EndpointDefinition',
41
+ 'FeedMode',
42
+ 'ParamSweep',
43
+ 'RequestShape',
44
+ 'ResumeValue',
45
+ 'RosterFanOut',
46
+ 'SingleFetch',
47
+ 'SnapshotMode',
48
+ 'SpecBuilder',
49
+ 'StaticGetSpecBuilder',
50
+ 'StorageKind',
51
+ 'SyncMode',
52
+ 'UrlPathTemplateError',
53
+ 'WatermarkMode',
54
+ 'render_url_path_template',
55
+ 'require_date_window',
56
+ 'require_feed_resume',
57
+ ]