@sourcegraph/cody-web 0.5.1 → 0.7.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/dist/{agent.worker-CHrb4rcq.js → agent.worker-Cjx_iNtn.mjs} +3602 -8945
- package/dist/agent.worker.js +2 -3
- package/dist/{time-date-C7nUVQ0Y.js → browser-BpZhCiRU.mjs} +11020 -4401
- package/dist/{cl100k_base-BgU9RXdk.js → cl100k_base-B4kyDDRQ.mjs} +3 -3
- package/dist/demo/App.d.ts.map +1 -1
- package/dist/{git-log-Bn_F1p4S.js → git-log-BWpOPYwA.mjs} +10 -10
- package/dist/{index-ZysJUhSy.js → index-D2gpkgry.mjs} +74 -74
- package/dist/index.js +26961 -14269
- package/dist/lib/components/CodyWebChat.d.ts +21 -0
- package/dist/lib/components/CodyWebChat.d.ts.map +1 -0
- package/dist/lib/components/skeleton/ChatSkeleton.d.ts +11 -0
- package/dist/lib/components/skeleton/ChatSkeleton.d.ts.map +1 -0
- package/dist/lib/components/use-cody-agent.d.ts +27 -0
- package/dist/lib/components/use-cody-agent.d.ts.map +1 -0
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/types.d.ts +5 -4
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/shell-DvMNfs3M.mjs +47 -0
- package/dist/style.css +138 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/dist/lib/components/CodyWebPanel.d.ts +0 -7
- package/dist/lib/components/CodyWebPanel.d.ts.map +0 -1
- package/dist/lib/components/CodyWebPanelProvider.d.ts +0 -31
- package/dist/lib/components/CodyWebPanelProvider.d.ts.map +0 -1
- package/dist/lib/utils/use-local-storage.d.ts +0 -14
- package/dist/lib/utils/use-local-storage.d.ts.map +0 -1
- package/dist/shell-DFgpuMKe.js +0 -47
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type FunctionComponent } from 'react';
|
|
2
|
+
import type { InitialContext } from '../types';
|
|
3
|
+
import '../global-styles/styles.css';
|
|
4
|
+
export interface CodyWebChatProps {
|
|
5
|
+
serverEndpoint: string;
|
|
6
|
+
accessToken: string | null;
|
|
7
|
+
createAgentWorker: () => Worker;
|
|
8
|
+
telemetryClientName?: string;
|
|
9
|
+
initialContext?: InitialContext;
|
|
10
|
+
customHeaders?: Record<string, string>;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The root component node for Cody Web Chat, implements Cody Agent client
|
|
15
|
+
* and connects VSCode Cody Chat UI with web-worker agent. The main component
|
|
16
|
+
* to use in Cody Web Consumers.
|
|
17
|
+
*
|
|
18
|
+
* You can see the demo usage of this component in demo/App.tsx
|
|
19
|
+
*/
|
|
20
|
+
export declare const CodyWebChat: FunctionComponent<CodyWebChatProps>;
|
|
21
|
+
//# sourceMappingURL=CodyWebChat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodyWebChat.d.ts","sourceRoot":"","sources":["../../../lib/components/CodyWebChat.tsx"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,iBAAiB,EAAmD,MAAM,OAAO,CAAA;AAgCxG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAK9C,OAAO,6BAA6B,CAAA;AAWpC,MAAM,WAAW,gBAAgB;IAC7B,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,iBAAiB,EAAE,MAAM,MAAM,CAAA;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AACD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,iBAAiB,CAAC,gBAAgB,CAqC3D,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
interface ChatSkeletonProps {
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Skeleton UI for Cody Web Chat UI (loading mock UI state), currently is used only
|
|
7
|
+
* for Cody Web UI since it takes noticeable time to load and initialize.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ChatSkeleton: FC<ChatSkeletonProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=ChatSkeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatSkeleton.d.ts","sourceRoot":"","sources":["../../../../lib/components/skeleton/ChatSkeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAK/B,UAAU,iBAAiB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CA4C9C,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type VSCodeWrapper } from 'cody-ai/webviews/utils/VSCodeApi';
|
|
2
|
+
import type { MessageConnection } from 'vscode-jsonrpc/browser';
|
|
3
|
+
import type { InitialContext } from '../types';
|
|
4
|
+
export interface AgentClient {
|
|
5
|
+
rpc: MessageConnection;
|
|
6
|
+
dispose(): void;
|
|
7
|
+
}
|
|
8
|
+
interface UseCodyWebAgentInput {
|
|
9
|
+
serverEndpoint: string;
|
|
10
|
+
accessToken: string | null;
|
|
11
|
+
createAgentWorker: () => Worker;
|
|
12
|
+
telemetryClientName?: string;
|
|
13
|
+
initialContext?: InitialContext;
|
|
14
|
+
customHeaders?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
interface UseCodyWebAgentResult {
|
|
17
|
+
client: AgentClient | Error | null;
|
|
18
|
+
vscodeAPI: VSCodeWrapper | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates Cody Web Agent instance and automatically creates a new chat.
|
|
22
|
+
* Uses cody web-worker agent under the hood with json rpc as a connection between
|
|
23
|
+
* main and web-worker threads, see agent.client.ts for more details
|
|
24
|
+
*/
|
|
25
|
+
export declare function useCodyWebAgent(input: UseCodyWebAgentInput): UseCodyWebAgentResult;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=use-cody-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-cody-agent.d.ts","sourceRoot":"","sources":["../../../lib/components/use-cody-agent.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAoB,MAAM,kCAAkC,CAAA;AAUvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAG/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAa9C,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,iBAAiB,CAAA;IACtB,OAAO,IAAI,IAAI,CAAA;CAClB;AAED,UAAU,oBAAoB;IAC1B,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,iBAAiB,EAAE,MAAM,MAAM,CAAA;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzC;AAED,UAAU,qBAAqB;IAC3B,MAAM,EAAE,WAAW,GAAG,KAAK,GAAG,IAAI,CAAA;IAClC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAA;CAClC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CA0DlF"}
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { CodyWebChat, type CodyWebChatProps } from './components/CodyWebChat';
|
|
2
|
+
export { ChatSkeleton } from './components/skeleton/ChatSkeleton';
|
|
3
3
|
export type { Repository, InitialContext } from './types';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAEjE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -3,11 +3,12 @@ export interface Repository {
|
|
|
3
3
|
name: string;
|
|
4
4
|
}
|
|
5
5
|
export type InitialContext = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
repository: Repository;
|
|
7
|
+
isDirectory: boolean;
|
|
8
|
+
fileURL: string | null;
|
|
9
|
+
fileRange: {
|
|
9
10
|
startLine: number;
|
|
10
11
|
endLine: number;
|
|
11
|
-
};
|
|
12
|
+
} | null;
|
|
12
13
|
};
|
|
13
14
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,cAAc,GAAG;IACzB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,cAAc,GAAG;IACzB,UAAU,EAAE,UAAU,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC3D,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { u as util, e as exec, o as os, a as env, w as window, p as path, b as workspace, U as Uri, l as logError } from "./agent.worker-Cjx_iNtn.mjs";
|
|
2
|
+
import { w as wrapInActiveSpan, T as TokenCounterUtils, C as ContextItemSource } from "./browser-BpZhCiRU.mjs";
|
|
3
|
+
var define_process_default = { env: {} };
|
|
4
|
+
const _exec = util.promisify(exec);
|
|
5
|
+
async function getContextFileFromShell(command) {
|
|
6
|
+
return wrapInActiveSpan("commands.context.command", async (span) => {
|
|
7
|
+
var _a, _b, _c;
|
|
8
|
+
const rootDir = os.homedir() || define_process_default.env.HOME || define_process_default.env.USERPROFILE || "";
|
|
9
|
+
if (!env.shell) {
|
|
10
|
+
void window.showErrorMessage("Shell command is not supported your current workspace.");
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
const filteredCommand = command.replaceAll(/(\s~\/)/g, ` ${rootDir}${path.sep}`);
|
|
14
|
+
const cwd = (_c = (_b = (_a = workspace.workspaceFolders) == null ? void 0 : _a[0]) == null ? void 0 : _b.uri) == null ? void 0 : _c.fsPath;
|
|
15
|
+
try {
|
|
16
|
+
const { stdout, stderr } = await _exec(filteredCommand, { cwd, encoding: "utf8" });
|
|
17
|
+
const output = JSON.stringify(stdout ?? stderr).trim();
|
|
18
|
+
if (!output) {
|
|
19
|
+
throw new Error("Empty output");
|
|
20
|
+
}
|
|
21
|
+
const content = outputWrapper.replace("{command}", command).replace("{output}", output);
|
|
22
|
+
const size = await TokenCounterUtils.countTokens(content);
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
type: "file",
|
|
26
|
+
content,
|
|
27
|
+
title: "Terminal Output",
|
|
28
|
+
uri: Uri.file(command),
|
|
29
|
+
source: ContextItemSource.Terminal,
|
|
30
|
+
size
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logError("getContextFileFromShell", "failed", { verbose: error });
|
|
35
|
+
void window.showErrorMessage(error.message);
|
|
36
|
+
throw new Error("Failed to get shell output for Custom Command.");
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const outputWrapper = `
|
|
41
|
+
Terminal output from the \`{command}\` command enclosed between <OUTPUT0412> tags:
|
|
42
|
+
<OUTPUT0412>
|
|
43
|
+
{output}
|
|
44
|
+
</OUTPUT0412>`;
|
|
45
|
+
export {
|
|
46
|
+
getContextFileFromShell
|
|
47
|
+
};
|
package/dist/style.css
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
.
|
|
1
|
+
._editor_9ox0p_1 {
|
|
2
2
|
position: relative;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
/* ContentEditable */
|
|
6
|
-
._content-
|
|
6
|
+
._content-editable_9ox0p_6 {
|
|
7
7
|
border: 0;
|
|
8
8
|
display: block;
|
|
9
9
|
position: relative;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/* Placeholder */
|
|
14
|
-
.
|
|
14
|
+
._placeholder_9ox0p_14 {
|
|
15
15
|
opacity: 0.6;
|
|
16
16
|
overflow: hidden;
|
|
17
17
|
position: absolute;
|
|
@@ -26,9 +26,13 @@
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/* Theme */
|
|
29
|
-
._theme-
|
|
29
|
+
._theme-paragraph_9ox0p_29 {
|
|
30
30
|
margin: 0;
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
html[data-ide='JetBrains'] ._theme-paragraph_9ox0p_29 {
|
|
34
|
+
padding: 0.5rem;
|
|
35
|
+
}
|
|
32
36
|
:root {
|
|
33
37
|
--description-font-size: 0.9em; /* match VS Code quickpick description */
|
|
34
38
|
}
|
|
@@ -3366,6 +3370,9 @@ imported in Sourcegraph shell.
|
|
|
3366
3370
|
.hover\:tw-underline:hover {
|
|
3367
3371
|
text-decoration-line: underline;
|
|
3368
3372
|
}
|
|
3373
|
+
.hover\:tw-no-underline:hover {
|
|
3374
|
+
text-decoration-line: none;
|
|
3375
|
+
}
|
|
3369
3376
|
.hover\:tw-opacity-100:hover {
|
|
3370
3377
|
opacity: 1;
|
|
3371
3378
|
}
|
|
@@ -3583,10 +3590,133 @@ body[data-vscode-theme-kind="vscode-high-contrast"] .high-contrast-dark\:tw-bord
|
|
|
3583
3590
|
.\[\&_kbd\]\:tw-mt-\[-4px\] kbd {
|
|
3584
3591
|
margin-top: -4px;
|
|
3585
3592
|
}
|
|
3586
|
-
|
|
3587
|
-
|
|
3593
|
+
|
|
3594
|
+
._root_1dr1n_2 {
|
|
3588
3595
|
display: flex;
|
|
3589
|
-
|
|
3590
|
-
|
|
3596
|
+
height: 100vh;
|
|
3597
|
+
width: 100%;
|
|
3598
|
+
font-size: 13px;
|
|
3599
|
+
overflow: hidden;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
._container_1dr1n_10 {
|
|
3603
|
+
height: 100%;
|
|
3604
|
+
flex-grow: 1;
|
|
3605
|
+
}
|
|
3606
|
+
:root {
|
|
3607
|
+
--cody-web-skeleton-main-color: #3e475e;
|
|
3608
|
+
--cody-web-skeleton-blink-color: #4d5875;
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
._root_1yqw7_6 {
|
|
3612
|
+
width: 100%;
|
|
3591
3613
|
height: 100%;
|
|
3614
|
+
display: flex;
|
|
3615
|
+
flex-direction: column;
|
|
3616
|
+
gap: 1rem;
|
|
3617
|
+
padding: 0.5rem 0.75rem;
|
|
3618
|
+
}
|
|
3619
|
+
|
|
3620
|
+
._header_1yqw7_15 {
|
|
3621
|
+
display: flex;
|
|
3622
|
+
gap: 0.5rem;
|
|
3623
|
+
padding: 0.25rem;
|
|
3624
|
+
align-items: center;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
._chat_1yqw7_22 {
|
|
3628
|
+
display: flex;
|
|
3629
|
+
flex-direction: column;
|
|
3630
|
+
gap: 0.25rem;
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
._chat-input_1yqw7_1 {
|
|
3634
|
+
width: 100%;
|
|
3635
|
+
border-radius: 3px;
|
|
3636
|
+
border: 2px solid var(--vscode-widget-border);
|
|
3637
|
+
padding: 0.5rem;
|
|
3638
|
+
display: flex;
|
|
3639
|
+
flex-direction: column;
|
|
3640
|
+
gap: 0.5rem;
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3643
|
+
._chat-mentions-row_1yqw7_1 {
|
|
3644
|
+
display: flex;
|
|
3645
|
+
gap: 0.25rem;
|
|
3646
|
+
align-items: center;
|
|
3647
|
+
}
|
|
3648
|
+
|
|
3649
|
+
._chat-submit-button_1yqw7_1 {
|
|
3650
|
+
margin-left: auto;
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3653
|
+
._message_1yqw7_48 {
|
|
3654
|
+
display: flex;
|
|
3655
|
+
flex-direction: column;
|
|
3656
|
+
gap: 0.25rem;
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
._message-content_1yqw7_1 {
|
|
3660
|
+
margin-top: 0.5rem;
|
|
3661
|
+
display: flex;
|
|
3662
|
+
gap: 0.5rem;
|
|
3663
|
+
flex-wrap: wrap;
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
._line_1yqw7_61 {
|
|
3667
|
+
width: 100%;
|
|
3668
|
+
max-width: 7rem;
|
|
3669
|
+
height: 0.75rem;
|
|
3670
|
+
flex-grow: 0;
|
|
3671
|
+
flex-shrink: 0;
|
|
3672
|
+
border-radius: 3px;
|
|
3673
|
+
background-size: 200% 100%;
|
|
3674
|
+
animation: _shine-lines_1yqw7_1 1s infinite linear;
|
|
3675
|
+
|
|
3676
|
+
background-image: linear-gradient(
|
|
3677
|
+
100deg,
|
|
3678
|
+
var(--cody-web-skeleton-main-color) 0,
|
|
3679
|
+
var(--cody-web-skeleton-blink-color) 40px,
|
|
3680
|
+
var(--cody-web-skeleton-main-color) 80px
|
|
3681
|
+
);
|
|
3682
|
+
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
._line-circle_1yqw7_1 {
|
|
3686
|
+
width: 1.5rem;
|
|
3687
|
+
height: 1.5rem;
|
|
3688
|
+
border-radius: 50%;
|
|
3689
|
+
flex-grow: 0;
|
|
3690
|
+
flex-shrink: 0;
|
|
3691
|
+
}
|
|
3692
|
+
|
|
3693
|
+
._line-circle-small_1yqw7_1 {
|
|
3694
|
+
width: 1rem;
|
|
3695
|
+
height: 1rem;
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3698
|
+
._line-small_1yqw7_1 {
|
|
3699
|
+
max-width: 5rem;
|
|
3700
|
+
height: 0.5rem;
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
._line-short-text_1yqw7_1 {
|
|
3704
|
+
|
|
3705
|
+
max-width: 3rem;
|
|
3706
|
+
}
|
|
3707
|
+
|
|
3708
|
+
._line-text_1yqw7_1 {
|
|
3709
|
+
|
|
3710
|
+
max-width: 8rem;
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
._line-long-text_1yqw7_1 {
|
|
3714
|
+
|
|
3715
|
+
max-width: 20rem;
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3718
|
+
@keyframes _shine-lines_1yqw7_1 {
|
|
3719
|
+
100% {
|
|
3720
|
+
background-position-x: -200%;
|
|
3721
|
+
}
|
|
3592
3722
|
}
|