compressed-context 0.1.0 → 0.1.1
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/package.json +64 -64
- package/src/compression/active-summary-cache.ts +50 -50
- package/src/compression/adopt.ts +57 -57
- package/src/compression/auto.ts +372 -372
- package/src/compression/babel.ts +85 -85
- package/src/compression/block.ts +25 -25
- package/src/compression/cache-history.ts +75 -75
- package/src/compression/compaction.ts +189 -189
- package/src/compression/decompress-tool.ts +74 -74
- package/src/compression/decompress.ts +292 -292
- package/src/compression/deleted-sessions.ts +24 -24
- package/src/compression/distill.ts +220 -220
- package/src/compression/events.ts +275 -275
- package/src/compression/markdown.ts +53 -53
- package/src/compression/normalize.ts +114 -114
- package/src/compression/render.ts +70 -70
- package/src/compression/schema.ts +84 -84
- package/src/compression/select.ts +123 -123
- package/src/compression/session-message.ts +112 -112
- package/src/compression/settings-rpc.ts +111 -111
- package/src/compression/settings.ts +175 -175
- package/src/compression/state.ts +248 -248
- package/src/compression/summarize.ts +595 -595
- package/src/compression/summary.ts +73 -73
- package/src/compression/tool.ts +142 -142
- package/src/compression/transcript-store.ts +258 -258
- package/src/compression/transcript.ts +63 -63
- package/src/compression/validate.ts +81 -81
- package/src/i18n/en.ts +93 -93
- package/src/i18n/index.ts +28 -28
- package/src/i18n/types.ts +89 -89
- package/src/i18n/zh.ts +93 -93
- package/src/index.ts +108 -108
- package/src/shared/blocks.ts +17 -17
- package/src/shared/cache.ts +199 -199
- package/src/shared/format.ts +23 -23
- package/src/shared/media.ts +184 -184
- package/src/shared/parse.ts +25 -25
- package/src/shared/parts.ts +72 -72
- package/src/shared/rpc.ts +145 -145
- package/src/shared/scan.ts +32 -32
- package/src/shared/settings.ts +471 -471
- package/src/shared/stats.ts +142 -142
- package/src/shared/tokens.ts +259 -259
- package/src/tui/chart/cache-chart.ts +237 -237
- package/src/tui/chart/color.ts +58 -58
- package/src/tui/index.tsx +111 -111
- package/src/tui/panel/cache.tsx +203 -203
- package/src/tui/panel/data.ts +105 -105
- package/src/tui/panel/index.tsx +176 -176
- package/src/tui/panel/summaries.tsx +192 -192
- package/src/tui/settings/dialogs.tsx +215 -215
- package/src/tui/settings/options.ts +238 -238
- package/src/tui/settings.tsx +418 -418
- package/src/tui/types.ts +4 -4
|
@@ -1,192 +1,192 @@
|
|
|
1
|
-
import type { Context } from "@opencode/plugin/tui/context"
|
|
2
|
-
import { SyntaxStyle, type RGBA } from "@opentui/core"
|
|
3
|
-
import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js"
|
|
4
|
-
|
|
5
|
-
import type { Messages } from "../../i18n/index.ts"
|
|
6
|
-
import type { SummaryBlock } from "../../shared/blocks.ts"
|
|
7
|
-
import { formatTimestamp, formatTokens } from "../../shared/format.ts"
|
|
8
|
-
import type { Settings } from "../../shared/settings.ts"
|
|
9
|
-
import type { UpdateSettings } from "../types.ts"
|
|
10
|
-
|
|
11
|
-
/** 输入:摘要等级;输出:对应主题色;T1 蓝、T2 黄、T3 红。 */
|
|
12
|
-
function tierColor(tier: SummaryBlock["tier"], theme: Context["theme"]): RGBA {
|
|
13
|
-
if (tier === 1) return theme.text.feedback.info.base
|
|
14
|
-
if (tier === 2) return theme.text.feedback.warning.base
|
|
15
|
-
return theme.text.feedback.error.base
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** 输入:无;输出:共享的 SyntaxStyle;预期:markdown 渲染器需要它,懒加载避免重复创建。 */
|
|
19
|
-
let sharedSyntaxStyle: SyntaxStyle | undefined
|
|
20
|
-
function getSyntaxStyle(): SyntaxStyle {
|
|
21
|
-
sharedSyntaxStyle ??= SyntaxStyle.create()
|
|
22
|
-
return sharedSyntaxStyle
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 输入:TUI 上下文 + 主题 + 块。
|
|
27
|
-
* 输出:占满可用高度的阅读弹窗。
|
|
28
|
-
* 预期:标题保持 `[T1] b1 : title`;Babel 按纯文本显示,其余交给 markdown 渲染器,esc 关闭。
|
|
29
|
-
*/
|
|
30
|
-
export function SummaryDialog(props: {
|
|
31
|
-
readonly context: Context
|
|
32
|
-
readonly theme: Context["theme"]
|
|
33
|
-
readonly block: SummaryBlock
|
|
34
|
-
}) {
|
|
35
|
-
const height = createMemo(() => Math.max(8, Math.min(30, props.context.renderer.height - 8)))
|
|
36
|
-
return (
|
|
37
|
-
<box paddingLeft={3} paddingRight={3} paddingBottom={1} gap={1}>
|
|
38
|
-
<box flexDirection="row" justifyContent="space-between" gap={1}>
|
|
39
|
-
<text fg={props.theme.text.base} wrapMode="word">
|
|
40
|
-
<b>{`[T${props.block.tier.toString()}] ${props.block.id} : ${props.block.title}`}</b>
|
|
41
|
-
</text>
|
|
42
|
-
<text
|
|
43
|
-
fg={props.theme.text.muted}
|
|
44
|
-
onMouseUp={() => {
|
|
45
|
-
props.context.ui.dialog.clear()
|
|
46
|
-
}}
|
|
47
|
-
>
|
|
48
|
-
esc
|
|
49
|
-
</text>
|
|
50
|
-
</box>
|
|
51
|
-
<scrollbox height={height()} scrollY={true} focused={true} width="100%">
|
|
52
|
-
<Show
|
|
53
|
-
when={props.block.format === "babel"}
|
|
54
|
-
fallback={
|
|
55
|
-
<markdown
|
|
56
|
-
content={props.block.body}
|
|
57
|
-
syntaxStyle={getSyntaxStyle()}
|
|
58
|
-
fg={props.theme.text.base}
|
|
59
|
-
conceal={true}
|
|
60
|
-
tableOptions={{ widthMode: "full", style: "columns" }}
|
|
61
|
-
/>
|
|
62
|
-
}
|
|
63
|
-
>
|
|
64
|
-
<text fg={props.theme.text.base} wrapMode="word">
|
|
65
|
-
{props.block.body}
|
|
66
|
-
</text>
|
|
67
|
-
</Show>
|
|
68
|
-
</scrollbox>
|
|
69
|
-
</box>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* 输入:主题 + 文案 + 设置 + 写入函数 + 摘要块。
|
|
75
|
-
* 输出:可折叠的摘要块列表;点击标题打开 markdown 阅读弹窗。
|
|
76
|
-
* 预期:只展示服务端返回的 active 链;hover 只让箭头动,标题和背景保持稳定。
|
|
77
|
-
*/
|
|
78
|
-
export function SummarySection(props: {
|
|
79
|
-
readonly context: Context
|
|
80
|
-
readonly theme: Context["theme"]
|
|
81
|
-
readonly copy: Messages
|
|
82
|
-
readonly settings: Settings
|
|
83
|
-
readonly updateSettings: UpdateSettings
|
|
84
|
-
readonly blocks: readonly SummaryBlock[]
|
|
85
|
-
}) {
|
|
86
|
-
const [hovered, setHovered] = createSignal<string | undefined>(undefined)
|
|
87
|
-
const [frame, setFrame] = createSignal(0)
|
|
88
|
-
|
|
89
|
-
// 只有 hover 时跑两帧;鼠标移出或销毁时清理,避免后台定时器。
|
|
90
|
-
createEffect(() => {
|
|
91
|
-
if (hovered() === undefined) {
|
|
92
|
-
setFrame(0)
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
|
-
const timer = setInterval(() => setFrame((value) => (value + 1) % 2), 180)
|
|
96
|
-
onCleanup(() => {
|
|
97
|
-
clearInterval(timer)
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
/** 输入:无;输出:无;预期:翻转摘要区折叠状态。 */
|
|
102
|
-
const toggleFold = (): void => {
|
|
103
|
-
void props.updateSettings((draft) => {
|
|
104
|
-
draft.summariesExpanded = !draft.summariesExpanded
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** 输入:块;输出:无;预期:打开该块的 markdown 阅读弹窗。 */
|
|
109
|
-
const openSummary = (block: SummaryBlock): void => {
|
|
110
|
-
props.context.ui.dialog.show(() => (
|
|
111
|
-
<SummaryDialog context={props.context} theme={props.theme} block={block} />
|
|
112
|
-
))
|
|
113
|
-
props.context.ui.dialog.set({ size: "large", centered: true })
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<Show when={props.settings.showSummaries}>
|
|
118
|
-
<box width="100%" flexDirection="column">
|
|
119
|
-
<box flexDirection="row" height={1} onMouseDown={toggleFold}>
|
|
120
|
-
<box flexDirection="row" gap={1}>
|
|
121
|
-
<text fg={props.theme.text.base}>{props.settings.summariesExpanded ? "▼" : "▶"}</text>
|
|
122
|
-
<text fg={props.theme.text.base}>
|
|
123
|
-
<b>{props.copy.summariesTitle}</b>
|
|
124
|
-
</text>
|
|
125
|
-
<text fg={props.theme.text.muted}>{`(${props.blocks.length.toString()})`}</text>
|
|
126
|
-
</box>
|
|
127
|
-
</box>
|
|
128
|
-
<Show when={props.settings.summariesExpanded}>
|
|
129
|
-
<Show
|
|
130
|
-
when={props.blocks.length > 0}
|
|
131
|
-
fallback={<text fg={props.theme.text.muted}>{props.copy.noData}</text>}
|
|
132
|
-
>
|
|
133
|
-
<box paddingLeft={2} flexDirection="column" width="100%">
|
|
134
|
-
<For each={props.blocks}>
|
|
135
|
-
{(block) => {
|
|
136
|
-
const meta = (): string => {
|
|
137
|
-
const parts: string[] = []
|
|
138
|
-
if (props.settings.showTimeline) parts.push(formatTimestamp(block.at))
|
|
139
|
-
if (block.sourceBlockIds !== undefined && block.sourceBlockIds.length > 0) {
|
|
140
|
-
parts.push(`merged ${block.sourceBlockIds.map((id) => `#${id}`).join(" + ")}`)
|
|
141
|
-
}
|
|
142
|
-
return parts.join(" ")
|
|
143
|
-
}
|
|
144
|
-
return (
|
|
145
|
-
<box flexDirection="column" width="100%">
|
|
146
|
-
<box
|
|
147
|
-
flexDirection="row"
|
|
148
|
-
gap={1}
|
|
149
|
-
onMouseOver={() => {
|
|
150
|
-
setHovered(block.id)
|
|
151
|
-
}}
|
|
152
|
-
onMouseOut={() => {
|
|
153
|
-
setHovered((current) => (current === block.id ? undefined : current))
|
|
154
|
-
}}
|
|
155
|
-
onMouseUp={() => {
|
|
156
|
-
openSummary(block)
|
|
157
|
-
}}
|
|
158
|
-
>
|
|
159
|
-
<text width={2} fg={tierColor(block.tier, props.theme)}>
|
|
160
|
-
{hovered() === block.id ? (frame() === 0 ? "▸ " : " ▸") : " "}
|
|
161
|
-
</text>
|
|
162
|
-
<text fg={props.theme.text.base} wrapMode="word" flexGrow={1}>
|
|
163
|
-
<span style={{ fg: tierColor(block.tier, props.theme) }}>
|
|
164
|
-
<b>{`[T${block.tier.toString()}]`}</b>
|
|
165
|
-
</span>
|
|
166
|
-
<span style={{ fg: props.theme.text.muted }}>
|
|
167
|
-
{` ${block.id} : `}
|
|
168
|
-
</span>
|
|
169
|
-
<span style={{ fg: props.theme.text.base }}>{block.title}</span>
|
|
170
|
-
<Show when={props.settings.showBlockTokens}>
|
|
171
|
-
<span style={{ fg: props.theme.text.muted }}>
|
|
172
|
-
{` ≈${formatTokens(block.tokensAfter)}`}
|
|
173
|
-
</span>
|
|
174
|
-
</Show>
|
|
175
|
-
</text>
|
|
176
|
-
</box>
|
|
177
|
-
<Show when={meta() !== ""}>
|
|
178
|
-
<text fg={props.theme.text.muted} wrapMode="word">
|
|
179
|
-
{` ${meta()}`}
|
|
180
|
-
</text>
|
|
181
|
-
</Show>
|
|
182
|
-
</box>
|
|
183
|
-
)
|
|
184
|
-
}}
|
|
185
|
-
</For>
|
|
186
|
-
</box>
|
|
187
|
-
</Show>
|
|
188
|
-
</Show>
|
|
189
|
-
</box>
|
|
190
|
-
</Show>
|
|
191
|
-
)
|
|
192
|
-
}
|
|
1
|
+
import type { Context } from "@opencode/plugin/tui/context"
|
|
2
|
+
import { SyntaxStyle, type RGBA } from "@opentui/core"
|
|
3
|
+
import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js"
|
|
4
|
+
|
|
5
|
+
import type { Messages } from "../../i18n/index.ts"
|
|
6
|
+
import type { SummaryBlock } from "../../shared/blocks.ts"
|
|
7
|
+
import { formatTimestamp, formatTokens } from "../../shared/format.ts"
|
|
8
|
+
import type { Settings } from "../../shared/settings.ts"
|
|
9
|
+
import type { UpdateSettings } from "../types.ts"
|
|
10
|
+
|
|
11
|
+
/** 输入:摘要等级;输出:对应主题色;T1 蓝、T2 黄、T3 红。 */
|
|
12
|
+
function tierColor(tier: SummaryBlock["tier"], theme: Context["theme"]): RGBA {
|
|
13
|
+
if (tier === 1) return theme.text.feedback.info.base
|
|
14
|
+
if (tier === 2) return theme.text.feedback.warning.base
|
|
15
|
+
return theme.text.feedback.error.base
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 输入:无;输出:共享的 SyntaxStyle;预期:markdown 渲染器需要它,懒加载避免重复创建。 */
|
|
19
|
+
let sharedSyntaxStyle: SyntaxStyle | undefined
|
|
20
|
+
function getSyntaxStyle(): SyntaxStyle {
|
|
21
|
+
sharedSyntaxStyle ??= SyntaxStyle.create()
|
|
22
|
+
return sharedSyntaxStyle
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 输入:TUI 上下文 + 主题 + 块。
|
|
27
|
+
* 输出:占满可用高度的阅读弹窗。
|
|
28
|
+
* 预期:标题保持 `[T1] b1 : title`;Babel 按纯文本显示,其余交给 markdown 渲染器,esc 关闭。
|
|
29
|
+
*/
|
|
30
|
+
export function SummaryDialog(props: {
|
|
31
|
+
readonly context: Context
|
|
32
|
+
readonly theme: Context["theme"]
|
|
33
|
+
readonly block: SummaryBlock
|
|
34
|
+
}) {
|
|
35
|
+
const height = createMemo(() => Math.max(8, Math.min(30, props.context.renderer.height - 8)))
|
|
36
|
+
return (
|
|
37
|
+
<box paddingLeft={3} paddingRight={3} paddingBottom={1} gap={1}>
|
|
38
|
+
<box flexDirection="row" justifyContent="space-between" gap={1}>
|
|
39
|
+
<text fg={props.theme.text.base} wrapMode="word">
|
|
40
|
+
<b>{`[T${props.block.tier.toString()}] ${props.block.id} : ${props.block.title}`}</b>
|
|
41
|
+
</text>
|
|
42
|
+
<text
|
|
43
|
+
fg={props.theme.text.muted}
|
|
44
|
+
onMouseUp={() => {
|
|
45
|
+
props.context.ui.dialog.clear()
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
esc
|
|
49
|
+
</text>
|
|
50
|
+
</box>
|
|
51
|
+
<scrollbox height={height()} scrollY={true} focused={true} width="100%">
|
|
52
|
+
<Show
|
|
53
|
+
when={props.block.format === "babel"}
|
|
54
|
+
fallback={
|
|
55
|
+
<markdown
|
|
56
|
+
content={props.block.body}
|
|
57
|
+
syntaxStyle={getSyntaxStyle()}
|
|
58
|
+
fg={props.theme.text.base}
|
|
59
|
+
conceal={true}
|
|
60
|
+
tableOptions={{ widthMode: "full", style: "columns" }}
|
|
61
|
+
/>
|
|
62
|
+
}
|
|
63
|
+
>
|
|
64
|
+
<text fg={props.theme.text.base} wrapMode="word">
|
|
65
|
+
{props.block.body}
|
|
66
|
+
</text>
|
|
67
|
+
</Show>
|
|
68
|
+
</scrollbox>
|
|
69
|
+
</box>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 输入:主题 + 文案 + 设置 + 写入函数 + 摘要块。
|
|
75
|
+
* 输出:可折叠的摘要块列表;点击标题打开 markdown 阅读弹窗。
|
|
76
|
+
* 预期:只展示服务端返回的 active 链;hover 只让箭头动,标题和背景保持稳定。
|
|
77
|
+
*/
|
|
78
|
+
export function SummarySection(props: {
|
|
79
|
+
readonly context: Context
|
|
80
|
+
readonly theme: Context["theme"]
|
|
81
|
+
readonly copy: Messages
|
|
82
|
+
readonly settings: Settings
|
|
83
|
+
readonly updateSettings: UpdateSettings
|
|
84
|
+
readonly blocks: readonly SummaryBlock[]
|
|
85
|
+
}) {
|
|
86
|
+
const [hovered, setHovered] = createSignal<string | undefined>(undefined)
|
|
87
|
+
const [frame, setFrame] = createSignal(0)
|
|
88
|
+
|
|
89
|
+
// 只有 hover 时跑两帧;鼠标移出或销毁时清理,避免后台定时器。
|
|
90
|
+
createEffect(() => {
|
|
91
|
+
if (hovered() === undefined) {
|
|
92
|
+
setFrame(0)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
const timer = setInterval(() => setFrame((value) => (value + 1) % 2), 180)
|
|
96
|
+
onCleanup(() => {
|
|
97
|
+
clearInterval(timer)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
/** 输入:无;输出:无;预期:翻转摘要区折叠状态。 */
|
|
102
|
+
const toggleFold = (): void => {
|
|
103
|
+
void props.updateSettings((draft) => {
|
|
104
|
+
draft.summariesExpanded = !draft.summariesExpanded
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** 输入:块;输出:无;预期:打开该块的 markdown 阅读弹窗。 */
|
|
109
|
+
const openSummary = (block: SummaryBlock): void => {
|
|
110
|
+
props.context.ui.dialog.show(() => (
|
|
111
|
+
<SummaryDialog context={props.context} theme={props.theme} block={block} />
|
|
112
|
+
))
|
|
113
|
+
props.context.ui.dialog.set({ size: "large", centered: true })
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<Show when={props.settings.showSummaries}>
|
|
118
|
+
<box width="100%" flexDirection="column">
|
|
119
|
+
<box flexDirection="row" height={1} onMouseDown={toggleFold}>
|
|
120
|
+
<box flexDirection="row" gap={1}>
|
|
121
|
+
<text fg={props.theme.text.base}>{props.settings.summariesExpanded ? "▼" : "▶"}</text>
|
|
122
|
+
<text fg={props.theme.text.base}>
|
|
123
|
+
<b>{props.copy.summariesTitle}</b>
|
|
124
|
+
</text>
|
|
125
|
+
<text fg={props.theme.text.muted}>{`(${props.blocks.length.toString()})`}</text>
|
|
126
|
+
</box>
|
|
127
|
+
</box>
|
|
128
|
+
<Show when={props.settings.summariesExpanded}>
|
|
129
|
+
<Show
|
|
130
|
+
when={props.blocks.length > 0}
|
|
131
|
+
fallback={<text fg={props.theme.text.muted}>{props.copy.noData}</text>}
|
|
132
|
+
>
|
|
133
|
+
<box paddingLeft={2} flexDirection="column" width="100%">
|
|
134
|
+
<For each={props.blocks}>
|
|
135
|
+
{(block) => {
|
|
136
|
+
const meta = (): string => {
|
|
137
|
+
const parts: string[] = []
|
|
138
|
+
if (props.settings.showTimeline) parts.push(formatTimestamp(block.at))
|
|
139
|
+
if (block.sourceBlockIds !== undefined && block.sourceBlockIds.length > 0) {
|
|
140
|
+
parts.push(`merged ${block.sourceBlockIds.map((id) => `#${id}`).join(" + ")}`)
|
|
141
|
+
}
|
|
142
|
+
return parts.join(" ")
|
|
143
|
+
}
|
|
144
|
+
return (
|
|
145
|
+
<box flexDirection="column" width="100%">
|
|
146
|
+
<box
|
|
147
|
+
flexDirection="row"
|
|
148
|
+
gap={1}
|
|
149
|
+
onMouseOver={() => {
|
|
150
|
+
setHovered(block.id)
|
|
151
|
+
}}
|
|
152
|
+
onMouseOut={() => {
|
|
153
|
+
setHovered((current) => (current === block.id ? undefined : current))
|
|
154
|
+
}}
|
|
155
|
+
onMouseUp={() => {
|
|
156
|
+
openSummary(block)
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
<text width={2} fg={tierColor(block.tier, props.theme)}>
|
|
160
|
+
{hovered() === block.id ? (frame() === 0 ? "▸ " : " ▸") : " "}
|
|
161
|
+
</text>
|
|
162
|
+
<text fg={props.theme.text.base} wrapMode="word" flexGrow={1}>
|
|
163
|
+
<span style={{ fg: tierColor(block.tier, props.theme) }}>
|
|
164
|
+
<b>{`[T${block.tier.toString()}]`}</b>
|
|
165
|
+
</span>
|
|
166
|
+
<span style={{ fg: props.theme.text.muted }}>
|
|
167
|
+
{` ${block.id} : `}
|
|
168
|
+
</span>
|
|
169
|
+
<span style={{ fg: props.theme.text.base }}>{block.title}</span>
|
|
170
|
+
<Show when={props.settings.showBlockTokens}>
|
|
171
|
+
<span style={{ fg: props.theme.text.muted }}>
|
|
172
|
+
{` ≈${formatTokens(block.tokensAfter)}`}
|
|
173
|
+
</span>
|
|
174
|
+
</Show>
|
|
175
|
+
</text>
|
|
176
|
+
</box>
|
|
177
|
+
<Show when={meta() !== ""}>
|
|
178
|
+
<text fg={props.theme.text.muted} wrapMode="word">
|
|
179
|
+
{` ${meta()}`}
|
|
180
|
+
</text>
|
|
181
|
+
</Show>
|
|
182
|
+
</box>
|
|
183
|
+
)
|
|
184
|
+
}}
|
|
185
|
+
</For>
|
|
186
|
+
</box>
|
|
187
|
+
</Show>
|
|
188
|
+
</Show>
|
|
189
|
+
</box>
|
|
190
|
+
</Show>
|
|
191
|
+
)
|
|
192
|
+
}
|