codex-partner 0.0.1__py3-none-any.whl

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.
Files changed (244) hide show
  1. app.py +5530 -0
  2. codex_partner/__init__.py +4 -0
  3. codex_partner/__main__.py +6 -0
  4. codex_partner/app_server.py +150 -0
  5. codex_partner/cli.py +35 -0
  6. codex_partner/commands.py +77 -0
  7. codex_partner/database.py +206 -0
  8. codex_partner/discovery.py +136 -0
  9. codex_partner/schemas.py +133 -0
  10. codex_partner-0.0.1.dist-info/METADATA +101 -0
  11. codex_partner-0.0.1.dist-info/RECORD +244 -0
  12. codex_partner-0.0.1.dist-info/WHEEL +5 -0
  13. codex_partner-0.0.1.dist-info/entry_points.txt +2 -0
  14. codex_partner-0.0.1.dist-info/top_level.txt +3 -0
  15. static/__init__.py +1 -0
  16. static/app.js +505 -0
  17. static/chat-worker.js +157 -0
  18. static/conversation.js +894 -0
  19. static/core.js +880 -0
  20. static/editor.js +142 -0
  21. static/index.html +71 -0
  22. static/mascot-dance.css +100 -0
  23. static/mascot-dance.js +46 -0
  24. static/settings.js +335 -0
  25. static/styles.css +690 -0
  26. static/vendor/ace/LICENSE +24 -0
  27. static/vendor/ace/ace.js +23 -0
  28. static/vendor/ace/ext-modelist.js +8 -0
  29. static/vendor/ace/mode-abap.js +8 -0
  30. static/vendor/ace/mode-abc.js +8 -0
  31. static/vendor/ace/mode-actionscript.js +8 -0
  32. static/vendor/ace/mode-ada.js +8 -0
  33. static/vendor/ace/mode-alda.js +8 -0
  34. static/vendor/ace/mode-apache_conf.js +8 -0
  35. static/vendor/ace/mode-apex.js +8 -0
  36. static/vendor/ace/mode-applescript.js +8 -0
  37. static/vendor/ace/mode-aql.js +8 -0
  38. static/vendor/ace/mode-asciidoc.js +8 -0
  39. static/vendor/ace/mode-asl.js +8 -0
  40. static/vendor/ace/mode-assembly_arm32.js +8 -0
  41. static/vendor/ace/mode-assembly_x86.js +8 -0
  42. static/vendor/ace/mode-astro.js +8 -0
  43. static/vendor/ace/mode-autohotkey.js +8 -0
  44. static/vendor/ace/mode-basic.js +8 -0
  45. static/vendor/ace/mode-batchfile.js +8 -0
  46. static/vendor/ace/mode-bibtex.js +8 -0
  47. static/vendor/ace/mode-c9search.js +8 -0
  48. static/vendor/ace/mode-c_cpp.js +8 -0
  49. static/vendor/ace/mode-cedar.js +8 -0
  50. static/vendor/ace/mode-cedarschema.js +8 -0
  51. static/vendor/ace/mode-cirru.js +8 -0
  52. static/vendor/ace/mode-clojure.js +8 -0
  53. static/vendor/ace/mode-clue.js +8 -0
  54. static/vendor/ace/mode-cobol.js +8 -0
  55. static/vendor/ace/mode-coffee.js +8 -0
  56. static/vendor/ace/mode-coldfusion.js +8 -0
  57. static/vendor/ace/mode-crystal.js +8 -0
  58. static/vendor/ace/mode-csharp.js +8 -0
  59. static/vendor/ace/mode-csound_document.js +8 -0
  60. static/vendor/ace/mode-csound_orchestra.js +8 -0
  61. static/vendor/ace/mode-csound_score.js +8 -0
  62. static/vendor/ace/mode-csp.js +8 -0
  63. static/vendor/ace/mode-css.js +8 -0
  64. static/vendor/ace/mode-csv.js +8 -0
  65. static/vendor/ace/mode-curly.js +8 -0
  66. static/vendor/ace/mode-cuttlefish.js +8 -0
  67. static/vendor/ace/mode-d.js +8 -0
  68. static/vendor/ace/mode-dart.js +8 -0
  69. static/vendor/ace/mode-diff.js +8 -0
  70. static/vendor/ace/mode-django.js +8 -0
  71. static/vendor/ace/mode-dockerfile.js +8 -0
  72. static/vendor/ace/mode-dot.js +8 -0
  73. static/vendor/ace/mode-drools.js +8 -0
  74. static/vendor/ace/mode-edifact.js +8 -0
  75. static/vendor/ace/mode-eiffel.js +8 -0
  76. static/vendor/ace/mode-ejs.js +8 -0
  77. static/vendor/ace/mode-elixir.js +8 -0
  78. static/vendor/ace/mode-elm.js +8 -0
  79. static/vendor/ace/mode-erlang.js +8 -0
  80. static/vendor/ace/mode-flix.js +8 -0
  81. static/vendor/ace/mode-forth.js +8 -0
  82. static/vendor/ace/mode-fortran.js +8 -0
  83. static/vendor/ace/mode-fsharp.js +8 -0
  84. static/vendor/ace/mode-fsl.js +8 -0
  85. static/vendor/ace/mode-ftl.js +8 -0
  86. static/vendor/ace/mode-gcode.js +8 -0
  87. static/vendor/ace/mode-gherkin.js +8 -0
  88. static/vendor/ace/mode-gitignore.js +8 -0
  89. static/vendor/ace/mode-glsl.js +8 -0
  90. static/vendor/ace/mode-gobstones.js +8 -0
  91. static/vendor/ace/mode-golang.js +8 -0
  92. static/vendor/ace/mode-graphqlschema.js +8 -0
  93. static/vendor/ace/mode-groovy.js +8 -0
  94. static/vendor/ace/mode-groq.js +8 -0
  95. static/vendor/ace/mode-haml.js +8 -0
  96. static/vendor/ace/mode-handlebars.js +8 -0
  97. static/vendor/ace/mode-haskell.js +8 -0
  98. static/vendor/ace/mode-haskell_cabal.js +8 -0
  99. static/vendor/ace/mode-haxe.js +8 -0
  100. static/vendor/ace/mode-hjson.js +8 -0
  101. static/vendor/ace/mode-html.js +8 -0
  102. static/vendor/ace/mode-html_elixir.js +8 -0
  103. static/vendor/ace/mode-html_ruby.js +8 -0
  104. static/vendor/ace/mode-ini.js +8 -0
  105. static/vendor/ace/mode-io.js +8 -0
  106. static/vendor/ace/mode-ion.js +8 -0
  107. static/vendor/ace/mode-jack.js +8 -0
  108. static/vendor/ace/mode-jade.js +8 -0
  109. static/vendor/ace/mode-java.js +8 -0
  110. static/vendor/ace/mode-javascript.js +8 -0
  111. static/vendor/ace/mode-jexl.js +8 -0
  112. static/vendor/ace/mode-json.js +8 -0
  113. static/vendor/ace/mode-json5.js +8 -0
  114. static/vendor/ace/mode-jsoniq.js +8 -0
  115. static/vendor/ace/mode-jsp.js +8 -0
  116. static/vendor/ace/mode-jssm.js +8 -0
  117. static/vendor/ace/mode-jsx.js +8 -0
  118. static/vendor/ace/mode-julia.js +8 -0
  119. static/vendor/ace/mode-kotlin.js +8 -0
  120. static/vendor/ace/mode-latex.js +8 -0
  121. static/vendor/ace/mode-latte.js +8 -0
  122. static/vendor/ace/mode-less.js +8 -0
  123. static/vendor/ace/mode-liquid.js +8 -0
  124. static/vendor/ace/mode-lisp.js +8 -0
  125. static/vendor/ace/mode-livescript.js +8 -0
  126. static/vendor/ace/mode-logiql.js +8 -0
  127. static/vendor/ace/mode-logtalk.js +8 -0
  128. static/vendor/ace/mode-lsl.js +8 -0
  129. static/vendor/ace/mode-lua.js +8 -0
  130. static/vendor/ace/mode-luapage.js +8 -0
  131. static/vendor/ace/mode-lucene.js +8 -0
  132. static/vendor/ace/mode-makefile.js +8 -0
  133. static/vendor/ace/mode-mariadb.js +8 -0
  134. static/vendor/ace/mode-markdown.js +8 -0
  135. static/vendor/ace/mode-mask.js +8 -0
  136. static/vendor/ace/mode-matlab.js +8 -0
  137. static/vendor/ace/mode-maze.js +8 -0
  138. static/vendor/ace/mode-mediawiki.js +8 -0
  139. static/vendor/ace/mode-mel.js +8 -0
  140. static/vendor/ace/mode-mips.js +8 -0
  141. static/vendor/ace/mode-mixal.js +8 -0
  142. static/vendor/ace/mode-mushcode.js +8 -0
  143. static/vendor/ace/mode-mysql.js +8 -0
  144. static/vendor/ace/mode-nasal.js +8 -0
  145. static/vendor/ace/mode-nginx.js +8 -0
  146. static/vendor/ace/mode-nim.js +8 -0
  147. static/vendor/ace/mode-nix.js +8 -0
  148. static/vendor/ace/mode-nsis.js +8 -0
  149. static/vendor/ace/mode-nunjucks.js +8 -0
  150. static/vendor/ace/mode-objectivec.js +8 -0
  151. static/vendor/ace/mode-ocaml.js +8 -0
  152. static/vendor/ace/mode-odin.js +8 -0
  153. static/vendor/ace/mode-partiql.js +8 -0
  154. static/vendor/ace/mode-pascal.js +8 -0
  155. static/vendor/ace/mode-perl.js +8 -0
  156. static/vendor/ace/mode-pgsql.js +8 -0
  157. static/vendor/ace/mode-php.js +8 -0
  158. static/vendor/ace/mode-php_laravel_blade.js +8 -0
  159. static/vendor/ace/mode-pig.js +8 -0
  160. static/vendor/ace/mode-plain_text.js +8 -0
  161. static/vendor/ace/mode-plsql.js +8 -0
  162. static/vendor/ace/mode-powershell.js +8 -0
  163. static/vendor/ace/mode-praat.js +8 -0
  164. static/vendor/ace/mode-prisma.js +8 -0
  165. static/vendor/ace/mode-prolog.js +8 -0
  166. static/vendor/ace/mode-properties.js +8 -0
  167. static/vendor/ace/mode-protobuf.js +8 -0
  168. static/vendor/ace/mode-prql.js +8 -0
  169. static/vendor/ace/mode-puppet.js +8 -0
  170. static/vendor/ace/mode-python.js +8 -0
  171. static/vendor/ace/mode-qml.js +8 -0
  172. static/vendor/ace/mode-r.js +8 -0
  173. static/vendor/ace/mode-raku.js +8 -0
  174. static/vendor/ace/mode-razor.js +8 -0
  175. static/vendor/ace/mode-rdoc.js +8 -0
  176. static/vendor/ace/mode-red.js +8 -0
  177. static/vendor/ace/mode-redshift.js +8 -0
  178. static/vendor/ace/mode-rhtml.js +8 -0
  179. static/vendor/ace/mode-robot.js +8 -0
  180. static/vendor/ace/mode-rst.js +8 -0
  181. static/vendor/ace/mode-ruby.js +8 -0
  182. static/vendor/ace/mode-rust.js +8 -0
  183. static/vendor/ace/mode-sac.js +8 -0
  184. static/vendor/ace/mode-sass.js +8 -0
  185. static/vendor/ace/mode-scad.js +8 -0
  186. static/vendor/ace/mode-scala.js +8 -0
  187. static/vendor/ace/mode-scheme.js +8 -0
  188. static/vendor/ace/mode-scrypt.js +8 -0
  189. static/vendor/ace/mode-scss.js +8 -0
  190. static/vendor/ace/mode-sh.js +8 -0
  191. static/vendor/ace/mode-sjs.js +8 -0
  192. static/vendor/ace/mode-slim.js +8 -0
  193. static/vendor/ace/mode-smarty.js +8 -0
  194. static/vendor/ace/mode-smithy.js +8 -0
  195. static/vendor/ace/mode-snippets.js +8 -0
  196. static/vendor/ace/mode-soy_template.js +8 -0
  197. static/vendor/ace/mode-space.js +8 -0
  198. static/vendor/ace/mode-sparql.js +8 -0
  199. static/vendor/ace/mode-sql.js +8 -0
  200. static/vendor/ace/mode-sqlserver.js +8 -0
  201. static/vendor/ace/mode-stylus.js +8 -0
  202. static/vendor/ace/mode-svg.js +8 -0
  203. static/vendor/ace/mode-swift.js +8 -0
  204. static/vendor/ace/mode-tcl.js +8 -0
  205. static/vendor/ace/mode-terraform.js +8 -0
  206. static/vendor/ace/mode-tex.js +8 -0
  207. static/vendor/ace/mode-text.js +8 -0
  208. static/vendor/ace/mode-textile.js +8 -0
  209. static/vendor/ace/mode-toml.js +8 -0
  210. static/vendor/ace/mode-tsv.js +8 -0
  211. static/vendor/ace/mode-tsx.js +8 -0
  212. static/vendor/ace/mode-turtle.js +8 -0
  213. static/vendor/ace/mode-twig.js +8 -0
  214. static/vendor/ace/mode-typescript.js +8 -0
  215. static/vendor/ace/mode-vala.js +8 -0
  216. static/vendor/ace/mode-vbscript.js +8 -0
  217. static/vendor/ace/mode-velocity.js +8 -0
  218. static/vendor/ace/mode-verilog.js +8 -0
  219. static/vendor/ace/mode-vhdl.js +8 -0
  220. static/vendor/ace/mode-visualforce.js +8 -0
  221. static/vendor/ace/mode-vue.js +8 -0
  222. static/vendor/ace/mode-wollok.js +8 -0
  223. static/vendor/ace/mode-xml.js +8 -0
  224. static/vendor/ace/mode-xquery.js +8 -0
  225. static/vendor/ace/mode-yaml.js +8 -0
  226. static/vendor/ace/mode-zeek.js +8 -0
  227. static/vendor/ace/mode-zig.js +8 -0
  228. static/vendor/ace/theme-tomorrow_night_eighties.js +8 -0
  229. static/vendor/i18next/LICENSE +21 -0
  230. static/vendor/i18next/i18next.min.js +1 -0
  231. static/vendor/toastui-editor/LICENSE +21 -0
  232. static/vendor/toastui-editor/toastui-editor-dark.css +474 -0
  233. static/vendor/toastui-editor/toastui-editor.css +1597 -0
  234. static/vendor/toastui-editor/toastui-editor.js +24 -0
  235. static/vendor/toastui-editor/zh-cn.js +7 -0
  236. static/vendor/xterm/LICENSE +21 -0
  237. static/vendor/xterm/addons/fit.LICENSE +19 -0
  238. static/vendor/xterm/addons/fit.js +2 -0
  239. static/vendor/xterm/addons/unicode11.LICENSE +19 -0
  240. static/vendor/xterm/addons/unicode11.js +2 -0
  241. static/vendor/xterm/addons/web-links.LICENSE +19 -0
  242. static/vendor/xterm/addons/web-links.js +2 -0
  243. static/vendor/xterm/xterm.css +285 -0
  244. static/vendor/xterm/xterm.js +2 -0
