@fluxpool/mcp-server 0.1.0 → 0.2.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 CHANGED
@@ -1,5 +1,8 @@
1
1
  # @fluxpool/mcp-server
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@fluxpool/mcp-server)](https://www.npmjs.com/package/@fluxpool/mcp-server)
4
+ [![license](https://img.shields.io/npm/l/@fluxpool/mcp-server)](LICENSE)
5
+
3
6
  Generate images and videos with [Fluxpool.ai](https://fluxpool.ai) from Claude,
4
7
  Cursor, or any MCP client — across Flux, Seedream, Seedance, Runway and more,
5
8
  billed against a single pool of Fluxpool credits.
@@ -19,6 +22,46 @@ Generation is **asynchronous**: `create_generation` returns an ID, then
19
22
  `check_generation` is polled until the status is `completed`. Output URLs are
20
23
  presigned and **expire after one hour** — download promptly.
21
24
 
25
+ ## Reference inputs (image / video / audio)
26
+
27
+ `create_generation` accepts an `inputs` array for image-to-image, video-to-video
28
+ and other reference-conditioned models. Every entry has the same shape:
29
+
30
+ ```json
31
+ { "type": "image", "source": "url", "value": "https://..." }
32
+ { "type": "image", "source": "data", "value": "data:image/png;base64,..." }
33
+ { "type": "image", "source": "local", "value": "./pic.png" }
34
+ ```
35
+
36
+ - **`type`** — `image`, `video`, or `audio`.
37
+ - **`source`** — how `value` should be interpreted:
38
+ - `url` — an https:// URL, passed through untouched.
39
+ - `data` — a base64 data-URI; the backend uploads it to S3 for you.
40
+ - `local` — a path on the machine running this bridge. Resolved locally
41
+ (see below) before being forwarded to the server.
42
+
43
+ ### Local file paths
44
+
45
+ `source: "local"` is a bridge convenience: the file is read on your machine,
46
+ base64-encoded, and sent to the server as a `data` entry. **The hosted
47
+ endpoint never sees a `local` from this bridge**, so `local` works only when
48
+ you connect via this package (not via the direct HTTP endpoint).
49
+
50
+ **Auto-compression for oversize images.** The backend caps inline data-URIs
51
+ at ~4.5 MB decoded. Images larger than 4 MB are automatically resized to
52
+ 2048px and re-encoded as webp. That path uses the optional
53
+ [`sharp`](https://sharp.pixelplumbing.com/) dependency:
54
+
55
+ ```bash
56
+ # From your MCP client machine — installs prebuilt binaries for your platform.
57
+ npm install -g sharp
58
+ ```
59
+
60
+ If `sharp` is not installed, oversize images are rejected with a message
61
+ pointing you here. Video and audio files above 4 MB are never auto-compressed
62
+ — use the two-step [`POST /v1/uploads`](https://api.fluxpool.ai) flow and pass
63
+ the returned URL with `source: "url"`.
64
+
22
65
  ## Get an API key
23
66
 
24
67
  Create one at **<https://app.fluxpool.ai/api>**. Keys look like `fp_live_…`.
@@ -200,19 +243,26 @@ Tests stub `fetch` and use a dummy key — they never touch the network.
200
243
 
201
244
  ### Releasing
202
245
 
246
+ See [PUBLISHING.md](PUBLISHING.md) for the full release process. Short
247
+ version:
248
+
203
249
  ```bash
204
- npm version patch && git push --follow-tags
250
+ npm publish --dry-run --access public # check the file list and warnings
251
+ npm version patch
252
+ npm publish --access public --otp=<code>
253
+ git push --follow-tags
205
254
  ```
206
255
 
207
- CI builds, tests, checks the tag matches `package.json`, and publishes via
208
- npm Trusted Publishing (OIDC) — no npm token is stored in this repo.
209
-
210
- ## Contributing
256
+ ## Support
211
257
 
212
- Issues and pull requests: <https://github.com/ZKcandy/fluxpool-mcp-server/issues>
258
+ Questions, bugs, or a tool you wish existed: email
259
+ <dev@fluxpool.ai>, open an issue at
260
+ <https://github.com/ZKcandy/fluxpool-mcp-server/issues>, or reach us through
261
+ <https://fluxpool.ai>.
213
262
 
214
263
  Because tools are defined server-side, adding or changing one is a backend
215
- change rather than a change here. Open an issue describing the tool you need.
264
+ change rather than a change to this package new tools reach you without
265
+ upgrading anything.
216
266
 
217
267
  ## License
218
268
 
package/dist/bridge.d.ts CHANGED
@@ -14,12 +14,15 @@
14
14
  */
15
15
  import type { Readable, Writable } from 'node:stream';
16
16
  import { type FluxpoolClient } from './client.js';
17
+ import { type ResolveOptions } from './localInputs.js';
17
18
  export interface BridgeOptions {
18
19
  client: FluxpoolClient;
19
20
  input?: Readable;
20
21
  output?: Writable;
21
22
  /** Defaults to stderr. Never stdout — that channel is the protocol. */
22
23
  log?: (message: string) => void;
24
+ /** Injection seams for local-input resolution — tests only. */
25
+ resolveOptions?: ResolveOptions;
23
26
  }
24
27
  export declare class Bridge {
25
28
  #private;
package/dist/bridge.js CHANGED
@@ -14,17 +14,20 @@
14
14
  */
15
15
  import { createInterface } from 'node:readline';
16
16
  import { errorResponse } from './client.js';
17
+ import { needsLocalResolution, resolveLocalInputs } from './localInputs.js';
17
18
  import { JSON_RPC } from './types.js';
18
19
  export class Bridge {
19
20
  #client;
20
21
  #input;
21
22
  #output;
22
23
  #log;
24
+ #resolveOptions;
23
25
  constructor(options) {
24
26
  this.#client = options.client;
25
27
  this.#input = options.input ?? process.stdin;
26
28
  this.#output = options.output ?? process.stdout;
27
29
  this.#log = options.log ?? ((message) => process.stderr.write(`${message}\n`));
30
+ this.#resolveOptions = options.resolveOptions;
28
31
  }
29
32
  /** Pump stdin until it closes. Resolves when the stream ends. */
30
33
  async run() {
@@ -55,6 +58,27 @@ export class Bridge {
55
58
  return;
56
59
  }
57
60
  const id = extractId(message);
61
+ // Local-file resolution runs BEFORE forwarding. It only fires when the
62
+ // message is a `tools/call` for `create_generation` and its arguments
63
+ // carry at least one `source: 'local'` entry — every other message
64
+ // (initialize, tools/list, check_generation, url/data inputs) skips
65
+ // straight through. Failures here become an INVALID_PARAMS response
66
+ // so the model on the other end gets a specific "your file didn't
67
+ // work" hint rather than a generic transport error.
68
+ if (needsLocalResolution(message)) {
69
+ try {
70
+ const params = message.params;
71
+ if (params && typeof params === 'object') {
72
+ params.arguments = await resolveLocalInputs(params.arguments, this.#resolveOptions);
73
+ }
74
+ }
75
+ catch (cause) {
76
+ if (id === null)
77
+ return;
78
+ this.write(errorResponse(id, JSON_RPC.INVALID_PARAMS, describe(cause)));
79
+ return;
80
+ }
81
+ }
58
82
  let response;
59
83
  try {
60
84
  response = await this.#client.send(message, id);
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Local-path resolution for `create_generation` inputs.
3
+ *
4
+ * The backend contract (project_api_image_input_unification) accepts three
5
+ * input sources:
6
+ * - `url` — https:// pass-through
7
+ * - `data` — base64 data-URI, backend inline-uploads to S3
8
+ * - `local` — client-side ONLY; the Lambda has no way to reach a caller's
9
+ * disk, so it rejects source=local with a 400.
10
+ *
11
+ * This module fills that gap for stdio MCP callers: when a `tools/call`
12
+ * message names a local file in `inputs[]`, we read it here, base64-encode
13
+ * (with optional sharp compression for oversize images), and rewrite the
14
+ * item to `source: 'data'` BEFORE the bridge forwards the request. The
15
+ * server never sees a `local` from this client.
16
+ *
17
+ * `sharp` is an optional dependency. If it is installed and an image
18
+ * exceeds the 4 MB data-URI target, we auto-resize + re-encode as webp
19
+ * so it fits. If not installed, oversize images get a clear error telling
20
+ * the user how to enable auto-compression. Non-image types (video/audio)
21
+ * never touch sharp regardless.
22
+ */
23
+ export interface InputItem {
24
+ type?: string;
25
+ source?: string;
26
+ value?: string;
27
+ [k: string]: unknown;
28
+ }
29
+ export interface ResolveOptions {
30
+ /** Injection seam for tests — defaults to Node's fs.readFile. */
31
+ readFile?: (path: string) => Promise<Buffer>;
32
+ /** Injection seam for tests — defaults to dynamic import('sharp'). */
33
+ loadSharp?: () => Promise<SharpModule | null>;
34
+ }
35
+ interface SharpModule {
36
+ default: SharpFactory;
37
+ }
38
+ interface SharpFactory {
39
+ (input: Buffer): SharpInstance;
40
+ }
41
+ interface SharpInstance {
42
+ rotate(): SharpInstance;
43
+ resize(options: {
44
+ width?: number;
45
+ height?: number;
46
+ fit?: 'inside' | 'cover' | 'contain';
47
+ withoutEnlargement?: boolean;
48
+ }): SharpInstance;
49
+ webp(options: {
50
+ quality: number;
51
+ }): SharpInstance;
52
+ toBuffer(): Promise<Buffer>;
53
+ }
54
+ /**
55
+ * Walk a params object, rewriting every {source:'local'} entry inside
56
+ * `inputs[]` to {source:'data'}. Mutates in place and returns it so
57
+ * callers can chain.
58
+ *
59
+ * Throws with a plain Error whose message the bridge relays back to the
60
+ * MCP client as a JSON-RPC error. The message is written for the human
61
+ * on the other end of the client, not for a machine.
62
+ */
63
+ export declare function resolveLocalInputs(params: unknown, options?: ResolveOptions): Promise<unknown>;
64
+ /**
65
+ * True when the message is a `tools/call` for `create_generation` that
66
+ * has `inputs[]` with at least one `source: 'local'` entry. Cheap check
67
+ * used by the bridge to decide whether to run the resolver.
68
+ */
69
+ export declare function needsLocalResolution(message: unknown): boolean;
70
+ export {};
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Local-path resolution for `create_generation` inputs.
3
+ *
4
+ * The backend contract (project_api_image_input_unification) accepts three
5
+ * input sources:
6
+ * - `url` — https:// pass-through
7
+ * - `data` — base64 data-URI, backend inline-uploads to S3
8
+ * - `local` — client-side ONLY; the Lambda has no way to reach a caller's
9
+ * disk, so it rejects source=local with a 400.
10
+ *
11
+ * This module fills that gap for stdio MCP callers: when a `tools/call`
12
+ * message names a local file in `inputs[]`, we read it here, base64-encode
13
+ * (with optional sharp compression for oversize images), and rewrite the
14
+ * item to `source: 'data'` BEFORE the bridge forwards the request. The
15
+ * server never sees a `local` from this client.
16
+ *
17
+ * `sharp` is an optional dependency. If it is installed and an image
18
+ * exceeds the 4 MB data-URI target, we auto-resize + re-encode as webp
19
+ * so it fits. If not installed, oversize images get a clear error telling
20
+ * the user how to enable auto-compression. Non-image types (video/audio)
21
+ * never touch sharp regardless.
22
+ */
23
+ import { promises as fs } from 'node:fs';
24
+ import path from 'node:path';
25
+ /**
26
+ * Backend cap is 4.5 MB decoded; we target 4 MB to leave headroom for the
27
+ * base64 overhead + JSON-RPC envelope size. Anything over this after
28
+ * compression is refused rather than silently truncated.
29
+ */
30
+ const DATA_URI_TARGET_BYTES = 4 * 1024 * 1024;
31
+ /**
32
+ * Fluxpool backend allow-list per type. Kept in sync with the backend
33
+ * ALLOWED_MIME_BY_TYPE (functions/ingestion/index.js). Keeping the client
34
+ * strict too means a mistyped MIME fails locally with a specific message,
35
+ * instead of trekking to the server for a generic 415.
36
+ */
37
+ const ALLOWED_MIME_BY_TYPE = {
38
+ image: new Set(['image/png', 'image/jpeg', 'image/jpg', 'image/webp', 'image/gif']),
39
+ video: new Set(['video/mp4', 'video/webm', 'video/quicktime']),
40
+ audio: new Set(['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/mp4']),
41
+ };
42
+ const MIME_BY_EXT = {
43
+ '.png': 'image/png',
44
+ '.jpg': 'image/jpeg',
45
+ '.jpeg': 'image/jpeg',
46
+ '.webp': 'image/webp',
47
+ '.gif': 'image/gif',
48
+ '.mp4': 'video/mp4',
49
+ '.webm': 'video/webm',
50
+ '.mov': 'video/quicktime',
51
+ '.mp3': 'audio/mpeg',
52
+ '.wav': 'audio/wav',
53
+ '.ogg': 'audio/ogg',
54
+ '.m4a': 'audio/mp4',
55
+ };
56
+ /**
57
+ * Walk a params object, rewriting every {source:'local'} entry inside
58
+ * `inputs[]` to {source:'data'}. Mutates in place and returns it so
59
+ * callers can chain.
60
+ *
61
+ * Throws with a plain Error whose message the bridge relays back to the
62
+ * MCP client as a JSON-RPC error. The message is written for the human
63
+ * on the other end of the client, not for a machine.
64
+ */
65
+ export async function resolveLocalInputs(params, options = {}) {
66
+ if (!isObject(params))
67
+ return params;
68
+ const inputs = params.inputs;
69
+ if (!Array.isArray(inputs))
70
+ return params;
71
+ const readFile = options.readFile ?? ((p) => fs.readFile(p));
72
+ const loadSharp = options.loadSharp ?? defaultLoadSharp;
73
+ let sharpModule; // lazy
74
+ for (let i = 0; i < inputs.length; i++) {
75
+ const item = inputs[i];
76
+ if (!isObject(item))
77
+ continue;
78
+ if (item.source !== 'local')
79
+ continue;
80
+ const type = String(item.type || 'image').toLowerCase();
81
+ const pathValue = item.value;
82
+ if (typeof pathValue !== 'string' || pathValue === '') {
83
+ throw new Error(`inputs[${i}].value must be a file path string when source='local'`);
84
+ }
85
+ if (!ALLOWED_MIME_BY_TYPE[type]) {
86
+ throw new Error(`inputs[${i}].type must be one of: image, video, audio (got '${type}')`);
87
+ }
88
+ let buf;
89
+ try {
90
+ buf = await readFile(pathValue);
91
+ }
92
+ catch (cause) {
93
+ throw new Error(`inputs[${i}]: could not read local file '${pathValue}': ${describe(cause)}`);
94
+ }
95
+ let mime = detectMimeFromPath(pathValue);
96
+ if (!mime || !ALLOWED_MIME_BY_TYPE[type].has(mime)) {
97
+ throw new Error(`inputs[${i}]: file '${path.basename(pathValue)}' has unsupported MIME ` +
98
+ `'${mime ?? 'unknown'}' for type='${type}'. ` +
99
+ `Allowed: ${Array.from(ALLOWED_MIME_BY_TYPE[type]).join(', ')}.`);
100
+ }
101
+ // Compress oversize images with sharp when available; refuse otherwise.
102
+ // Video and audio never touch sharp — those callers must use the
103
+ // two-step upload endpoint for oversize files.
104
+ if (buf.length > DATA_URI_TARGET_BYTES) {
105
+ if (type !== 'image') {
106
+ throw new Error(`inputs[${i}]: ${type} file '${path.basename(pathValue)}' is ` +
107
+ `${(buf.length / (1024 * 1024)).toFixed(1)} MB, over the ` +
108
+ `${DATA_URI_TARGET_BYTES / (1024 * 1024)} MB inline cap. ` +
109
+ `Use POST https://api.fluxpool.ai/v1/uploads to upload the file ` +
110
+ `and pass source='url' with the returned URL.`);
111
+ }
112
+ if (sharpModule === undefined)
113
+ sharpModule = await loadSharp();
114
+ if (sharpModule === null) {
115
+ throw new Error(`inputs[${i}]: image '${path.basename(pathValue)}' is ` +
116
+ `${(buf.length / (1024 * 1024)).toFixed(1)} MB, over the ` +
117
+ `${DATA_URI_TARGET_BYTES / (1024 * 1024)} MB inline cap. ` +
118
+ `Install optional dependency 'sharp' (npm i sharp) to enable ` +
119
+ `automatic compression, or resize the image before passing it.`);
120
+ }
121
+ const compressed = await compressWithSharp(sharpModule, buf);
122
+ buf = compressed;
123
+ mime = 'image/webp';
124
+ }
125
+ item.source = 'data';
126
+ item.value = `data:${mime};base64,${buf.toString('base64')}`;
127
+ }
128
+ return params;
129
+ }
130
+ /**
131
+ * Two-pass compression: try quality 82, drop to 65 if still over the cap,
132
+ * fail with a clear message if even 65 isn't enough. Two passes cover
133
+ * everyday phone photos (1-4 MB after resize at q82) and unusually large
134
+ * source images (drops to q65 for extreme cases) without going into
135
+ * an unbounded quality-reduction loop.
136
+ */
137
+ async function compressWithSharp(mod, buf) {
138
+ const pipeline = (quality) => mod
139
+ .default(buf)
140
+ .rotate() // honour EXIF orientation before resizing
141
+ .resize({ width: 2048, height: 2048, fit: 'inside', withoutEnlargement: true })
142
+ .webp({ quality })
143
+ .toBuffer();
144
+ const first = await pipeline(82);
145
+ if (first.length <= DATA_URI_TARGET_BYTES)
146
+ return first;
147
+ const second = await pipeline(65);
148
+ if (second.length <= DATA_URI_TARGET_BYTES)
149
+ return second;
150
+ throw new Error(`Image is still ${(second.length / (1024 * 1024)).toFixed(1)} MB after ` +
151
+ `resize to 2048px + webp q65. Resize the source further or upload it ` +
152
+ `via POST https://api.fluxpool.ai/v1/uploads and pass source='url'.`);
153
+ }
154
+ async function defaultLoadSharp() {
155
+ try {
156
+ // Dynamic import so sharp stays a truly optional dependency: callers
157
+ // who never pass a local path never pay the ~30 MB install cost.
158
+ // The string is opaque to tsc so a missing @types/sharp does not
159
+ // become a build error — the module is loaded (or not) at runtime.
160
+ const specifier = 'sharp';
161
+ return (await import(specifier));
162
+ }
163
+ catch {
164
+ return null;
165
+ }
166
+ }
167
+ function detectMimeFromPath(p) {
168
+ const ext = path.extname(p).toLowerCase();
169
+ return MIME_BY_EXT[ext] ?? null;
170
+ }
171
+ function isObject(value) {
172
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
173
+ }
174
+ function describe(cause) {
175
+ return cause instanceof Error ? cause.message : String(cause);
176
+ }
177
+ /**
178
+ * True when the message is a `tools/call` for `create_generation` that
179
+ * has `inputs[]` with at least one `source: 'local'` entry. Cheap check
180
+ * used by the bridge to decide whether to run the resolver.
181
+ */
182
+ export function needsLocalResolution(message) {
183
+ if (!isObject(message))
184
+ return false;
185
+ if (message.method !== 'tools/call')
186
+ return false;
187
+ const params = message.params;
188
+ if (!isObject(params))
189
+ return false;
190
+ if (params.name !== 'create_generation')
191
+ return false;
192
+ const args = params.arguments;
193
+ if (!isObject(args))
194
+ return false;
195
+ const inputs = args.inputs;
196
+ if (!Array.isArray(inputs))
197
+ return false;
198
+ return inputs.some((it) => isObject(it) && it.source === 'local');
199
+ }
200
+ //# sourceMappingURL=localInputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localInputs.js","sourceRoot":"","sources":["../src/localInputs.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,50 +1,59 @@
1
- {
2
- "name": "@fluxpool/mcp-server",
3
- "version": "0.1.0",
4
- "description": "MCP server for Fluxpool.ai — generate images and videos across Flux, Seedream, Seedance, Runway and more from Claude, Cursor, or any MCP client.",
5
- "keywords": [
6
- "mcp",
7
- "model-context-protocol",
8
- "fluxpool",
9
- "ai",
10
- "image-generation",
11
- "video-generation",
12
- "claude",
13
- "cursor"
14
- ],
15
- "homepage": "https://fluxpool.ai",
16
- "bugs": {
17
- "url": "https://github.com/ZKcandy/fluxpool-mcp-server/issues"
18
- },
19
- "repository": {
20
- "type": "git",
21
- "url": "git+https://github.com/ZKcandy/fluxpool-mcp-server.git"
22
- },
23
- "license": "MIT",
24
- "author": "Fluxpool",
25
- "type": "module",
26
- "bin": {
27
- "fluxpool-mcp": "dist/index.js"
28
- },
29
- "files": [
30
- "dist",
31
- "README.md",
32
- "LICENSE"
33
- ],
34
- "engines": {
35
- "node": ">=20"
36
- },
37
- "scripts": {
38
- "build": "tsc",
39
- "prepublishOnly": "npm run build && npm test",
40
- "start": "node dist/index.js",
41
- "test": "npm run build && node --test test/"
42
- },
43
- "dependencies": {
44
- "@modelcontextprotocol/sdk": "^1.0.4"
45
- },
46
- "devDependencies": {
47
- "@types/node": "^22.10.2",
48
- "typescript": "^5.7.2"
49
- }
50
- }
1
+ {
2
+ "name": "@fluxpool/mcp-server",
3
+ "version": "0.2.0",
4
+ "description": "MCP server for Fluxpool.ai — generate images and videos across Flux, Seedream, Seedance, Runway and more from Claude, Cursor, or any MCP client.",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "fluxpool",
9
+ "ai",
10
+ "image-generation",
11
+ "video-generation",
12
+ "claude",
13
+ "cursor"
14
+ ],
15
+ "homepage": "https://fluxpool.ai",
16
+ "bugs": {
17
+ "url": "https://github.com/ZKcandy/fluxpool-mcp-server/issues",
18
+ "email": "dev@fluxpool.ai"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/ZKcandy/fluxpool-mcp-server.git"
23
+ },
24
+ "license": "MIT",
25
+ "author": "Fluxpool <dev@fluxpool.ai>",
26
+ "type": "module",
27
+ "bin": {
28
+ "fluxpool-mcp": "dist/index.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "prepublishOnly": "npm run build && npm test",
41
+ "start": "node dist/index.js",
42
+ "test": "npm run build && node --test test/"
43
+ },
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.0.4"
46
+ },
47
+ "optionalDependencies": {
48
+ "sharp": "^0.33.5"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "sharp": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^22.10.2",
57
+ "typescript": "^5.7.2"
58
+ }
59
+ }