@promptbook/core 0.104.0-10 → 0.104.0-12
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/esm/index.es.js +154 -32
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/types.index.d.ts +8 -0
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +24 -0
- package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +5 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.tools.test.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +2 -2
- package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
- package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
- package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +2 -2
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +0 -54
- package/esm/typings/src/commitments/META/META_DESCRIPTION.d.ts +41 -0
- package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +2 -2
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizardOrCli.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/LlmExecutionToolsWithTotalUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/limitTotalUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/getSingleLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/joinLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
- package/esm/typings/src/llm-providers/openai/utils/mapToolsToOpenAi.d.ts +8 -0
- package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
- package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
- package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
- package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
- package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
- package/esm/typings/src/types/LlmToolDefinition.d.ts +20 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +13 -0
- package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +154 -32
- package/umd/index.umd.js.map +1 -1
package/umd/index.umd.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* @generated
|
|
29
29
|
* @see https://github.com/webgptorg/promptbook
|
|
30
30
|
*/
|
|
31
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-
|
|
31
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-12';
|
|
32
32
|
/**
|
|
33
33
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
34
34
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -3764,7 +3764,7 @@
|
|
|
3764
3764
|
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
3765
3765
|
* TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
|
|
3766
3766
|
* > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
|
|
3767
|
-
* TODO: [👷♂️]
|
|
3767
|
+
* TODO: [👷♂️] Write a comprehensive manual explaining the construction and usage of LLM tools in the Promptbook ecosystem
|
|
3768
3768
|
*/
|
|
3769
3769
|
|
|
3770
3770
|
/**
|
|
@@ -4004,7 +4004,7 @@
|
|
|
4004
4004
|
}
|
|
4005
4005
|
/**
|
|
4006
4006
|
* TODO: [🙆] `getSingleLlmExecutionTools` vs `joinLlmExecutionTools` - explain difference or pick one
|
|
4007
|
-
* TODO: [👷♂️]
|
|
4007
|
+
* TODO: [👷♂️] Write a comprehensive manual about how to construct and use LLM execution tools in Promptbook
|
|
4008
4008
|
*/
|
|
4009
4009
|
|
|
4010
4010
|
/**
|
|
@@ -4021,7 +4021,7 @@
|
|
|
4021
4021
|
}
|
|
4022
4022
|
/**
|
|
4023
4023
|
* TODO: [🙆] `getSingleLlmExecutionTools` vs `joinLlmExecutionTools` - explain difference or pick one
|
|
4024
|
-
* TODO: [👷♂️]
|
|
4024
|
+
* TODO: [👷♂️] Write a comprehensive manual about how to construct and use LLM execution tools in Promptbook
|
|
4025
4025
|
*/
|
|
4026
4026
|
|
|
4027
4027
|
/**
|
|
@@ -10606,19 +10606,37 @@
|
|
|
10606
10606
|
`);
|
|
10607
10607
|
}
|
|
10608
10608
|
applyToAgentModelRequirements(requirements, content) {
|
|
10609
|
-
// We simply mark that browser capability is enabled in metadata
|
|
10610
|
-
// Get existing metadata
|
|
10611
|
-
const existingMetadata = requirements.metadata || {};
|
|
10612
10609
|
// Get existing tools array or create new one
|
|
10613
|
-
const existingTools =
|
|
10614
|
-
// Add '
|
|
10615
|
-
const updatedTools = existingTools.
|
|
10616
|
-
|
|
10610
|
+
const existingTools = requirements.tools || [];
|
|
10611
|
+
// Add 'web_browser' to tools if not already present
|
|
10612
|
+
const updatedTools = existingTools.some((tool) => tool.name === 'web_browser')
|
|
10613
|
+
? existingTools
|
|
10614
|
+
: [
|
|
10615
|
+
...existingTools,
|
|
10616
|
+
{
|
|
10617
|
+
name: 'web_browser',
|
|
10618
|
+
description: spaceTrim$1.spaceTrim(`
|
|
10619
|
+
A tool that can browse the web.
|
|
10620
|
+
Use this tool when you need to access specific websites or browse the internet.
|
|
10621
|
+
`),
|
|
10622
|
+
parameters: {
|
|
10623
|
+
type: 'object',
|
|
10624
|
+
properties: {
|
|
10625
|
+
url: {
|
|
10626
|
+
type: 'string',
|
|
10627
|
+
description: 'The URL to browse',
|
|
10628
|
+
},
|
|
10629
|
+
},
|
|
10630
|
+
required: ['url'],
|
|
10631
|
+
},
|
|
10632
|
+
},
|
|
10633
|
+
];
|
|
10634
|
+
// Return requirements with updated tools and metadata
|
|
10617
10635
|
return {
|
|
10618
10636
|
...requirements,
|
|
10637
|
+
tools: updatedTools,
|
|
10619
10638
|
metadata: {
|
|
10620
|
-
...
|
|
10621
|
-
tools: updatedTools,
|
|
10639
|
+
...requirements.metadata,
|
|
10622
10640
|
useBrowser: true,
|
|
10623
10641
|
},
|
|
10624
10642
|
};
|
|
@@ -10711,13 +10729,13 @@
|
|
|
10711
10729
|
* The `USE SEARCH ENGINE` commitment indicates that the agent should utilize a search engine tool
|
|
10712
10730
|
* to access and retrieve up-to-date information from the internet when necessary.
|
|
10713
10731
|
*
|
|
10714
|
-
* The content following `USE SEARCH ENGINE` is
|
|
10732
|
+
* The content following `USE SEARCH ENGINE` is an arbitrary text that the agent should know (e.g. search scope or instructions).
|
|
10715
10733
|
*
|
|
10716
10734
|
* Example usage in agent source:
|
|
10717
10735
|
*
|
|
10718
10736
|
* ```book
|
|
10719
10737
|
* USE SEARCH ENGINE
|
|
10720
|
-
* USE SEARCH ENGINE
|
|
10738
|
+
* USE SEARCH ENGINE Hledej informace o Přemyslovcích
|
|
10721
10739
|
* ```
|
|
10722
10740
|
*
|
|
10723
10741
|
* @private [🪔] Maybe export the commitments through some package
|
|
@@ -10749,7 +10767,7 @@
|
|
|
10749
10767
|
|
|
10750
10768
|
## Key aspects
|
|
10751
10769
|
|
|
10752
|
-
- The content following \`USE SEARCH ENGINE\` is
|
|
10770
|
+
- The content following \`USE SEARCH ENGINE\` is an arbitrary text that the agent should know (e.g. search scope or instructions).
|
|
10753
10771
|
- The actual search engine tool usage is handled by the agent runtime
|
|
10754
10772
|
- Allows the agent to search for current information from the web
|
|
10755
10773
|
- Useful for research tasks, finding facts, and accessing dynamic content
|
|
@@ -10774,20 +10792,39 @@
|
|
|
10774
10792
|
`);
|
|
10775
10793
|
}
|
|
10776
10794
|
applyToAgentModelRequirements(requirements, content) {
|
|
10777
|
-
// We simply mark that search engine capability is enabled in metadata
|
|
10778
|
-
// Get existing metadata
|
|
10779
|
-
const existingMetadata = requirements.metadata || {};
|
|
10780
10795
|
// Get existing tools array or create new one
|
|
10781
|
-
const existingTools =
|
|
10782
|
-
// Add '
|
|
10783
|
-
const updatedTools = existingTools.
|
|
10784
|
-
|
|
10796
|
+
const existingTools = requirements.tools || [];
|
|
10797
|
+
// Add 'web_search' to tools if not already present
|
|
10798
|
+
const updatedTools = existingTools.some((tool) => tool.name === 'web_search')
|
|
10799
|
+
? existingTools
|
|
10800
|
+
: [
|
|
10801
|
+
...existingTools,
|
|
10802
|
+
{
|
|
10803
|
+
name: 'web_search',
|
|
10804
|
+
description: spaceTrim$1.spaceTrim(`
|
|
10805
|
+
Search the internet for information.
|
|
10806
|
+
Use this tool when you need to find up-to-date information or facts that you don't know.
|
|
10807
|
+
${!content ? '' : `Search scope / instructions: ${content}`}
|
|
10808
|
+
`),
|
|
10809
|
+
parameters: {
|
|
10810
|
+
type: 'object',
|
|
10811
|
+
properties: {
|
|
10812
|
+
query: {
|
|
10813
|
+
type: 'string',
|
|
10814
|
+
description: 'The search query',
|
|
10815
|
+
},
|
|
10816
|
+
},
|
|
10817
|
+
required: ['query'],
|
|
10818
|
+
},
|
|
10819
|
+
},
|
|
10820
|
+
];
|
|
10821
|
+
// Return requirements with updated tools and metadata
|
|
10785
10822
|
return {
|
|
10786
10823
|
...requirements,
|
|
10824
|
+
tools: updatedTools,
|
|
10787
10825
|
metadata: {
|
|
10788
|
-
...
|
|
10789
|
-
|
|
10790
|
-
useSearchEngine: true,
|
|
10826
|
+
...requirements.metadata,
|
|
10827
|
+
useSearchEngine: content || true,
|
|
10791
10828
|
},
|
|
10792
10829
|
};
|
|
10793
10830
|
}
|
|
@@ -11896,7 +11933,57 @@
|
|
|
11896
11933
|
}
|
|
11897
11934
|
const meta = {};
|
|
11898
11935
|
const links = [];
|
|
11936
|
+
const capabilities = [];
|
|
11899
11937
|
for (const commitment of parseResult.commitments) {
|
|
11938
|
+
if (commitment.type === 'USE BROWSER') {
|
|
11939
|
+
capabilities.push({
|
|
11940
|
+
type: 'browser',
|
|
11941
|
+
label: 'Browser',
|
|
11942
|
+
iconName: 'Globe',
|
|
11943
|
+
});
|
|
11944
|
+
continue;
|
|
11945
|
+
}
|
|
11946
|
+
if (commitment.type === 'USE SEARCH ENGINE') {
|
|
11947
|
+
capabilities.push({
|
|
11948
|
+
type: 'search-engine',
|
|
11949
|
+
label: 'Search Internet',
|
|
11950
|
+
iconName: 'Search',
|
|
11951
|
+
});
|
|
11952
|
+
continue;
|
|
11953
|
+
}
|
|
11954
|
+
if (commitment.type === 'KNOWLEDGE') {
|
|
11955
|
+
const content = spaceTrim__default["default"](commitment.content).split('\n')[0] || '';
|
|
11956
|
+
let label = content;
|
|
11957
|
+
let iconName = 'Book';
|
|
11958
|
+
if (content.startsWith('http://') || content.startsWith('https://')) {
|
|
11959
|
+
try {
|
|
11960
|
+
const url = new URL(content);
|
|
11961
|
+
if (url.pathname.endsWith('.pdf')) {
|
|
11962
|
+
label = url.pathname.split('/').pop() || 'Document.pdf';
|
|
11963
|
+
iconName = 'FileText';
|
|
11964
|
+
}
|
|
11965
|
+
else {
|
|
11966
|
+
label = url.hostname.replace(/^www\./, '');
|
|
11967
|
+
}
|
|
11968
|
+
}
|
|
11969
|
+
catch (e) {
|
|
11970
|
+
// Invalid URL, treat as text
|
|
11971
|
+
}
|
|
11972
|
+
}
|
|
11973
|
+
else {
|
|
11974
|
+
// Text content - take first few words
|
|
11975
|
+
const words = content.split(/\s+/);
|
|
11976
|
+
if (words.length > 4) {
|
|
11977
|
+
label = words.slice(0, 4).join(' ') + '...';
|
|
11978
|
+
}
|
|
11979
|
+
}
|
|
11980
|
+
capabilities.push({
|
|
11981
|
+
type: 'knowledge',
|
|
11982
|
+
label,
|
|
11983
|
+
iconName,
|
|
11984
|
+
});
|
|
11985
|
+
continue;
|
|
11986
|
+
}
|
|
11900
11987
|
if (commitment.type === 'META LINK') {
|
|
11901
11988
|
const linkValue = spaceTrim__default["default"](commitment.content);
|
|
11902
11989
|
links.push(linkValue);
|
|
@@ -11907,6 +11994,10 @@
|
|
|
11907
11994
|
meta.image = spaceTrim__default["default"](commitment.content);
|
|
11908
11995
|
continue;
|
|
11909
11996
|
}
|
|
11997
|
+
if (commitment.type === 'META DESCRIPTION') {
|
|
11998
|
+
meta.description = spaceTrim__default["default"](commitment.content);
|
|
11999
|
+
continue;
|
|
12000
|
+
}
|
|
11910
12001
|
if (commitment.type === 'META COLOR') {
|
|
11911
12002
|
meta.color = normalizeSeparator(commitment.content);
|
|
11912
12003
|
continue;
|
|
@@ -11943,6 +12034,7 @@
|
|
|
11943
12034
|
meta,
|
|
11944
12035
|
links,
|
|
11945
12036
|
parameters,
|
|
12037
|
+
capabilities,
|
|
11946
12038
|
};
|
|
11947
12039
|
}
|
|
11948
12040
|
/**
|
|
@@ -12245,7 +12337,7 @@
|
|
|
12245
12337
|
});
|
|
12246
12338
|
}
|
|
12247
12339
|
/**
|
|
12248
|
-
*
|
|
12340
|
+
* Retrieves the permanent ID of an agent by its name or permanent ID.
|
|
12249
12341
|
*/
|
|
12250
12342
|
async getAgentPermanentId(agentNameOrPermanentId) {
|
|
12251
12343
|
const selectResult = await this.supabaseClient
|
|
@@ -12259,7 +12351,7 @@
|
|
|
12259
12351
|
return selectResult.data.permanentId;
|
|
12260
12352
|
}
|
|
12261
12353
|
/**
|
|
12262
|
-
*
|
|
12354
|
+
* Retrieves the source code of an agent by its name or permanent ID.
|
|
12263
12355
|
*/
|
|
12264
12356
|
async getAgentSource(agentNameOrPermanentId) {
|
|
12265
12357
|
const selectResult = await this.supabaseClient
|
|
@@ -12536,6 +12628,7 @@
|
|
|
12536
12628
|
getTableName(tableName) {
|
|
12537
12629
|
const { tablePrefix = '' } = this.options || {};
|
|
12538
12630
|
return `${tablePrefix}${tableName}`;
|
|
12631
|
+
// <- TODO: [🏧] DRY
|
|
12539
12632
|
}
|
|
12540
12633
|
}
|
|
12541
12634
|
/**
|
|
@@ -17090,7 +17183,7 @@
|
|
|
17090
17183
|
* TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
|
|
17091
17184
|
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
17092
17185
|
* TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
|
|
17093
|
-
* TODO: [👷♂️]
|
|
17186
|
+
* TODO: [👷♂️] Write a comprehensive manual about the construction of LLM tools
|
|
17094
17187
|
*/
|
|
17095
17188
|
|
|
17096
17189
|
/**
|
|
@@ -17978,6 +18071,22 @@
|
|
|
17978
18071
|
* TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
17979
18072
|
*/
|
|
17980
18073
|
|
|
18074
|
+
/**
|
|
18075
|
+
* Maps Promptbook tools to OpenAI tools.
|
|
18076
|
+
*
|
|
18077
|
+
* @private
|
|
18078
|
+
*/
|
|
18079
|
+
function mapToolsToOpenAi(tools) {
|
|
18080
|
+
return tools.map((tool) => ({
|
|
18081
|
+
type: 'function',
|
|
18082
|
+
function: {
|
|
18083
|
+
name: tool.name,
|
|
18084
|
+
description: tool.description,
|
|
18085
|
+
parameters: tool.parameters,
|
|
18086
|
+
},
|
|
18087
|
+
}));
|
|
18088
|
+
}
|
|
18089
|
+
|
|
17981
18090
|
/**
|
|
17982
18091
|
* Parses an OpenAI error message to identify which parameter is unsupported
|
|
17983
18092
|
*
|
|
@@ -18175,6 +18284,9 @@
|
|
|
18175
18284
|
},
|
|
18176
18285
|
],
|
|
18177
18286
|
user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
18287
|
+
tools: currentModelRequirements.tools === undefined
|
|
18288
|
+
? undefined
|
|
18289
|
+
: mapToolsToOpenAi(currentModelRequirements.tools),
|
|
18178
18290
|
};
|
|
18179
18291
|
const start = $getCurrentDate();
|
|
18180
18292
|
if (this.options.isVerbose) {
|
|
@@ -18319,6 +18431,7 @@
|
|
|
18319
18431
|
const rawPromptContent = templateParameters(content, { ...parameters, modelName });
|
|
18320
18432
|
const rawRequest = {
|
|
18321
18433
|
...modelSettings,
|
|
18434
|
+
model: modelName,
|
|
18322
18435
|
prompt: rawPromptContent,
|
|
18323
18436
|
user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
18324
18437
|
};
|
|
@@ -18573,8 +18686,8 @@
|
|
|
18573
18686
|
const rawPromptContent = templateParameters(content, { ...parameters, modelName });
|
|
18574
18687
|
const rawRequest = {
|
|
18575
18688
|
...modelSettings,
|
|
18576
|
-
size: modelSettings.size || '1024x1024',
|
|
18577
18689
|
prompt: rawPromptContent,
|
|
18690
|
+
size: modelSettings.size || '1024x1024',
|
|
18578
18691
|
user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
18579
18692
|
response_format: 'url', // TODO: [🧠] Maybe allow b64_json
|
|
18580
18693
|
};
|
|
@@ -18976,6 +19089,7 @@
|
|
|
18976
19089
|
thread: {
|
|
18977
19090
|
messages: threadMessages,
|
|
18978
19091
|
},
|
|
19092
|
+
tools: modelRequirements.tools === undefined ? undefined : mapToolsToOpenAi(modelRequirements.tools),
|
|
18979
19093
|
// <- TODO: Add user identification here> user: this.options.user,
|
|
18980
19094
|
};
|
|
18981
19095
|
const start = $getCurrentDate();
|
|
@@ -19499,6 +19613,8 @@
|
|
|
19499
19613
|
modelRequirements: {
|
|
19500
19614
|
...chatPrompt.modelRequirements,
|
|
19501
19615
|
...modelRequirements,
|
|
19616
|
+
// Spread tools to convert readonly array to mutable
|
|
19617
|
+
tools: modelRequirements.tools ? [...modelRequirements.tools] : chatPrompt.modelRequirements.tools,
|
|
19502
19618
|
// Prepend agent system message to existing system message
|
|
19503
19619
|
systemMessage: modelRequirements.systemMessage +
|
|
19504
19620
|
(chatPrompt.modelRequirements.systemMessage
|
|
@@ -19592,6 +19708,11 @@
|
|
|
19592
19708
|
* Links found in the agent source
|
|
19593
19709
|
*/
|
|
19594
19710
|
this.links = [];
|
|
19711
|
+
/**
|
|
19712
|
+
* Capabilities of the agent
|
|
19713
|
+
* This is parsed from commitments like USE BROWSER, USE SEARCH ENGINE, KNOWLEDGE, etc.
|
|
19714
|
+
*/
|
|
19715
|
+
this.capabilities = [];
|
|
19595
19716
|
/**
|
|
19596
19717
|
* Metadata like image or color
|
|
19597
19718
|
*/
|
|
@@ -19601,11 +19722,12 @@
|
|
|
19601
19722
|
this.agentSource = agentSource;
|
|
19602
19723
|
this.agentSource.subscribe((source) => {
|
|
19603
19724
|
this.updateAgentSource(source);
|
|
19604
|
-
const { agentName, personaDescription, initialMessage, links, meta } = parseAgentSource(source);
|
|
19725
|
+
const { agentName, personaDescription, initialMessage, links, meta, capabilities } = parseAgentSource(source);
|
|
19605
19726
|
this._agentName = agentName;
|
|
19606
19727
|
this.personaDescription = personaDescription;
|
|
19607
19728
|
this.initialMessage = initialMessage;
|
|
19608
19729
|
this.links = links;
|
|
19730
|
+
this.capabilities = capabilities;
|
|
19609
19731
|
this.meta = { ...this.meta, ...meta };
|
|
19610
19732
|
});
|
|
19611
19733
|
}
|
|
@@ -21176,7 +21298,7 @@
|
|
|
21176
21298
|
'Serious and focused AI consultant.',
|
|
21177
21299
|
];
|
|
21178
21300
|
/**
|
|
21179
|
-
*
|
|
21301
|
+
* Generates a random agent persona description.
|
|
21180
21302
|
*
|
|
21181
21303
|
* @private internal helper function
|
|
21182
21304
|
*/
|