native-update 1.4.8 → 2.0.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.
Files changed (77) hide show
  1. package/Readme.md +13 -1
  2. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +15 -0
  3. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +23 -7
  4. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +152 -4
  5. package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +14 -1
  6. package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +10 -1
  7. package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +18 -18
  8. package/cli/AGENTS.md +29 -0
  9. package/cli/CLAUDE.md +51 -0
  10. package/dist/esm/__tests__/security-enforcement.test.d.ts +1 -0
  11. package/dist/esm/__tests__/security-enforcement.test.js +95 -0
  12. package/dist/esm/__tests__/security-enforcement.test.js.map +1 -0
  13. package/dist/esm/core/config.d.ts +6 -15
  14. package/dist/esm/core/config.js +1 -4
  15. package/dist/esm/core/config.js.map +1 -1
  16. package/dist/esm/core/security.d.ts +11 -3
  17. package/dist/esm/core/security.js +19 -6
  18. package/dist/esm/core/security.js.map +1 -1
  19. package/dist/esm/definitions.d.ts +38 -24
  20. package/dist/esm/definitions.js.map +1 -1
  21. package/dist/esm/firestore/firestore-client.js +4 -0
  22. package/dist/esm/firestore/firestore-client.js.map +1 -1
  23. package/dist/esm/firestore/schema.d.ts +2 -0
  24. package/dist/esm/firestore/schema.js.map +1 -1
  25. package/dist/esm/index.d.ts +1 -2
  26. package/dist/esm/index.js +0 -2
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/live-update/download-manager.d.ts +36 -5
  29. package/dist/esm/live-update/download-manager.js +61 -22
  30. package/dist/esm/live-update/download-manager.js.map +1 -1
  31. package/dist/esm/live-update/update-manager.d.ts +12 -1
  32. package/dist/esm/live-update/update-manager.js +38 -10
  33. package/dist/esm/live-update/update-manager.js.map +1 -1
  34. package/dist/esm/live-update/version-manager.d.ts +9 -0
  35. package/dist/esm/live-update/version-manager.js +40 -0
  36. package/dist/esm/live-update/version-manager.js.map +1 -1
  37. package/dist/esm/plugin.js +95 -175
  38. package/dist/esm/plugin.js.map +1 -1
  39. package/dist/esm/web.d.ts +18 -1
  40. package/dist/esm/web.js +69 -24
  41. package/dist/esm/web.js.map +1 -1
  42. package/dist/plugin.cjs.js +1 -1
  43. package/dist/plugin.cjs.js.map +1 -1
  44. package/dist/plugin.esm.js +1 -1
  45. package/dist/plugin.esm.js.map +1 -1
  46. package/dist/plugin.js +2 -2
  47. package/dist/plugin.js.map +1 -1
  48. package/docs/AGENTS.md +38 -0
  49. package/docs/CHANGELOG.md +167 -0
  50. package/docs/CLAUDE.md +101 -0
  51. package/docs/MIGRATION.md +87 -0
  52. package/docs/README.md +13 -2
  53. package/docs/deployment/HOSTINGER_DEPLOY.md +329 -0
  54. package/docs/features/laravel-nova-backend/ASSESSMENT-SUMMARY.md +96 -0
  55. package/docs/features/laravel-nova-backend/IMPLEMENTATION-PLAN.md +504 -0
  56. package/docs/features/laravel-nova-backend/credentials.ignore.md +34 -0
  57. package/docs/features/laravel-nova-backend/progress-tracker.json +184 -0
  58. package/docs/guides/no-cost-backend-implementation-plan.md +77 -0
  59. package/docs/guides/no-cost-firestore-google-drive-backend.md +60 -0
  60. package/docs/project-knowledge-base/01-system-overview.md +218 -0
  61. package/docs/project-knowledge-base/02-routes-pages-forms-users.md +346 -0
  62. package/docs/project-knowledge-base/03-tech-stack-modules-services.md +347 -0
  63. package/docs/project-knowledge-base/04-data-models-integrations.md +307 -0
  64. package/docs/project-knowledge-base/05-docs-corpus-inventory.md +193 -0
  65. package/docs/project-knowledge-base/06-operations-testing-legal-content.md +170 -0
  66. package/docs/project-knowledge-base/README.md +90 -0
  67. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-16.md +454 -0
  68. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-24.md +66 -0
  69. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-25.md +67 -0
  70. package/docs/seo-aeo-rules.json +3043 -0
  71. package/docs/tracking/seo-checklist-tracker.json +333 -0
  72. package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +50 -6
  73. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +238 -8
  74. package/ios/Plugin/NativeUpdatePlugin.swift +8 -0
  75. package/ios/Plugin/Security/SecurityManager.swift +13 -14
  76. package/package.json +31 -32
  77. package/docs/play-console-rejection-rules.json +0 -428
