@youdotcom-oss/mcp 1.6.0 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdotcom-oss/mcp",
3
- "version": "1.6.0",
3
+ "version": "2.0.0",
4
4
  "description": "You.com API Model Context Protocol Server - For programmatic API access, use @youdotcom-oss/api",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "mcpName": "io.github.youdotcom-oss/mcp",
58
58
  "dependencies": {
59
- "@youdotcom-oss/api": "0.1.1",
59
+ "@youdotcom-oss/api": "0.2.0",
60
60
  "zod": "^4.3.6",
61
61
  "@hono/mcp": "^0.2.3",
62
62
  "@modelcontextprotocol/sdk": "^1.25.3",
@@ -16,12 +16,12 @@ export const ContentsStructuredContentSchema = z.object({
16
16
  html: z.string().optional().describe('HTML content'),
17
17
  metadata: z
18
18
  .object({
19
- jsonld: z.array(z.record(z.string(), z.unknown())).optional(),
20
- opengraph: z.record(z.string(), z.string()).optional(),
21
- twitter: z.record(z.string(), z.string()).optional(),
19
+ favicon_url: z.string().describe('Favicon URL'),
20
+ site_name: z.string().optional().nullable().describe('Site name'),
22
21
  })
23
22
  .optional()
24
- .describe('Structured metadata'),
23
+ .nullable()
24
+ .describe('Page metadata'),
25
25
  }),
26
26
  )
27
27
  .describe('Extracted items'),
