PageSourceSearch

https://natik.tech/src/pages/Chat.tsx?t=1787849505805

js natik.tech collected 2026-09-24 15:12:42 UTC 25,409 bytes, 353 lines download raw bytes

1import { createHotContext as __vite__createHotContext } from "/@vite/client";import.meta.hot = __vite__createHotContext("/src/pages/Chat.tsx");const useEffect = __vite__cjsImport0_react["useEffect"]; const useState = __vite__cjsImport0_react["useState"]; const useRef = __vite__cjsImport0_react["useRef"];const _jsxDEV = __vite__cjsImport10_react_jsxDevRuntime["jsxDEV"];import __vite__cjsImport0_react from "/node_modules/.vite/deps/react.js?v=b98736ab";
2import { useParams } from "/node_modules/.vite/deps/react-router-dom.js?v=b98736ab";
3import { Send, ArrowLeft } from "/node_modules/.vite/deps/lucide-react.js?v=b98736ab";
4import { format } from "/node_modules/.vite/deps/date-fns.js?v=b98736ab";
5import { Link } from "/node_modules/.vite/deps/react-router-dom.js?v=b98736ab";
6import { chatApi } from "/src/api/client.ts?t=1787849488420";
7import { useAuth } from "/src/context/AuthContext.tsx?t=1787849494723";
8import { useSocket } from "/src/context/SocketContext.tsx?t=1787849497982";
9import Navbar from "/src/components/Navbar.tsx?t=1787849501551";
10import LoadingSpinner from "/src/components/LoadingSpinner.tsx?t=1787849490510";
11var _jsxFileName = "/var/www/english/frontend/src/pages/Chat.tsx";
12import __vite__cjsImport10_react_jsxDevRuntime from "/node_modules/.vite/deps/react_jsx-dev-runtime.js?v=b98736ab";
13var _s = $RefreshSig$();
14const Chat = () => {
15	_s();
16	const { roomId } = useParams();
17	const { user } = useAuth();
18	const { socket } = useSocket();
19	const [messages, setMessages] = useState([]);
20	const [input, setInput] = useState("");
21	const [loading, setLoading] = useState(true);
22	const [typing, setTyping] = useState(null);
23	const messagesEndRef = useRef(null);
24	const typingTimer = useRef(null);
25	useEffect(() => {
26		if (!roomId) return;
27		chatApi.getRoom(roomId).then((r) => {
28			setMessages(r.data.messages);
29			setLoading(false);
30		});
31		chatApi.markRead(roomId);
32	}, [roomId]);
33	useEffect(() => {
34		if (!socket || !roomId) return;
35		socket.emit("chat:join", roomId);
36		const onMessage = (msg) => setMessages((prev) => [...prev, msg]);
37		const onTyping = (data) => {
38			setTyping(data.isTyping ? data.name : null);
39		};
40		socket.on("chat:message", onMessage);
41		socket.on("chat:typing", onTyping);
42		return () => {
43			socket.off("chat:message", onMessage);
44			socket.off("chat:typing", onTyping);
45		};
46	}, [socket, roomId]);
47	useEffect(() => {
48		messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
49	}, [messages]);
50	const sendMessage = () => {
51		if (!input.trim() || !socket || !roomId) return;
52		socket.emit("chat:message", {
53			roomId,
54			content: input.trim()
55		});
56		setInput("");
57	};
58	const handleInputChange = (v) => {
59		setInput(v);
60		if (!socket || !roomId) return;
61		socket.emit("chat:typing", {
62			roomId,
63			isTyping: v.length > 0
64		});
65		if (typingTimer.current) clearTimeout(typingTimer.current);
66		typingTimer.current = setTimeout(() => socket.emit("chat:typing", {
67			roomId,
68			isTyping: false
69		}), 2e3);
70	};
71	if (loading) return /* @__PURE__ */ _jsxDEV("div", {
72		className: "min-h-screen bg-primary-50 flex items-center justify-center",
73		children: /* @__PURE__ */ _jsxDEV(LoadingSpinner, { size: "lg" }, void 0, false, {
74			fileName: _jsxFileName,
75			lineNumber: 65,
76			columnNumber: 7
77		}, this)
78	}, void 0, false, {
79		fileName: _jsxFileName,
80		lineNumber: 64,
81		columnNumber: 5
82	}, this);
83	return /* @__PURE__ */ _jsxDEV("div", {
84		className: "min-h-screen bg-primary-50 flex flex-col",
85		children: [/* @__PURE__ */ _jsxDEV(Navbar, {}, void 0, false, {
86			fileName: _jsxFileName,
87			lineNumber: 71,
88			columnNumber: 7
89		}, this), /* @__PURE__ */ _jsxDEV("div", {
90			className: "flex-1 max-w-3xl w-full mx-auto flex flex-col p-4",
91			children: [
92				/* @__PURE__ */ _jsxDEV("div", {
93					className: "card mb-4 flex items-center gap-3 py-3",
94					children: [
95						/* @__PURE__ */ _jsxDEV(Link, {
96							to: user?.role === "teacher" ? "/teacher/students" : "/student",
97							className: "p-2 hover:bg-primary-50 rounded-xl transition-colors",
98							children: /* @__PURE__ */ _jsxDEV(ArrowLeft, { className: "w-5 h-5 text-ink-500" }, void 0, false, {
99								fileName: _jsxFileName,
100								lineNumber: 75,
101								columnNumber: 13
102							}, this)
103						}, void 0, false, {
104							fileName: _jsxFileName,
105							lineNumber: 74,
106							columnNumber: 11
107						}, this),
108						/* @__PURE__ */ _jsxDEV("div", {
109							className: "w-9 h-9 bg-primary-500 rounded-full flex items-center justify-center text-white font-bold",
110							children: "💬"
111						}, void 0, false, {
112							fileName: _jsxFileName,
113							lineNumber: 77,
114							columnNumber: 11
115						}, this),
116						/* @__PURE__ */ _jsxDEV("div", { children: [/* @__PURE__ */ _jsxDEV("p", {
117							className: "font-bold text-ink-800",
118							children: "Chat Room"
119						}, void 0, false, {
120							fileName: _jsxFileName,
121							lineNumber: 81,
122							columnNumber: 13
123						}, this), /* @__PURE__ */ _jsxDEV("p", {
124							className: "text-xs text-ink-400",
125							children: roomId
126						}, void 0, false, {
127							fileName: _jsxFileName,
128							lineNumber: 82,
129							columnNumber: 13
130						}, this)] }, void 0, true, {
131							fileName: _jsxFileName,
132							lineNumber: 80,
133							columnNumber: 11
134						}, this)
135					]
136				}, void 0, true, {
137					fileName: _jsxFileName,
138					lineNumber: 73,
139					columnNumber: 9
140				}, this),
141				/* @__PURE__ */ _jsxDEV("div", {
142					className: "flex-1 card overflow-y-auto flex flex-col gap-3",
143					style: {
144						minHeight: "60vh",
145						maxHeight: "60vh"
146					},
147					children: [
148						messages.length === 0 && /* @__PURE__ */ _jsxDEV("div", {
149							className: "text-center text-ink-400 my-auto py-8",
150							children: "No messages yet. Say hello! 👋"
151						}, void 0, false, {
152							fileName: _jsxFileName,
153							lineNumber: 88,
154							columnNumber: 13
155						}, this),
156						messages.map((m) => {
157							const isMine = m.sender?._id === user?.id || m.sender?.id === user?.id;
158							return /* @__PURE__ */ _jsxDEV("div", {
159								className: `flex gap-2 ${isMine ? "flex-row-reverse" : "flex-row"}`,
160								children: [!isMine && /* @__PURE__ */ _jsxDEV("div", {
161									className: "w-8 h-8 bg-primary-100 rounded-full flex items-center justify-center text-primary-600 font-bold text-sm flex-shrink-0 mt-auto",
162									children: m.sender?.name?.[0]
163								}, void 0, false, {
164									fileName: _jsxFileName,
165									lineNumber: 95,
166									columnNumber: 19
167								}, this), /* @__PURE__ */ _jsxDEV("div", {
168									className: `max-w-xs lg:max-w-md ${isMine ? "items-end" : "items-start"} flex flex-col gap-1`,
169									children: [
170										!isMine && /* @__PURE__ */ _jsxDEV("p", {
171											className: "text-xs text-ink-400 px-1",
172											children: m.sender?.name
173										}, void 0, false, {
174											fileName: _jsxFileName,
175											lineNumber: 100,
176											columnNumber: 31
177										}, this),
178										/* @__PURE__ */ _jsxDEV("div", {
179											className: isMine ? "chat-bubble-sent" : "chat-bubble-received",
180											children: /* @__PURE__ */ _jsxDEV("p", {
181												className: "text-sm leading-relaxed",
182												children: m.content
183											}, void 0, false, {
184												fileName: _jsxFileName,
185												lineNumber: 102,
186												columnNumber: 21
187											}, this)
188										}, void 0, false, {
189											fileName: _jsxFileName,
190											lineNumber: 101,
191											columnNumber: 19
192										}, this),
193										/* @__PURE__ */ _jsxDEV("p", {
194											className: "text-xs text-ink-400 px-1",
195											children: format(new Date(m.createdAt), "HH:mm")
196										}, void 0, false, {
197											fileName: _jsxFileName,
198											lineNumber: 104,
199											columnNumber: 19
200										}, this)
201									]
202								}, void 0, true, {
203									fileName: _jsxFileName,
204									lineNumber: 99,
205									columnNumber: 17
206								}, this)]
207							}, m._id, true, {
208								fileName: _jsxFileName,
209								lineNumber: 93,
210								columnNumber: 15
211							}, this);
212						}),
213						typing && /* @__PURE__ */ _jsxDEV("div", {
214							className: "flex gap-2",
215							children: [/* @__PURE__ */ _jsxDEV("div", {
216								className: "w-8 h-8 bg-primary-100 rounded-full flex items-center justify-center text-primary-600 font-bold text-sm flex-shrink-0",
217								children: "?"
218							}, void 0, false, {
219								fileName: _jsxFileName,
220								lineNumber: 111,
221								columnNumber: 15
222							}, this), /* @__PURE__ */ _jsxDEV("div", {
223								className: "chat-bubble-received flex items-center gap-1",
224								children: [/* @__PURE__ */ _jsxDEV("span", {
225									className: "text-sm text-ink-500",
226									children: [typing, " is typing"]
227								}, void 0, true, {
228									fileName: _jsxFileName,
229									lineNumber: 113,
230									columnNumber: 17
231								}, this), /* @__PURE__ */ _jsxDEV("span", {
232									className: "flex gap-0.5",
233									children: [
234										0,
235										1,
236										2
237									].map((i) => /* @__PURE__ */ _jsxDEV("span", {
238										className: "w-1.5 h-1.5 bg-ink-400 rounded-full animate-bounce",
239										style: { animationDelay: `${i * .15}s` }
240									}, i, false, {
241										fileName: _jsxFileName,
242										lineNumber: 115,
243										columnNumber: 39
244									}, this))
245								}, void 0, false, {
246									fileName: _jsxFileName,
247									lineNumber: 114,
248									columnNumber: 17
249								}, this)]
250							}, void 0, true, {
251								fileName: _jsxFileName,
252								lineNumber: 112,
253								columnNumber: 15
254							}, this)]
255						}, void 0, true, {
256							fileName: _jsxFileName,
257							lineNumber: 110,
258							columnNumber: 13
259						}, this),
260						/* @__PURE__ */ _jsxDEV("div", { ref: messagesEndRef }, void 0, false, {
261							fileName: _jsxFileName,
262							lineNumber: 120,
263							columnNumber: 11
264						}, this)
265					]
266				}, void 0, true, {
267					fileName: _jsxFileName,
268					lineNumber: 86,
269					columnNumber: 9
270				}, this),
271				/* @__PURE__ */ _jsxDEV("div", {
272					className: "card mt-4 flex items-center gap-3 py-3",
273					children: [/* @__PURE__ */ _jsxDEV("input", {
274						className: "input flex-1",
275						placeholder: "Type a message...",
276						value: input,
277						onChange: (e) => handleInputChange(e.target.value),
278						onKeyDown: (e) => {
279							if (e.key === "Enter" && !e.shiftKey) {
280								e.preventDefault();
281								sendMessage();
282							}
283						}
284					}, void 0, false, {
285						fileName: _jsxFileName,
286						lineNumber: 124,
287						columnNumber: 11
288					}, this), /* @__PURE__ */ _jsxDEV("button", {
289						onClick: sendMessage,
290						className: "btn-primary p-3 aspect-square",
291						disabled: !input.trim(),
292						children: /* @__PURE__ */ _jsxDEV(Send, { className: "w-5 h-5" }, void 0, false, {
293							fileName: _jsxFileName,
294							lineNumber: 132,
295							columnNumber: 13
296						}, this)
297					}, void 0, false, {
298						fileName: _jsxFileName,
299						lineNumber: 131,
300						columnNumber: 11
301					}, this)]
302				}, void 0, true, {
303					fileName: _jsxFileName,
304					lineNumber: 123,
305					columnNumber: 9
306				}, this)
307			]
308		}, void 0, true, {
309			fileName: _jsxFileName,
310			lineNumber: 72,
311			columnNumber: 7
312		}, this)]
313	}, void 0, true, {
314		fileName: _jsxFileName,
315		lineNumber: 70,
316		columnNumber: 5
317	}, this);
318};
319_s(Chat, "PVsQUFbXsgoxBx6Yx55s2vTD58k=", false, function() {
320	return [
321		useParams,
322		useAuth,
323		useSocket
324	];
325});
326_c = Chat;
327export default Chat;
328var _c;
329$RefreshReg$(_c, "Chat");
330import * as RefreshRuntime from "/@react-refresh";
331const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
332import * as __vite_react_currentExports from "/src/pages/Chat.tsx?t=1787849505805";
333if (import.meta.hot && !inWebWorker) {
334  if (!window.$RefreshReg$) {
335    throw new Error(
336      "@vitejs/plugin-react can't detect preamble. Something is wrong."
337    );
338  }
339
340  const currentExports = __vite_react_currentExports;
341  queueMicrotask(() => {
342    RefreshRuntime.registerExportsForReactRefresh("/var/www/english/frontend/src/pages/Chat.tsx", currentExports);
343    import.meta.hot.accept((nextExports) => {
344      if (!nextExports) return;
345      const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate("/var/www/english/frontend/src/pages/Chat.tsx", currentExports, nextExports);
346      if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
347    });
348  });
349}
350function $RefreshReg$(type, id) { return RefreshRuntime.register(type, "/var/www/english/frontend/src/pages/Chat.tsx" + ' ' + id); }
351function $RefreshSig$() { return RefreshRuntime.createSignatureFunctionForTransform(); }
352
353//# sourceMappingURL=data:application/json;base64,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7VUFBYyxXQUFVO1VBQXFELE9BQU8sRUFBRSxnQkFBZ0IsR0FBRyxJQUFJLElBQUssR0FBRztTQUFJLEdBQTlHOzs7O2dCQUE4RyxDQUFDO1FBQzFJOzs7O2dCQUNIOzs7OztlQUNGOzs7Ozs7TUFFUCx3QkFBQyxPQUFELEVBQUssS0FBSyxlQUFpQjs7Ozs7S0FDeEI7Ozs7OztJQUVMLHdCQUFDLE9BQUQ7S0FBSyxXQUFVO2VBQWYsQ0FDRSx3QkFBQyxTQUFEO01BQ0UsV0FBVTtNQUNWLGFBQVk7TUFDWixPQUFPO01BQ1AsV0FBVyxNQUFNLGtCQUFrQixFQUFFLE9BQU8sS0FBSztNQUNqRCxZQUFZLE1BQU07T0FBRSxJQUFJLEVBQUUsUUFBUSxXQUFXLENBQUMsRUFBRSxVQUFVO1FBQUUsRUFBRSxlQUFlO1FBQUcsWUFBWTtPQUFHO01BQUU7S0FDbEc7Ozs7ZUFDRCx3QkFBQyxVQUFEO01BQVEsU0FBUztNQUFhLFdBQVU7TUFBZ0MsVUFBVSxDQUFDLE1BQU0sS0FBSztnQkFDNUYsd0JBQUMsTUFBRCxFQUFNLFdBQVUsVUFBVzs7Ozs7S0FDckI7Ozs7YUFDTDs7Ozs7O0dBQ0Y7Ozs7O1VBQ0Y7Ozs7OztBQUVUOzs7Ozs7Ozs7QUFFQSxlQUFlIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkNoYXQudHN4Il0sInZlcnNpb24iOjMsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVzZUVmZmVjdCwgdXNlU3RhdGUsIHVzZVJlZiB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IHVzZVBhcmFtcyB9IGZyb20gJ3JlYWN0LXJvdXRlci1kb20nO1xuaW1wb3J0IHsgU2VuZCwgQXJyb3dMZWZ0IH0gZnJvbSAnbHVjaWRlLXJlYWN0JztcbmltcG9ydCB7IGZvcm1hdCB9IGZyb20gJ2RhdGUtZm5zJztcbmltcG9ydCB7IExpbmsgfSBmcm9tICdyZWFjdC1yb3V0ZXItZG9tJztcbmltcG9ydCB7IGNoYXRBcGkgfSBmcm9tICcuLi9hcGkvY2xpZW50JztcbmltcG9ydCB7IE1lc3NhZ2UgfSBmcm9tICcuLi90eXBlcyc7XG5pbXBvcnQgeyB1c2VBdXRoIH0gZnJvbSAnLi4vY29udGV4dC9BdXRoQ29udGV4dCc7XG5pbXBvcnQgeyB1c2VTb2NrZXQgfSBmcm9tICcuLi9jb250ZXh0L1NvY2tldENvbnRleHQnO1xuaW1wb3J0IE5hdmJhciBmcm9tICcuLi9jb21wb25lbnRzL05hdmJhcic7XG5pbXBvcnQgTG9h
353ZGluZ1NwaW5uZXIgZnJvbSAnLi4vY29tcG9uZW50cy9Mb2FkaW5nU3Bpbm5lcic7XG5cbmNvbnN0IENoYXQgPSAoKSA9PiB7XG4gIGNvbnN0IHsgcm9vbUlkIH0gPSB1c2VQYXJhbXM8eyByb29tSWQ6IHN0cmluZyB9PigpO1xuICBjb25zdCB7IHVzZXIgfSA9IHVzZUF1dGgoKTtcbiAgY29uc3QgeyBzb2NrZXQgfSA9IHVzZVNvY2tldCgpO1xuICBjb25zdCBbbWVzc2FnZXMsIHNldE1lc3NhZ2VzXSA9IHVzZVN0YXRlPE1lc3NhZ2VbXT4oW10pO1xuICBjb25zdCBbaW5wdXQsIHNldElucHV0XSA9IHVzZVN0YXRlKCcnKTtcbiAgY29uc3QgW2xvYWRpbmcsIHNldExvYWRpbmddID0gdXNlU3RhdGUodHJ1ZSk7XG4gIGNvbnN0IFt0eXBpbmcsIHNldFR5cGluZ10gPSB1c2VTdGF0ZTxzdHJpbmcgfCBudWxsPihudWxsKTtcbiAgY29uc3QgbWVzc2FnZXNFbmRSZWYgPSB1c2VSZWY8SFRNTERpdkVsZW1lbnQ+KG51bGwpO1xuICBjb25zdCB0eXBpbmdUaW1lciA9IHVzZVJlZjxSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGw+KG51bGwpO1xuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKCFyb29tSWQpIHJldHVybjtcbiAgICBjaGF0QXBpLmdldFJvb20ocm9vbUlkKS50aGVuKChyKSA9PiB7XG4gICAgICBzZXRNZXNzYWdlcyhyLmRhdGEubWVzc2FnZXMpO1xuICAgICAgc2V0TG9hZGluZyhmYWxzZSk7XG4gICAgfSk7XG4gICAgY2hhdEFwaS5tYXJrUmVhZChyb29tSWQpO1xuICB9LCBbcm9vbUlkXSk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBpZiAoIXNvY2tldCB8fCAhcm9vbUlkKSByZXR1cm47XG4gICAgc29ja2V0LmVtaXQoJ2NoYXQ6am9pbicsIHJvb21JZCk7XG5cbiAgICBjb25zdCBvbk1lc3NhZ2UgPSAobXNnOiBNZXNzYWdlKSA9PiBzZXRNZXNzYWdlcygocHJldikgPT4gWy4uLnByZXYsIG1zZ10pO1xuICAgIGNvbnN0IG9uVHlwaW5nID0gKGRhdGE6IHsgbmFtZTogc3RyaW5nOyBpc1R5cGluZzogYm9vbGVhbiB9KSA9PiB7XG4gICAgICBzZXRUeXBpbmcoZGF0YS5pc1R5cGluZyA/IGRhdGEubmFtZSA6IG51bGwpO1xuICAgIH07XG5cbiAgICBzb2NrZXQub24oJ2NoYXQ6bWVzc2FnZScsIG9uTWVzc2FnZSk7XG4gICAgc29ja2V0Lm9uKCdjaGF0OnR5cGluZycsIG9uVHlwaW5nKTtcbiAgICByZXR1cm4gKCkgPT4geyBzb2NrZXQub2ZmKCdjaGF0Om1lc3NhZ2UnLCBvbk1lc3NhZ2UpOyBzb2NrZXQub2ZmKCdjaGF0OnR5cGluZycsIG9uVHlwaW5nKTsgfTtcbiAgfSwgW3NvY2tldCwgcm9vbUlkXSk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHsgbWVzc2FnZXNFbmRSZWYuY3VycmVudD8uc2Nyb2xsSW50b1ZpZXcoeyBiZWhhdmlvcjogJ3Ntb290aCcgfSk7IH0sIFttZXNzYWdlc10pO1xuXG4gIGNvbnN0IHNlbmRNZXNzYWdlID0gKCkgPT4ge1xuICAgIGlmICghaW5wdXQudHJpbSgpIHx8ICFzb2NrZXQgfHwgIXJvb21JZCkgcmV0dXJuO1xuICAgIHNvY2tldC5lbWl0KCdjaGF0Om1lc3NhZ2UnLCB7IHJvb21JZCwgY29udGVudDogaW5wdXQudHJpbSgpIH0pO1xuICAgIHNldElucHV0KCcnKTtcbiAgfTtcblxuICBjb25zdCBoYW5kbGVJbnB1dENoYW5nZSA9ICh2OiBzdHJpbmcpID0+IHtcbiAgICBzZXRJbnB1dCh2KTtcbiAgICBpZiAoIXNvY2tldCB8fCAhcm9vbUlkKSByZXR1cm47XG4gICAgc29ja2V0LmVtaXQoJ2NoYXQ6dHlwaW5nJywgeyByb29tSWQsIGlzVHlwaW5nOiB2Lmxlbmd0aCA+IDAgfSk7XG4gICAgaWYgKHR5cGluZ1RpbWVyLmN1cnJlbnQpIGNsZWFyVGltZW91dCh0eXBpbmdUaW1lci5jdXJyZW50KTtcbiAgICB0eXBpbmdUaW1lci5jdXJyZW50ID0gc2V0VGltZW91dCgoKSA9PiBzb2NrZXQuZW1pdCgnY2hhdDp0eXBpbmcnLCB7IHJvb21JZCwgaXNUeXBpbmc6IGZhbHNlIH0pLCAyMDAwKTtcbiAgfTtcblxuICBpZiAobG9hZGluZykgcmV0dXJuIChcbiAgICA8ZGl2IGNsYXNzTmFtZT1cIm1pbi1oLXNjcmVlbiBiZy1wcmltYXJ5LTUwIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyXCI+XG4gICAgICA8TG9hZGluZ1NwaW5uZXIgc2l6ZT1cImxnXCIgLz5cbiAgICA8L2Rpdj5cbiAgKTtcblxuICByZXR1cm4gKFxuICAgIDxkaXYgY2xhc3NOYW1lPVwibWluLWgtc2NyZWVuIGJnLXByaW1hcnktNTAgZmxleCBmbGV4LWNvbFwiPlxuICAgICAgPE5hdmJhciAvPlxuICAgICAgPGRpdiBjbGFzc05hbWU9XCJmbGV4LTEgbWF4LXctM3hsIHctZnVsbCBteC1hdXRvIGZsZXggZmxleC1jb2wgcC00XCI+XG4gICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiY2FyZCBtYi00IGZsZXggaXRlbXMtY2VudGVyIGdhcC0zIHB5LTNcIj5cbiAgICAgICAgICA8TGluayB0bz17dXNlcj8ucm9sZSA9PT0gJ3RlYWNoZXInID8gJy90ZWFjaGVyL3N0dWRlbnRzJyA6ICcvc3R1ZGVudCd9IGNsYXNzTmFtZT1cInAtMiBob3ZlcjpiZy1wcmltYXJ5LTUwIHJvdW5kZWQteGwgdHJhbnNpdGlvbi1jb2xvcnNcIj5cbiAgICAgICAgICAgIDxBcnJvd0xlZnQgY2xhc3NOYW1lPVwidy01IGgtNSB0ZXh0LWluay01MDBcIiAvPlxuICAgICAgICAgIDwvTGluaz5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cInctOSBoLTkgYmctcHJpbWFyeS01MDAgcm91bmRlZC1mdWxsIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHRleHQtd2hpdGUgZm9udC1ib2xkXCI+XG4gICAgICAgICAgICDwn5KsXG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxwIGNsYXNzTmFtZT1cImZvbnQtYm9sZCB0ZXh0LWluay04MDBcIj5DaGF0IFJvb208L3A+XG4gICAgICAgICAgICA8cCBjbGFzc05hbWU9XCJ0ZXh0LXhzIHRleHQtaW5rLTQwMFwiPntyb29tSWR9PC9wPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImZsZXgtMSBjYXJkIG92ZXJmbG93LXktYXV0byBmbGV4IGZsZXgtY29sIGdhcC0zXCIgc3R5bGU9e3sgbWluSGVpZ2h0OiAnNjB2aCcsIG1heEhlaWdodDogJzYwdmgnIH19PlxuICAgICAgICAgIHttZXNzYWdlcy5sZW5ndGggPT09IDAgJiYgKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJ0ZXh0LWNlbnRlciB0ZXh0LWluay00MDAgbXktYXV0byBweS04XCI+Tm8gbWVzc2FnZXMgeWV0LiBTYXkgaGVsbG8hIPCfkYs8L2Rpdj5cbiAgICAgICAgICApfVxuICAgICAgICAgI
353HttZXNzYWdlcy5tYXAoKG0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGlzTWluZSA9IG0uc2VuZGVyPy5faWQgPT09IHVzZXI/LmlkIHx8IG0uc2VuZGVyPy5pZCA9PT0gdXNlcj8uaWQ7XG4gICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICA8ZGl2IGtleT17bS5faWR9IGNsYXNzTmFtZT17YGZsZXggZ2FwLTIgJHtpc01pbmUgPyAnZmxleC1yb3ctcmV2ZXJzZScgOiAnZmxleC1yb3cnfWB9PlxuICAgICAgICAgICAgICAgIHshaXNNaW5lICYmIChcbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwidy04IGgtOCBiZy1wcmltYXJ5LTEwMCByb3VuZGVkLWZ1bGwgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgdGV4dC1wcmltYXJ5LTYwMCBmb250LWJvbGQgdGV4dC1zbSBmbGV4LXNocmluay0wIG10LWF1dG9cIj5cbiAgICAgICAgICAgICAgICAgICAge20uc2VuZGVyPy5uYW1lPy5bMF19XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICApfVxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPXtgbWF4LXcteHMgbGc6bWF4LXctbWQgJHtpc01pbmUgPyAnaXRlbXMtZW5kJyA6ICdpdGVtcy1zdGFydCd9IGZsZXggZmxleC1jb2wgZ2FwLTFgfT5cbiAgICAgICAgICAgICAgICAgIHshaXNNaW5lICYmIDxwIGNsYXNzTmFtZT1cInRleHQteHMgdGV4dC1pbmstNDAwIHB4LTFcIj57bS5zZW5kZXI/Lm5hbWV9PC9wPn1cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPXtpc01pbmUgPyAnY2hhdC1idWJibGUtc2VudCcgOiAnY2hhdC1idWJibGUtcmVjZWl2ZWQnfT5cbiAgICAgICAgICAgICAgICAgICAgPHAgY2xhc3NOYW1lPVwidGV4dC1zbSBsZWFkaW5nLXJlbGF4ZWRcIj57bS5jb250ZW50fTwvcD5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgPHAgY2xhc3NOYW1lPVwidGV4dC14cyB0ZXh0LWluay00MDAgcHgtMVwiPntmb3JtYXQobmV3IERhdGUobS5jcmVhdGVkQXQpLCAnSEg6bW0nKX08L3A+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KX1cbiAgICAgICAgICB7dHlwaW5nICYmIChcbiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiZmxleCBnYXAtMlwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cInctOCBoLTggYmctcHJpbWFyeS0xMDAgcm91bmRlZC1mdWxsIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHRleHQtcHJpbWFyeS02MDAgZm9udC1ib2xkIHRleHQtc20gZmxleC1zaHJpbmstMFwiPj88L2Rpdj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJjaGF0LWJ1YmJsZS1yZWNlaXZlZCBmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMVwiPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT1cInRleHQtc20gdGV4dC1pbmstNTAwXCI+e3R5cGluZ30gaXMgdHlwaW5nPC9zcGFuPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT1cImZsZXggZ2FwLTAuNVwiPlxuICAgICAgICAgICAgICAgICAge1swLDEsMl0ubWFwKChpKSA9PiA8c3BhbiBrZXk9e2l9IGNsYXNzTmFtZT1cInctMS41IGgtMS41IGJnLWluay00MDAgcm91bmRlZC1mdWxsIGFuaW1hdGUtYm91bmNlXCIgc3R5bGU9e3sgYW5pbWF0aW9uRGVsYXk6IGAke2kgKiAwLjE1fXNgIH19IC8+KX1cbiAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgKX1cbiAgICAgICAgICA8ZGl2IHJlZj17bWVzc2FnZXNFbmRSZWZ9IC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiY2FyZCBtdC00IGZsZXggaXRlbXMtY2VudGVyIGdhcC0zIHB5LTNcIj5cbiAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIGNsYXNzTmFtZT1cImlucHV0IGZsZXgtMVwiXG4gICAgICAgICAgICBwbGFjZWhvbGRlcj1cIlR5cGUgYSBtZXNzYWdlLi4uXCJcbiAgICAgICAgICAgIHZhbHVlPXtpbnB1dH1cbiAgICAgICAgICAgIG9uQ2hhbmdlPXsoZSkgPT4gaGFuZGxlSW5wdXRDaGFuZ2UoZS50YXJnZXQudmFsdWUpfVxuICAgICAgICAgICAgb25LZXlEb3duPXsoZSkgPT4geyBpZiAoZS5rZXkgPT09ICdFbnRlcicgJiYgIWUuc2hpZnRLZXkpIHsgZS5wcmV2ZW50RGVmYXVsdCgpOyBzZW5kTWVzc2FnZSgpOyB9IH19XG4gICAgICAgICAgLz5cbiAgICAgICAgICA8YnV0dG9uIG9uQ2xpY2s9e3NlbmRNZXNzYWdlfSBjbGFzc05hbWU9XCJidG4tcHJpbWFyeSBwLTMgYXNwZWN0LXNxdWFyZVwiIGRpc2FibGVkPXshaW5wdXQudHJpbSgpfT5cbiAgICAgICAgICAgIDxTZW5kIGNsYXNzTmFtZT1cInctNSBoLTVcIiAvPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICApO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgQ2hhdDtcbiJdfQ==

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.