@@ -0,0 +1,333 @@
1
+ {
2
+ "project": "native-update",
3
+ "projectUrl": "https://nativeupdate.aoneahsan.com",
4
+ "projectDescription": "Capacitor plugin for OTA updates, app store updates & in-app reviews",
5
+ "createdAt": "2026-04-10",
6
+ "lastUpdated": "2026-04-10",
7
+ "summary": {
8
+ "totalItems": 47,
9
+ "completed": 14,
10
+ "inProgress": 0,
11
+ "pending": 22,
12
+ "notApplicable": 0,
13
+ "requiresDeployment": 11
14
+ },
15
+ "phases": {
16
+ "phase1_technical_foundation": {
17
+ "name": "Phase 1: Technical Foundation",
18
+ "description": "Core technical SEO setup that must be done first",
19
+ "items": [
20
+ {
21
+ "id": "P1-01",
22
+ "task": "Google Search Console - Add property, verify via HTML meta tag or DNS TXT, submit sitemap.xml",
23
+ "status": "requires_deployment",
24
+ "notes": "Must deploy first, then verify at search.google.com/search-console",
25
+ "implementedAt": null
26
+ },
27
+ {
28
+ "id": "P1-02",
29
+ "task": "Bing Webmaster Tools - Add site, verify via meta tag, submit sitemap.xml, import from GSC",
30
+ "status": "requires_deployment",
31
+ "notes": "bing.com/webmasters - has auto-import from Google Search Console",
32
+ "implementedAt": null
33
+ },
34
+ {
35
+ "id": "P1-03",
36
+ "task": "Yandex Webmaster - Add site, verify via meta tag, submit sitemap.xml",
37
+ "status": "requires_deployment",
38
+ "notes": "webmaster.yandex.com",
39
+ "implementedAt": null
40
+ },
41
+ {
42
+ "id": "P1-04",
43
+ "task": "Sitemap.xml - Ensure valid sitemap exists at /sitemap.xml with all public pages",
44
+ "status": "completed",
45
+ "notes": "Cleaned up: removed internal docs (reports, trackers, plans), login/signup. Now 62 clean public URLs.",
46
+ "implementedAt": "2026-04-10"
47
+ },
48
+ {
49
+ "id": "P1-05",
50
+ "task": "robots.txt - Ensure it exists and points to sitemap with correct project URL",
51
+ "status": "completed",
52
+ "notes": "Already exists with AI crawler allowlisting and correct sitemap URL",
53
+ "implementedAt": "2026-03-27"
54
+ },
55
+ {
56
+ "id": "P1-06",
57
+ "task": "SSL Certificate - All pages must be HTTPS",
58
+ "status": "completed",
59
+ "notes": "Already served via HTTPS on nativeupdate.aoneahsan.com",
60
+ "implementedAt": "2025-12-27"
61
+ },
62
+ {
63
+ "id": "P1-07",
64
+ "task": "Mobile Responsive - Test at search.google.com/test/mobile-friendly",
65
+ "status": "requires_deployment",
66
+ "notes": "Deploy then test. Site uses Tailwind CSS with responsive design.",
67
+ "implementedAt": null
68
+ },
69
+ {
70
+ "id": "P1-08",
71
+ "task": "Page Speed - Test at pagespeed.web.dev, aim for 90+ mobile",
72
+ "status": "requires_deployment",
73
+ "notes": "Deploy then test. Optimize based on results.",
74
+ "implementedAt": null
75
+ },
76
+ {
77
+ "id": "P1-09",
78
+ "task": "Core Web Vitals - Check in GSC after a few weeks. LCP < 2.5s, FID < 100ms, CLS < 0.1",
79
+ "status": "requires_deployment",
80
+ "notes": "Needs GSC data accumulation over weeks",
81
+ "implementedAt": null
82
+ }
83
+ ]
84
+ },
85
+ "phase2_on_page_seo": {
86
+ "name": "Phase 2: On-Page SEO",
87
+ "description": "Per-page SEO optimization for every public page",
88
+ "items": [
89
+ {
90
+ "id": "P2-01",
91
+ "task": "Title Tags - Every page needs unique <title> under 60 chars",
92
+ "status": "completed",
93
+ "notes": "usePageSEO hook applied to all 14 public pages with unique titles",
94
+ "implementedAt": "2026-04-10"
95
+ },
96
+ {
97
+ "id": "P2-02",
98
+ "task": "Meta Descriptions - Every page needs unique <meta description> under 155 chars",
99
+ "status": "completed",
100
+ "notes": "usePageSEO hook sets per-page descriptions on all 14 public pages",
101
+ "implementedAt": "2026-04-10"
102
+ },
103
+ {
104
+ "id": "P2-03",
105
+ "task": "H1 Tags - One H1 per page matching the page topic",
106
+ "status": "completed",
107
+ "notes": "Verified: all pages have exactly one H1 tag. Hidden SEO div also has H1 for crawlers.",
108
+ "implementedAt": "2026-04-10"
109
+ },
110
+ {
111
+ "id": "P2-04",
112
+ "task": "H2/H3 Structure - Logical heading hierarchy on every page",
113
+ "status": "completed",
114
+ "notes": "Pages use proper H1->H2->H3 hierarchy. Hidden SEO div has structured headings.",
115
+ "implementedAt": "2026-04-10"
116
+ },
117
+ {
118
+ "id": "P2-05",
119
+ "task": "Image Alt Text - Every image needs descriptive alt text",
120
+ "status": "pending",
121
+ "notes": "Need to audit all img/svg elements across pages for alt text",
122
+ "implementedAt": null
123
+ },
124
+ {
125
+ "id": "P2-06",
126
+ "task": "Internal Linking - Cross-link related pages (features->docs, pricing->features, etc.)",
127
+ "status": "pending",
128
+ "notes": "Pages have some CTAs but need more cross-linking for SEO juice",
129
+ "implementedAt": null
130
+ },
131
+ {
132
+ "id": "P2-07",
133
+ "task": "Canonical URLs - Add <link rel=canonical> per page to prevent duplicates",
134
+ "status": "completed",
135
+ "notes": "usePageSEO hook sets per-page canonical URL on every page dynamically",
136
+ "implementedAt": "2026-04-10"
137
+ },
138
+ {
139
+ "id": "P2-08",
140
+ "task": "Structured Data / Schema Markup - JSON-LD per page type (WebApplication, FAQPage, Article, BreadcrumbList)",
141
+ "status": "completed",
142
+ "notes": "BreadcrumbList auto-generated per page via usePageSEO. SoftwareApplication, FAQPage (10 Q&A), WebSite, Organization in postbuild.",
143
+ "implementedAt": "2026-04-10"
144
+ },
145
+ {
146
+ "id": "P2-09",
147
+ "task": "Open Graph tags - Per-page og:title, og:description, og:url, og:image",
148
+ "status": "completed",
149
+ "notes": "usePageSEO hook sets per-page OG tags on all pages",
150
+ "implementedAt": "2026-04-10"
151
+ },
152
+ {
153
+ "id": "P2-10",
154
+ "task": "Twitter Card tags - Per-page twitter:title, twitter:description",
155
+ "status": "completed",
156
+ "notes": "usePageSEO hook sets per-page Twitter Card tags on all pages",
157
+ "implementedAt": "2026-04-10"
158
+ }
159
+ ]
160
+ },
161
+ "phase3_content_seo": {
162
+ "name": "Phase 3: Content SEO",
163
+ "description": "Content strategy for long-tail keywords and organic traffic",
164
+ "items": [
165
+ {
166
+ "id": "P3-01",
167
+ "task": "Blog section - Create blog route and infrastructure for SEO content",
168
+ "status": "pending",
169
+ "notes": "No blog exists yet. Need /blog route with markdown-based posts.",
170
+ "implementedAt": null
171
+ },
172
+ {
173
+ "id": "P3-02",
174
+ "task": "Blog Posts - Write 5-10 initial posts targeting long-tail keywords",
175
+ "status": "pending",
176
+ "notes": "Topics: 'how to deploy OTA updates capacitor', 'capacitor vs codepush', 'mobile app update strategies', etc.",
177
+ "implementedAt": null
178
+ },
179
+ {
180
+ "id": "P3-03",
181
+ "task": "Keyword Research - Identify target keywords using free tools",
182
+ "status": "pending",
183
+ "notes": "Google Keyword Planner, Ubersuggest, AnswerThePublic, Google Autocomplete",
184
+ "implementedAt": null
185
+ },
186
+ {
187
+ "id": "P3-04",
188
+ "task": "FAQ Sections - Add visible FAQ with schema on key pages (home, features, pricing, docs)",
189
+ "status": "pending",
190
+ "notes": "FAQ schema exists in postbuild (expanded to 10 Q&A) but no visible FAQ sections on pages yet",
191
+ "implementedAt": null
192
+ },
193
+ {
194
+ "id": "P3-05",
195
+ "task": "Long-form feature descriptions - 300-500 words of unique content per feature page",
196
+ "status": "pending",
197
+ "notes": "Features page exists but may need more descriptive content per feature",
198
+ "implementedAt": null
199
+ }
200
+ ]
201
+ },
202
+ "phase4_niche_seo": {
203
+ "name": "Phase 4: Niche & Competitive SEO",
204
+ "description": "Niche-specific and competitive positioning content",
205
+ "items": [
206
+ {
207
+ "id": "P4-01",
208
+ "task": "Capacitor-specific keywords - Target 'capacitor ota updates', 'capacitor live updates plugin', 'capacitor code push alternative'",
209
+ "status": "pending",
210
+ "notes": "These are the primary niche keywords for this product",
211
+ "implementedAt": null
212
+ },
213
+ {
214
+ "id": "P4-02",
215
+ "task": "Comparison blog posts - 'Native Update vs CodePush', 'Native Update vs Capgo', 'Best Capacitor OTA plugins 2026'",
216
+ "status": "pending",
217
+ "notes": "Create honest comparison content highlighting strengths",
218
+ "implementedAt": null
219
+ },
220
+ {
221
+ "id": "P4-03",
222
+ "task": "Feature-specific landing content - Each feature (OTA, app updates, reviews) should have rich descriptive content",
223
+ "status": "pending",
224
+ "notes": "Dedicated feature pages exist in /docs/features/ but marketing pages need richer content",
225
+ "implementedAt": null
226
+ }
227
+ ]
228
+ },
229
+ "phase5_monitoring": {
230
+ "name": "Phase 5: Monitoring & Iteration",
231
+ "description": "Ongoing monitoring and optimization",
232
+ "items": [
233
+ {
234
+ "id": "P5-01",
235
+ "task": "Google Search Console - Weekly check: queries, indexed pages, errors",
236
+ "status": "requires_deployment",
237
+ "notes": "Requires GSC setup first (P1-01)",
238
+ "implementedAt": null
239
+ },
240
+ {
241
+ "id": "P5-02",
242
+ "task": "Track Rankings - Use free tier Ubersuggest/SERPRobot for 10-20 priority keywords",
243
+ "status": "pending",
244
+ "notes": "Set up after deployment and GSC verification",
245
+ "implementedAt": null
246
+ },
247
+ {
248
+ "id": "P5-03",
249
+ "task": "Fix Crawl Errors - Check GSC Coverage and fix any errors",
250
+ "status": "requires_deployment",
251
+ "notes": "Requires GSC data",
252
+ "implementedAt": null
253
+ },
254
+ {
255
+ "id": "P5-04",
256
+ "task": "Update Content - Refresh content every 3-6 months",
257
+ "status": "pending",
258
+ "notes": "Set reminder for quarterly content refresh",
259
+ "implementedAt": null
260
+ }
261
+ ]
262
+ },
263
+ "aeo_aio_optimization": {
264
+ "name": "AEO & AIO Optimization",
265
+ "description": "Answer Engine Optimization and AI Optimization for ChatGPT, Claude, Perplexity visibility",
266
+ "items": [
267
+ {
268
+ "id": "AI-01",
269
+ "task": "FAQ Schema - Add FAQPage JSON-LD to main pages and blog posts",
270
+ "status": "completed",
271
+ "notes": "Expanded to 10 Q&A pairs in postbuild-seo.ts covering installation, CodePush comparison, rollback, staged rollouts, security, platform support.",
272
+ "implementedAt": "2026-04-10"
273
+ },
274
+ {
275
+ "id": "AI-02",
276
+ "task": "Answer-First Content - Start descriptions with direct, concise answers in first paragraph",
277
+ "status": "pending",
278
+ "notes": "Review all page content for answer-first structure",
279
+ "implementedAt": null
280
+ },
281
+ {
282
+ "id": "AI-03",
283
+ "task": "How-to Guides - Step-by-step guides for common tasks",
284
+ "status": "pending",
285
+ "notes": "Docs have some guides. Need blog posts with 'How to' format.",
286
+ "implementedAt": null
287
+ },
288
+ {
289
+ "id": "AI-04",
290
+ "task": "Definition-Style Openings - Clear definitions at start of key pages",
291
+ "status": "pending",
292
+ "notes": "'Native Update is a Capacitor plugin that...' pattern on all key pages",
293
+ "implementedAt": null
294
+ },
295
+ {
296
+ "id": "AI-05",
297
+ "task": "Comparison Content - 'Native Update vs X' style content",
298
+ "status": "pending",
299
+ "notes": "Same as P4-02, cross-referenced",
300
+ "implementedAt": null
301
+ },
302
+ {
303
+ "id": "AI-06",
304
+ "task": "Structured Data Everywhere - Maximum schema markup coverage",
305
+ "status": "completed",
306
+ "notes": "WebSite, Organization, SoftwareApplication, FAQPage in postbuild. BreadcrumbList per-page via usePageSEO hook.",
307
+ "implementedAt": "2026-04-10"
308
+ },
309
+ {
310
+ "id": "AI-07",
311
+ "task": "Clear Product Description - 2-3 sentence quotable description for AI systems",
312
+ "status": "completed",
313
+ "notes": "Updated index.html hidden content with detailed, specific, quotable description including feature names and specifics.",
314
+ "implementedAt": "2026-04-10"
315
+ },
316
+ {
317
+ "id": "AI-08",
318
+ "task": "Be Specific - Use exact numbers and specifics instead of vague claims",
319
+ "status": "completed",
320
+ "notes": "Updated descriptions to include '3 core features', specific feature names, framework list, installation commands.",
321
+ "implementedAt": "2026-04-10"
322
+ },
323
+ {
324
+ "id": "AI-09",
325
+ "task": "AI Crawler Access in robots.txt - Allow GPTBot, ClaudeBot, PerplexityBot etc.",
326
+ "status": "completed",
327
+ "notes": "Already implemented in robots.txt with full AI crawler allowlisting",
328
+ "implementedAt": "2026-03-27"
329
+ }
330
+ ]
331
+ }
332
+ }
333
+ }
@@ -3,9 +3,23 @@ import Capacitor
3
3
  import BackgroundTasks