static/chat-worker.js ADDED
@@ -0,0 +1,157 @@
1
+ /* Chat history normalization stays off the UI thread; output is sanitized HTML. */
2
+ const escapeHtml = (value = "") => String(value).replace(/[&<>"']/g, char => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[char]);
3
+
4
+ function valueOf(raw) {
5
+ if (typeof raw !== "string") return raw;
6
+ try { return JSON.parse(raw); } catch (_) { return raw; }
7
+ }
8
+
9
+ function timestamp(event) {
10
+ const raw = event?.ts ?? event?.created_at;
11
+ const numeric = Number(raw);
12
+ if (Number.isFinite(numeric)) return numeric < 1e12 ? numeric * 1000 : numeric;
13
+ const parsed = Date.parse(String(raw || ""));
14
+ return Number.isFinite(parsed) ? parsed : 0;
15
+ }
16
+
17
+ function eventText(raw, labels) {
18
+ const payload = valueOf(raw);
19
+ if (typeof payload === "string") return payload;
20
+ if (!payload || typeof payload !== "object") return String(payload ?? "");
21
+ if (["userMessage", "browserMessage"].includes(payload.type)) return payload.text || (payload.content || []).map(item => item.text || "").join("\n");
22
+ if (payload.type === "agentMessage") return payload.text || "";
23
+ if (payload.type === "agentMessageStarted") return "";
24
+ if (payload.type === "agent_delta") return payload.delta || "";
25
+ if (payload.type === "reasoning") return payload.text || payload.summary || "";
26
+ if (payload.type === "fileChange") return payload.text || labels.fileChanged;
27
+ if (payload.type === "contextCompaction") return labels.contextCompressed;
28
+ if (payload.type === "externalTurnStarted") return labels.terminalTurnStarted;
29
+ if (payload.type === "turn_completed") return labels.terminalTurnCompleted;
30
+ if (payload.type === "turn_aborted") return labels.terminalTurnAborted;
31
+ if (["slashCommand", "commandResult"].includes(payload.type)) return payload.text || "";
32
+ if (payload.type === "codex") return payload.method ? `Codex · ${payload.method}` : labels.codexActivity;
33
+ return payload.delta || payload.text || JSON.stringify(payload);
34
+ }
35
+
36
+ function isUser(event) {
37
+ const payload = valueOf(event.payload);
38
+ return ["userMessage", "browserMessage", "slashCommand"].includes(payload?.type) || event.stream === "user";
39
+ }
40
+
41
+ function isAssistant(event) {
42
+ const payload = valueOf(event.payload);
43
+ return ["agentMessage", "agent_delta", "commandResult"].includes(payload?.type) || event.stream === "assistant";
44
+ }
45
+
46
+ function mergeEvents(events, messages) {
47
+ const visible = (messages || []).filter(message => ["running", "steering", "steered", "sent"].includes(message.status));
48
+ const deliveryCounts = new Map();
49
+ for (const message of visible) {
50
+ const body = String(message.body || "").trim();
51
+ if (body) deliveryCounts.set(body, (deliveryCounts.get(body) || 0) + 1);
52
+ }
53
+ const merged = [];
54
+ for (const event of events || []) {
55
+ const payload = valueOf(event.payload);
56
+ if (payload?.type === "userMessage") {
57
+ const body = eventText(payload, {}).trim();
58
+ if (deliveryCounts.has(body)) {
59
+ const remaining = deliveryCounts.get(body) || 0;
60
+ if (remaining <= 0) continue;
61
+ deliveryCounts.set(body, remaining - 1);
62
+ }
63
+ }
64
+ merged.push(event);
65
+ }
66
+ const nativeCounts = new Map();
67
+ // Native thread history often omits client_message_id, so body order is the
68
+ // stable fallback for suppressing a duplicated durable browser message.
69
+ for (const event of merged) {
70
+ const payload = valueOf(event.payload);
71
+ if (payload?.type !== "userMessage") continue;
72
+ const body = eventText(payload, {}).trim();
73
+ if (body) nativeCounts.set(body, (nativeCounts.get(body) || 0) + 1);
74
+ }
75
+ for (const message of visible) {
76
+ const body = String(message.body || "").trim();
77
+ if (body && (nativeCounts.get(body) || 0) > 0) {
78
+ nativeCounts.set(body, nativeCounts.get(body) - 1);
79
+ continue;
80
+ }
81
+ merged.push({
82
+ id: `browser-${message.id}`,
83
+ session_id: message.session_id || `browser-${message.id}`,
84
+ ts: message.created_at || new Date().toISOString(),
85
+ stream: "user",
86
+ payload: { type: "browserMessage", text: message.body || "", status: message.status, error: message.error || "", client_message_id: message.id },
87
+ });
88
+ }
89
+ return merged.map((event, index) => ({ event, index })).sort((a, b) => timestamp(a.event) - timestamp(b.event) || a.index - b.index).map(item => item.event);
90
+ }
91
+
92
+ function markdown(text) {
93
+ const files = [];
94
+ const clean = String(text || "")
95
+ .replace(/\[\[codex-file:([^\]]+)\]\]/g, (_, path) => { files.push(decodeURIComponent(path)); return ""; })
96
+ .replace(/(?:Uploaded to workspace|已上传到工作区)\s*[::]\s*([^\n\r,。]+?\.[a-z0-9]{1,12})(?=\s|[,。]|$)/gi, (_, path) => { files.push(path.trim()); return ""; })
97
+ .replace(/\[(?:Attachments?|附件)\s*[::]\s*[^\]]+\]/gi, "")
98
+ .trim();
99
+ const body = escapeHtml(clean)
100
+ .replace(/```(?:[a-zA-Z0-9_+-]+)?\n?([\s\S]*?)```/g, '<pre class="code-block">$1</pre>')
101
+ .replace(/`([^`\n]+)`/g, '<code class="inline-code">$1</code>')
102
+ .replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
103
+ .replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noreferrer">$1</a>')
104
+ .replace(/^###\s+(.+)$/gm, "<h4>$1</h4>")
105
+ .replace(/^[-*]\s+(.+)$/gm, '<span class="markdown-bullet">$1</span>')
106
+ .replace(/\n/g, "<br>");
107
+ return body + [...new Set(files)].map(path => {
108
+ const safePath = escapeHtml(path);
109
+ if (/\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(path)) return `<div class="chat-file-attachment chat-image-attachment" data-chat-file="${safePath}"><span class="chat-file-preview" hidden></span></div>`;
110
+ const name = escapeHtml(path.split("/").pop() || path);
111
+ return `<div class="chat-file-attachment" data-chat-file="${safePath}"><span class="chat-file-icon">▤</span><span class="chat-file-copy"><strong>${name}</strong><small>${safePath}</small></span><span class="chat-file-preview" hidden></span></div>`;
112
+ }).join("");
113
+ }
114
+
115
+ function buildBlocks(events, rawActivity, labels) {
116
+ const blocks = []; const assistantItems = new Map(); const userItems = new Map(); let current = null;
117
+ for (const event of events) {
118
+ if (["metrics", "history"].includes(event.stream)) continue;
119
+ const text = eventText(event.payload, labels).trim();
120
+ if (!text) continue;
121
+ const role = isUser(event) ? "user" : isAssistant(event) ? "assistant" : "activity";
122
+ const payload = valueOf(event.payload);
123
+ if (role === "activity") {
124
+ if (!rawActivity && ["app-server", "stdout", "stderr"].includes(event.stream)) continue;
125
+ let group = blocks[blocks.length - 1];
126
+ if (!group || group.role !== "activities") { group = { role: "activities", items: [] }; blocks.push(group); }
127
+ group.items.push(text); current = null; continue;
128
+ }
129
+ const commandBlock = ["slashCommand", "commandResult"].includes(payload?.type);
130
+ const itemId = payload?.item_id || "";
131
+ const itemMap = role === "assistant" ? assistantItems : userItems;
132
+ if (itemId && itemMap.has(itemId)) {
133
+ current = itemMap.get(itemId);
134
+ if (payload.type === "agentMessage") { current.text = text; current.streaming = false; }
135
+ else if (payload.type === "agent_delta") { current.text += text; current.streaming = true; }
136
+ else current.text = text;
137
+ continue;
138
+ }
139
+ if (!current || current.role !== role || role === "user" || commandBlock || current.commandBlock) {
140
+ current = { role, text: "", session: event.session_id, commandBlock, itemId, delivery: payload?.type === "browserMessage" ? payload.status : "", error: payload?.error || "", streaming: payload?.type === "agent_delta", origin: event.stream === "rollout" ? "terminal" : "web", time: event.ts || event.created_at || "" };
141
+ blocks.push(current); if (itemId) itemMap.set(itemId, current);
142
+ }
143
+ current.text += `${current.text ? "\n" : ""}${text}`;
144
+ }
145
+ for (const block of blocks) if (block.role !== "activities") block.html = markdown(block.text);
146
+ return blocks;
147
+ }
148
+
149
+ self.onmessage = event => {
150
+ const { requestId, events, messages, rawActivity, labels } = event.data;
151
+ try {
152
+ const merged = mergeEvents(events, messages);
153
+ self.postMessage({ requestId, blocks: buildBlocks(merged, rawActivity, labels || {}) });
154
+ } catch (error) {
155
+ self.postMessage({ requestId, error: String(error?.message || error) });
156
+ }
157
+ };