freshcontext-mcp 0.1.4 → 0.1.5
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/README.md +71 -33
- package/dist/server.js +1 -0
- package/package.json +4 -1
- package/src/server.ts +2 -0
- package/src/server.ts.bak +204 -0
package/README.md
CHANGED
|
@@ -21,14 +21,14 @@ Every piece of data extracted by `freshcontext-mcp` is wrapped in a structured e
|
|
|
21
21
|
[FRESHCONTEXT]
|
|
22
22
|
Source: https://github.com/owner/repo
|
|
23
23
|
Published: 2024-11-03
|
|
24
|
-
Retrieved: 2026-03-
|
|
24
|
+
Retrieved: 2026-03-04T10:14:00Z
|
|
25
25
|
Confidence: high
|
|
26
26
|
---
|
|
27
27
|
... content ...
|
|
28
28
|
[/FRESHCONTEXT]
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
The AI agent always knows **when it's looking at data**, not just what the data says.
|
|
31
|
+
The AI agent always knows **when it's looking at data**, not just what the data says.
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
@@ -60,13 +60,33 @@ The AI agent always knows **when it's looking at data**, not just what the data
|
|
|
60
60
|
|
|
61
61
|
## Quick Start
|
|
62
62
|
|
|
63
|
-
###
|
|
63
|
+
### Option A — Cloud (no install, works immediately)
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
No Node, no Playwright, nothing to install. Just add this to your Claude Desktop config and restart.
|
|
66
|
+
|
|
67
|
+
**Mac:** open `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
68
|
+
**Windows:** open `%APPDATA%\Claude\claude_desktop_config.json`
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"freshcontext": {
|
|
74
|
+
"command": "npx",
|
|
75
|
+
"args": ["-y", "mcp-remote", "https://freshcontext-mcp.gimmanuel73.workers.dev/mcp"]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
67
79
|
```
|
|
68
80
|
|
|
69
|
-
|
|
81
|
+
Restart Claude Desktop. The freshcontext tools will appear in your session.
|
|
82
|
+
|
|
83
|
+
> **Note:** If `claude_desktop_config.json` doesn't exist yet, create it with the content above.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Option B — Local (full Playwright, faster for heavy use)
|
|
88
|
+
|
|
89
|
+
**Prerequisites:** Node.js 18+ ([nodejs.org](https://nodejs.org))
|
|
70
90
|
|
|
71
91
|
```bash
|
|
72
92
|
git clone https://github.com/PrinceGabriel-lgtm/freshcontext-mcp
|
|
@@ -76,39 +96,56 @@ npx playwright install chromium
|
|
|
76
96
|
npm run build
|
|
77
97
|
```
|
|
78
98
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Add to your `claude_desktop_config.json`:
|
|
82
|
-
|
|
83
|
-
**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
84
|
-
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
99
|
+
Then add to your Claude Desktop config:
|
|
85
100
|
|
|
101
|
+
**Mac** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
86
102
|
```json
|
|
87
103
|
{
|
|
88
104
|
"mcpServers": {
|
|
89
|
-
"freshcontext
|
|
105
|
+
"freshcontext": {
|
|
90
106
|
"command": "node",
|
|
91
|
-
"args": ["/
|
|
107
|
+
"args": ["/Users/YOUR_USERNAME/path/to/freshcontext-mcp/dist/server.js"]
|
|
92
108
|
}
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
111
|
```
|
|
96
112
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
### Or use the Cloudflare edge deployment (no install needed)
|
|
100
|
-
|
|
113
|
+
**Windows** (`%APPDATA%\Claude\claude_desktop_config.json`):
|
|
101
114
|
```json
|
|
102
115
|
{
|
|
103
116
|
"mcpServers": {
|
|
104
|
-
"freshcontext
|
|
105
|
-
"command": "
|
|
106
|
-
"args": ["-
|
|
117
|
+
"freshcontext": {
|
|
118
|
+
"command": "node",
|
|
119
|
+
"args": ["C:\\Users\\YOUR_USERNAME\\path\\to\\freshcontext-mcp\\dist\\server.js"]
|
|
107
120
|
}
|
|
108
121
|
}
|
|
109
122
|
}
|
|
110
123
|
```
|
|
111
124
|
|
|
125
|
+
Restart Claude Desktop.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Troubleshooting (Mac)
|
|
130
|
+
|
|
131
|
+
**"command not found: node"** — Node isn't on your PATH inside Claude Desktop's environment. Use the full path:
|
|
132
|
+
```bash
|
|
133
|
+
which node # copy this output
|
|
134
|
+
```
|
|
135
|
+
Then replace `"command": "node"` with `"command": "/usr/local/bin/node"` (or whatever `which node` returned).
|
|
136
|
+
|
|
137
|
+
**"npx: command not found"** — Same issue. Run `which npx` and use the full path for Option A:
|
|
138
|
+
```json
|
|
139
|
+
"command": "/usr/local/bin/npx"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Config file doesn't exist** — Create it. On Mac:
|
|
143
|
+
```bash
|
|
144
|
+
mkdir -p ~/Library/Application\ Support/Claude
|
|
145
|
+
touch ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
146
|
+
```
|
|
147
|
+
Then paste the config JSON above into it.
|
|
148
|
+
|
|
112
149
|
---
|
|
113
150
|
|
|
114
151
|
## Usage Examples
|
|
@@ -162,12 +199,12 @@ This makes freshness **verifiable**, not assumed.
|
|
|
162
199
|
Uses headless Chromium via Playwright. Full browser rendering for JavaScript-heavy sites.
|
|
163
200
|
|
|
164
201
|
### Cloud (Cloudflare Workers)
|
|
165
|
-
The `worker/` directory contains a Cloudflare Workers deployment
|
|
202
|
+
The `worker/` directory contains a Cloudflare Workers deployment. No Playwright dependency — runs at the edge globally.
|
|
166
203
|
|
|
167
204
|
```bash
|
|
168
205
|
cd worker
|
|
169
206
|
npm install
|
|
170
|
-
npx wrangler secret put
|
|
207
|
+
npx wrangler secret put API_KEY
|
|
171
208
|
npx wrangler deploy
|
|
172
209
|
```
|
|
173
210
|
|
|
@@ -180,15 +217,16 @@ freshcontext-mcp/
|
|
|
180
217
|
├── src/
|
|
181
218
|
│ ├── server.ts # MCP server, all tool registrations
|
|
182
219
|
│ ├── types.ts # FreshContext interfaces
|
|
220
|
+
│ ├── security.ts # Input validation, domain allowlists
|
|
183
221
|
│ ├── adapters/
|
|
184
|
-
│ │ ├── github.ts
|
|
185
|
-
│ │ ├── hackernews.ts
|
|
186
|
-
│ │ ├── scholar.ts
|
|
187
|
-
│ │ ├── yc.ts
|
|
188
|
-
│ │ ├── repoSearch.ts
|
|
189
|
-
│ │ └── packageTrends.ts
|
|
222
|
+
│ │ ├── github.ts
|
|
223
|
+
│ │ ├── hackernews.ts
|
|
224
|
+
│ │ ├── scholar.ts
|
|
225
|
+
│ │ ├── yc.ts
|
|
226
|
+
│ │ ├── repoSearch.ts
|
|
227
|
+
│ │ └── packageTrends.ts
|
|
190
228
|
│ └── tools/
|
|
191
|
-
│ └── freshnessStamp.ts
|
|
229
|
+
│ └── freshnessStamp.ts
|
|
192
230
|
└── worker/ # Cloudflare Workers deployment
|
|
193
231
|
└── src/worker.ts
|
|
194
232
|
```
|
|
@@ -205,17 +243,17 @@ freshcontext-mcp/
|
|
|
205
243
|
- [x] npm/PyPI package trends
|
|
206
244
|
- [x] `extract_landscape` composite tool
|
|
207
245
|
- [x] Cloudflare Workers deployment
|
|
246
|
+
- [x] Worker auth + rate limiting + domain allowlists
|
|
208
247
|
- [ ] Product Hunt launches adapter
|
|
209
|
-
- [ ]
|
|
248
|
+
- [ ] Finance/market data adapter
|
|
210
249
|
- [ ] TTL-based caching layer
|
|
211
250
|
- [ ] `freshness_score` numeric metric
|
|
212
|
-
- [ ] Webhook support for real-time updates
|
|
213
251
|
|
|
214
252
|
---
|
|
215
253
|
|
|
216
254
|
## Contributing
|
|
217
255
|
|
|
218
|
-
PRs welcome. New adapters are the highest-value contribution — see
|
|
256
|
+
PRs welcome. New adapters are the highest-value contribution — see `src/adapters/` for the pattern. Each adapter returns `{ raw, content_date, freshness_confidence }`.
|
|
219
257
|
|
|
220
258
|
---
|
|
221
259
|
|
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "freshcontext-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Real-time web extraction MCP server with freshness timestamps for AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"type": "module",
|
|
26
26
|
"main": "dist/server.js",
|
|
27
|
+
"bin": {
|
|
28
|
+
"freshcontext-mcp": "dist/server.js"
|
|
29
|
+
},
|
|
27
30
|
"scripts": {
|
|
28
31
|
"build": "tsc",
|
|
29
32
|
"dev": "tsx watch src/server.ts",
|
package/src/server.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
4
|
import { z } from "zod";
|
|
@@ -202,3 +203,4 @@ async function main() {
|
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
main().catch(console.error);
|
|
206
|
+
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { githubAdapter } from "./adapters/github.js";
|
|
5
|
+
import { scholarAdapter } from "./adapters/scholar.js";
|
|
6
|
+
import { hackerNewsAdapter } from "./adapters/hackernews.js";
|
|
7
|
+
import { ycAdapter } from "./adapters/yc.js";
|
|
8
|
+
import { repoSearchAdapter } from "./adapters/repoSearch.js";
|
|
9
|
+
import { packageTrendsAdapter } from "./adapters/packageTrends.js";
|
|
10
|
+
import { stampFreshness, formatForLLM } from "./tools/freshnessStamp.js";
|
|
11
|
+
import { SecurityError, formatSecurityError } from "./security.js";
|
|
12
|
+
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: "freshcontext-mcp",
|
|
15
|
+
version: "0.1.0",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// ─── Tool: extract_github ────────────────────────────────────────────────────
|
|
19
|
+
server.registerTool(
|
|
20
|
+
"extract_github",
|
|
21
|
+
{
|
|
22
|
+
description:
|
|
23
|
+
"Extract real-time data from a GitHub repository — README, stars, forks, language, topics, last commit. Returns timestamped freshcontext.",
|
|
24
|
+
inputSchema: z.object({
|
|
25
|
+
url: z.string().url().describe("Full GitHub repo URL e.g. https://github.com/owner/repo"),
|
|
26
|
+
max_length: z.number().optional().default(6000).describe("Max content length"),
|
|
27
|
+
}),
|
|
28
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
29
|
+
},
|
|
30
|
+
async ({ url, max_length }) => {
|
|
31
|
+
try {
|
|
32
|
+
const result = await githubAdapter({ url, maxLength: max_length });
|
|
33
|
+
const ctx = stampFreshness(result, { url, maxLength: max_length }, "github");
|
|
34
|
+
return { content: [{ type: "text", text: formatForLLM(ctx) }] };
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return { content: [{ type: "text", text: formatSecurityError(err) }] };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// ─── Tool: extract_scholar ───────────────────────────────────────────────────
|
|
42
|
+
server.registerTool(
|
|
43
|
+
"extract_scholar",
|
|
44
|
+
{
|
|
45
|
+
description:
|
|
46
|
+
"Extract research results from a Google Scholar search URL. Returns titles, authors, publication years, and snippets — all timestamped.",
|
|
47
|
+
inputSchema: z.object({
|
|
48
|
+
url: z.string().url().describe("Google Scholar search URL e.g. https://scholar.google.com/scholar?q=..."),
|
|
49
|
+
max_length: z.number().optional().default(6000),
|
|
50
|
+
}),
|
|
51
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
52
|
+
},
|
|
53
|
+
async ({ url, max_length }) => {
|
|
54
|
+
try {
|
|
55
|
+
const result = await scholarAdapter({ url, maxLength: max_length });
|
|
56
|
+
const ctx = stampFreshness(result, { url, maxLength: max_length }, "google_scholar");
|
|
57
|
+
return { content: [{ type: "text", text: formatForLLM(ctx) }] };
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return { content: [{ type: "text", text: formatSecurityError(err) }] };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// ─── Tool: extract_hackernews ────────────────────────────────────────────────
|
|
65
|
+
server.registerTool(
|
|
66
|
+
"extract_hackernews",
|
|
67
|
+
{
|
|
68
|
+
description:
|
|
69
|
+
"Extract top stories or search results from Hacker News. Real-time dev/tech community sentiment with post timestamps.",
|
|
70
|
+
inputSchema: z.object({
|
|
71
|
+
url: z.string().url().describe("HN URL e.g. https://news.ycombinator.com or https://hn.algolia.com/?q=..."),
|
|
72
|
+
max_length: z.number().optional().default(4000),
|
|
73
|
+
}),
|
|
74
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
75
|
+
},
|
|
76
|
+
async ({ url, max_length }) => {
|
|
77
|
+
try {
|
|
78
|
+
const result = await hackerNewsAdapter({ url, maxLength: max_length });
|
|
79
|
+
const ctx = stampFreshness(result, { url, maxLength: max_length }, "hackernews");
|
|
80
|
+
return { content: [{ type: "text", text: formatForLLM(ctx) }] };
|
|
81
|
+
} catch (err) {
|
|
82
|
+
return { content: [{ type: "text", text: formatSecurityError(err) }] };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// ─── Tool: extract_yc ──────────────────────────────────────────────────────────
|
|
88
|
+
server.registerTool(
|
|
89
|
+
"extract_yc",
|
|
90
|
+
{
|
|
91
|
+
description:
|
|
92
|
+
"Scrape YC company listings. Use https://www.ycombinator.com/companies?query=KEYWORD to find startups in a space. Returns name, batch, tags, description per company with freshness timestamp.",
|
|
93
|
+
inputSchema: z.object({
|
|
94
|
+
url: z.string().url().describe("YC companies URL e.g. https://www.ycombinator.com/companies?query=mcp"),
|
|
95
|
+
max_length: z.number().optional().default(6000),
|
|
96
|
+
}),
|
|
97
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
98
|
+
},
|
|
99
|
+
async ({ url, max_length }) => {
|
|
100
|
+
try {
|
|
101
|
+
const result = await ycAdapter({ url, maxLength: max_length });
|
|
102
|
+
const ctx = stampFreshness(result, { url, maxLength: max_length }, "ycombinator");
|
|
103
|
+
return { content: [{ type: "text", text: formatForLLM(ctx) }] };
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return { content: [{ type: "text", text: formatSecurityError(err) }] };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// ─── Tool: search_repos ──────────────────────────────────────────────────────
|
|
111
|
+
server.registerTool(
|
|
112
|
+
"search_repos",
|
|
113
|
+
{
|
|
114
|
+
description:
|
|
115
|
+
"Search GitHub for repositories matching a keyword or topic. Returns top results by stars with activity signals. Use to find competitors, similar tools, or related projects.",
|
|
116
|
+
inputSchema: z.object({
|
|
117
|
+
query: z.string().describe("Search query e.g. 'mcp server typescript' or 'cashflow prediction python'"),
|
|
118
|
+
max_length: z.number().optional().default(6000),
|
|
119
|
+
}),
|
|
120
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
121
|
+
},
|
|
122
|
+
async ({ query, max_length }) => {
|
|
123
|
+
try {
|
|
124
|
+
const result = await repoSearchAdapter({ url: query, maxLength: max_length });
|
|
125
|
+
const ctx = stampFreshness(result, { url: query, maxLength: max_length }, "github_search");
|
|
126
|
+
return { content: [{ type: "text", text: formatForLLM(ctx) }] };
|
|
127
|
+
} catch (err) {
|
|
128
|
+
return { content: [{ type: "text", text: formatSecurityError(err) }] };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// ─── Tool: package_trends ────────────────────────────────────────────────────
|
|
134
|
+
server.registerTool(
|
|
135
|
+
"package_trends",
|
|
136
|
+
{
|
|
137
|
+
description:
|
|
138
|
+
"Look up npm and PyPI package metadata — version history, release cadence, last updated. Use to gauge ecosystem activity around a tool or dependency. Supports comma-separated list of packages.",
|
|
139
|
+
inputSchema: z.object({
|
|
140
|
+
packages: z.string().describe("Package name(s) e.g. 'langchain' or 'npm:zod,pypi:fastapi'"),
|
|
141
|
+
max_length: z.number().optional().default(5000),
|
|
142
|
+
}),
|
|
143
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
144
|
+
},
|
|
145
|
+
async ({ packages, max_length }) => {
|
|
146
|
+
try {
|
|
147
|
+
const result = await packageTrendsAdapter({ url: packages, maxLength: max_length });
|
|
148
|
+
const ctx = stampFreshness(result, { url: packages, maxLength: max_length }, "package_registry");
|
|
149
|
+
return { content: [{ type: "text", text: formatForLLM(ctx) }] };
|
|
150
|
+
} catch (err) {
|
|
151
|
+
return { content: [{ type: "text", text: formatSecurityError(err) }] };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// ─── Tool: extract_landscape ─────────────────────────────────────────────────
|
|
157
|
+
server.registerTool(
|
|
158
|
+
"extract_landscape",
|
|
159
|
+
{
|
|
160
|
+
description:
|
|
161
|
+
"Composite intelligence tool. Given a project idea or keyword, simultaneously queries YC startups, GitHub repos, HN sentiment, and package activity to answer: Who is building this? Is it funded? What's getting traction? Returns a unified timestamped landscape report.",
|
|
162
|
+
inputSchema: z.object({
|
|
163
|
+
topic: z.string().describe("Your project idea or keyword e.g. 'mcp server' or 'cashflow prediction'"),
|
|
164
|
+
max_length: z.number().optional().default(8000),
|
|
165
|
+
}),
|
|
166
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
167
|
+
},
|
|
168
|
+
async ({ topic, max_length }) => {
|
|
169
|
+
const perSection = Math.floor((max_length ?? 8000) / 4);
|
|
170
|
+
|
|
171
|
+
const [ycResult, repoResult, hnResult, pkgResult] = await Promise.allSettled([
|
|
172
|
+
ycAdapter({ url: `https://www.ycombinator.com/companies?query=${encodeURIComponent(topic)}`, maxLength: perSection }),
|
|
173
|
+
repoSearchAdapter({ url: topic, maxLength: perSection }),
|
|
174
|
+
hackerNewsAdapter({ url: `https://hn.algolia.com/api/v1/search?query=${encodeURIComponent(topic)}&tags=story&hitsPerPage=15`, maxLength: perSection }),
|
|
175
|
+
packageTrendsAdapter({ url: topic, maxLength: perSection }),
|
|
176
|
+
]);
|
|
177
|
+
|
|
178
|
+
const section = (label: string, result: PromiseSettledResult<{ raw: string; content_date: string | null; freshness_confidence: string }>) =>
|
|
179
|
+
result.status === "fulfilled"
|
|
180
|
+
? `## ${label}\n${result.value.raw}`
|
|
181
|
+
: `## ${label}\n[Error: ${(result as PromiseRejectedResult).reason}]`;
|
|
182
|
+
|
|
183
|
+
const combined = [
|
|
184
|
+
`# Landscape Report: "${topic}"`,
|
|
185
|
+
`Generated: ${new Date().toISOString()}`,
|
|
186
|
+
"",
|
|
187
|
+
section("🚀 YC Startups in this space", ycResult),
|
|
188
|
+
section("📦 Top GitHub repos", repoResult),
|
|
189
|
+
section("💬 HN sentiment (last month)", hnResult),
|
|
190
|
+
section("📊 Package ecosystem", pkgResult),
|
|
191
|
+
].join("\n\n");
|
|
192
|
+
|
|
193
|
+
return { content: [{ type: "text", text: combined }] };
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// ─── Start ───────────────────────────────────────────────────────────────────
|
|
198
|
+
async function main() {
|
|
199
|
+
const transport = new StdioServerTransport();
|
|
200
|
+
await server.connect(transport);
|
|
201
|
+
console.error("freshcontext-mcp running on stdio");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
main().catch(console.error);
|