4
4
  import UserNotifications
5
5
 
6
+ /// BackgroundUpdatePlugin schedules silent OTA update checks via
7
+ /// `BGAppRefreshTask` on iOS 13+. The host app **must** declare the
8
+ /// scheduler identifier in its own `Info.plist` — the framework's plist
9
+ /// declaration does not propagate into the app bundle. Add:
10
+ ///
11
+ /// <key>BGTaskSchedulerPermittedIdentifiers</key>
12
+ /// <array>
13
+ /// <string>com.aoneahsan.nativeupdate.background</string>
14
+ /// </array>
15
+ ///
16
+ /// and (for the Capabilities pane) ensure `background-app-refresh` is
17
+ /// listed under `UIBackgroundModes`. Without those entries iOS will
18
+ /// silently refuse to register the task and background updates never
19
+ /// run — there is no runtime error.
6
20
  @objc(BackgroundUpdatePlugin)
7
21
  public class BackgroundUpdatePlugin: CAPPlugin {
8
-
22
+
9
23
  private let backgroundTaskIdentifier = "com.aoneahsan.nativeupdate.background"
10
24
  private var backgroundUpdateConfig: BackgroundUpdateConfig?
11
25
  private var backgroundUpdateStatus = BackgroundUpdateStatus(
@@ -133,19 +147,49 @@ public class BackgroundUpdatePlugin: CAPPlugin {
133
147
 
134
148
  private func scheduleBackgroundTask(interval: Int) {
135
149
  guard #available(iOS 13.0, *) else {
136
- NSLog("BackgroundTasks framework not available on iOS < 13.0")
150
+ NSLog("[native-update] BackgroundTasks framework not available on iOS < 13.0")
137
151
  return
138
152
  }
139
-
153
+
154
+ // Cancel any prior pending request with this identifier before
155
+ // submitting a new one. iOS documents submit() as replacing an
156
+ // existing request of the same identifier, but a few OS versions
157
+ // have been observed to fail the second submit with an
158
+ // already-scheduled error instead of replacing. Explicit cancel
159
+ // is the reliable path.
160
+ BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundTaskIdentifier)
161
+
140
162
  let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier)
141
163
  request.earliestBeginDate = Date(timeIntervalSinceNow: TimeInterval(interval / 1000))
142
-
164
+
143
165
  do {
144
166
  try BGTaskScheduler.shared.submit(request)
145
167
  backgroundUpdateStatus.nextCheckTime = Int(Date().timeIntervalSince1970 * 1000) + interval
146
- NSLog("Background task scheduled for \(interval)ms from now")
168
+ NSLog("[native-update] Background task scheduled for \(interval)ms from now")
169
+ } catch let error as BGTaskScheduler.Error {
170
+ // Surface a specific diagnostic. .notPermitted almost always
171
+ // means the host app's Info.plist is missing the scheduler
172
+ // identifier — which is a silent failure mode otherwise.
173
+ switch error.code {
174
+ case .notPermitted:
175
+ NSLog("[native-update] BGTaskScheduler .notPermitted — host app is missing BGTaskSchedulerPermittedIdentifiers entry for \(backgroundTaskIdentifier) in Info.plist")
176
+ case .tooManyPendingTaskRequests:
177
+ NSLog("[native-update] BGTaskScheduler .tooManyPendingTaskRequests — another task is already queued; background updates will run on the existing schedule")
178
+ case .unavailable:
179
+ NSLog("[native-update] BGTaskScheduler .unavailable — background tasks are disabled on this device (likely simulator or Low Power Mode)")
180
+ @unknown default:
181
+ NSLog("[native-update] Failed to schedule background task: \(error.localizedDescription)")
182
+ }
183
+ backgroundUpdateStatus.lastError = UpdateError(
184
+ code: "BGTASK_SUBMIT_FAILED",
185
+ message: error.localizedDescription
186
+ )
147
187
  } catch {
148
- NSLog("Failed to schedule background task: \(error.localizedDescription)")
188
+ NSLog("[native-update] Failed to schedule background task: \(error.localizedDescription)")
189
+ backgroundUpdateStatus.lastError = UpdateError(
190
+ code: "BGTASK_SUBMIT_FAILED",
191
+ message: error.localizedDescription
192
+ )
149
193
  }
150
194
  }
151
195