@mentionable/tracker 0.1.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/README.md +144 -0
- package/dist/chunk-JBLZVSYS.js +115 -0
- package/dist/cloudflare.d.ts +47 -0
- package/dist/cloudflare.js +54 -0
- package/dist/core-CfJZm23p.d.ts +5 -0
- package/dist/next.d.ts +33 -0
- package/dist/next.js +44 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# @mentionable/tracker
|
|
2
|
+
|
|
3
|
+
Track AI bot crawls on your website. Monitor when GPTBot, ClaudeBot, PerplexityBot, Grok and others crawl your pages.
|
|
4
|
+
|
|
5
|
+
See which pages AI models are indexing, how often they come back, and correlate crawl data with your AI visibility on [Mentionable](https://mentionable.io).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @mentionable/tracker
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Next.js
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// middleware.ts
|
|
19
|
+
import { withMentionable } from '@mentionable/tracker/next'
|
|
20
|
+
|
|
21
|
+
export default withMentionable({
|
|
22
|
+
apiKey: process.env.MENTIONABLE_API_KEY!,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const config = {
|
|
26
|
+
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That's it. Every AI bot crawl is now tracked in your [Mentionable dashboard](https://mentionable.io).
|
|
31
|
+
|
|
32
|
+
### Cloudflare Worker
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// src/index.ts
|
|
36
|
+
import { withMentionable } from '@mentionable/tracker/cloudflare'
|
|
37
|
+
|
|
38
|
+
export default withMentionable({
|
|
39
|
+
apiKey: 'mtbl_xxxxx', // or use env: true to read from MENTIONABLE_API_KEY env var
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx wrangler deploy
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Works in front of any origin: Shopify, WordPress, custom backends. The Worker proxies the request and reports crawl data without adding any latency.
|
|
48
|
+
|
|
49
|
+
### Existing Middleware (Next.js)
|
|
50
|
+
|
|
51
|
+
If you already have a `middleware.ts`, use the handler directly:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
// middleware.ts
|
|
55
|
+
import { NextResponse } from 'next/server'
|
|
56
|
+
import { createMentionable } from '@mentionable/tracker/next'
|
|
57
|
+
|
|
58
|
+
const mentionable = createMentionable({
|
|
59
|
+
apiKey: process.env.MENTIONABLE_API_KEY!,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
export async function middleware(req) {
|
|
63
|
+
// your existing logic
|
|
64
|
+
mentionable.track(req)
|
|
65
|
+
|
|
66
|
+
return NextResponse.next()
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Existing Cloudflare Worker
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { createMentionable } from '@mentionable/tracker/cloudflare'
|
|
74
|
+
|
|
75
|
+
const mentionable = createMentionable({
|
|
76
|
+
apiKey: 'mtbl_xxxxx',
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
export default {
|
|
80
|
+
async fetch(request, env, ctx) {
|
|
81
|
+
// your existing logic
|
|
82
|
+
mentionable.track(request, ctx)
|
|
83
|
+
|
|
84
|
+
return fetch(request)
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## What Gets Tracked
|
|
90
|
+
|
|
91
|
+
The tracker sends minimal, non-sensitive data to the Mentionable API:
|
|
92
|
+
|
|
93
|
+
| Field | Description |
|
|
94
|
+
| -------- | ---------------------------- |
|
|
95
|
+
| `ua` | User-Agent header |
|
|
96
|
+
| `path` | Request path (e.g. `/pricing`) |
|
|
97
|
+
| `host` | Hostname |
|
|
98
|
+
| `method` | HTTP method |
|
|
99
|
+
| `ip` | Client IP (for bot identification) |
|
|
100
|
+
| `status` | Response status code |
|
|
101
|
+
| `t` | Timestamp |
|
|
102
|
+
|
|
103
|
+
No cookies, no request bodies, no personal data.
|
|
104
|
+
|
|
105
|
+
## Configuration
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
withMentionable({
|
|
109
|
+
// Required
|
|
110
|
+
apiKey: 'mtbl_xxxxx',
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## How It Works
|
|
115
|
+
|
|
116
|
+
1. The middleware intercepts incoming requests
|
|
117
|
+
2. It forwards the User-Agent + request metadata to the Mentionable API (fire-and-forget, zero latency impact)
|
|
118
|
+
3. Mentionable detects and classifies the bot server-side
|
|
119
|
+
4. Data appears in your dashboard within seconds
|
|
120
|
+
|
|
121
|
+
The detection logic lives on Mentionable's servers, not in the package. When new AI bots emerge, they're detected automatically without any update on your end.
|
|
122
|
+
|
|
123
|
+
## Performance
|
|
124
|
+
|
|
125
|
+
The tracker is designed to have zero impact on your site:
|
|
126
|
+
|
|
127
|
+
- **Non-blocking**: requests are sent with fire-and-forget (no `await`)
|
|
128
|
+
- **Cloudflare**: uses `ctx.waitUntil()` so the response is never delayed
|
|
129
|
+
- **Next.js**: runs on the Edge Runtime, adds < 1ms overhead
|
|
130
|
+
- **Tiny payload**: ~200 bytes per event
|
|
131
|
+
|
|
132
|
+
## Get Your API Key
|
|
133
|
+
|
|
134
|
+
1. Sign up at [mentionable.com](https://mentionable.io)
|
|
135
|
+
2. Go to Settings > API
|
|
136
|
+
3. Copy your API key (starts with `mtbl_`)
|
|
137
|
+
|
|
138
|
+
## Links
|
|
139
|
+
|
|
140
|
+
- [Mentionable Dashboard](https://mentionable.io)
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/core.ts
|
|
2
|
+
var API_URL = "https://api.mentionable.io/v1/track";
|
|
3
|
+
var BOTS_URL = "https://api.mentionable.io/v1/bots";
|
|
4
|
+
var REFRESH_INTERVAL = 24 * 60 * 60 * 1e3;
|
|
5
|
+
var FALLBACK_BOTS = [
|
|
6
|
+
// OpenAI
|
|
7
|
+
"GPTBot",
|
|
8
|
+
"ChatGPT-User",
|
|
9
|
+
"OAI-SearchBot",
|
|
10
|
+
// Anthropic
|
|
11
|
+
"ClaudeBot",
|
|
12
|
+
"anthropic-ai",
|
|
13
|
+
// Google
|
|
14
|
+
"Google-Extended",
|
|
15
|
+
"GoogleOther",
|
|
16
|
+
// Perplexity
|
|
17
|
+
"PerplexityBot",
|
|
18
|
+
// Meta
|
|
19
|
+
"Meta-ExternalAgent",
|
|
20
|
+
"FacebookBot",
|
|
21
|
+
// Apple
|
|
22
|
+
"Applebot-Extended",
|
|
23
|
+
// Amazon
|
|
24
|
+
"Amazonbot",
|
|
25
|
+
// ByteDance
|
|
26
|
+
"Bytespider",
|
|
27
|
+
// Common Crawl
|
|
28
|
+
"CCBot",
|
|
29
|
+
// Cohere
|
|
30
|
+
"cohere-ai",
|
|
31
|
+
// Diffbot
|
|
32
|
+
"Diffbot",
|
|
33
|
+
// You.com
|
|
34
|
+
"YouBot",
|
|
35
|
+
// AI2
|
|
36
|
+
"AI2Bot",
|
|
37
|
+
// xAI
|
|
38
|
+
"Grok",
|
|
39
|
+
// Huawei / Asiabot
|
|
40
|
+
"PetalBot",
|
|
41
|
+
// Webz.io
|
|
42
|
+
"Omgilibot",
|
|
43
|
+
// Imagesift
|
|
44
|
+
"ImagesiftBot",
|
|
45
|
+
// Timpi
|
|
46
|
+
"Timpibot"
|
|
47
|
+
];
|
|
48
|
+
function createBotMatcher() {
|
|
49
|
+
let patterns = FALLBACK_BOTS;
|
|
50
|
+
let lastFetch = 0;
|
|
51
|
+
let pending = null;
|
|
52
|
+
async function fetchPatterns(apiKey) {
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch(BOTS_URL, {
|
|
55
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
56
|
+
});
|
|
57
|
+
if (res.ok) {
|
|
58
|
+
const data = await res.json();
|
|
59
|
+
if (Array.isArray(data.patterns)) {
|
|
60
|
+
patterns = data.patterns;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
lastFetch = Date.now();
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
/**
|
|
69
|
+
* Kick off a background refresh if the list is stale (>24 h) or never fetched.
|
|
70
|
+
* Returns the pending promise when a fetch was started, `undefined` otherwise.
|
|
71
|
+
*/
|
|
72
|
+
refresh(apiKey) {
|
|
73
|
+
if (lastFetch > 0 && Date.now() - lastFetch < REFRESH_INTERVAL) return;
|
|
74
|
+
if (pending) return pending;
|
|
75
|
+
pending = fetchPatterns(apiKey).finally(() => {
|
|
76
|
+
pending = null;
|
|
77
|
+
});
|
|
78
|
+
return pending;
|
|
79
|
+
},
|
|
80
|
+
/** Case-insensitive substring match against the current pattern list. */
|
|
81
|
+
isBot(ua) {
|
|
82
|
+
const lower = ua.toLowerCase();
|
|
83
|
+
return patterns.some((p) => lower.includes(p.toLowerCase()));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function buildPayload(options) {
|
|
88
|
+
return {
|
|
89
|
+
ua: options.ua,
|
|
90
|
+
path: options.path,
|
|
91
|
+
host: options.host,
|
|
92
|
+
method: options.method,
|
|
93
|
+
ip: options.ip,
|
|
94
|
+
status: options.status ?? 200,
|
|
95
|
+
t: Date.now()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function sendEvent(event, apiKey) {
|
|
99
|
+
return fetch(API_URL, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "application/json",
|
|
103
|
+
Authorization: `Bearer ${apiKey}`
|
|
104
|
+
},
|
|
105
|
+
body: JSON.stringify(event)
|
|
106
|
+
}).then(() => {
|
|
107
|
+
}).catch(() => {
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
createBotMatcher,
|
|
113
|
+
buildPayload,
|
|
114
|
+
sendEvent
|
|
115
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { M as MentionableConfig } from './core-CfJZm23p.js';
|
|
2
|
+
|
|
3
|
+
interface CloudflareConfig extends MentionableConfig {
|
|
4
|
+
/** Set to `true` to read the API key from the `MENTIONABLE_API_KEY` env var at runtime. */
|
|
5
|
+
env?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface CloudflareEnv {
|
|
8
|
+
MENTIONABLE_API_KEY?: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
interface CloudflareExecutionContext {
|
|
12
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
13
|
+
passThroughOnException(): void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Standalone Worker handler that proxies requests to the origin and tracks AI bot crawls.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { withMentionable } from '@mentionable/tracker/cloudflare'
|
|
20
|
+
*
|
|
21
|
+
* export default withMentionable({
|
|
22
|
+
* apiKey: 'mtbl_xxxxx',
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
declare function withMentionable(config: CloudflareConfig): {
|
|
27
|
+
fetch(request: Request, env: CloudflareEnv, ctx: CloudflareExecutionContext): Promise<Response>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Composable tracker for use inside an existing Cloudflare Worker.
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* const mentionable = createMentionable({ apiKey: 'mtbl_xxxxx' })
|
|
34
|
+
*
|
|
35
|
+
* export default {
|
|
36
|
+
* async fetch(request, env, ctx) {
|
|
37
|
+
* mentionable.track(request, ctx)
|
|
38
|
+
* return fetch(request)
|
|
39
|
+
* },
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function createMentionable(config: MentionableConfig): {
|
|
44
|
+
track(request: Request, ctx: CloudflareExecutionContext): void;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { type CloudflareConfig, MentionableConfig, createMentionable, withMentionable };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPayload,
|
|
3
|
+
createBotMatcher,
|
|
4
|
+
sendEvent
|
|
5
|
+
} from "./chunk-JBLZVSYS.js";
|
|
6
|
+
|
|
7
|
+
// src/cloudflare.ts
|
|
8
|
+
function extractPayload(request, status) {
|
|
9
|
+
return buildPayload({
|
|
10
|
+
ua: request.headers.get("user-agent") || "",
|
|
11
|
+
path: new URL(request.url).pathname,
|
|
12
|
+
host: request.headers.get("host") || "",
|
|
13
|
+
method: request.method,
|
|
14
|
+
ip: request.headers.get("cf-connecting-ip") || request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || "",
|
|
15
|
+
status
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function resolveApiKey(config, env) {
|
|
19
|
+
return config.env && env.MENTIONABLE_API_KEY || config.apiKey;
|
|
20
|
+
}
|
|
21
|
+
function withMentionable(config) {
|
|
22
|
+
const bots = createBotMatcher();
|
|
23
|
+
return {
|
|
24
|
+
async fetch(request, env, ctx) {
|
|
25
|
+
const apiKey = resolveApiKey(config, env);
|
|
26
|
+
const refreshing = bots.refresh(apiKey);
|
|
27
|
+
if (refreshing) ctx.waitUntil(refreshing);
|
|
28
|
+
const response = await fetch(request);
|
|
29
|
+
const ua = request.headers.get("user-agent") || "";
|
|
30
|
+
if (bots.isBot(ua)) {
|
|
31
|
+
const event = extractPayload(request, response.status);
|
|
32
|
+
ctx.waitUntil(sendEvent(event, apiKey));
|
|
33
|
+
}
|
|
34
|
+
return response;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function createMentionable(config) {
|
|
39
|
+
const bots = createBotMatcher();
|
|
40
|
+
return {
|
|
41
|
+
track(request, ctx) {
|
|
42
|
+
const refreshing = bots.refresh(config.apiKey);
|
|
43
|
+
if (refreshing) ctx.waitUntil(refreshing);
|
|
44
|
+
const ua = request.headers.get("user-agent") || "";
|
|
45
|
+
if (!bots.isBot(ua)) return;
|
|
46
|
+
const event = extractPayload(request);
|
|
47
|
+
ctx.waitUntil(sendEvent(event, config.apiKey));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
createMentionable,
|
|
53
|
+
withMentionable
|
|
54
|
+
};
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { M as MentionableConfig } from './core-CfJZm23p.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Standalone middleware that tracks AI bot crawls.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* // middleware.ts
|
|
9
|
+
* import { withMentionable } from '@mentionable/tracker/next'
|
|
10
|
+
*
|
|
11
|
+
* export default withMentionable({
|
|
12
|
+
* apiKey: process.env.MENTIONABLE_API_KEY!,
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function withMentionable(config: MentionableConfig): (req: NextRequest) => NextResponse<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Composable tracker for use inside an existing middleware.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* const mentionable = createMentionable({ apiKey: process.env.MENTIONABLE_API_KEY! })
|
|
22
|
+
*
|
|
23
|
+
* export async function middleware(req) {
|
|
24
|
+
* mentionable.track(req)
|
|
25
|
+
* return NextResponse.next()
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function createMentionable(config: MentionableConfig): {
|
|
30
|
+
track(req: NextRequest): void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { MentionableConfig, createMentionable, withMentionable };
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPayload,
|
|
3
|
+
createBotMatcher,
|
|
4
|
+
sendEvent
|
|
5
|
+
} from "./chunk-JBLZVSYS.js";
|
|
6
|
+
|
|
7
|
+
// src/next.ts
|
|
8
|
+
import { NextResponse } from "next/server";
|
|
9
|
+
function extractPayload(req) {
|
|
10
|
+
return buildPayload({
|
|
11
|
+
ua: req.headers.get("user-agent") || "",
|
|
12
|
+
path: new URL(req.url).pathname,
|
|
13
|
+
host: req.headers.get("host") || "",
|
|
14
|
+
method: req.method,
|
|
15
|
+
ip: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || ""
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function withMentionable(config) {
|
|
19
|
+
const bots = createBotMatcher();
|
|
20
|
+
return function middleware(req) {
|
|
21
|
+
bots.refresh(config.apiKey);
|
|
22
|
+
const ua = req.headers.get("user-agent") || "";
|
|
23
|
+
if (!bots.isBot(ua)) return NextResponse.next();
|
|
24
|
+
const event = extractPayload(req);
|
|
25
|
+
sendEvent(event, config.apiKey);
|
|
26
|
+
return NextResponse.next();
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function createMentionable(config) {
|
|
30
|
+
const bots = createBotMatcher();
|
|
31
|
+
return {
|
|
32
|
+
track(req) {
|
|
33
|
+
bots.refresh(config.apiKey);
|
|
34
|
+
const ua = req.headers.get("user-agent") || "";
|
|
35
|
+
if (!bots.isBot(ua)) return;
|
|
36
|
+
const event = extractPayload(req);
|
|
37
|
+
sendEvent(event, config.apiKey);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
createMentionable,
|
|
43
|
+
withMentionable
|
|
44
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mentionable/tracker",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Track AI bot crawls on your website. Monitor when GPTBot, ClaudeBot, PerplexityBot, Grok and others crawl your pages.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./next": {
|
|
8
|
+
"types": "./dist/next.d.ts",
|
|
9
|
+
"default": "./dist/next.js"
|
|
10
|
+
},
|
|
11
|
+
"./cloudflare": {
|
|
12
|
+
"types": "./dist/cloudflare.d.ts",
|
|
13
|
+
"default": "./dist/cloudflare.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"next": "^15.0.0",
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.0.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"next": ">=13.0.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependenciesMeta": {
|
|
33
|
+
"next": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"ai",
|
|
39
|
+
"bot",
|
|
40
|
+
"crawler",
|
|
41
|
+
"tracking",
|
|
42
|
+
"seo",
|
|
43
|
+
"mentionable",
|
|
44
|
+
"gptbot",
|
|
45
|
+
"claudebot",
|
|
46
|
+
"perplexitybot"
|
|
47
|
+
],
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"sideEffects": false
|
|
50
|
+
}
|