6ee5ali commited on
Commit
ba6a049
·
verified ·
1 Parent(s): ebd42d1

import cv2 import numpy as np def remove_sticker(image_path, mask_path, output_path): # قراءة الصورة والقناع (اللاصقة) img = cv2.imread(image_path) mask = cv2.imread(mask_path, 0) # قراءة كصورة رمادية # تطبيق خوارزمية الاستعادة result = cv2.inpaint(img, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA) # حفظ النتيجة cv2.imwrite(output_path, result) - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +459 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Face2
3
- emoji: 🌍
4
- colorFrom: indigo
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: face2
3
+ emoji: 🐳
4
+ colorFrom: pink
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,459 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sticker Remover Tool</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #ccc;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #4f46e5;
16
+ background-color: #eef2ff;
17
+ }
18
+ .canvas-container {
19
+ position: relative;
20
+ margin: 0 auto;
21
+ }
22
+ .processing-overlay {
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ width: 100%;
27
+ height: 100%;
28
+ background: rgba(0,0,0,0.7);
29
+ display: flex;
30
+ flex-direction: column;
31
+ justify-content: center;
32
+ align-items: center;
33
+ color: white;
34
+ z-index: 10;
35
+ }
36
+ .spinner {
37
+ width: 40px;
38
+ height: 40px;
39
+ border: 4px solid rgba(255,255,255,0.3);
40
+ border-radius: 50%;
41
+ border-top-color: #fff;
42
+ animation: spin 1s ease-in-out infinite;
43
+ }
44
+ @keyframes spin {
45
+ to { transform: rotate(360deg); }
46
+ }
47
+ .brush-size-control {
48
+ -webkit-appearance: none;
49
+ width: 100%;
50
+ height: 8px;
51
+ border-radius: 4px;
52
+ background: #d1d5db;
53
+ }
54
+ .brush-size-control::-webkit-slider-thumb {
55
+ -webkit-appearance: none;
56
+ width: 20px;
57
+ height: 20px;
58
+ border-radius: 50%;
59
+ background: #4f46e5;
60
+ cursor: pointer;
61
+ }
62
+ </style>
63
+ </head>
64
+ <body class="bg-gray-50 min-h-screen">
65
+ <div class="container mx-auto px-4 py-8">
66
+ <header class="text-center mb-8">
67
+ <h1 class="text-4xl font-bold text-indigo-600 mb-2">Sticker Remover</h1>
68
+ <p class="text-gray-600 max-w-2xl mx-auto">
69
+ Remove unwanted stickers, watermarks, or objects from your images with our AI-powered tool.
70
+ </p>
71
+ </header>
72
+
73
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden max-w-4xl mx-auto">
74
+ <div class="md:flex">
75
+ <!-- Left Panel - Controls -->
76
+ <div class="md:w-1/3 p-6 bg-gray-50 border-r border-gray-200">
77
+ <div class="space-y-6">
78
+ <div>
79
+ <h2 class="text-lg font-medium text-gray-900 mb-3">Upload Image</h2>
80
+ <div id="image-dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
81
+ <div class="flex flex-col items-center justify-center">
82
+ <i class="fas fa-cloud-upload-alt text-4xl text-indigo-400 mb-3"></i>
83
+ <p class="text-gray-500 mb-1">Drag & drop your image here</p>
84
+ <p class="text-sm text-gray-400">or click to browse</p>
85
+ <input type="file" id="image-input" accept="image/*" class="hidden">
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ <div id="mask-controls" class="hidden">
91
+ <h2 class="text-lg font-medium text-gray-900 mb-3">Mark the Sticker</h2>
92
+ <div class="space-y-4">
93
+ <div>
94
+ <label class="block text-sm font-medium text-gray-700 mb-1">Brush Size</label>
95
+ <input type="range" min="1" max="50" value="15" class="brush-size-control" id="brush-size">
96
+ <div class="flex justify-between text-xs text-gray-500 mt-1">
97
+ <span>Small</span>
98
+ <span>Large</span>
99
+ </div>
100
+ </div>
101
+
102
+ <div class="flex space-x-3">
103
+ <button id="draw-btn" class="flex-1 bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition flex items-center justify-center">
104
+ <i class="fas fa-paint-brush mr-2"></i> Draw
105
+ </button>
106
+ <button id="erase-btn" class="flex-1 bg-gray-200 text-gray-700 py-2 px-4 rounded-md hover:bg-gray-300 transition flex items-center justify-center">
107
+ <i class="fas fa-eraser mr-2"></i> Erase
108
+ </button>
109
+ </div>
110
+
111
+ <div class="flex space-x-3">
112
+ <button id="clear-btn" class="flex-1 bg-gray-200 text-gray-700 py-2 px-4 rounded-md hover:bg-gray-300 transition">
113
+ Clear Mask
114
+ </button>
115
+ <button id="process-btn" class="flex-1 bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition">
116
+ Remove Sticker
117
+ </button>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <!-- Right Panel - Canvas -->
125
+ <div class="md:w-2/3 p-6">
126
+ <div class="canvas-container">
127
+ <div id="canvas-wrapper" class="relative">
128
+ <canvas id="image-canvas" class="max-w-full border border-gray-200 rounded-lg hidden"></canvas>
129
+ <canvas id="mask-canvas" class="absolute top-0 left-0 max-w-full border border-gray-200 rounded-lg hidden" style="opacity: 0.5;"></canvas>
130
+
131
+ <div id="dropzone-placeholder" class="flex items-center justify-center h-64 bg-gray-100 rounded-lg">
132
+ <div class="text-center p-6">
133
+ <i class="fas fa-image text-4xl text-gray-300 mb-3"></i>
134
+ <h3 class="text-lg font-medium text-gray-500">No image selected</h3>
135
+ <p class="text-gray-400 mt-1">Upload an image to get started</p>
136
+ </div>
137
+ </div>
138
+
139
+ <div id="processing-overlay" class="processing-overlay hidden">
140
+ <div class="spinner mb-4"></div>
141
+ <p class="text-xl font-medium mb-2">Processing Image</p>
142
+ <p class="text-sm text-gray-300">Removing sticker and reconstructing image...</p>
143
+ </div>
144
+ </div>
145
+
146
+ <div id="result-controls" class="mt-4 hidden">
147
+ <div class="flex justify-between">
148
+ <button id="download-btn" class="bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 transition flex items-center">
149
+ <i class="fas fa-download mr-2"></i> Download Result
150
+ </button>
151
+ <button id="reset-btn" class="bg-gray-200 text-gray-700 py-2 px-4 rounded-md hover:bg-gray-300 transition">
152
+ Start Over
153
+ </button>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ <div class="mt-12 bg-white rounded-xl shadow-lg overflow-hidden max-w-4xl mx-auto p-6">
162
+ <h2 class="text-xl font-bold text-gray-800 mb-4">How It Works</h2>
163
+ <div class="grid md:grid-cols-3 gap-6">
164
+ <div class="text-center">
165
+ <div class="bg-indigo-100 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
166
+ <i class="fas fa-upload text-indigo-600 text-2xl"></i>
167
+ </div>
168
+ <h3 class="font-medium text-gray-800 mb-2">1. Upload Image</h3>
169
+ <p class="text-gray-600 text-sm">Select an image containing the sticker or object you want to remove.</p>
170
+ </div>
171
+ <div class="text-center">
172
+ <div class="bg-indigo-100 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
173
+ <i class="fas fa-paint-brush text-indigo-600 text-2xl"></i>
174
+ </div>
175
+ <h3 class="font-medium text-gray-800 mb-2">2. Mark the Area</h3>
176
+ <p class="text-gray-600 text-sm">Use the brush tool to mark the exact area you want to remove.</p>
177
+ </div>
178
+ <div class="text-center">
179
+ <div class="bg-indigo-100 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
180
+ <i class="fas fa-magic text-indigo-600 text-2xl"></i>
181
+ </div>
182
+ <h3 class="font-medium text-gray-800 mb-2">3. Download Result</h3>
183
+ <p class="text-gray-600 text-sm">Our AI will seamlessly remove the marked area and reconstruct the image.</p>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <script>
190
+ document.addEventListener('DOMContentLoaded', function() {
191
+ // DOM Elements
192
+ const imageDropzone = document.getElementById('image-dropzone');
193
+ const imageInput = document.getElementById('image-input');
194
+ const dropzonePlaceholder = document.getElementById('dropzone-placeholder');
195
+ const imageCanvas = document.getElementById('image-canvas');
196
+ const maskCanvas = document.getElementById('mask-canvas');
197
+ const maskControls = document.getElementById('mask-controls');
198
+ const resultControls = document.getElementById('result-controls');
199
+ const processingOverlay = document.getElementById('processing-overlay');
200
+ const drawBtn = document.getElementById('draw-btn');
201
+ const eraseBtn = document.getElementById('erase-btn');
202
+ const clearBtn = document.getElementById('clear-btn');
203
+ const processBtn = document.getElementById('process-btn');
204
+ const downloadBtn = document.getElementById('download-btn');
205
+ const resetBtn = document.getElementById('reset-btn');
206
+ const brushSizeControl = document.getElementById('brush-size');
207
+
208
+ // Canvas contexts
209
+ const imageCtx = imageCanvas.getContext('2d');
210
+ const maskCtx = maskCanvas.getContext('2d');
211
+
212
+ // State variables
213
+ let isDrawing = false;
214
+ let isErasing = false;
215
+ let brushSize = 15;
216
+ let originalImage = null;
217
+
218
+ // Event Listeners
219
+ imageDropzone.addEventListener('click', () => imageInput.click());
220
+ imageInput.addEventListener('change', handleImageUpload);
221
+
222
+ // Drag and drop events
223
+ imageDropzone.addEventListener('dragover', (e) => {
224
+ e.preventDefault();
225
+ imageDropzone.classList.add('active');
226
+ });
227
+
228
+ imageDropzone.addEventListener('dragleave', () => {
229
+ imageDropzone.classList.remove('active');
230
+ });
231
+
232
+ imageDropzone.addEventListener('drop', (e) => {
233
+ e.preventDefault();
234
+ imageDropzone.classList.remove('active');
235
+
236
+ if (e.dataTransfer.files.length) {
237
+ imageInput.files = e.dataTransfer.files;
238
+ handleImageUpload({ target: imageInput });
239
+ }
240
+ });
241
+
242
+ // Brush size control
243
+ brushSizeControl.addEventListener('input', () => {
244
+ brushSize = parseInt(brushSizeControl.value);
245
+ });
246
+
247
+ // Tool buttons
248
+ drawBtn.addEventListener('click', () => {
249
+ isErasing = false;
250
+ drawBtn.classList.remove('bg-gray-200', 'text-gray-700');
251
+ drawBtn.classList.add('bg-indigo-600', 'text-white');
252
+ eraseBtn.classList.remove('bg-indigo-600', 'text-white');
253
+ eraseBtn.classList.add('bg-gray-200', 'text-gray-700');
254
+ });
255
+
256
+ eraseBtn.addEventListener('click', () => {
257
+ isErasing = true;
258
+ eraseBtn.classList.remove('bg-gray-200', 'text-gray-700');
259
+ eraseBtn.classList.add('bg-indigo-600', 'text-white');
260
+ drawBtn.classList.remove('bg-indigo-600', 'text-white');
261
+ drawBtn.classList.add('bg-gray-200', 'text-gray-700');
262
+ });
263
+
264
+ clearBtn.addEventListener('click', () => {
265
+ maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height);
266
+ });
267
+
268
+ processBtn.addEventListener('click', processImage);
269
+ downloadBtn.addEventListener('click', downloadResult);
270
+ resetBtn.addEventListener('click', resetTool);
271
+
272
+ // Canvas drawing events
273
+ maskCanvas.addEventListener('mousedown', startDrawing);
274
+ maskCanvas.addEventListener('mousemove', draw);
275
+ maskCanvas.addEventListener('mouseup', stopDrawing);
276
+ maskCanvas.addEventListener('mouseout', stopDrawing);
277
+
278
+ // Touch events for mobile
279
+ maskCanvas.addEventListener('touchstart', handleTouchStart);
280
+ maskCanvas.addEventListener('touchmove', handleTouchMove);
281
+ maskCanvas.addEventListener('touchend', stopDrawing);
282
+
283
+ // Functions
284
+ function handleImageUpload(e) {
285
+ const file = e.target.files[0];
286
+ if (!file) return;
287
+
288
+ const reader = new FileReader();
289
+ reader.onload = function(event) {
290
+ originalImage = new Image();
291
+ originalImage.onload = function() {
292
+ setupCanvases(originalImage);
293
+ dropzonePlaceholder.classList.add('hidden');
294
+ imageCanvas.classList.remove('hidden');
295
+ maskCanvas.classList.remove('hidden');
296
+ maskControls.classList.remove('hidden');
297
+ };
298
+ originalImage.src = event.target.result;
299
+ };
300
+ reader.readAsDataURL(file);
301
+ }
302
+
303
+ function setupCanvases(image) {
304
+ const maxWidth = 800;
305
+ const maxHeight = 600;
306
+ let width = image.width;
307
+ let height = image.height;
308
+
309
+ // Scale down if necessary
310
+ if (width > maxWidth || height > maxHeight) {
311
+ const ratio = Math.min(maxWidth / width, maxHeight / height);
312
+ width = width * ratio;
313
+ height = height * ratio;
314
+ }
315
+
316
+ // Set canvas dimensions
317
+ imageCanvas.width = width;
318
+ imageCanvas.height = height;
319
+ maskCanvas.width = width;
320
+ maskCanvas.height = height;
321
+
322
+ // Draw the image
323
+ imageCtx.drawImage(image, 0, 0, width, height);
324
+
325
+ // Initialize mask canvas with transparent
326
+ maskCtx.clearRect(0, 0, width, height);
327
+ }
328
+
329
+ function startDrawing(e) {
330
+ isDrawing = true;
331
+ draw(e);
332
+ }
333
+
334
+ function draw(e) {
335
+ if (!isDrawing) return;
336
+
337
+ const rect = maskCanvas.getBoundingClientRect();
338
+ const x = (e.clientX || e.touches[0].clientX) - rect.left;
339
+ const y = (e.clientY || e.touches[0].clientY) - rect.top;
340
+
341
+ maskCtx.globalCompositeOperation = 'source-over';
342
+ maskCtx.fillStyle = isErasing ? 'rgba(0, 0, 0, 0)' : 'rgba(255, 0, 0, 0.5)';
343
+ maskCtx.beginPath();
344
+ maskCtx.arc(x, y, brushSize, 0, Math.PI * 2);
345
+ maskCtx.fill();
346
+ }
347
+
348
+ function handleTouchStart(e) {
349
+ e.preventDefault();
350
+ if (e.touches.length === 1) {
351
+ const touch = e.touches[0];
352
+ const mouseEvent = new MouseEvent('mousedown', {
353
+ clientX: touch.clientX,
354
+ clientY: touch.clientY
355
+ });
356
+ startDrawing(mouseEvent);
357
+ }
358
+ }
359
+
360
+ function handleTouchMove(e) {
361
+ e.preventDefault();
362
+ if (e.touches.length === 1) {
363
+ const touch = e.touches[0];
364
+ const mouseEvent = new MouseEvent('mousemove', {
365
+ clientX: touch.clientX,
366
+ clientY: touch.clientY
367
+ });
368
+ draw(mouseEvent);
369
+ }
370
+ }
371
+
372
+ function stopDrawing() {
373
+ isDrawing = false;
374
+ }
375
+
376
+ function processImage() {
377
+ processingOverlay.classList.remove('hidden');
378
+
379
+ // Simulate processing delay
380
+ setTimeout(() => {
381
+ processingOverlay.classList.add('hidden');
382
+ resultControls.classList.remove('hidden');
383
+
384
+ // In a real app, this would send the image data to a backend service
385
+ // that runs the actual OpenCV code
386
+ alert("In a real application, this would send the image to a backend service that uses OpenCV to remove the sticker. The demo simulates this process.");
387
+ }, 2000);
388
+ }
389
+
390
+ function downloadResult() {
391
+ // Create a temporary canvas with the result
392
+ const tempCanvas = document.createElement('canvas');
393
+ tempCanvas.width = imageCanvas.width;
394
+ tempCanvas.height = imageCanvas.height;
395
+ const tempCtx = tempCanvas.getContext('2d');
396
+
397
+ // Draw the original image
398
+ tempCtx.drawImage(imageCanvas, 0, 0);
399
+
400
+ // In a real app, this would apply the actual inpainting algorithm
401
+ // Here we just simulate it by blurring the masked area
402
+ const maskData = maskCtx.getImageData(0, 0, maskCanvas.width, maskCanvas.height).data;
403
+
404
+ tempCtx.save();
405
+ tempCtx.beginPath();
406
+
407
+ // Find all red pixels in the mask (our marked area)
408
+ for (let y = 0; y < maskCanvas.height; y++) {
409
+ for (let x = 0; x < maskCanvas.width; x++) {
410
+ const i = (y * maskCanvas.width + x) * 4;
411
+ if (maskData[i] > 200 && maskData[i+1] < 50 && maskData[i+2] < 50) {
412
+ tempCtx.rect(x, y, 1, 1);
413
+ }
414
+ }
415
+ }
416
+
417
+ tempCtx.clip();
418
+
419
+ // Apply a blur effect to simulate inpainting
420
+ tempCtx.filter = 'blur(8px)';
421
+ tempCtx.drawImage(imageCanvas, 0, 0);
422
+ tempCtx.filter = 'none';
423
+
424
+ tempCtx.restore();
425
+
426
+ // Download the result
427
+ const link = document.createElement('a');
428
+ link.download = 'sticker-removed.png';
429
+ link.href = tempCanvas.toDataURL('image/png');
430
+ link.click();
431
+ }
432
+
433
+ function resetTool() {
434
+ // Reset all elements to initial state
435
+ imageCanvas.classList.add('hidden');
436
+ maskCanvas.classList.add('hidden');
437
+ dropzonePlaceholder.classList.remove('hidden');
438
+ maskControls.classList.add('hidden');
439
+ resultControls.classList.add('hidden');
440
+
441
+ // Clear canvases
442
+ imageCtx.clearRect(0, 0, imageCanvas.width, imageCanvas.height);
443
+ maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height);
444
+
445
+ // Reset input
446
+ imageInput.value = '';
447
+ originalImage = null;
448
+
449
+ // Reset tools
450
+ isErasing = false;
451
+ drawBtn.classList.remove('bg-gray-200', 'text-gray-700');
452
+ drawBtn.classList.add('bg-indigo-600', 'text-white');
453
+ eraseBtn.classList.remove('bg-indigo-600', 'text-white');
454
+ eraseBtn.classList.add('bg-gray-200', 'text-gray-700');
455
+ }
456
+ });
457
+ </script>
458
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=6ee5ali/face2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
459
+ </html>