Spaces:
Sleeping
Sleeping
updated the system
Browse files- __pycache__/app.cpython-311.pyc +0 -0
- app.py +30 -26
- static/css/style.css +12 -6
- templates/index.html +119 -17
__pycache__/app.cpython-311.pyc
ADDED
Binary file (3.91 kB). View file
|
|
app.py
CHANGED
@@ -1,25 +1,18 @@
|
|
1 |
-
import
|
2 |
-
from flask import Flask, render_template, jsonify, request, redirect, url_for
|
3 |
from tensorflow.keras.models import load_model
|
4 |
-
import numpy as np
|
5 |
from numpy.random import randn
|
6 |
-
|
|
|
7 |
import base64
|
8 |
from io import BytesIO
|
9 |
|
10 |
app = Flask(__name__)
|
11 |
|
12 |
-
GENERATED_FOLDER = 'static/generated'
|
13 |
-
|
14 |
-
app.config['GENERATED_FOLDER'] = GENERATED_FOLDER
|
15 |
-
|
16 |
# Load your GAN model from the H5 file
|
17 |
model = load_model('gan.h5')
|
18 |
|
19 |
def generate_latent_points(latent_dim, n_samples):
|
20 |
-
# generate points in the latent space
|
21 |
x_input = randn(latent_dim * n_samples)
|
22 |
-
# reshape into a batch of inputs for the network
|
23 |
z_input = x_input.reshape(n_samples, latent_dim)
|
24 |
return z_input
|
25 |
|
@@ -27,38 +20,49 @@ def generate_images(model, latent_points):
|
|
27 |
generated_images = model.predict(latent_points)
|
28 |
return generated_images
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
41 |
buf = BytesIO()
|
42 |
fig.savefig(buf, format='png')
|
43 |
buf.seek(0)
|
44 |
-
|
45 |
-
|
46 |
return base64.b64encode(buf.read()).decode('utf-8')
|
47 |
|
48 |
@app.route('/')
|
49 |
def index():
|
50 |
-
return render_template('index.html')
|
|
|
|
|
51 |
|
52 |
@app.route('/generate', methods=['POST'])
|
53 |
def generate():
|
54 |
latent_dim = 100
|
55 |
-
n_samples = 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
latent_points = generate_latent_points(latent_dim, n_samples)
|
57 |
generated_images = generate_images(model, latent_points)
|
58 |
generated_images = (generated_images + 1) / 2.0
|
59 |
-
img_data = plot_generated(generated_images,
|
60 |
|
61 |
return jsonify({'success': True, 'generated_image': img_data})
|
62 |
|
|
|
63 |
if __name__ == '__main__':
|
64 |
app.run(debug=True)
|
|
|
1 |
+
from flask import Flask, render_template, request, jsonify
|
|
|
2 |
from tensorflow.keras.models import load_model
|
|
|
3 |
from numpy.random import randn
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import numpy as np
|
6 |
import base64
|
7 |
from io import BytesIO
|
8 |
|
9 |
app = Flask(__name__)
|
10 |
|
|
|
|
|
|
|
|
|
11 |
# Load your GAN model from the H5 file
|
12 |
model = load_model('gan.h5')
|
13 |
|
14 |
def generate_latent_points(latent_dim, n_samples):
|
|
|
15 |
x_input = randn(latent_dim * n_samples)
|
|
|
16 |
z_input = x_input.reshape(n_samples, latent_dim)
|
17 |
return z_input
|
18 |
|
|
|
20 |
generated_images = model.predict(latent_points)
|
21 |
return generated_images
|
22 |
|
23 |
+
def plot_generated(examples, n_rows, n_cols, image_size=(80, 80)):
|
24 |
+
fig, axes = plt.subplots(n_rows, n_cols, figsize=(15, 10))
|
25 |
+
|
26 |
+
for i in range(n_rows):
|
27 |
+
for j in range(n_cols):
|
28 |
+
index = i * n_cols + j
|
29 |
+
if index < len(examples):
|
30 |
+
axes[i, j].axis('off')
|
31 |
+
axes[i, j].imshow(examples[index, :, :])
|
32 |
+
else:
|
33 |
+
axes[i, j].axis('off')
|
34 |
+
|
35 |
buf = BytesIO()
|
36 |
fig.savefig(buf, format='png')
|
37 |
buf.seek(0)
|
38 |
+
plt.close(fig)
|
39 |
+
|
40 |
return base64.b64encode(buf.read()).decode('utf-8')
|
41 |
|
42 |
@app.route('/')
|
43 |
def index():
|
44 |
+
return render_template('index.html')
|
45 |
+
|
46 |
+
import math
|
47 |
|
48 |
@app.route('/generate', methods=['POST'])
|
49 |
def generate():
|
50 |
latent_dim = 100
|
51 |
+
n_samples = max(int(request.form.get('n_samples', 4)), 1)
|
52 |
+
|
53 |
+
# Calculate the number of rows dynamically based on the square root of n_samples
|
54 |
+
n_rows = max(int(math.sqrt(n_samples)), 1)
|
55 |
+
|
56 |
+
# Calculate the number of columns based on the number of rows
|
57 |
+
n_cols = (n_samples + n_rows - 1) // n_rows
|
58 |
+
|
59 |
latent_points = generate_latent_points(latent_dim, n_samples)
|
60 |
generated_images = generate_images(model, latent_points)
|
61 |
generated_images = (generated_images + 1) / 2.0
|
62 |
+
img_data = plot_generated(generated_images, n_rows, n_cols)
|
63 |
|
64 |
return jsonify({'success': True, 'generated_image': img_data})
|
65 |
|
66 |
+
|
67 |
if __name__ == '__main__':
|
68 |
app.run(debug=True)
|
static/css/style.css
CHANGED
@@ -183,10 +183,13 @@ textarea {
|
|
183 |
|
184 |
input {
|
185 |
height: 40px;
|
186 |
-
|
|
|
|
|
187 |
outline: none;
|
188 |
line-height: normal;
|
189 |
font-size: 14px;
|
|
|
190 |
}
|
191 |
|
192 |
input[type="submit"] {
|
@@ -2735,7 +2738,7 @@ blockquote {
|
|
2735 |
max-height: 400px;
|
2736 |
width: 100%;
|
2737 |
padding: 25px;
|
2738 |
-
background:
|
2739 |
box-shadow: 0 8px 32px 0 rgba(154, 154, 154, 0.37);
|
2740 |
backdrop-filter: blur(2.2px);
|
2741 |
-webkit-backdrop-filter: blur(2.2px);
|
@@ -2765,7 +2768,7 @@ blockquote {
|
|
2765 |
align-items: center;
|
2766 |
justify-content: center;
|
2767 |
flex-direction: column;
|
2768 |
-
padding: 0px
|
2769 |
}
|
2770 |
|
2771 |
.drag-area:hover {
|
@@ -2914,7 +2917,8 @@ button {
|
|
2914 |
font-weight: 400;
|
2915 |
position: relative;
|
2916 |
padding: 12px 35px;
|
2917 |
-
background: linear-gradient(45deg, #8B5F8B, #
|
|
|
2918 |
/* Violet Gradient */
|
2919 |
font-size: 17px;
|
2920 |
font-weight: 500;
|
@@ -2993,9 +2997,9 @@ button {
|
|
2993 |
}
|
2994 |
|
2995 |
.uploadbutton:hover {
|
2996 |
-
border: 2px solid #
|
2997 |
background: #f5f5f5;
|
2998 |
-
color: #
|
2999 |
transition: all .3s ease-in-out;
|
3000 |
}
|
3001 |
|
@@ -3063,6 +3067,8 @@ button {
|
|
3063 |
margin-top: 15px;
|
3064 |
display: flex;
|
3065 |
justify-content: center;
|
|
|
|
|
3066 |
}
|
3067 |
|
3068 |
input #file-input {
|
|
|
183 |
|
184 |
input {
|
185 |
height: 40px;
|
186 |
+
text-align: center;
|
187 |
+
width: 70px;
|
188 |
+
margin: 10px 0 10px 0;
|
189 |
outline: none;
|
190 |
line-height: normal;
|
191 |
font-size: 14px;
|
192 |
+
border-radius: 8px;
|
193 |
}
|
194 |
|
195 |
input[type="submit"] {
|
|
|
2738 |
max-height: 400px;
|
2739 |
width: 100%;
|
2740 |
padding: 25px;
|
2741 |
+
background: rgba(246, 145, 255, 0.103);
|
2742 |
box-shadow: 0 8px 32px 0 rgba(154, 154, 154, 0.37);
|
2743 |
backdrop-filter: blur(2.2px);
|
2744 |
-webkit-backdrop-filter: blur(2.2px);
|
|
|
2768 |
align-items: center;
|
2769 |
justify-content: center;
|
2770 |
flex-direction: column;
|
2771 |
+
padding: 0px 0px;
|
2772 |
}
|
2773 |
|
2774 |
.drag-area:hover {
|
|
|
2917 |
font-weight: 400;
|
2918 |
position: relative;
|
2919 |
padding: 12px 35px;
|
2920 |
+
background: linear-gradient(45deg, #8B5F8B, #9400d3e3);
|
2921 |
+
;
|
2922 |
/* Violet Gradient */
|
2923 |
font-size: 17px;
|
2924 |
font-weight: 500;
|
|
|
2997 |
}
|
2998 |
|
2999 |
.uploadbutton:hover {
|
3000 |
+
border: 2px solid #9400D3;
|
3001 |
background: #f5f5f5;
|
3002 |
+
color: #9400D3;
|
3003 |
transition: all .3s ease-in-out;
|
3004 |
}
|
3005 |
|
|
|
3067 |
margin-top: 15px;
|
3068 |
display: flex;
|
3069 |
justify-content: center;
|
3070 |
+
align-items: center;
|
3071 |
+
flex-direction: column;
|
3072 |
}
|
3073 |
|
3074 |
input #file-input {
|
templates/index.html
CHANGED
@@ -128,9 +128,8 @@
|
|
128 |
}
|
129 |
|
130 |
#generated-image-container img {
|
131 |
-
width: 250px;
|
132 |
height: 250px;
|
133 |
-
padding:
|
134 |
}
|
135 |
|
136 |
.loaderx {
|
@@ -326,9 +325,79 @@
|
|
326 |
}
|
327 |
|
328 |
.disabled-button {
|
329 |
-
background
|
330 |
-
|
331 |
cursor: not-allowed;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
332 |
}
|
333 |
</style>
|
334 |
</head>
|
@@ -354,10 +423,11 @@
|
|
354 |
<!-- Banner Content -->
|
355 |
<div id="banner-content" class="row clearfix">
|
356 |
<!-- Left column -->
|
357 |
-
<
|
358 |
-
|
|
|
359 |
<div class="col-lg-3 wow bounceInUp" data-wow-offset="2" data-wow-duration="1.5s" data-wow-delay="0.2s">
|
360 |
-
<h1>Welcome to
|
361 |
<h2>Our cutting-edge graphics ensure that your FIFA player avatar looks as lifelike as possible, bringing an unparalleled level of realism to your virtual soccer experience.</h2>
|
362 |
</div>
|
363 |
<!-- right (wider) -->
|
@@ -379,13 +449,15 @@
|
|
379 |
<circle class="loader-ring loader-ring-c" cx="85" cy="120" r="70" fill="none" stroke="#000" stroke-width="20" stroke-dasharray="0 440" stroke-linecap="round"></circle>
|
380 |
<circle class="loader-ring loader-ring-d" cx="155" cy="120" r="70" fill="none" stroke="#000" stroke-width="20" stroke-dasharray="0 440" stroke-linecap="round"></circle>
|
381 |
</svg></div>
|
382 |
-
<p id="instructions">ⓘ Click the button to generate your FiFa Player Avatar. Generated images will
|
383 |
|
384 |
</div>
|
385 |
</div>
|
386 |
<div class="buttondiv">
|
387 |
-
<
|
388 |
-
|
|
|
|
|
389 |
<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 784.11 815.53" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" version="1.1" xml:space="preserve"
|
390 |
xmlns="http://www.w3.org/2000/svg">
|
391 |
<defs>
|
@@ -494,12 +566,22 @@
|
|
494 |
</div>
|
495 |
<!--End of Row-->
|
496 |
</header>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
</div>
|
498 |
</div>
|
499 |
</div>
|
500 |
|
501 |
<!-- index_ajax.html -->
|
502 |
-
|
503 |
<script>
|
504 |
function handleGenerateClick() {
|
505 |
// Get the generated image container
|
@@ -512,6 +594,9 @@
|
|
512 |
generateButton.disabled = true;
|
513 |
generateButton.classList.add("disabled-button");
|
514 |
|
|
|
|
|
|
|
515 |
// Hide the generated image
|
516 |
generatedImageContainer.style.display = "none";
|
517 |
|
@@ -525,12 +610,20 @@
|
|
525 |
// Make an AJAX request to update the generated image
|
526 |
fetch("/generate", {
|
527 |
method: "POST",
|
|
|
|
|
|
|
528 |
})
|
529 |
.then(response => response.json())
|
530 |
.then(data => {
|
531 |
if (data.success) {
|
532 |
// Update the generated image directly
|
533 |
-
generatedImageContainer.innerHTML = '<img src="data:image/png;base64,' + data.generated_image + '" alt="Generated Image">';
|
|
|
|
|
|
|
|
|
|
|
534 |
} else {
|
535 |
// Handle error if needed
|
536 |
console.error("Image generation failed");
|
@@ -541,10 +634,6 @@
|
|
541 |
|
542 |
// Show the generated image
|
543 |
generatedImageContainer.style.display = "block";
|
544 |
-
|
545 |
-
// Enable the button and remove the disabled style
|
546 |
-
generateButton.disabled = false;
|
547 |
-
generateButton.classList.remove("disabled-button");
|
548 |
})
|
549 |
.catch(error => {
|
550 |
// Handle error if needed
|
@@ -554,11 +643,24 @@
|
|
554 |
// Show the generated image even in case of an error
|
555 |
generatedImageContainer.style.display = "block";
|
556 |
|
557 |
-
// Enable the button
|
558 |
generateButton.disabled = false;
|
559 |
generateButton.classList.remove("disabled-button");
|
|
|
560 |
});
|
561 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
562 |
</script>
|
563 |
|
564 |
|
|
|
128 |
}
|
129 |
|
130 |
#generated-image-container img {
|
|
|
131 |
height: 250px;
|
132 |
+
padding: 20px 0px;
|
133 |
}
|
134 |
|
135 |
.loaderx {
|
|
|
325 |
}
|
326 |
|
327 |
.disabled-button {
|
328 |
+
background: linear-gradient(45deg, #6b486b, #7100a1);
|
329 |
+
opacity: 0.5;
|
330 |
cursor: not-allowed;
|
331 |
+
box-shadow: 0 0 0 #7a65878c;
|
332 |
+
pointer-events: none;
|
333 |
+
}
|
334 |
+
|
335 |
+
.zoom-modal {
|
336 |
+
display: none;
|
337 |
+
position: fixed;
|
338 |
+
top: 0;
|
339 |
+
left: 0;
|
340 |
+
width: 100%;
|
341 |
+
height: 100%;
|
342 |
+
background: rgba(0, 0, 0, 0.8);
|
343 |
+
justify-content: center;
|
344 |
+
align-items: center;
|
345 |
+
}
|
346 |
+
|
347 |
+
.zoom-content {
|
348 |
+
max-width: 80%;
|
349 |
+
max-height: 80%;
|
350 |
+
text-align: center;
|
351 |
+
/* Center the content horizontally */
|
352 |
+
position: relative;
|
353 |
+
}
|
354 |
+
|
355 |
+
.zoom-image {
|
356 |
+
position: relative;
|
357 |
+
max-width: 40%;
|
358 |
+
max-height: 40%;
|
359 |
+
margin: 0 auto;
|
360 |
+
/* Center the image horizontally */
|
361 |
+
display: block;
|
362 |
+
/* Remove default inline styling */
|
363 |
+
border-radius: 10px;
|
364 |
+
}
|
365 |
+
|
366 |
+
.image-container {
|
367 |
+
position: relative;
|
368 |
+
}
|
369 |
+
|
370 |
+
.exit-modal-button-top-right {
|
371 |
+
position: sticky;
|
372 |
+
right: 0;
|
373 |
+
left: 67%;
|
374 |
+
z-index: 1;
|
375 |
+
background-color: #de2d2d9e;
|
376 |
+
color: #ffffff;
|
377 |
+
border: none;
|
378 |
+
padding: 5px 10px;
|
379 |
+
cursor: pointer;
|
380 |
+
border-radius: 5px 5px 5px 0px;
|
381 |
+
}
|
382 |
+
|
383 |
+
.label {
|
384 |
+
display: block;
|
385 |
+
/* Display the label as a block to force it on top */
|
386 |
+
margin-bottom: 10px;
|
387 |
+
/* Add some spacing between label and input/button */
|
388 |
+
}
|
389 |
+
|
390 |
+
.input-button-container {
|
391 |
+
display: inline-block;
|
392 |
+
/* Display the input and button on the same line */
|
393 |
+
}
|
394 |
+
|
395 |
+
.footer {
|
396 |
+
padding: 10px;
|
397 |
+
text-align: center;
|
398 |
+
position: sticky;
|
399 |
+
bottom: 0;
|
400 |
+
width: 100%;
|
401 |
}
|
402 |
</style>
|
403 |
</head>
|
|
|
423 |
<!-- Banner Content -->
|
424 |
<div id="banner-content" class="row clearfix">
|
425 |
<!-- Left column -->
|
426 |
+
<h2>
|
427 |
+
<br><br>
|
428 |
+
</h2>
|
429 |
<div class="col-lg-3 wow bounceInUp" data-wow-offset="2" data-wow-duration="1.5s" data-wow-delay="0.2s">
|
430 |
+
<h1>Welcome to<br> <span class="easytext">FIFA Player Avatar</span> Generator!</h1>
|
431 |
<h2>Our cutting-edge graphics ensure that your FIFA player avatar looks as lifelike as possible, bringing an unparalleled level of realism to your virtual soccer experience.</h2>
|
432 |
</div>
|
433 |
<!-- right (wider) -->
|
|
|
449 |
<circle class="loader-ring loader-ring-c" cx="85" cy="120" r="70" fill="none" stroke="#000" stroke-width="20" stroke-dasharray="0 440" stroke-linecap="round"></circle>
|
450 |
<circle class="loader-ring loader-ring-d" cx="155" cy="120" r="70" fill="none" stroke="#000" stroke-width="20" stroke-dasharray="0 440" stroke-linecap="round"></circle>
|
451 |
</svg></div>
|
452 |
+
<p id="instructions">ⓘ Click the button to generate your FiFa Player Avatar. Generated images will shown here, you can click the picture to zoom.</p>
|
453 |
|
454 |
</div>
|
455 |
</div>
|
456 |
<div class="buttondiv">
|
457 |
+
<label for="n_samples">Choose or enter the desired number of samples (4-20):</label>
|
458 |
+
<input type="number" id="n_samples" name="n_samples" value="4" min="4" max="20">
|
459 |
+
<button class="uploadbutton wow bounceInUp" data-wow-offset="3" data-wow-duration="1.5s" data-wow-delay="0.5s" type="submit" value="Upload" onclick="handleGenerateClick()">Generate
|
460 |
+
<div class="star-1">
|
461 |
<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 784.11 815.53" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" version="1.1" xml:space="preserve"
|
462 |
xmlns="http://www.w3.org/2000/svg">
|
463 |
<defs>
|
|
|
566 |
</div>
|
567 |
<!--End of Row-->
|
568 |
</header>
|
569 |
+
<div class="footer wow bounceInUp" data-wow-offset="3" data-wow-duration="2s" data-wow-delay="0.5s">
|
570 |
+
<p>Developed by Dave Fagarita | Jimuel Servandil | Jannica Mae Magno | Jeziah Lois Catanus</p>
|
571 |
+
</div>
|
572 |
+
</div>
|
573 |
+
</div>
|
574 |
+
</div>
|
575 |
+
<div id="zoomModal" class="zoom-modal">
|
576 |
+
<div class="zoom-content">
|
577 |
+
<div id="zoomedImageContainer" class="image-container">
|
578 |
+
<button class="exit-modal-button-top-right" onclick="closeZoomModal()">x</button>
|
579 |
+
<img id="zoomedImage" class="zoom-image" alt="Zoomed Image">
|
580 |
</div>
|
581 |
</div>
|
582 |
</div>
|
583 |
|
584 |
<!-- index_ajax.html -->
|
|
|
585 |
<script>
|
586 |
function handleGenerateClick() {
|
587 |
// Get the generated image container
|
|
|
594 |
generateButton.disabled = true;
|
595 |
generateButton.classList.add("disabled-button");
|
596 |
|
597 |
+
// Change the button text to "Generating..."
|
598 |
+
generateButton.innerText = "Generating...";
|
599 |
+
|
600 |
// Hide the generated image
|
601 |
generatedImageContainer.style.display = "none";
|
602 |
|
|
|
610 |
// Make an AJAX request to update the generated image
|
611 |
fetch("/generate", {
|
612 |
method: "POST",
|
613 |
+
body: new URLSearchParams({
|
614 |
+
n_samples: document.querySelector("input[name='n_samples']").value,
|
615 |
+
}),
|
616 |
})
|
617 |
.then(response => response.json())
|
618 |
.then(data => {
|
619 |
if (data.success) {
|
620 |
// Update the generated image directly
|
621 |
+
generatedImageContainer.innerHTML = '<img src="data:image/png;base64,' + data.generated_image + '" alt="Generated Image" onclick="openZoomModal(this)">';
|
622 |
+
|
623 |
+
// Enable the button, remove the disabled style, and restore the original text
|
624 |
+
generateButton.disabled = false;
|
625 |
+
generateButton.classList.remove("disabled-button");
|
626 |
+
generateButton.innerText = "Generate";
|
627 |
} else {
|
628 |
// Handle error if needed
|
629 |
console.error("Image generation failed");
|
|
|
634 |
|
635 |
// Show the generated image
|
636 |
generatedImageContainer.style.display = "block";
|
|
|
|
|
|
|
|
|
637 |
})
|
638 |
.catch(error => {
|
639 |
// Handle error if needed
|
|
|
643 |
// Show the generated image even in case of an error
|
644 |
generatedImageContainer.style.display = "block";
|
645 |
|
646 |
+
// Enable the button, remove the disabled style, and restore the original text
|
647 |
generateButton.disabled = false;
|
648 |
generateButton.classList.remove("disabled-button");
|
649 |
+
generateButton.innerText = "Generate";
|
650 |
});
|
651 |
}
|
652 |
+
|
653 |
+
// Function to open the zoom modal
|
654 |
+
function openZoomModal(imageElement) {
|
655 |
+
var zoomedImage = document.getElementById("zoomedImage");
|
656 |
+
zoomedImage.src = imageElement.src;
|
657 |
+
document.getElementById("zoomModal").style.display = "flex";
|
658 |
+
}
|
659 |
+
|
660 |
+
// Function to close the zoom modal
|
661 |
+
function closeZoomModal() {
|
662 |
+
document.getElementById("zoomModal").style.display = "none";
|
663 |
+
}
|
664 |
</script>
|
665 |
|
666 |
|