seawolf2357 commited on
Commit
32b2b9a
ยท
verified ยท
1 Parent(s): f0f6fd0

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +919 -255
index.html CHANGED
@@ -1,276 +1,940 @@
1
- <!-- EV Cook Visitor Tracking Script v6.0 -->
2
- <!-- ์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”์ ํ•˜๋ ค๋Š” ์›น์‚ฌ์ดํŠธ์˜ </body> ํƒœ๊ทธ ๋ฐ”๋กœ ์•ž์— ์‚ฝ์ž…ํ•˜์„ธ์š” -->
3
- <script>
4
- (function() {
5
- // ========== ์„ค์ • ==========
6
- const TRACKING_SERVER = 'https://seawolf2357-evcook.hf.space';
7
- const SITE_ID = '38e0a883'; // ์„œ๋ฒ„์—์„œ ์ƒ์„ฑํ•œ ์‚ฌ์ดํŠธ ID๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”
8
- const PROCESS_TRACKING_FN_INDEX = 10;
9
- const DEBUG_MODE = false; // true๋กœ ์„ค์ •ํ•˜๋ฉด ์ฝ˜์†”์— ์ƒ์„ธ ๋กœ๊ทธ ์ถœ๋ ฅ
10
-
11
- // ========== ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ==========
12
- function log(level, message, data) {
13
- if (DEBUG_MODE || level === 'error') {
14
- const prefix = `[EV Cook Tracker ${new Date().toLocaleTimeString()}]`;
15
- console[level === 'error' ? 'error' : 'log'](`${prefix} ${message}`, data || '');
16
- }
17
- }
18
-
19
- // ๋””๋ฐ”์ด์Šค ID ์ƒ์„ฑ/์กฐํšŒ
20
- function getDeviceId() {
21
- let deviceId = localStorage.getItem('_evcook_device_id');
22
- if (!deviceId) {
23
- const components = [
24
- screen.width + 'x' + screen.height,
25
- navigator.hardwareConcurrency || 0,
26
- navigator.deviceMemory || 0,
27
- navigator.platform,
28
- navigator.language,
29
- new Date().getTimezoneOffset(),
30
- navigator.vendor || '',
31
- screen.colorDepth,
32
- window.devicePixelRatio || 1
33
- ];
34
-
35
- let hash = 0;
36
- const str = components.join('|');
37
- for (let i = 0; i < str.length; i++) {
38
- const char = str.charCodeAt(i);
39
- hash = ((hash << 5) - hash) + char;
40
- hash = hash & hash;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
- deviceId = 'DEV_' + Math.abs(hash).toString(36).toUpperCase();
44
- localStorage.setItem('_evcook_device_id', deviceId);
45
- log('info', 'New device ID generated:', deviceId);
46
- }
47
- return deviceId;
48
- }
49
-
50
- // WebGL ์ •๋ณด ์ˆ˜์ง‘
51
- function getWebGLInfo() {
52
- try {
53
- const canvas = document.createElement('canvas');
54
- const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
55
- if (!gl) return 'Not supported';
56
 
57
- const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
58
- if (debugInfo) {
59
- return gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
 
 
 
 
 
 
 
60
  }
61
- return 'Unknown';
62
- } catch(e) {
63
- return 'Error';
64
- }
65
- }
66
-
67
- // ========== ์ถ”์  ๋ฐ์ดํ„ฐ ์ „์†ก ==========
68
- async function sendTrackingData(eventType, eventData = {}) {
69
- const data = {
70
- siteId: SITE_ID,
71
- deviceId: getDeviceId(),
72
- eventType: eventType,
73
- eventData: eventData,
74
- pageUrl: window.location.href,
75
- pageTitle: document.title,
76
- referrer: document.referrer,
77
- userAgent: navigator.userAgent,
78
- screenResolution: screen.width + 'x' + screen.height,
79
- platform: navigator.platform,
80
- language: navigator.language,
81
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
82
- cpuCores: navigator.hardwareConcurrency || 0,
83
- deviceMemory: navigator.deviceMemory || 0,
84
- gpuInfo: getWebGLInfo(),
85
- timestamp: new Date().toISOString()
86
- };
87
 
88
- log('info', `Sending ${eventType} event`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
- // ๋ฐฉ๋ฒ• 1: Gradio Client API
91
- try {
92
- const response = await fetch(TRACKING_SERVER + '/call/process_tracking', {
93
- method: 'POST',
94
- headers: { 'Content-Type': 'application/json' },
95
- body: JSON.stringify({ data: [JSON.stringify(data)] })
96
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
- if (response.ok) {
99
- const result = await response.json();
100
- if (result.event_id) {
101
- log('info', 'Event sent successfully via Client API');
102
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
  }
105
- } catch (e) {
106
- log('debug', 'Client API failed:', e.message);
107
- }
108
-
109
- // ๋ฐฉ๋ฒ• 2: Direct API with fn_index
110
- try {
111
- const response = await fetch(TRACKING_SERVER + '/api/predict', {
112
- method: 'POST',
113
- headers: { 'Content-Type': 'application/json' },
114
- body: JSON.stringify({
115
- data: [JSON.stringify(data)],
116
- fn_index: PROCESS_TRACKING_FN_INDEX
117
- })
118
- });
119
 
120
- if (response.ok) {
121
- log('info', 'Event sent successfully via Direct API');
122
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  }
124
- } catch (e) {
125
- log('debug', 'Direct API failed:', e.message);
126
- }
127
-
128
- // ๋ฐฉ๋ฒ• 3: Queue API (ํด๋ฐฑ)
129
- try {
130
- const session_hash = Math.random().toString(36).substring(2, 15);
131
- const response = await fetch(TRACKING_SERVER + '/queue/join', {
132
- method: 'POST',
133
- headers: { 'Content-Type': 'application/json' },
134
- body: JSON.stringify({
135
- data: [JSON.stringify(data)],
136
- fn_index: PROCESS_TRACKING_FN_INDEX,
137
- session_hash: session_hash
138
- })
139
- });
140
 
141
- if (response.ok) {
142
- log('info', 'Event sent successfully via Queue API');
143
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
- } catch (e) {
146
- log('debug', 'Queue API failed:', e.message);
147
- }
148
-
149
- log('error', 'All tracking methods failed');
150
- return false;
151
- }
152
-
153
- // ========== ์ „์—ญ ์ถ”์  ๊ฐ์ฒด ==========
154
- window._evCookTracker = {
155
- trackEvent: function(eventName, eventData) {
156
- return sendTrackingData('custom', { name: eventName, data: eventData });
157
- },
158
-
159
- trackPageView: function(pageData) {
160
- return sendTrackingData('pageview', pageData || {});
161
- },
162
-
163
- getDeviceId: getDeviceId,
164
-
165
- // ์„ค์ • ๋ณ€๊ฒฝ
166
- setDebugMode: function(enabled) {
167
- DEBUG_MODE = enabled;
168
- log('info', 'Debug mode ' + (enabled ? 'enabled' : 'disabled'));
169
- }
170
- };
171
-
172
- // ========== ์ž๋™ ์ถ”์  ==========
173
-
174
- // ํŽ˜์ด์ง€ ๋กœ๋“œ ์ถ”์ 
175
- function trackPageLoad() {
176
- const loadData = {
177
- loadTime: window.performance && window.performance.timing ?
178
- window.performance.timing.loadEventEnd - window.performance.timing.navigationStart : 0,
179
- source: document.referrer || 'direct'
180
  };
181
- sendTrackingData('pageview', loadData);
182
- }
183
-
184
- if (document.readyState === 'loading') {
185
- document.addEventListener('DOMContentLoaded', trackPageLoad);
186
- } else {
187
- trackPageLoad();
188
- }
189
-
190
- // URL ๋ณ€๊ฒฝ ๊ฐ์ง€ (SPA ์ง€์›)
191
- let lastUrl = location.href;
192
- new MutationObserver(() => {
193
- const url = location.href;
194
- if (url !== lastUrl) {
195
- lastUrl = url;
196
- sendTrackingData('navigation', {
197
- from: lastUrl.substring(0, 200),
198
- to: url.substring(0, 200)
199
  });
 
 
 
200
  }
201
- }).observe(document, { subtree: true, childList: true });
202
-
203
- // ์Šคํฌ๋กค ์ถ”์  (์ตœ์ดˆ 100px ์Šคํฌ๋กค ์‹œ)
204
- let scrollTracked = false;
205
- window.addEventListener('scroll', () => {
206
- if (!scrollTracked && window.scrollY > 100) {
207
- scrollTracked = true;
208
- sendTrackingData('scroll', {
209
- depth: window.scrollY,
210
- pageHeight: document.documentElement.scrollHeight
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  }
213
- });
214
-
215
- // ํŽ˜์ด์ง€ ์ดํƒˆ ์‹œ๊ฐ„ ์ถ”์ 
216
- const sessionStartTime = Date.now();
217
- window.addEventListener('beforeunload', () => {
218
- const timeOnPage = Math.floor((Date.now() - sessionStartTime) / 1000);
219
- // ๋™๊ธฐ ์š”์ฒญ (๋น„์ฝ˜ API ์‚ฌ์šฉ)
220
- if (navigator.sendBeacon) {
221
- const data = {
222
- siteId: SITE_ID,
223
- deviceId: getDeviceId(),
224
- eventType: 'page_exit',
225
- eventData: { timeOnPage: timeOnPage, scrollDepth: window.scrollY },
226
- timestamp: new Date().toISOString()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  };
228
- navigator.sendBeacon(
229
- TRACKING_SERVER + '/api/predict',
230
- JSON.stringify({
231
- data: [JSON.stringify(data)],
232
- fn_index: PROCESS_TRACKING_FN_INDEX
233
- })
234
- );
235
- }
236
- });
237
-
238
- // ์˜ค๋ฅ˜ ์ถ”์  (์„ ํƒ์‚ฌํ•ญ)
239
- window.addEventListener('error', function(e) {
240
- if (Math.random() < 0.1) { // 10% ์ƒ˜ํ”Œ๋ง
241
- sendTrackingData('error', {
242
- message: e.message,
243
- source: e.filename,
244
- line: e.lineno,
245
- column: e.colno,
246
- stack: e.error ? e.error.stack : ''
247
  });
248
  }
249
- });
250
-
251
- // ์ดˆ๊ธฐํ™” ์™„๋ฃŒ
252
- log('info', 'EV Cook Tracker initialized', {
253
- server: TRACKING_SERVER,
254
- siteId: SITE_ID,
255
- deviceId: getDeviceId()
256
- });
257
-
258
- })();
259
- </script>
260
- <!-- End EV Cook Tracking Script -->
261
-
262
- <!--
263
- ์‚ฌ์šฉ๋ฒ•:
264
- 1. ์œ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ์ถ”์ ํ•˜๋ ค๋Š” ์›น์‚ฌ์ดํŠธ์˜ </body> ํƒœ๊ทธ ๋ฐ”๋กœ ์•ž์— ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”.
265
- 2. SITE_ID๋ฅผ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑํ•œ ์‹ค์ œ ์‚ฌ์ดํŠธ ID๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”.
266
- 3. ํ•„์š”์‹œ DEBUG_MODE๋ฅผ true๋กœ ์„ค์ •ํ•˜์—ฌ ์ฝ˜์†”์—์„œ ์ƒ์„ธ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
267
-
268
- ์ปค์Šคํ…€ ์ด๋ฒคํŠธ ์ „์†ก:
269
- window._evCookTracker.trackEvent('button_click', { buttonId: 'submit-btn' });
270
-
271
- ์ˆ˜๋™ ํŽ˜์ด์ง€๋ทฐ ์ „์†ก:
272
- window._evCookTracker.trackPageView({ customData: 'value' });
273
-
274
- ๋””๋ฒ„๊ทธ ๋ชจ๋“œ ์ผœ๊ธฐ:
275
- window._evCookTracker.setDebugMode(true);
276
- -->
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>EV Cook Site - ๋ฐฉ๋ฌธ์ž ์ถ”์  ํ™œ์„ฑํ™”</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
16
+ background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
17
+ min-height: 100vh;
18
+ color: #333;
19
+ }
20
+
21
+ .header {
22
+ background: rgba(255, 255, 255, 0.95);
23
+ padding: 20px 0;
24
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
25
+ }
26
+
27
+ .header-content {
28
+ max-width: 1200px;
29
+ margin: 0 auto;
30
+ padding: 0 20px;
31
+ display: flex;
32
+ justify-content: space-between;
33
+ align-items: center;
34
+ }
35
+
36
+ .logo {
37
+ font-size: 28px;
38
+ font-weight: bold;
39
+ color: #1e3c72;
40
+ }
41
+
42
+ .nav {
43
+ display: flex;
44
+ gap: 30px;
45
+ }
46
+
47
+ .nav a {
48
+ color: #333;
49
+ text-decoration: none;
50
+ font-weight: 500;
51
+ transition: color 0.3s;
52
+ }
53
+
54
+ .nav a:hover {
55
+ color: #1e3c72;
56
+ }
57
+
58
+ .main-container {
59
+ max-width: 1200px;
60
+ margin: 50px auto;
61
+ padding: 0 20px;
62
+ }
63
+
64
+ .hero-section {
65
+ background: white;
66
+ border-radius: 20px;
67
+ padding: 60px;
68
+ text-align: center;
69
+ box-shadow: 0 20px 60px rgba(0,0,0,0.1);
70
+ margin-bottom: 40px;
71
+ }
72
+
73
+ .hero-section h1 {
74
+ font-size: 48px;
75
+ color: #1e3c72;
76
+ margin-bottom: 20px;
77
+ }
78
+
79
+ .hero-section p {
80
+ font-size: 20px;
81
+ color: #666;
82
+ margin-bottom: 30px;
83
+ }
84
+
85
+ .tracking-status {
86
+ background: #e8f5e9;
87
+ border: 2px solid #4caf50;
88
+ border-radius: 10px;
89
+ padding: 20px;
90
+ margin: 20px 0;
91
+ }
92
+
93
+ .tracking-status h3 {
94
+ color: #2e7d32;
95
+ margin-bottom: 10px;
96
+ }
97
+
98
+ .info-grid {
99
+ display: grid;
100
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
101
+ gap: 20px;
102
+ margin-top: 40px;
103
+ }
104
+
105
+ .info-card {
106
+ background: white;
107
+ padding: 30px;
108
+ border-radius: 15px;
109
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
110
+ transition: transform 0.3s;
111
+ }
112
+
113
+ .info-card:hover {
114
+ transform: translateY(-5px);
115
+ }
116
+
117
+ .info-card h3 {
118
+ color: #1e3c72;
119
+ margin-bottom: 15px;
120
+ font-size: 24px;
121
+ }
122
+
123
+ .info-card p {
124
+ color: #666;
125
+ line-height: 1.6;
126
+ }
127
+
128
+ .status-indicator {
129
+ display: inline-flex;
130
+ align-items: center;
131
+ gap: 8px;
132
+ background: #f5f5f5;
133
+ padding: 8px 16px;
134
+ border-radius: 20px;
135
+ font-size: 14px;
136
+ }
137
+
138
+ .status-indicator.active {
139
+ background: #e8f5e9;
140
+ color: #2e7d32;
141
+ }
142
+
143
+ .status-dot {
144
+ width: 8px;
145
+ height: 8px;
146
+ border-radius: 50%;
147
+ background: #4caf50;
148
+ animation: pulse 2s infinite;
149
+ }
150
+
151
+ @keyframes pulse {
152
+ 0% {
153
+ box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7);
154
+ }
155
+ 70% {
156
+ box-shadow: 0 0 0 10px rgba(76, 175, 80, 0);
157
+ }
158
+ 100% {
159
+ box-shadow: 0 0 0 0 rgba(76, 175, 80, 0);
160
  }
161
+ }
162
+
163
+ .tracking-details {
164
+ background: #f8f9fa;
165
+ padding: 20px;
166
+ border-radius: 10px;
167
+ margin-top: 20px;
168
+ font-family: monospace;
169
+ font-size: 14px;
170
+ }
171
+
172
+ .tracking-details .row {
173
+ display: flex;
174
+ justify-content: space-between;
175
+ padding: 8px 0;
176
+ border-bottom: 1px solid #e0e0e0;
177
+ }
178
+
179
+ .tracking-details .row:last-child {
180
+ border-bottom: none;
181
+ }
182
+
183
+ .tracking-details .label {
184
+ font-weight: bold;
185
+ color: #555;
186
+ }
187
+
188
+ .tracking-details .value {
189
+ color: #1e3c72;
190
+ }
191
+
192
+ .buttons {
193
+ display: flex;
194
+ gap: 15px;
195
+ margin-top: 30px;
196
+ justify-content: center;
197
+ flex-wrap: wrap;
198
+ }
199
+
200
+ button {
201
+ padding: 12px 30px;
202
+ background: #1e3c72;
203
+ color: white;
204
+ border: none;
205
+ border-radius: 8px;
206
+ font-size: 16px;
207
+ font-weight: 500;
208
+ cursor: pointer;
209
+ transition: all 0.3s;
210
+ }
211
+
212
+ button:hover {
213
+ background: #2a5298;
214
+ transform: translateY(-2px);
215
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
216
+ }
217
+
218
+ button.secondary {
219
+ background: #757575;
220
+ }
221
+
222
+ button.secondary:hover {
223
+ background: #616161;
224
+ }
225
+
226
+ .footer {
227
+ text-align: center;
228
+ padding: 40px 20px;
229
+ color: white;
230
+ margin-top: 60px;
231
+ }
232
+
233
+ .console-hint {
234
+ background: #fff3cd;
235
+ border: 1px solid #ffeaa7;
236
+ padding: 15px;
237
+ border-radius: 8px;
238
+ margin: 20px 0;
239
+ text-align: center;
240
+ }
241
+
242
+ .console-hint code {
243
+ background: #f8f9fa;
244
+ padding: 2px 6px;
245
+ border-radius: 3px;
246
+ font-family: monospace;
247
+ }
248
+
249
+ .debug-panel {
250
+ background: #f0f0f0;
251
+ border: 2px solid #999;
252
+ border-radius: 10px;
253
+ padding: 20px;
254
+ margin: 20px 0;
255
+ display: none;
256
+ }
257
+
258
+ .debug-panel h3 {
259
+ color: #333;
260
+ margin-bottom: 10px;
261
+ }
262
+
263
+ .debug-log {
264
+ background: white;
265
+ border: 1px solid #ccc;
266
+ border-radius: 5px;
267
+ padding: 10px;
268
+ height: 200px;
269
+ overflow-y: auto;
270
+ font-family: monospace;
271
+ font-size: 12px;
272
+ }
273
+
274
+ .debug-log .log-entry {
275
+ margin: 2px 0;
276
+ padding: 2px 5px;
277
+ }
278
+
279
+ .debug-log .success {
280
+ color: #2e7d32;
281
+ background: #e8f5e9;
282
+ }
283
+
284
+ .debug-log .error {
285
+ color: #c62828;
286
+ background: #ffebee;
287
+ }
288
+
289
+ .debug-log .info {
290
+ color: #1565c0;
291
+ background: #e3f2fd;
292
+ }
293
+ </style>
294
+ </head>
295
+ <body>
296
+ <header class="header">
297
+ <div class="header-content">
298
+ <div class="logo">โšก EV Cook</div>
299
+ <nav class="nav">
300
+ <a href="#home">ํ™ˆ</a>
301
+ <a href="#about">์†Œ๊ฐœ</a>
302
+ <a href="#tracking">์ถ”์ ์ •๋ณด</a>
303
+ <a href="#contact">๋ฌธ์˜</a>
304
+ </nav>
305
+ </div>
306
+ </header>
307
+
308
+ <div class="main-container">
309
+ <section class="hero-section">
310
+ <h1>EV Cook ์ถ”์  ๋ฐ๋ชจ ์‚ฌ์ดํŠธ</h1>
311
+ <p>์ด ์‚ฌ์ดํŠธ๋Š” ๋ฐฉ๋ฌธ์ž ์ถ”์  ์‹œ์Šคํ…œ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค</p>
312
+
313
+ <div class="tracking-status">
314
+ <h3>๐Ÿ” ์ถ”์  ์ƒํƒœ</h3>
315
+ <div class="status-indicator active">
316
+ <span class="status-dot"></span>
317
+ <span>์ถ”์  ํ™œ์„ฑํ™”๋จ</span>
318
+ </div>
319
+
320
+ <div class="tracking-details">
321
+ <div class="row">
322
+ <span class="label">Device ID:</span>
323
+ <span class="value" id="deviceId">๋กœ๋”ฉ ์ค‘...</span>
324
+ </div>
325
+ <div class="row">
326
+ <span class="label">์ถ”์  ์„œ๋ฒ„:</span>
327
+ <span class="value">seawolf2357-evcook.hf.space</span>
328
+ </div>
329
+ <div class="row">
330
+ <span class="label">์‚ฌ์ดํŠธ ID:</span>
331
+ <span class="value">38e0a883</span>
332
+ </div>
333
+ <div class="row">
334
+ <span class="label">์ถ”์  ์‹œ์ž‘:</span>
335
+ <span class="value" id="trackingStart">-</span>
336
+ </div>
337
+ <div class="row">
338
+ <span class="label">์ „์†ก ์ƒํƒœ:</span>
339
+ <span class="value" id="trackingStatus">๋Œ€๊ธฐ ์ค‘...</span>
340
+ </div>
341
+ </div>
342
+ </div>
343
+
344
+ <div class="buttons">
345
+ <button onclick="testTracking()">๐Ÿ“Š ์ถ”์  ํ…Œ์ŠคํŠธ</button>
346
+ <button onclick="sendCustomEvent()">๐ŸŽฏ ์ปค์Šคํ…€ ์ด๋ฒคํŠธ</button>
347
+ <button onclick="viewDetails()" class="secondary">๐Ÿ“‹ ์ƒ์„ธ ์ •๋ณด</button>
348
+ <button onclick="toggleDebug()" class="secondary">๐Ÿ› ๋””๋ฒ„๊ทธ ํŒจ๋„</button>
349
+ </div>
350
+ </section>
351
+
352
+ <div class="debug-panel" id="debugPanel">
353
+ <h3>๐Ÿ› ๋””๋ฒ„๊ทธ ๋กœ๊ทธ</h3>
354
+ <div class="debug-log" id="debugLog"></div>
355
+ <div class="buttons" style="margin-top: 10px;">
356
+ <button onclick="clearDebugLog()" class="secondary">๋กœ๊ทธ ์ง€์šฐ๊ธฐ</button>
357
+ <button onclick="window._tracker.debug.checkConfig()" class="secondary">์„œ๋ฒ„ ๊ตฌ์กฐ ํ™•์ธ</button>
358
+ <button onclick="window._tracker.debug.testAllMethods()" class="secondary">๋ชจ๋“  ๋ฐฉ๋ฒ• ํ…Œ์ŠคํŠธ</button>
359
+ </div>
360
+ </div>
361
+
362
+ <div class="info-grid">
363
+ <div class="info-card">
364
+ <h3>๐Ÿš€ ์‹ค์‹œ๊ฐ„ ์ถ”์ </h3>
365
+ <p>ํŽ˜์ด์ง€ ๋ฐฉ๋ฌธ, ํด๋ฆญ, ์Šคํฌ๋กค ๋“ฑ ๋ชจ๋“  ์‚ฌ์šฉ์ž ํ™œ๋™์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถ”์ ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฝ˜์†”์—์„œ ์ถ”์  ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
366
+ </div>
367
+ <div class="info-card">
368
+ <h3>๐Ÿ”’ ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ</h3>
369
+ <p>๋””๋ฐ”์ด์Šค ID๋Š” ๋ธŒ๋ผ์šฐ์ € ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋˜๋ฉฐ, ๊ฐœ์ธ์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋Š” ์ˆ˜์ง‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.</p>
370
+ </div>
371
+ <div class="info-card">
372
+ <h3>๐Ÿ“ˆ ๋ถ„์„ ๋Œ€์‹œ๋ณด๋“œ</h3>
373
+ <p>์ˆ˜์ง‘๋œ ๋ฐ์ดํ„ฐ๋Š” ์ถ”์  ์„œ๋ฒ„์˜ ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
374
+ </div>
375
+ </div>
376
+
377
+ <div class="console-hint">
378
+ ๐Ÿ’ก <strong>๊ฐœ๋ฐœ์ž ๋„๊ตฌ ํ™œ์šฉ:</strong> <code>F12</code>๋ฅผ ๋ˆŒ๋Ÿฌ Console ํƒญ์—์„œ ์ถ”์  ์ด๋ฒคํŠธ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•˜์„ธ์š”!
379
+ </div>
380
+
381
+ <div id="detailsSection" style="display: none;">
382
+ <section class="hero-section" style="margin-top: 40px;">
383
+ <h2>๐Ÿ“Š ๋ธŒ๋ผ์šฐ์ € ์ƒ์„ธ ์ •๋ณด</h2>
384
+ <pre id="browserDetails" style="text-align: left; background: #f5f5f5; padding: 20px; border-radius: 8px; overflow-x: auto;"></pre>
385
+ </section>
386
+ </div>
387
+ </div>
388
+
389
+ <footer class="footer">
390
+ <p>&copy; 2025 EV Cook. ๋ชจ๋“  ๊ถŒ๋ฆฌ ๋ณด์œ .</p>
391
+ <p>์ถ”์  ์„œ๋ฒ„: <a href="https://seawolf2357-evcook.hf.space" target="_blank" style="color: white;">seawolf2357-evcook.hf.space</a></p>
392
+ </footer>
393
+
394
+ <!-- ์™„๋ฒฝํ•œ ๋ฐฉ๋ฌธ์ž ์ถ”์  ์Šคํฌ๋ฆฝํŠธ -->
395
+ <script>
396
+ (function() {
397
+ // ์ถ”์  ์„œ๋ฒ„ ์„ค์ •
398
+ const TRACKING_SERVER = 'https://seawolf2357-evcook.hf.space';
399
+ const SITE_ID = '38e0a883';
400
+ const PROCESS_TRACKING_FN_INDEX = 10; // ์„œ๋ฒ„ ๋ถ„์„ ๊ฒฐ๊ณผ process_tracking์˜ fn_index
401
+
402
+ // ๋””๋ฒ„๊ทธ ๋กœ๊น…
403
+ const debugLog = [];
404
+ function addDebugLog(type, message) {
405
+ const timestamp = new Date().toLocaleTimeString();
406
+ const logEntry = { type, message, timestamp };
407
+ debugLog.push(logEntry);
408
 
409
+ // ์ฝ˜์†”์—๋„ ์ถœ๋ ฅ
410
+ const consoleMethod = type === 'error' ? 'error' : type === 'success' ? 'log' : 'info';
411
+ console[consoleMethod](`[Tracker ${timestamp}] ${message}`);
 
 
 
 
 
 
 
 
 
 
412
 
413
+ // UI ์—…๋ฐ์ดํŠธ
414
+ updateDebugPanel();
415
+ }
416
+
417
+ function updateDebugPanel() {
418
+ const debugLogEl = document.getElementById('debugLog');
419
+ if (debugLogEl) {
420
+ debugLogEl.innerHTML = debugLog.slice(-50).reverse().map(entry =>
421
+ `<div class="log-entry ${entry.type}">[${entry.timestamp}] ${entry.message}</div>`
422
+ ).join('');
423
  }
424
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
 
426
+ // ๋””๋ฐ”์ด์Šค ID ์ƒ์„ฑ/์กฐํšŒ
427
+ function getDeviceId() {
428
+ let deviceId = localStorage.getItem('_tracker_device_id');
429
+ if (!deviceId) {
430
+ // ํ•˜๋“œ์›จ์–ด ๊ธฐ๋ฐ˜ ID ์ƒ์„ฑ
431
+ const components = [
432
+ screen.width + 'x' + screen.height,
433
+ navigator.hardwareConcurrency || 0,
434
+ navigator.deviceMemory || 0,
435
+ navigator.platform,
436
+ navigator.language,
437
+ new Date().getTimezoneOffset(),
438
+ navigator.vendor,
439
+ screen.colorDepth,
440
+ window.devicePixelRatio || 1
441
+ ];
442
+
443
+ // ๋” ๊ฐ•๋ ฅํ•œ ํ•ด์‹œ ํ•จ์ˆ˜
444
+ let hash = 0;
445
+ const str = components.join('|');
446
+ for (let i = 0; i < str.length; i++) {
447
+ const char = str.charCodeAt(i);
448
+ hash = ((hash << 5) - hash) + char;
449
+ hash = hash & hash;
450
+ }
451
+
452
+ deviceId = 'DEV_' + Math.abs(hash).toString(36).toUpperCase();
453
+ localStorage.setItem('_tracker_device_id', deviceId);
454
+ addDebugLog('info', `์ƒˆ Device ID ์ƒ์„ฑ: ${deviceId}`);
455
+ }
456
+ return deviceId;
457
+ }
458
 
459
+ // WebGL ์ •๋ณด ์ˆ˜์ง‘
460
+ function getWebGLInfo() {
461
+ try {
462
+ const canvas = document.createElement('canvas');
463
+ const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
464
+ if (!gl) return 'Not supported';
465
+
466
+ const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
467
+ if (debugInfo) {
468
+ return gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
469
+ }
470
+ return 'Unknown';
471
+ } catch(e) {
472
+ return 'Error: ' + e.message;
473
+ }
474
+ }
475
+
476
+ // ์ถ”์  ๋ฐ์ดํ„ฐ ์ „์†ก (๋ชจ๋“  ๋ฐฉ๋ฒ• ์‹œ๋„)
477
+ async function collectAndSend(eventType = 'pageview', eventData = {}) {
478
+ const data = {
479
+ siteId: SITE_ID,
480
+ deviceId: getDeviceId(),
481
+ eventType: eventType,
482
+ eventData: eventData,
483
+ pageUrl: window.location.href,
484
+ pageTitle: document.title,
485
+ referrer: document.referrer,
486
+ userAgent: navigator.userAgent,
487
+ screenResolution: screen.width + 'x' + screen.height,
488
+ platform: navigator.platform,
489
+ language: navigator.language,
490
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
491
+ cpuCores: navigator.hardwareConcurrency || 0,
492
+ deviceMemory: navigator.deviceMemory || 0,
493
+ gpuInfo: getWebGLInfo(),
494
+ timestamp: new Date().toISOString()
495
+ };
496
 
497
+ addDebugLog('info', `์ด๋ฒคํŠธ ์ „์†ก ์‹œ์ž‘: ${eventType}`);
498
+ updateTrackingStatus('์ „์†ก ์ค‘...');
499
+
500
+ let success = false;
501
+
502
+ // ๋ฐฉ๋ฒ• 1: Gradio Client API (/call/process_tracking)
503
+ if (!success) {
504
+ try {
505
+ addDebugLog('info', '๋ฐฉ๋ฒ• 1: Gradio Client API ์‹œ๋„');
506
+ const response = await fetch(TRACKING_SERVER + '/call/process_tracking', {
507
+ method: 'POST',
508
+ headers: {
509
+ 'Content-Type': 'application/json',
510
+ },
511
+ body: JSON.stringify({
512
+ data: [JSON.stringify(data)]
513
+ })
514
+ });
515
+
516
+ if (response.ok) {
517
+ const result = await response.json();
518
+
519
+ // event_id๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฒฐ๊ณผ ๊ฐ€์ ธ์˜ค๊ธฐ
520
+ if (result.event_id) {
521
+ const resultResponse = await fetch(TRACKING_SERVER + '/call/process_tracking/' + result.event_id);
522
+ if (resultResponse.ok) {
523
+ addDebugLog('success', 'โœ… ๋ฐฉ๋ฒ• 1 ์„ฑ๊ณต: Gradio Client API');
524
+ success = true;
525
+ updateTrackingStatus('์ „์†ก ์™„๋ฃŒ (Client API)');
526
+ }
527
+ }
528
+ }
529
+ } catch (e) {
530
+ addDebugLog('error', `๋ฐฉ๋ฒ• 1 ์‹คํŒจ: ${e.message}`);
531
  }
532
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
 
534
+ // ๋ฐฉ๋ฒ• 2: Direct API with fn_index=10
535
+ if (!success) {
536
+ try {
537
+ addDebugLog('info', `๋ฐฉ๋ฒ• 2: Direct API (fn_index=${PROCESS_TRACKING_FN_INDEX}) ์‹œ๋„`);
538
+ const response = await fetch(TRACKING_SERVER + '/api/predict', {
539
+ method: 'POST',
540
+ headers: {
541
+ 'Content-Type': 'application/json',
542
+ },
543
+ body: JSON.stringify({
544
+ data: [JSON.stringify(data)],
545
+ fn_index: PROCESS_TRACKING_FN_INDEX
546
+ })
547
+ });
548
+
549
+ if (response.ok) {
550
+ const result = await response.json();
551
+ addDebugLog('success', 'โœ… ๋ฐฉ๋ฒ• 2 ์„ฑ๊ณต: Direct API');
552
+ success = true;
553
+ updateTrackingStatus('์ „์†ก ์™„๋ฃŒ (Direct API)');
554
+ } else {
555
+ addDebugLog('error', `๋ฐฉ๋ฒ• 2 ์‹คํŒจ: HTTP ${response.status}`);
556
+ }
557
+ } catch (e) {
558
+ addDebugLog('error', `๋ฐฉ๋ฒ• 2 ์‹คํŒจ: ${e.message}`);
559
+ }
560
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
 
562
+ // ๋ฐฉ๋ฒ• 3: Queue API
563
+ if (!success) {
564
+ try {
565
+ addDebugLog('info', '๋ฐฉ๋ฒ• 3: Queue API ์‹œ๋„');
566
+ const session_hash = Math.random().toString(36).substring(2, 15);
567
+
568
+ const joinResponse = await fetch(TRACKING_SERVER + '/queue/join', {
569
+ method: 'POST',
570
+ headers: {
571
+ 'Content-Type': 'application/json',
572
+ },
573
+ body: JSON.stringify({
574
+ data: [JSON.stringify(data)],
575
+ fn_index: PROCESS_TRACKING_FN_INDEX,
576
+ session_hash: session_hash
577
+ })
578
+ });
579
+
580
+ if (joinResponse.ok) {
581
+ // SSE๋กœ ๊ฒฐ๊ณผ ๋ฐ›๊ธฐ
582
+ const reader = joinResponse.body.getReader();
583
+ const decoder = new TextDecoder();
584
+
585
+ while (true) {
586
+ const { done, value } = await reader.read();
587
+ if (done) break;
588
+
589
+ const text = decoder.decode(value);
590
+ if (text.includes('process_completed')) {
591
+ addDebugLog('success', 'โœ… ๋ฐฉ๋ฒ• 3 ์„ฑ๊ณต: Queue API');
592
+ success = true;
593
+ updateTrackingStatus('์ „์†ก ์™„๋ฃŒ (Queue API)');
594
+ break;
595
+ }
596
+ }
597
+ }
598
+ } catch (e) {
599
+ addDebugLog('error', `๋ฐฉ๋ฒ• 3 ์‹คํŒจ: ${e.message}`);
600
+ }
601
+ }
602
+
603
+ // ๋ฐฉ๋ฒ• 4: Run endpoint
604
+ if (!success) {
605
+ try {
606
+ addDebugLog('info', '๋ฐฉ๋ฒ• 4: Run endpoint ์‹œ๋„');
607
+ const response = await fetch(TRACKING_SERVER + '/run/process_tracking', {
608
+ method: 'POST',
609
+ headers: {
610
+ 'Content-Type': 'application/json',
611
+ },
612
+ body: JSON.stringify({
613
+ data: [JSON.stringify(data)]
614
+ })
615
+ });
616
+
617
+ if (response.ok) {
618
+ addDebugLog('success', 'โœ… ๋ฐฉ๋ฒ• 4 ์„ฑ๊ณต: Run endpoint');
619
+ success = true;
620
+ updateTrackingStatus('์ „์†ก ์™„๋ฃŒ (Run API)');
621
+ }
622
+ } catch (e) {
623
+ addDebugLog('error', `๋ฐฉ๋ฒ• 4 ์‹คํŒจ: ${e.message}`);
624
+ }
625
+ }
626
+
627
+ if (!success) {
628
+ addDebugLog('error', 'โŒ ๋ชจ๋“  ์ „์†ก ๋ฐฉ๋ฒ• ์‹คํŒจ');
629
+ updateTrackingStatus('์ „์†ก ์‹คํŒจ');
630
+ }
631
+
632
+ return success;
633
+ }
634
+
635
+ // ์ถ”์  ์ƒํƒœ ์—…๋ฐ์ดํŠธ
636
+ function updateTrackingStatus(status) {
637
+ const statusEl = document.getElementById('trackingStatus');
638
+ if (statusEl) {
639
+ statusEl.textContent = status;
640
+ }
641
+ }
642
+
643
+ // ์ „์—ญ ์ถ”์  ๊ฐ์ฒด
644
+ window._tracker = {
645
+ trackEvent: function(eventName, eventData) {
646
+ return collectAndSend('custom', { name: eventName, data: eventData });
647
+ },
648
+
649
+ // ๋””๋ฒ„๊น… ๋„๊ตฌ
650
+ debug: {
651
+ getDeviceId: getDeviceId,
652
+ getWebGLInfo: getWebGLInfo,
653
+
654
+ // ์„œ๋ฒ„ ๊ตฌ์กฐ ํ™•์ธ
655
+ checkConfig: async function() {
656
+ addDebugLog('info', '์„œ๋ฒ„ ๊ตฌ์กฐ ํ™•์ธ ์ค‘...');
657
+ try {
658
+ const response = await fetch(TRACKING_SERVER + '/config');
659
+ const config = await response.json();
660
+
661
+ addDebugLog('info', `Gradio ๋ฒ„์ „: ${config.version}`);
662
+
663
+ if (config.dependencies) {
664
+ addDebugLog('info', `API ํ•จ์ˆ˜ ๊ฐœ์ˆ˜: ${config.dependencies.length}`);
665
+ config.dependencies.forEach((dep, i) => {
666
+ if (dep.api_name) {
667
+ addDebugLog('info', `[${i}] ${dep.api_name}`);
668
+ }
669
+ });
670
+ }
671
+ } catch (e) {
672
+ addDebugLog('error', `์„œ๋ฒ„ ๊ตฌ์กฐ ํ™•์ธ ์‹คํŒจ: ${e.message}`);
673
+ }
674
+ },
675
+
676
+ // ๋ชจ๋“  ๋ฐฉ๋ฒ• ํ…Œ์ŠคํŠธ
677
+ testAllMethods: async function() {
678
+ addDebugLog('info', '=== ๋ชจ๋“  ์ „์†ก ๋ฐฉ๋ฒ• ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ===');
679
+ const testData = {
680
+ test: true,
681
+ method: 'all',
682
+ timestamp: new Date().toISOString()
683
+ };
684
+ await collectAndSend('test_all_methods', testData);
685
+ },
686
+
687
+ // ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ
688
+ test: function() {
689
+ return collectAndSend('debug_test', {
690
+ test: true,
691
+ timestamp: new Date().toISOString(),
692
+ random: Math.random()
693
+ });
694
+ },
695
+
696
+ // ๋กœ๊ทธ ํ™•์ธ
697
+ getLogs: function() {
698
+ return debugLog;
699
+ }
700
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
  };
702
+
703
+ // ํŽ˜์ด์ง€ ๋กœ๋“œ์‹œ ์ถ”์ 
704
+ if (document.readyState === 'loading') {
705
+ document.addEventListener('DOMContentLoaded', () => {
706
+ addDebugLog('info', 'DOM ๋กœ๋“œ ์™„๋ฃŒ, pageview ์ „์†ก');
707
+ collectAndSend();
 
 
 
 
 
 
 
 
 
 
 
 
708
  });
709
+ } else {
710
+ addDebugLog('info', 'ํŽ˜์ด์ง€ ์ด๋ฏธ ๋กœ๋“œ๋จ, pageview ์ „์†ก');
711
+ collectAndSend();
712
  }
713
+
714
+ // SPA ์ง€์› - URL ๋ณ€๊ฒฝ ๊ฐ์ง€
715
+ let lastUrl = location.href;
716
+ new MutationObserver(() => {
717
+ const url = location.href;
718
+ if (url !== lastUrl) {
719
+ lastUrl = url;
720
+ addDebugLog('info', `URL ๋ณ€๊ฒฝ ๊ฐ์ง€: ${url}`);
721
+ collectAndSend('navigation', { from: lastUrl, to: url });
722
+ }
723
+ }).observe(document, {subtree: true, childList: true});
724
+
725
+ // ์Šคํฌ๋กค ์ถ”์ 
726
+ let scrollTracked = false;
727
+ window.addEventListener('scroll', () => {
728
+ if (!scrollTracked && window.scrollY > 100) {
729
+ scrollTracked = true;
730
+ addDebugLog('info', `์Šคํฌ๋กค ์ด๋ฒคํŠธ: ${window.scrollY}px`);
731
+ window._tracker.trackEvent('scroll', { depth: window.scrollY });
732
+ }
733
+ });
734
+
735
+ // ํด๋ฆญ ์ถ”์  (์„ ํƒ์‚ฌํ•ญ)
736
+ document.addEventListener('click', (e) => {
737
+ const target = e.target;
738
+ if (target.tagName === 'A' || target.tagName === 'BUTTON') {
739
+ const trackData = {
740
+ element: target.tagName,
741
+ text: target.textContent.substring(0, 50),
742
+ href: target.href || '',
743
+ id: target.id || '',
744
+ class: target.className || ''
745
+ };
746
+ window._tracker.trackEvent('click', trackData);
747
+ }
748
+ });
749
+
750
+ // ํŽ˜์ด์ง€ ์ดํƒˆ ์ถ”์  (์„ ํƒ์‚ฌํ•ญ)
751
+ window.addEventListener('beforeunload', () => {
752
+ const timeOnPage = Math.floor((Date.now() - window._trackerStartTime) / 1000);
753
+ window._tracker.trackEvent('page_exit', {
754
+ timeOnPage: timeOnPage,
755
+ scrollDepth: window.scrollY
756
  });
757
+ });
758
+
759
+ // ์‹œ์ž‘ ์‹œ๊ฐ„ ๊ธฐ๋ก
760
+ window._trackerStartTime = Date.now();
761
+
762
+ // ์ดˆ๊ธฐํ™” ๋ฉ”์‹œ์ง€
763
+ console.log('%c๐Ÿ” EV Cook Tracker v6.0 (์™„๋ฒฝํ•œ ๋ฒ„์ „)', 'color: #4CAF50; font-size: 16px; font-weight: bold;');
764
+ console.log('%c์„œ๋ฒ„: ' + TRACKING_SERVER, 'color: #2196F3');
765
+ console.log('%c์‚ฌ์ดํŠธ ID: ' + SITE_ID, 'color: #2196F3');
766
+ console.log('%cDevice ID: ' + getDeviceId(), 'color: #2196F3');
767
+ console.log('%cprocess_tracking fn_index: ' + PROCESS_TRACKING_FN_INDEX, 'color: #2196F3');
768
+ console.log('\n%c๐Ÿ“š ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ช…๋ น์–ด:', 'font-weight: bold');
769
+ console.log('โ€ข window._tracker.trackEvent(name, data) - ์ปค์Šคํ…€ ์ด๋ฒคํŠธ ์ „์†ก');
770
+ console.log('โ€ข window._tracker.debug.checkConfig() - ์„œ๋ฒ„ ๊ตฌ์กฐ ํ™•์ธ');
771
+ console.log('โ€ข window._tracker.debug.test() - ํ…Œ์ŠคํŠธ ์ด๋ฒคํŠธ ์ „์†ก');
772
+ console.log('โ€ข window._tracker.debug.testAllMethods() - ๋ชจ๋“  ๋ฐฉ๋ฒ• ํ…Œ์ŠคํŠธ');
773
+ console.log('โ€ข window._tracker.debug.getLogs() - ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ํ™•์ธ');
774
+
775
+ addDebugLog('success', 'EV Cook Tracker ์ดˆ๊ธฐํ™” ์™„๋ฃŒ');
776
+ })();
777
+ </script>
778
+ <!-- End Visitor Tracking Script -->
779
+
780
+ <!-- ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ์Šคํฌ๋ฆฝํŠธ -->
781
+ <script>
782
+ // ํŽ˜์ด์ง€ ๋กœ๋“œ์‹œ ์‹คํ–‰
783
+ window.addEventListener('DOMContentLoaded', () => {
784
+ // Device ID ํ‘œ์‹œ
785
+ setTimeout(() => {
786
+ const deviceId = localStorage.getItem('_tracker_device_id');
787
+ if (deviceId) {
788
+ document.getElementById('deviceId').textContent = deviceId;
789
+ }
790
+ document.getElementById('trackingStart').textContent = new Date().toLocaleString('ko-KR');
791
+ }, 500);
792
+ });
793
+
794
+ // ์ถ”์  ํ…Œ์ŠคํŠธ
795
+ function testTracking() {
796
+ if (window._tracker) {
797
+ window._tracker.trackEvent('test_button_click', {
798
+ button: 'tracking_test',
799
+ timestamp: Date.now(),
800
+ location: 'hero_section',
801
+ userAction: true
802
+ }).then(success => {
803
+ if (success) {
804
+ alert('โœ… ์ถ”์  ์ด๋ฒคํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n\n๋””๋ฒ„๊ทธ ํŒจ๋„์—์„œ ์ƒ์„ธ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜์„ธ์š”.');
805
+ } else {
806
+ alert('โŒ ์ถ”์  ์ด๋ฒคํŠธ ์ „์†ก์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.\n\n๋””๋ฒ„๊ทธ ํŒจ๋„์—์„œ ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•˜์„ธ์š”.');
807
+ }
808
+ });
809
+ } else {
810
+ alert('โŒ ์ถ”์  ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋กœ๋“œ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.');
811
+ }
812
  }
813
+
814
+ // ์ปค์Šคํ…€ ์ด๋ฒคํŠธ ์ „์†ก
815
+ function sendCustomEvent() {
816
+ const eventName = prompt('์ด๋ฒคํŠธ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”:', 'custom_action');
817
+ if (eventName && window._tracker) {
818
+ const eventData = {
819
+ custom_name: eventName,
820
+ user_input: true,
821
+ timestamp: Date.now(),
822
+ metadata: {
823
+ viewport: {
824
+ width: window.innerWidth,
825
+ height: window.innerHeight
826
+ },
827
+ scroll: {
828
+ x: window.scrollX,
829
+ y: window.scrollY
830
+ }
831
+ }
832
+ };
833
+
834
+ window._tracker.trackEvent(eventName, eventData);
835
+
836
+ alert(`โœ… '${eventName}' ์ด๋ฒคํŠธ๊ฐ€ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค!`);
837
+ console.log('[Custom Event]', eventName, eventData);
838
+ }
839
+ }
840
+
841
+ // ์ƒ์„ธ ์ •๋ณด ๋ณด๊ธฐ
842
+ function viewDetails() {
843
+ const details = {
844
+ tracking: {
845
+ deviceId: localStorage.getItem('_tracker_device_id'),
846
+ siteId: '38e0a883',
847
+ serverUrl: 'https://seawolf2357-evcook.hf.space',
848
+ startTime: window._trackerStartTime ? new Date(window._trackerStartTime).toLocaleString() : 'Unknown'
849
+ },
850
+ browser: {
851
+ userAgent: navigator.userAgent,
852
+ platform: navigator.platform,
853
+ vendor: navigator.vendor,
854
+ language: navigator.language,
855
+ languages: navigator.languages,
856
+ cookieEnabled: navigator.cookieEnabled,
857
+ doNotTrack: navigator.doNotTrack,
858
+ onLine: navigator.onLine,
859
+ plugins: navigator.plugins.length
860
+ },
861
+ screen: {
862
+ resolution: screen.width + 'x' + screen.height,
863
+ availableResolution: screen.availWidth + 'x' + screen.availHeight,
864
+ colorDepth: screen.colorDepth,
865
+ pixelRatio: window.devicePixelRatio,
866
+ orientation: screen.orientation ? screen.orientation.type : 'Unknown'
867
+ },
868
+ viewport: {
869
+ width: window.innerWidth,
870
+ height: window.innerHeight,
871
+ scrollX: window.scrollX,
872
+ scrollY: window.scrollY
873
+ },
874
+ hardware: {
875
+ cpuCores: navigator.hardwareConcurrency || 'Unknown',
876
+ deviceMemory: navigator.deviceMemory ? navigator.deviceMemory + 'GB' : 'Unknown',
877
+ maxTouchPoints: navigator.maxTouchPoints || 0,
878
+ webGL: window._tracker.debug.getWebGLInfo()
879
+ },
880
+ location: {
881
+ href: window.location.href,
882
+ hostname: window.location.hostname,
883
+ protocol: window.location.protocol,
884
+ pathname: window.location.pathname,
885
+ search: window.location.search,
886
+ hash: window.location.hash
887
+ },
888
+ time: {
889
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
890
+ offset: new Date().getTimezoneOffset(),
891
+ locale: new Date().toLocaleString(),
892
+ timeOnPage: window._trackerStartTime ? Math.floor((Date.now() - window._trackerStartTime) / 1000) + '์ดˆ' : 'Unknown'
893
+ },
894
+ storage: {
895
+ localStorage: typeof(Storage) !== "undefined",
896
+ sessionStorage: typeof(sessionStorage) !== "undefined",
897
+ indexedDB: 'indexedDB' in window,
898
+ cookies: navigator.cookieEnabled
899
+ }
900
  };
901
+
902
+ document.getElementById('browserDetails').textContent = JSON.stringify(details, null, 2);
903
+ document.getElementById('detailsSection').style.display = 'block';
904
+
905
+ // ์ƒ์„ธ ์ •๋ณด ๋ณด๊ธฐ๋„ ์ถ”์ 
906
+ window._tracker.trackEvent('view_details', {
907
+ action: 'show_browser_info',
908
+ detailsViewed: Object.keys(details)
 
 
 
 
 
 
 
 
 
 
 
909
  });
910
  }
911
+
912
+ // ๋””๋ฒ„๊ทธ ํŒจ๋„ ํ† ๊ธ€
913
+ function toggleDebug() {
914
+ const panel = document.getElementById('debugPanel');
915
+ if (panel) {
916
+ panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
917
+ if (panel.style.display === 'block') {
918
+ window._tracker.trackEvent('debug_panel_opened', { timestamp: Date.now() });
919
+ }
920
+ }
921
+ }
922
+
923
+ // ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ์ง€์šฐ๊ธฐ
924
+ function clearDebugLog() {
925
+ window._tracker.debug.getLogs().length = 0;
926
+ const debugLogEl = document.getElementById('debugLog');
927
+ if (debugLogEl) {
928
+ debugLogEl.innerHTML = '<div class="log-entry info">๋กœ๊ทธ๊ฐ€ ์ง€์›Œ์กŒ์Šต๋‹ˆ๋‹ค.</div>';
929
+ }
930
+ }
931
+
932
+ // ์ฝ˜์†”์— ์ถ”์  ์ •๋ณด ์ถœ๋ ฅ
933
+ console.log('%c๐Ÿ” EV Cook ์ถ”์  ์‹œ์Šคํ…œ ํ™œ์„ฑํ™”๋จ', 'color: #4CAF50; font-size: 16px; font-weight: bold;');
934
+ console.log('%c์ถ”์  ์„œ๋ฒ„:', 'font-weight: bold;', 'https://seawolf2357-evcook.hf.space');
935
+ console.log('%c์‚ฌ์ดํŠธ ID:', 'font-weight: bold;', '38e0a883');
936
+ console.log('%cDevice ID:', 'font-weight: bold;', localStorage.getItem('_tracker_device_id') || '์ƒ์„ฑ ์ค‘...');
937
+ console.log('\n%c๐Ÿ’ก Tip: ๋””๋ฒ„๊ทธ ํŒจ๋„ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ ์ถ”์  ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”!', 'color: #666;');
938
+ </script>
939
+ </body>
940
+ </html>