gangtise-openapi-cli 0.7.7 → 0.9.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 +29 -1
- package/dist/src/cli.js +86 -0
- package/dist/src/core/endpoints.js +57 -0
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,9 @@ export GANGTISE_TOKEN="Bearer xxx"
|
|
|
59
59
|
| | `foreign-report list` / `download` | 外资研报(含中文翻译下载) |
|
|
60
60
|
| | `announcement list` / `download` | 公告(含 Markdown 下载) |
|
|
61
61
|
| **Quote** | `day-kline` / `day-kline-hk` | A股/港股日K线 |
|
|
62
|
-
|
|
|
62
|
+
| | `minute-kline` | A股分钟K线 |
|
|
63
|
+
| **Fundamental** | `income-statement` / `balance-sheet` / `cash-flow` | 三大财务报表(累计) |
|
|
64
|
+
| | `income-statement-quarterly` / `cash-flow-quarterly` | 利润表/现金流量表(单季度) |
|
|
63
65
|
| | `main-business` | 主营构成(按地区/产品拆分) |
|
|
64
66
|
| | `valuation-analysis` | 估值分析 |
|
|
65
67
|
| **AI** | `knowledge-batch` | 知识库批量检索 |
|
|
@@ -70,7 +72,11 @@ export GANGTISE_TOKEN="Bearer xxx"
|
|
|
70
72
|
| | `peer-comparison` | 同业对比 |
|
|
71
73
|
| | `earnings-review` / `earnings-review-check` | 业绩回顾 |
|
|
72
74
|
| | `theme-tracking` | 主题跟踪 |
|
|
75
|
+
| | `hot-topic` | 热点话题 |
|
|
73
76
|
| | `research-outline` | 研究提纲 |
|
|
77
|
+
| | `management-discuss-announcement` | 管理层讨论-财报 |
|
|
78
|
+
| | `management-discuss-earnings-call` | 管理层讨论-业绩会 |
|
|
79
|
+
| | `viewpoint-debate` / `viewpoint-debate-check` | 观点PK(异步) |
|
|
74
80
|
| **Vault** | `drive-list` / `drive-download` | 云盘文件列表与下载 |
|
|
75
81
|
| **Raw** | `call` | 原始接口调用(可访问任意 endpoint) |
|
|
76
82
|
|
|
@@ -159,6 +165,7 @@ gangtise ai knowledge-batch --query 比亚迪 --query 最近热门概念
|
|
|
159
165
|
- `insight announcement list`
|
|
160
166
|
- `ai security-clue`
|
|
161
167
|
- `vault drive-list`
|
|
168
|
+
- `ai hot-topic`
|
|
162
169
|
|
|
163
170
|
规则:
|
|
164
171
|
- **有时间范围时**(传了 `--start-time/--end-time` 或 `--start-date/--end-date`):**省略 `--size`**,CLI 自动翻页查全
|
|
@@ -224,6 +231,8 @@ gangtise quote day-kline --security 600519.SH --start-date 2026-03-01 --end-date
|
|
|
224
231
|
gangtise quote day-kline --format json
|
|
225
232
|
# 港股日K线
|
|
226
233
|
gangtise quote day-kline-hk --security 00700.HK --start-date 2026-03-01 --end-date 2026-03-31
|
|
234
|
+
# A股分钟K线
|
|
235
|
+
gangtise quote minute-kline --security 600519.SH --start-time "2026-04-15 09:30:00" --end-time "2026-04-15 15:00:00" --field open --field close --field volume
|
|
227
236
|
```
|
|
228
237
|
|
|
229
238
|
### Fundamental
|
|
@@ -241,7 +250,13 @@ gangtise fundamental cash-flow --security-code 600519.SH --fiscal-year 2025 --pe
|
|
|
241
250
|
# 最新一期完整现金流量表
|
|
242
251
|
gangtise fundamental cash-flow --security-code 600519.SH --format json
|
|
243
252
|
gangtise fundamental main-business --security-code 600519.SH --breakdown region
|
|
253
|
+
# 多报告期:--period 可传多个值
|
|
254
|
+
gangtise fundamental main-business --security-code 600519.SH --breakdown product --period annual --period interim
|
|
244
255
|
gangtise fundamental valuation-analysis --security-code 600519.SH --indicator peTtm
|
|
256
|
+
# 利润表(单季度)
|
|
257
|
+
gangtise fundamental income-statement-quarterly --security-code 600519.SH --fiscal-year 2025 --period q2 --field netProfit
|
|
258
|
+
# 现金流量表(单季度)
|
|
259
|
+
gangtise fundamental cash-flow-quarterly --security-code 600519.SH --fiscal-year 2025 --period q2 --field netOpCashFlows
|
|
245
260
|
```
|
|
246
261
|
|
|
247
262
|
### AI
|
|
@@ -256,7 +271,20 @@ gangtise ai investment-logic --security-code 600519.SH
|
|
|
256
271
|
gangtise ai peer-comparison --security-code 600519.SH
|
|
257
272
|
gangtise ai earnings-review --security-code 600519.SH --period 2025q3
|
|
258
273
|
gangtise ai theme-tracking --theme-id 121000131 --date 2026-03-01 --type morning
|
|
274
|
+
gangtise ai hot-topic --start-date 2026-03-22 --end-date 2026-03-27 --category morningBriefing --category noonBriefing --with-related-securities --with-close-reading
|
|
275
|
+
# 不传 --category 默认查全部类型(早报+午报+盘中快报+晚报),--with-related-securities 和 --with-close-reading 默认开启
|
|
276
|
+
gangtise ai hot-topic --start-date 2026-04-15 --end-date 2026-04-17
|
|
259
277
|
gangtise ai research-outline --security-code 600519.SH
|
|
278
|
+
# 管理层讨论-财报
|
|
279
|
+
gangtise ai management-discuss-announcement --report-date 2025-06-30 --security-code 000001.SZ --dimension businessOperation
|
|
280
|
+
# 管理层讨论-业绩会
|
|
281
|
+
gangtise ai management-discuss-earnings-call --report-date 2025-06-30 --security-code 000001.SZ --dimension financialPerformance
|
|
282
|
+
# 观点PK(异步,返回 dataId)
|
|
283
|
+
gangtise ai viewpoint-debate --viewpoint "飞天茅台的批价低点是1500元"
|
|
284
|
+
# 等待生成完成后查询结果
|
|
285
|
+
gangtise ai viewpoint-debate-check --data-id 202603310528
|
|
286
|
+
# 也可以 --wait 同步等待结果(最长3分钟)
|
|
287
|
+
gangtise ai viewpoint-debate --viewpoint "比亚迪股价将突破500元" --wait
|
|
260
288
|
gangtise ai knowledge-resource-download --resource-type 60 --source-id 3052524 --output ./resource.txt
|
|
261
289
|
```
|
|
262
290
|
|
package/dist/src/cli.js
CHANGED
|
@@ -356,12 +356,20 @@ quote.command("day-kline-hk").option("--security <code>", "Security code (HK sto
|
|
|
356
356
|
const client = await createClient();
|
|
357
357
|
await printData(await client.call("quote.day-kline-hk", { securityList: maybeArray(options.security), startDate: options.startDate, endDate: options.endDate, limit: options.limit ? Number(options.limit) : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
358
358
|
});
|
|
359
|
+
quote.command("minute-kline").option("--security <code>", "Security code (A-share only: .SH/.SZ/.BJ)").option("--start-time <datetime>", "Start time (yyyy-MM-dd HH:mm:ss)").option("--end-time <datetime>", "End time (yyyy-MM-dd HH:mm:ss)").option("--limit <number>", "Max rows per request (default: 5000, max: 10000)").option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
360
|
+
const client = await createClient();
|
|
361
|
+
await printData(await client.call("quote.minute-kline", { securityCode: options.security, startTime: options.startTime, endTime: options.endTime, limit: options.limit ? Number(options.limit) : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
362
|
+
});
|
|
359
363
|
program.addCommand(quote);
|
|
360
364
|
const fundamental = new Command("fundamental").description("Fundamental APIs");
|
|
361
365
|
fundamental.command("income-statement").requiredOption("--security-code <code>").option("--start-date <date>").option("--end-date <date>").option("--fiscal-year <year>", "Fiscal year", collectList, []).option("--period <period>", "Period", collectList, []).option("--report-type <type>", "Report type", collectList, []).option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
362
366
|
const client = await createClient();
|
|
363
367
|
await printData(await client.call("fundamental.income-statement", { securityCode: options.securityCode, startDate: options.startDate, endDate: options.endDate, fiscalYear: maybeArray(options.fiscalYear), period: options.period.length ? options.period : undefined, reportType: options.reportType.length ? options.reportType : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
364
368
|
});
|
|
369
|
+
fundamental.command("income-statement-quarterly").requiredOption("--security-code <code>").option("--start-date <date>").option("--end-date <date>").option("--fiscal-year <year>", "Fiscal year", collectList, []).option("--period <period>", "Period: q1/q2/q3/q4/latest", collectList, []).option("--report-type <type>", "Report type", collectList, []).option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
370
|
+
const client = await createClient();
|
|
371
|
+
await printData(await client.call("fundamental.income-statement-quarterly", { securityCode: options.securityCode, startDate: options.startDate, endDate: options.endDate, fiscalYear: maybeArray(options.fiscalYear), period: options.period.length ? options.period : undefined, reportType: options.reportType.length ? options.reportType : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
372
|
+
});
|
|
365
373
|
fundamental.command("balance-sheet").requiredOption("--security-code <code>").option("--start-date <date>").option("--end-date <date>").option("--fiscal-year <year>", "Fiscal year", collectList, []).option("--period <period>", "Period", collectList, []).option("--report-type <type>", "Report type", collectList, []).option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
366
374
|
const client = await createClient();
|
|
367
375
|
await printData(await client.call("fundamental.balance-sheet", { securityCode: options.securityCode, startDate: options.startDate, endDate: options.endDate, fiscalYear: maybeArray(options.fiscalYear), period: options.period.length ? options.period : undefined, reportType: options.reportType.length ? options.reportType : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
@@ -370,6 +378,10 @@ fundamental.command("cash-flow").requiredOption("--security-code <code>").option
|
|
|
370
378
|
const client = await createClient();
|
|
371
379
|
await printData(await client.call("fundamental.cash-flow", { securityCode: options.securityCode, startDate: options.startDate, endDate: options.endDate, fiscalYear: maybeArray(options.fiscalYear), period: options.period.length ? options.period : undefined, reportType: options.reportType.length ? options.reportType : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
372
380
|
});
|
|
381
|
+
fundamental.command("cash-flow-quarterly").requiredOption("--security-code <code>").option("--start-date <date>").option("--end-date <date>").option("--fiscal-year <year>", "Fiscal year", collectList, []).option("--period <period>", "Period: q1/q2/q3/q4/latest", collectList, []).option("--report-type <type>", "Report type", collectList, []).option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
382
|
+
const client = await createClient();
|
|
383
|
+
await printData(await client.call("fundamental.cash-flow-quarterly", { securityCode: options.securityCode, startDate: options.startDate, endDate: options.endDate, fiscalYear: maybeArray(options.fiscalYear), period: options.period.length ? options.period : undefined, reportType: options.reportType.length ? options.reportType : undefined, fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
384
|
+
});
|
|
373
385
|
fundamental.command("main-business").requiredOption("--security-code <code>").option("--start-date <date>").option("--end-date <date>").addOption(new Option("--breakdown <type>", "Breakdown: product/industry/region").choices(["product", "industry", "region"]).default("product")).option("--period <type>", "Period: interim/annual", collectList, []).option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
374
386
|
const client = await createClient();
|
|
375
387
|
await printData(await client.call("fundamental.main-business", { securityCode: options.securityCode, startDate: options.startDate, endDate: options.endDate, breakdown: options.breakdown, periodList: maybeArray(options.period), fieldList: maybeArray(options.field) }), parseFormat(options.format), options.output);
|
|
@@ -467,6 +479,80 @@ ai.command("research-outline").requiredOption("--security-code <code>").option("
|
|
|
467
479
|
const client = await createClient();
|
|
468
480
|
await printData(await client.call("ai.research-outline", { securityCode: options.securityCode }), parseFormat(options.format), options.output);
|
|
469
481
|
});
|
|
482
|
+
ai.command("hot-topic").option("--from <number>", "Starting offset", "0").option("--size <number>", "Total rows to return; omit to fetch all").option("--start-date <date>", "Start date (yyyy-MM-dd)").option("--end-date <date>", "End date (yyyy-MM-dd)").option("--category <name>", "Report type: morningBriefing/noonBriefing/afternoonFlash/eveningBriefing", collectList, []).option("--with-related-securities", "Include related securities info", true).option("--with-close-reading", "Include close reading content", true).option("--format <format>", "Output format", "json").option("--output <path>").action(async (options) => {
|
|
483
|
+
const client = await createClient();
|
|
484
|
+
const ALL_CATEGORIES = ["morningBriefing", "noonBriefing", "afternoonFlash", "eveningBriefing"];
|
|
485
|
+
await printData(await client.call("ai.hot-topic", {
|
|
486
|
+
from: Number(options.from),
|
|
487
|
+
size: options.size === undefined ? undefined : Number(options.size),
|
|
488
|
+
startDate: options.startDate,
|
|
489
|
+
endDate: options.endDate,
|
|
490
|
+
categoryList: options.category.length > 0 ? options.category : ALL_CATEGORIES,
|
|
491
|
+
withRelatedSecurities: options.withRelatedSecurities || undefined,
|
|
492
|
+
withCloseReading: options.withCloseReading || undefined,
|
|
493
|
+
}), parseFormat(options.format), options.output);
|
|
494
|
+
});
|
|
495
|
+
ai.command("management-discuss-announcement").requiredOption("--report-date <date>", "Report date (yyyy-MM-dd, e.g. 2025-06-30)").requiredOption("--security-code <code>", "Security code (e.g. 000001.SZ)").addOption(new Option("--dimension <name>", "Discussion dimension").choices(["businessOperation", "financialPerformance", "developmentAndRisk"]).makeOptionMandatory()).option("--format <format>", "Output format", "json").option("--output <path>").action(async (options) => {
|
|
496
|
+
const client = await createClient();
|
|
497
|
+
await printData(await client.call("ai.management-discuss-announcement", {
|
|
498
|
+
reportDate: options.reportDate,
|
|
499
|
+
securityCode: options.securityCode,
|
|
500
|
+
discussionDimension: options.dimension,
|
|
501
|
+
}), parseFormat(options.format), options.output);
|
|
502
|
+
});
|
|
503
|
+
ai.command("management-discuss-earnings-call").requiredOption("--report-date <date>", "Report date (yyyy-MM-dd, e.g. 2025-06-30)").requiredOption("--security-code <code>", "Security code (e.g. 000001.SZ)").addOption(new Option("--dimension <name>", "Discussion dimension").choices(["businessOperation", "financialPerformance", "developmentAndRisk"]).makeOptionMandatory()).option("--format <format>", "Output format", "json").option("--output <path>").action(async (options) => {
|
|
504
|
+
const client = await createClient();
|
|
505
|
+
await printData(await client.call("ai.management-discuss-earnings-call", {
|
|
506
|
+
reportDate: options.reportDate,
|
|
507
|
+
securityCode: options.securityCode,
|
|
508
|
+
discussionDimension: options.dimension,
|
|
509
|
+
}), parseFormat(options.format), options.output);
|
|
510
|
+
});
|
|
511
|
+
ai.command("viewpoint-debate").requiredOption("--viewpoint <text>", "Viewpoint text (max 1000 chars)").option("--wait", "Wait for content generation (blocking, up to 3 min)").option("--format <format>", "Output format", "json").option("--output <path>").action(async (options) => {
|
|
512
|
+
const client = await createClient();
|
|
513
|
+
// Step 1: get dataId
|
|
514
|
+
const idResult = await client.call("ai.viewpoint-debate.get-id", { viewpoint: options.viewpoint });
|
|
515
|
+
const dataId = idResult?.dataId;
|
|
516
|
+
if (!dataId) {
|
|
517
|
+
process.stderr.write("Failed to get viewpoint debate ID.\n");
|
|
518
|
+
process.exitCode = 1;
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
// Non-blocking: return dataId immediately
|
|
522
|
+
if (!options.wait) {
|
|
523
|
+
process.stderr.write(`Viewpoint debate task submitted. dataId: ${dataId}\n`);
|
|
524
|
+
process.stdout.write(`${JSON.stringify({ dataId, status: "pending", hint: `Run 'gangtise ai viewpoint-debate-check --data-id ${dataId}' in ~2 minutes to get results` })}\n`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
// Blocking (--wait): poll for content
|
|
528
|
+
process.stderr.write(`Got dataId: ${dataId}, waiting for content generation...\n`);
|
|
529
|
+
let attempts = 0;
|
|
530
|
+
const maxAttempts = 12;
|
|
531
|
+
const delayMs = 15_000;
|
|
532
|
+
while (attempts < maxAttempts) {
|
|
533
|
+
attempts++;
|
|
534
|
+
const contentResult = await client.call("ai.viewpoint-debate.get-content", { dataId });
|
|
535
|
+
if (contentResult?.data?.content) {
|
|
536
|
+
await printData(contentResult.data, parseFormat(options.format), options.output);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
if (attempts < maxAttempts) {
|
|
540
|
+
process.stderr.write(`Attempt ${attempts}/${maxAttempts}: content not ready, retrying in 15s...\n`);
|
|
541
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
process.stderr.write(`Content not available after ${maxAttempts} attempts. Try again later with: gangtise ai viewpoint-debate-check --data-id ${dataId}\n`);
|
|
545
|
+
process.exitCode = 1;
|
|
546
|
+
});
|
|
547
|
+
ai.command("viewpoint-debate-check").requiredOption("--data-id <id>", "dataId from viewpoint-debate").option("--format <format>", "Output format", "json").option("--output <path>").action(async (options) => {
|
|
548
|
+
const client = await createClient();
|
|
549
|
+
const contentResult = await client.call("ai.viewpoint-debate.get-content", { dataId: options.dataId });
|
|
550
|
+
if (contentResult?.data?.content) {
|
|
551
|
+
await printData(contentResult.data, parseFormat(options.format), options.output);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
process.stdout.write(`${JSON.stringify({ dataId: options.dataId, status: "pending", hint: "Content not ready yet, retry in ~2 minutes" })}\n`);
|
|
555
|
+
});
|
|
470
556
|
const vault = new Command("vault").description("Vault APIs");
|
|
471
557
|
vault.command("drive-list").option("--from <number>", "Starting offset", "0").option("--size <number>", "Total rows to return; omit to fetch all").option("--start-time <datetime>").option("--end-time <datetime>").option("--keyword <text>").option("--file-type <number>", "File type", collectNumberList, []).option("--space-type <number>", "Space type", collectNumberList, []).option("--format <format>", "Output format", "table").option("--output <path>").action(async (options) => {
|
|
472
558
|
const client = await createClient();
|
|
@@ -282,6 +282,63 @@ export const ENDPOINTS = {
|
|
|
282
282
|
kind: "json",
|
|
283
283
|
description: "Get company research outline",
|
|
284
284
|
},
|
|
285
|
+
aiHotTopic: {
|
|
286
|
+
key: "ai.hot-topic",
|
|
287
|
+
method: "POST",
|
|
288
|
+
path: "/application/open-ai/hot-topic/getList",
|
|
289
|
+
kind: "json",
|
|
290
|
+
description: "List hot topic reports",
|
|
291
|
+
pagination: { enabled: true, maxPageSize: 20 },
|
|
292
|
+
},
|
|
293
|
+
aiManagementDiscussAnnouncement: {
|
|
294
|
+
key: "ai.management-discuss-announcement",
|
|
295
|
+
method: "POST",
|
|
296
|
+
path: "/application/open-ai/management-discuss/from-announcement",
|
|
297
|
+
kind: "json",
|
|
298
|
+
description: "Management discussion from financial reports (half-year/annual)",
|
|
299
|
+
},
|
|
300
|
+
aiManagementDiscussEarningsCall: {
|
|
301
|
+
key: "ai.management-discuss-earnings-call",
|
|
302
|
+
method: "POST",
|
|
303
|
+
path: "/application/open-ai/management-discuss/from-earningsCall",
|
|
304
|
+
kind: "json",
|
|
305
|
+
description: "Management discussion from earnings calls",
|
|
306
|
+
},
|
|
307
|
+
aiViewpointDebateGetId: {
|
|
308
|
+
key: "ai.viewpoint-debate.get-id",
|
|
309
|
+
method: "POST",
|
|
310
|
+
path: "/application/open-ai/agent/viewpoint-debate-getid",
|
|
311
|
+
kind: "json",
|
|
312
|
+
description: "Get viewpoint debate ID",
|
|
313
|
+
},
|
|
314
|
+
aiViewpointDebateGetContent: {
|
|
315
|
+
key: "ai.viewpoint-debate.get-content",
|
|
316
|
+
method: "POST",
|
|
317
|
+
path: "/application/open-ai/agent/viewpoint-debate-getcontent",
|
|
318
|
+
kind: "json",
|
|
319
|
+
description: "Get viewpoint debate content",
|
|
320
|
+
},
|
|
321
|
+
quoteMinuteKline: {
|
|
322
|
+
key: "quote.minute-kline",
|
|
323
|
+
method: "POST",
|
|
324
|
+
path: "/application/open-quote/kline/minute",
|
|
325
|
+
kind: "json",
|
|
326
|
+
description: "Query A-share minute kline (SH/SZ/BJ)",
|
|
327
|
+
},
|
|
328
|
+
fundamentalIncomeStatementQuarterly: {
|
|
329
|
+
key: "fundamental.income-statement-quarterly",
|
|
330
|
+
method: "POST",
|
|
331
|
+
path: "/application/open-fundamental/financial-report/income-statement/quarterly",
|
|
332
|
+
kind: "json",
|
|
333
|
+
description: "Query income statement (quarterly)",
|
|
334
|
+
},
|
|
335
|
+
fundamentalCashFlowQuarterly: {
|
|
336
|
+
key: "fundamental.cash-flow-quarterly",
|
|
337
|
+
method: "POST",
|
|
338
|
+
path: "/application/open-fundamental/financial-report/cash-flow-statement/quarterly",
|
|
339
|
+
kind: "json",
|
|
340
|
+
description: "Query cash flow statement (quarterly)",
|
|
341
|
+
},
|
|
285
342
|
vaultDriveList: {
|
|
286
343
|
key: "vault.drive.list",
|
|
287
344
|
method: "POST",
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated — DO NOT EDIT
|
|
2
|
-
export const CLI_VERSION = "0.
|
|
2
|
+
export const CLI_VERSION = "0.9.0";
|