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.