@@ -47,30 +47,12 @@ export const formatContentsResponse = (
47
47
  if (formats.includes('metadata') && item.metadata) {
48
48
  textParts.push('\n### Metadata\n')
49
49
 
50
- if (item.metadata.jsonld && item.metadata.jsonld.length > 0) {
51
- textParts.push('\n**JSON-LD:**\n')
52
- const jsonldStr = JSON.stringify(item.metadata.jsonld, null, 2)
53
- if (jsonldStr.length > 2000) {
54
- textParts.push(jsonldStr.substring(0, 2000))
55
- textParts.push('\n...(truncated for display, see structuredContent for full data)')
56
- } else {
57
- textParts.push(jsonldStr)
58
- }
59
- textParts.push('\n')
50
+ if (item.metadata.site_name) {
51
+ textParts.push(`**Site Name:** ${item.metadata.site_name}\n`)
60
52
  }
61
53
 
62
- if (item.metadata.opengraph) {
63
- textParts.push('\n**OpenGraph:**\n')
64
- for (const [key, value] of Object.entries(item.metadata.opengraph)) {
65
- textParts.push(`- ${key}: ${value}\n`)
66
- }
67
- }
68
-
69
- if (item.metadata.twitter) {
70
- textParts.push('\n**Twitter:**\n')
71
- for (const [key, value] of Object.entries(item.metadata.twitter)) {
72
- textParts.push(`- ${key}: ${value}\n`)
73
- }
54
+ if (item.metadata.favicon_url) {
55
+ textParts.push(`**Favicon:** ${item.metadata.favicon_url}\n`)
74
56
  }
75
57
  }
76
58
 
@@ -79,10 +61,10 @@ export const formatContentsResponse = (
79
61
  // Add to structured content
80
62
  items.push({
81
63
  url: item.url,
82
- title: item.title,
83
- markdown: item.markdown,
84
- html: item.html,
85
- metadata: item.metadata,
64
+ title: item.title ?? undefined,
65
+ markdown: item.markdown ?? undefined,
66
+ html: item.html ?? undefined,
67
+ metadata: item.metadata ?? undefined,
86
68
  })
87
69
  }
88
70
 
package/src/http.ts CHANGED
@@ -3,7 +3,6 @@ import { type Context, Hono } from 'hono'
3
3
  import { trimTrailingSlash } from 'hono/trailing-slash'
4
4
  import packageJson from '../package.json' with { type: 'json' }
5
5
  import { registerContentsTool } from './contents/register-contents-tool.ts'
6
- import { registerExpressTool } from './express/register-express-tool.ts'
7
6
  import { getMCpServer } from './get-mcp-server.ts'
8
7
  import { registerSearchTool } from './search/register-search-tool.ts'
9
8
  import { useGetClientVersion } from './shared/use-client-version.ts'
@@ -39,7 +38,6 @@ const handleMcpRequest = async (c: Context) => {
39
38
  YDC_API_KEY,
40
39
  getUserAgent,
41
40
  })
42
- registerExpressTool({ mcp, YDC_API_KEY, getUserAgent })
43
41
  registerContentsTool({ mcp, YDC_API_KEY, getUserAgent })
44
42
 
45
43
  const transport = new StreamableHTTPTransport()
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Generic search result type that works for both Search and Express APIs
3
- * Used by both search.utils.ts and express.utils.ts
2
+ * Generic search result type for Search API results
3
+ * Used by search.utils.ts
4
4
  */
5
5
  type GenericSearchResult = {
6
6
  url: string
@@ -13,7 +13,7 @@ type GenericSearchResult = {
13
13
 
14
14
  /**
15
15
  * Format array of search results into display text
16
- * Used by both search and express agent formatting
16
+ * Used by search result formatting
17
17
  * @param results - Array of search results to format
18
18
  */
19
19
  export const formatSearchResultsText = (results: GenericSearchResult[]): string => {
@@ -38,7 +38,7 @@ export const formatSearchResultsText = (results: GenericSearchResult[]): string
38
38
  if (result.snippets && result.snippets.length > 0) {
39
39
  parts.push(`Snippets:\n- ${result.snippets.join('\n- ')}`)
40
40
  }
41
- // Handle single snippet (from Express API)
41
+ // Handle single snippet
42
42
  else if (result.snippet) {
43
43
  parts.push(`Snippet: ${result.snippet}`)
44
44
  }
@@ -3,7 +3,7 @@ import packageJson from '../../package.json' with { type: 'json' }
3
3
 
4
4
  /**
5
5
  * Creates User-Agent string for API requests
6
- * Used by search and express agent API calls
6
+ * Used by search and contents API calls
7
7
  */
8
8
  const setUserAgent = (client: string) => `MCP/${packageJson.version} (You.com; ${client})`
9
9
 
package/src/stdio.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
3
3
  import { registerContentsTool } from './contents/register-contents-tool.ts'
4
- import { registerExpressTool } from './express/register-express-tool.ts'
5
4
  import { getMCpServer } from './get-mcp-server.ts'
6
5
  import { registerSearchTool } from './search/register-search-tool.ts'
7
6
  import { useGetClientVersion } from './shared/use-client-version.ts'
@@ -13,7 +12,6 @@ try {
13
12
  const getUserAgent = useGetClientVersion(mcp)
14
13
 
15
14
  registerSearchTool({ mcp, YDC_API_KEY, getUserAgent })
16
- registerExpressTool({ mcp, YDC_API_KEY, getUserAgent })
17
15
  registerContentsTool({ mcp, YDC_API_KEY, getUserAgent })
18
16
 
19
17
  const transport = new StdioServerTransport()
@@ -212,13 +212,12 @@ describe('registerSearchTool', () => {
212
212
  )
213
213
 
214
214
  test(
215
- 'handles site parameter',
215
+ 'handles site: operator in query',
216
216
  async () => {
217
217
  const result = await client.callTool({
218
218
  name: 'you-search',
219
219
  arguments: {
220
- query: 'react components',
221
- site: 'github.com',
220
+ query: 'react components site:github.com',
222
221
  },
223
222
  })
224
223
 
@@ -229,13 +228,12 @@ describe('registerSearchTool', () => {
229
228
  )
230
229
 
231
230
  test(
232
- 'handles fileType parameter',
231
+ 'handles filetype: operator in query',
233
232
  async () => {
234
233
  const result = await client.callTool({
235
234
  name: 'you-search',
236
235
  arguments: {
237
- query: 'documentation',
238
- fileType: 'pdf',
236
+ query: 'documentation filetype:pdf',
239
237
  },
240
238
  })
241
239
 
@@ -246,13 +244,12 @@ describe('registerSearchTool', () => {
246
244
  )
247
245
 
248
246
  test(
249
- 'handles language parameter',
247
+ 'handles lang: operator in query',
250
248
  async () => {
251
249
  const result = await client.callTool({
252
250
  name: 'you-search',
253
251
  arguments: {
254
- query: 'tutorial',
255
- language: 'es',
252
+ query: 'tutorial lang:es',
256
253
  },
257
254
  })
258
255
 
@@ -263,13 +260,12 @@ describe('registerSearchTool', () => {
263
260
  )
264
261
 
265
262
  test(
266
- 'handles exactTerms parameter',
263
+ 'handles + operator for required terms in query',
267
264
  async () => {
268
265
  const result = await client.callTool({
269
266
  name: 'you-search',
270
267
  arguments: {
271
- query: 'programming',
272
- exactTerms: 'javascript|typescript',
268
+ query: 'programming +javascript +typescript',
273
269
  },
274
270
  })
275
271
 
@@ -280,13 +276,12 @@ describe('registerSearchTool', () => {
280
276
  )
281
277
 
282
278
  test(
283
- 'handles excludeTerms parameter',
279
+ 'handles - operator for excluded terms in query',
284
280
  async () => {
285
281
  const result = await client.callTool({
286
282
  name: 'you-search',
287
283
  arguments: {
288
- query: 'tutorial',
289
- excludeTerms: 'beginner|basic',
284
+ query: 'tutorial -beginner -basic',
290
285
  },
291
286
  })
292
287
 
@@ -297,54 +292,17 @@ describe('registerSearchTool', () => {
297
292
  )
298
293
 
299
294
  test(
300
- 'handles multi-word phrases with parentheses in exactTerms',
301
- async () => {
302
- const result = await client.callTool({
303
- name: 'you-search',
304
- arguments: {
305
- query: 'programming',
306
- exactTerms: '(machine learning)|typescript',
307
- },
308
- })
309
-
310
- const content = result.content as { type: string; text: string }[]
311
- expect(content[0]?.text).toContain('programming')
312
- },
313
- { retry: 2 },
314
- )
315
-
316
- test(
317
- 'handles multi-word phrases with parentheses in excludeTerms',
318
- async () => {
319
- const result = await client.callTool({
320
- name: 'you-search',
321
- arguments: {
322
- query: 'programming',
323
- excludeTerms: '(social media)|ads',
324
- },
325
- })
326
-
327
- const content = result.content as { type: string; text: string }[]
328
- expect(content[0]?.text).toContain('programming')
329
- },
330
- { retry: 2 },
331
- )
332
-
333
- test(
334
- 'handles complex search with multiple parameters',
295
+ 'handles complex search with multiple operators in query',
335
296
  async () => {
336
297
  const result = await client.callTool({
337
298
  name: 'you-search',
338
299
  arguments: {
339
- query: 'machine learning tutorial',
300
+ query: 'machine learning tutorial site:github.com filetype:md lang:en',
340
301
  count: 5,
341
302
  offset: 1,
342
303
  freshness: 'month',
343
304
  country: 'US',
344
305
  safesearch: 'moderate',
345
- site: 'github.com',
346
- fileType: 'md',
347
- language: 'en',
348
306
  },
349
307
  })
350
308
 
@@ -431,25 +389,6 @@ describe('registerSearchTool', () => {
431
389
  { retry: 2 },
432
390
  )
433
391
 
434
- test(
435
- 'returns error when both exactTerms and excludeTerms are provided',
436
- async () => {
437
- const result = await client.callTool({
438
- name: 'you-search',
439
- arguments: {
440
- query: 'programming',
441
- exactTerms: 'javascript',
442
- excludeTerms: 'beginner',
443
- },
444
- })
445
-
446
- expect(result.isError).toBe(true)
447
- const content = result.content as { type: string; text: string }[]
448
- expect(content[0]?.text).toContain('Cannot specify both exactTerms and excludeTerms - please use only one')
449
- },
450
- { retry: 2 },
451
- )
452
-
453
392
  test('handles API errors gracefully', async () => {
454
393
  try {
455
394
  await client.callTool({
@@ -1,23 +0,0 @@
1
- import * as z from 'zod'
2
-
3
- // Minimal schema for structuredContent (reduces payload duplication)
4
- export const ExpressStructuredContentSchema = z.object({
5
- answer: z.string().describe('AI answer'),
6
- hasResults: z.boolean().describe('Has web results'),
7
- resultCount: z.number().describe('Result count'),
8
- agent: z.string().optional().describe('Agent ID'),
9
- results: z
10
- .object({
11
- web: z
12
- .array(
13
- z.object({
14
- url: z.string().describe('URL'),
15
- title: z.string().describe('Title'),
16
- }),
17
- )
18
- .optional()
19
- .describe('Web results'),
20
- })
21
- .optional()
22
- .describe('Search results'),
23
- })
@@ -1,44 +0,0 @@
1
- import type { ExpressAgentMcpResponse } from '@youdotcom-oss/api'
2
- import { formatSearchResultsText } from '../shared/format-search-results-text.ts'
3
-
4
- export const formatExpressAgentResponse = (response: ExpressAgentMcpResponse) => {
5
- const _agentId = response.agent || 'express'
6
- const content: Array<{ type: 'text'; text: string }> = []
7
-
8
- // 1. Answer first (always present)
9
- content.push({
10
- type: 'text',
11
- text: `Express Agent Answer:\n\n${response.answer}`,
12
- })
13
-
14
- // 2. Search results second (if present when web_search tool was used) - without URLs in text
15
- if (response.results?.web?.length) {
16
- const formattedResults = formatSearchResultsText(response.results.web)
17
- content.push({
18
- type: 'text',
19
- text: `\nSearch Results:\n\n${formattedResults}`,
20
- })
21
- }
22
-
23
- // Extract URLs and titles for structuredContent
24
- const structuredResults = response.results?.web?.length
25
- ? {
26
- web: response.results.web.map((result) => ({
27
- url: result.url,
28
- title: result.title,
29
- })),
30
- }
31
- : undefined
32
-
33
- return {
34
- content,
35
- structuredContent: {
36
- answer: response.answer,
37
- hasResults: !!response.results?.web?.length,
38
- resultCount: response.results?.web?.length || 0,
39
- agent: response.agent,
40
- results: structuredResults,
41
- },
42
- fullResponse: response,
43
- }
44
- }
@@ -1,67 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
- import { callExpressAgent, ExpressAgentInputSchema, generateErrorReportLink } from '@youdotcom-oss/api'
3
- import { getLogger } from '../shared/get-logger.ts'
4
- import { ExpressStructuredContentSchema } from './express.schema.ts'
5
- import { formatExpressAgentResponse } from './express.utils.ts'
6
-
7
- export const registerExpressTool = ({
8
- mcp,
9
- YDC_API_KEY,
10
- getUserAgent,
11
- }: {
12
- mcp: McpServer
13
- YDC_API_KEY?: string
14
- getUserAgent: () => string
15
- }) => {
16
- mcp.registerTool(
17
- 'you-express',
18
- {
19
- title: 'Express Agent',
20
- description: 'Fast AI answers with web search',
21
- inputSchema: ExpressAgentInputSchema.shape,
22
- outputSchema: ExpressStructuredContentSchema.shape,
23
- },
24
- async (agentInput) => {
25
- const logger = getLogger(mcp)
26
-
27
- try {
28
- const response = await callExpressAgent({
29
- agentInput,
30
- YDC_API_KEY,
31
- getUserAgent,
32
- })
33
-
34
- await logger({
35
- level: 'info',
36
- data: `Express agent call successful for input: "${agentInput.input}"`,
37
- })
38
-
39
- const { content, structuredContent } = formatExpressAgentResponse(response)
40
- return { content, structuredContent }
41
- } catch (err: unknown) {
42
- const errorMessage = err instanceof Error ? err.message : String(err)
43
- const reportLink = generateErrorReportLink({
44
- errorMessage,
45
- tool: 'you-express',
46
- clientInfo: getUserAgent(),
47
- })
48
-
49
- await logger({
50
- level: 'error',
51
- data: `Express agent call failed: ${errorMessage}\n\nReport this issue: ${reportLink}`,
52
- })
53
-
54
- return {
55
- content: [
56
- {
57
- type: 'text' as const,
58
- text: `Error: ${errorMessage}`,
59
- },
60
- ],
61
- structuredContent: undefined,
62
- isError: true,
63
- }
64
- }
65
- },
66
- )
67
- }
@@ -1,177 +0,0 @@
1
- import { describe, expect, setDefaultTimeout, test } from 'bun:test'
2
- import type { ExpressAgentMcpResponse } from '@youdotcom-oss/api'
3
- import { formatExpressAgentResponse } from '../express.utils.ts'
4
-
5
- setDefaultTimeout(20_000)
6
-
7
- describe('formatExpressAgentResponse', () => {
8
- test('formats response with answer only (no search results)', () => {
9
- const mockResponse: ExpressAgentMcpResponse = {
10
- answer: 'The capital of France is Paris.',
11
- agent: 'express',
12
- }
13
-
14
- const result = formatExpressAgentResponse(mockResponse)
15
-
16
- // Verify content array has 1 item (answer only)
17
- expect(result).toHaveProperty('content')
18
- expect(Array.isArray(result.content)).toBe(true)
19
- expect(result.content.length).toBe(1)
20
-
21
- // Verify answer content
22
- expect(result.content[0]).toHaveProperty('type', 'text')
23
- expect(result.content[0]).toHaveProperty('text')
24
- expect(result.content[0]?.text).toContain('Express Agent Answer')
25
- expect(result.content[0]?.text).toContain('The capital of France is Paris.')
26
-
27
- // Verify structuredContent is minimal (not full response)
28
- expect(result).toHaveProperty('structuredContent')
29
- expect(result).toHaveProperty('fullResponse')
30
- expect(result.structuredContent).toHaveProperty('answer')
31
- expect(result.structuredContent).toHaveProperty('hasResults')
32
- expect(result.structuredContent).toHaveProperty('resultCount')
33
- expect(result.structuredContent).toHaveProperty('agent')
34
- expect(result.structuredContent.answer).toBe(mockResponse.answer)
35
- expect(result.structuredContent.hasResults).toBe(false)
36
- expect(result.structuredContent.resultCount).toBe(0)
37
- // No results, so results field should be undefined
38
- expect(result.structuredContent.results).toBeUndefined()
39
- expect(result.fullResponse).toEqual(mockResponse)
40
- })
41
-
42
- test('formats response with answer and search results', () => {
43
- const mockResponse: ExpressAgentMcpResponse = {
44
- answer: 'Quantum computing is advancing rapidly with recent breakthroughs in error correction.',
45
- results: {
46
- web: [
47
- {
48
- url: 'https://example.com/quantum1',
49
- title: 'Quantum Computing Breakthrough',
50
- snippet: 'Scientists achieve quantum error correction milestone.',
51
- },
52
- {
53
- url: 'https://example.com/quantum2',
54
- title: 'Latest in Quantum Research',
55
- snippet: 'New quantum processor demonstrates superiority.',
56
- },
57
- ],
58
- },
59
- agent: 'express',
60
- }
61
-
62
- const result = formatExpressAgentResponse(mockResponse)
63
-
64
- // Verify content array has 2 items (answer + search results)
65
- expect(result.content.length).toBe(2)
66
-
67
- // Verify answer comes FIRST
68
- expect(result.content[0]?.type).toBe('text')
69
- expect(result.content[0]?.text).toContain('Express Agent Answer')
70
- expect(result.content[0]?.text).toContain('Quantum computing is advancing rapidly')
71
-
72
- // Verify search results come SECOND
73
- expect(result.content[1]?.type).toBe('text')
74
- expect(result.content[1]?.text).toContain('Search Results')
75
- expect(result.content[1]?.text).toContain('Quantum Computing Breakthrough')
76
- expect(result.content[1]?.text).toContain('Latest in Quantum Research')
77
- // URLs should be in text content
78
- expect(result.content[1]?.text).toContain('https://example.com/quantum1')
79
- expect(result.content[1]?.text).toContain('https://example.com/quantum2')
80
-
81
- // Verify structuredContent is minimal with counts
82
- expect(result.structuredContent).toHaveProperty('answer')
83
- expect(result.structuredContent).toHaveProperty('hasResults')
84
- expect(result.structuredContent).toHaveProperty('resultCount')
85
- expect(result.structuredContent.answer).toBe(mockResponse.answer)
86
- expect(result.structuredContent.hasResults).toBe(true)
87
- expect(result.structuredContent.resultCount).toBe(2)
88
-
89
- // URLs should be in structuredContent.results
90
- expect(result.structuredContent).toHaveProperty('results')
91
- expect(result.structuredContent.results?.web).toBeDefined()
92
- expect(result.structuredContent.results?.web?.length).toBe(2)
93
- expect(result.structuredContent.results?.web?.[0]).toEqual({
94
- url: 'https://example.com/quantum1',
95
- title: 'Quantum Computing Breakthrough',
96
- })
97
- expect(result.structuredContent.results?.web?.[1]).toEqual({
98
- url: 'https://example.com/quantum2',
99
- title: 'Latest in Quantum Research',
100
- })
101
-
102
- // Verify fullResponse has complete data
103
- expect(result.fullResponse).toEqual(mockResponse)
104
- expect(result.fullResponse.results?.web).toHaveLength(2)
105
- })
106
-
107
- test('structuredContent validation for answer only', () => {
108
- const mockResponse: ExpressAgentMcpResponse = {
109
- answer: 'Neural networks are computational models inspired by biological neurons.',
110
- agent: 'express',
111
- }
112
-
113
- const result = formatExpressAgentResponse(mockResponse)
114
-
115
- // Verify structure matches minimal schema
116
- expect(result.structuredContent).toMatchObject({
117
- answer: expect.any(String),
118
- hasResults: false,
119
- resultCount: 0,
120
- agent: 'express',
121
- })
122
-
123
- // Verify fullResponse has complete data
124
- expect(result.fullResponse.results).toBeUndefined()
125
- })
126
-
127
- test('structuredContent validation for answer with results', () => {
128
- const mockResponse: ExpressAgentMcpResponse = {
129
- answer: 'Recent AI breakthroughs include advances in language models and computer vision.',
130
- results: {
131
- web: [
132
- {
133
- url: 'https://example.com/ai-breakthrough',
134
- title: 'AI Breakthrough 2025',
135
- snippet: 'Major advances in artificial intelligence.',
136
- },
137
- ],
138
- },
139
- agent: 'express',
140
- }
141
-
142
- const result = formatExpressAgentResponse(mockResponse)
143
-
144
- // Verify structuredContent is minimal with counts
145
- expect(result.structuredContent).toHaveProperty('answer')
146
- expect(result.structuredContent).toHaveProperty('hasResults')
147
- expect(result.structuredContent).toHaveProperty('resultCount')
148
- expect(result.structuredContent).toHaveProperty('agent')
149
- expect(result.structuredContent.answer).toBe(
150
- 'Recent AI breakthroughs include advances in language models and computer vision.',
151
- )
152
- expect(result.structuredContent.agent).toBe('express')
153
- expect(result.structuredContent.hasResults).toBe(true)
154
- expect(result.structuredContent.resultCount).toBe(1)
155
-
156
- // URLs should be in structuredContent.results
157
- expect(result.structuredContent).toHaveProperty('results')
158
- expect(result.structuredContent.results?.web).toBeDefined()
159
- expect(result.structuredContent.results?.web?.length).toBe(1)
160
- expect(result.structuredContent.results?.web?.[0]).toEqual({
161
- url: 'https://example.com/ai-breakthrough',
162
- title: 'AI Breakthrough 2025',
163
- })
164
-
165
- // Verify fullResponse has complete search results
166
- expect(result.fullResponse).toEqual(mockResponse)
167
- expect(result.fullResponse.results).toBeDefined()
168
- expect(Array.isArray(result.fullResponse.results?.web)).toBe(true)
169
- expect(result.fullResponse.results?.web.length).toBe(1)
170
-
171
- // Verify search result fields in fullResponse
172
- const searchResult = result.fullResponse.results?.web[0]
173
- expect(searchResult?.url).toBe('https://example.com/ai-breakthrough')
174
- expect(searchResult?.title).toBe('AI Breakthrough 2025')
175
- expect(searchResult?.snippet).toBe('Major advances in artificial intelligence.')
176
- })
177
- })