mirror of
https://github.com/Doctorado-ML/beflask.git
synced 2025-08-17 16:15:51 +00:00
solve report and compare
This commit is contained in:
BIN
app/app.db
BIN
app/app.db
Binary file not shown.
@@ -17,10 +17,3 @@ class Config(object):
|
|||||||
"DATABASE_URL"
|
"DATABASE_URL"
|
||||||
) or "sqlite:///" + os.path.join(basedir, "app.db")
|
) or "sqlite:///" + os.path.join(basedir, "app.db")
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def save():
|
|
||||||
with open(dotenv_file, "w") as f:
|
|
||||||
f.write("FRAMEWORK=" + Config.FRAMEWORK + "\n")
|
|
||||||
f.write("OUTPUT=" + Config.OUTPUT + "\n")
|
|
||||||
f.write("COMPARE=" + str(Config.COMPARE) + "\n")
|
|
||||||
|
@@ -7,6 +7,7 @@ from flask_login import current_user
|
|||||||
from flask import Blueprint, current_app, send_file
|
from flask import Blueprint, current_app, send_file
|
||||||
from flask import render_template, current_app, request, redirect, url_for
|
from flask import render_template, current_app, request, redirect, url_for
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
|
from ..config import Config
|
||||||
|
|
||||||
# import shutil
|
# import shutil
|
||||||
# import xlsxwriter
|
# import xlsxwriter
|
||||||
@@ -15,6 +16,25 @@ from flask_login import login_required
|
|||||||
results = Blueprint("results", __name__, template_folder="templates")
|
results = Blueprint("results", __name__, template_folder="templates")
|
||||||
|
|
||||||
|
|
||||||
|
class AjaxResponse:
|
||||||
|
def __init__(self, success, file_name, code=200):
|
||||||
|
self.success = success
|
||||||
|
self.file_name = file_name
|
||||||
|
self.code = code
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return (
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"success": self.success,
|
||||||
|
"file": self.file_name,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
self.code,
|
||||||
|
{"ContentType": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@results.route("/select")
|
@results.route("/select")
|
||||||
@login_required
|
@login_required
|
||||||
def select(compare="False"):
|
def select(compare="False"):
|
||||||
@@ -63,6 +83,13 @@ def best(file_name):
|
|||||||
return render_template("datasets.html", datasets=datos)
|
return render_template("datasets.html", datasets=datos)
|
||||||
|
|
||||||
|
|
||||||
|
@results.route("/set_compare", methods=["POST"])
|
||||||
|
def set_compare():
|
||||||
|
compare = request.json["compare"]
|
||||||
|
current_app.config.update(COMPARE=compare)
|
||||||
|
return AjaxResponse(True, "Ok").to_string()
|
||||||
|
|
||||||
|
|
||||||
@results.route("/report/<file_name>")
|
@results.route("/report/<file_name>")
|
||||||
@login_required
|
@login_required
|
||||||
def report(file_name):
|
def report(file_name):
|
||||||
@@ -70,17 +97,14 @@ def report(file_name):
|
|||||||
with open(os.path.join(Folders.results, file_name)) as f:
|
with open(os.path.join(Folders.results, file_name)) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
try:
|
try:
|
||||||
compare = current_app.config["COMPARE"]
|
summary = process_data(file_name, current_app.config["COMPARE"], data)
|
||||||
summary = process_data(file_name, compare, data)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return render_template("error.html", message=str(e), compare=compare)
|
return render_template("error.html", message=str(e))
|
||||||
return render_template(
|
return render_template(
|
||||||
"report.html",
|
"report.html",
|
||||||
data=data,
|
data=data,
|
||||||
file=file_name,
|
file=file_name,
|
||||||
summary=summary,
|
summary=summary,
|
||||||
framework=current_app.config["FRAMEWORK"],
|
|
||||||
back=back,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
110
app/results/templates/_table_report.html
Normal file
110
app/results/templates/_table_report.html
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<div id="app">
|
||||||
|
<section class="section">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div>
|
||||||
|
<table class="table table-bordered bg-light">
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-info text-white">
|
||||||
|
<th class="text-center">Platform</th>
|
||||||
|
<th class="text-center">Model</th>
|
||||||
|
<th class="text-center">Date</th>
|
||||||
|
<th class="text-center">Time</th>
|
||||||
|
{% if data.duration > 7200 %}
|
||||||
|
{% set unit = "h" %}
|
||||||
|
{% set divider = 3600 %}
|
||||||
|
{% else %}
|
||||||
|
{% set unit = "min" %}
|
||||||
|
{% set divider = 60 %}
|
||||||
|
{% endif %}
|
||||||
|
<th class="text-center">Duration ({{ unit }})</th>
|
||||||
|
<th class="text-center">Stratified</th>
|
||||||
|
<th class="text-center">Discretized</th>
|
||||||
|
<th class="text-center"># Folds</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">{{ data.platform }}</th>
|
||||||
|
<th class="text-center">{{ data.model }} {{ data.version }}</th>
|
||||||
|
<th class="text-center">{{ data.date }}</th>
|
||||||
|
<th class="text-center">{{ data.time }}</th>
|
||||||
|
<th class="text-center">{{ "%.2f" % (data.duration/divider) }}</th>
|
||||||
|
<th class="text-center">{{ data.stratified }}</th>
|
||||||
|
<th class="text-center">{{ data.discretized }}</th>
|
||||||
|
<th class="text-center">{{ data.folds }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center bg-info text-white">Language</th>
|
||||||
|
<th class="text-center" colspan=3>{{ data.language }} {{ data.language_version }}</th>
|
||||||
|
<th class="text-center bg-info text-white">Seeds</th>
|
||||||
|
<th class="text-center" colspan=6>{{ data.seeds }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
<div>
|
||||||
|
<button class="{{ button }}" onclick="excelFile()">
|
||||||
|
<i class="mdi mdi-file-excel"></i> Excel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<table id="report-table"
|
||||||
|
class="table table-striped table-hover table-bordered bg-light">
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-primary text-white">
|
||||||
|
<th class="text-center">Dataset</th>
|
||||||
|
<th class="text-center">Samples</th>
|
||||||
|
<th class="text-center">Features</th>
|
||||||
|
<th class="text-center">Classes</th>
|
||||||
|
<th class="text-center">Nodes</th>
|
||||||
|
<th class="text-center">{{ data.score_name|capitalize }}</th>
|
||||||
|
<th class="text-center">Time</th>
|
||||||
|
<th class="text-center">hyperparameters</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in data.results %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.dataset }}</td>
|
||||||
|
<td class="{{ right }}">{{ '{:,}'.format(item.samples) }}</td>
|
||||||
|
<td class="{{ right }}">{{"%d" % item.features}}</td>
|
||||||
|
<td class="{{ right }}">{{"%d" % item.classes}}</td>
|
||||||
|
<td class="{{ right }}">{{ '{:,.2f}'.format(item.nodes) }}</td>
|
||||||
|
<td class="{{ right }}">{{"%.6f±%.4f" % (item.score, item.score_std)}} {{ item.symbol|safe }}</td>
|
||||||
|
<td class="{{ right }}">{{"%.6f±%.4f" % (item.time, item.time_std)}}</td>
|
||||||
|
<td class="{{ center }}">{{ item.hyperparameters }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% if summary|length > 0 %}
|
||||||
|
<div class="col-4 col-lg-4">
|
||||||
|
<table class="table table-bordered bg-light">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center bg-primary text-white">Symbol</th>
|
||||||
|
<th class="text-center bg-primary text-white">Meaning</th>
|
||||||
|
<th class="text-center bg-primary text-white">Count</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for key, value in summary.items() %}
|
||||||
|
<tr>
|
||||||
|
<td class="{{ center }}">{{ key }}</td>
|
||||||
|
<td>{{ value[0] }}</td>
|
||||||
|
<td class={{ right }}>
|
||||||
|
{{ '{:,}'.format(value[1]) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<h7>
|
||||||
|
<b>
|
||||||
|
Total score: {{ "%.6f" % (data.results | sum(attribute="score") ) }}
|
||||||
|
</b>
|
||||||
|
</h7>
|
||||||
|
<h7>
|
||||||
|
Number of files: {{ data.results | length }}
|
||||||
|
</h7>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
@@ -41,11 +41,11 @@
|
|||||||
<td>
|
<td>
|
||||||
{% set file_best = "best_results_" ~ parts[1] ~ "_" ~ parts[2] ~ ".json" %}
|
{% set file_best = "best_results_" ~ parts[1] ~ "_" ~ parts[2] ~ ".json" %}
|
||||||
<button class="btn btn-primary btn-small"
|
<button class="btn btn-primary btn-small"
|
||||||
onclick="{{ url_for("results.report", file_name=file) }}">
|
onclick='location.href="{{ url_for("results.report", file_name=file) }}"'>
|
||||||
<i class="mdi mdi-table-eye"></i>
|
<i class="mdi mdi-table-eye"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary btn-small"
|
<button class="btn btn-primary btn-small"
|
||||||
onclick="{{ url_for("results.best", file_name=file_best) }}"
|
onclick='location.href="{{ url_for("results.best", file_name=file_best) }}"'
|
||||||
hidden="true"
|
hidden="true"
|
||||||
name="best_buttons">
|
name="best_buttons">
|
||||||
<i class="mdi mdi-star-circle-outline"></i>
|
<i class="mdi mdi-star-circle-outline"></i>
|
||||||
|
246
app/results/templates/error.html
Normal file
246
app/results/templates/error.html
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Error</title>
|
||||||
|
<style>@import url(https://fonts.googleapis.com/css?family=opensans:500);
|
||||||
|
body{
|
||||||
|
background: #33cc99;
|
||||||
|
color:#fff;
|
||||||
|
font-family: 'Open Sans', sans-serif;
|
||||||
|
max-height:700px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.c{
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width:80%;
|
||||||
|
margin:100px auto;
|
||||||
|
}
|
||||||
|
._404{
|
||||||
|
font-size: 220px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
z-index: 2;
|
||||||
|
height: 250px;
|
||||||
|
letter-spacing: 15px;
|
||||||
|
}
|
||||||
|
._1{
|
||||||
|
text-align:center;
|
||||||
|
display:block;
|
||||||
|
position:relative;
|
||||||
|
letter-spacing: 12px;
|
||||||
|
font-size: 4em;
|
||||||
|
line-height: 80%;
|
||||||
|
}
|
||||||
|
._2{
|
||||||
|
text-align:center;
|
||||||
|
display:block;
|
||||||
|
position: relative;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.text{
|
||||||
|
font-size: 70px;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 19px 0px 0px 0px;
|
||||||
|
/* top: 256.301px; */
|
||||||
|
z-index: 3;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 1.2em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.btn{
|
||||||
|
background-color: rgb( 255, 255, 255 );
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 358px;
|
||||||
|
padding: 5px;
|
||||||
|
z-index: 5;
|
||||||
|
font-size: 25px;
|
||||||
|
margin:0 auto;
|
||||||
|
color:#33cc99;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 10px
|
||||||
|
}
|
||||||
|
.right{
|
||||||
|
float:right;
|
||||||
|
width:60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr{
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
border-top: 5px solid #fff;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0px auto;
|
||||||
|
width: 420px;
|
||||||
|
height:10px;
|
||||||
|
z-index: -10;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr:after {
|
||||||
|
content: "\2022";
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -0.75em;
|
||||||
|
font-size: 2em;
|
||||||
|
padding: 0 0.2em;
|
||||||
|
background: #33cc99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cloud {
|
||||||
|
width: 350px; height: 120px;
|
||||||
|
|
||||||
|
background: #FFF;
|
||||||
|
background: linear-gradient(top, #FFF 100%);
|
||||||
|
background: -webkit-linear-gradient(top, #FFF 100%);
|
||||||
|
background: -moz-linear-gradient(top, #FFF 100%);
|
||||||
|
background: -ms-linear-gradient(top, #FFF 100%);
|
||||||
|
background: -o-linear-gradient(top, #FFF 100%);
|
||||||
|
|
||||||
|
border-radius: 100px;
|
||||||
|
-webkit-border-radius: 100px;
|
||||||
|
-moz-border-radius: 100px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
margin: 120px auto 20px;
|
||||||
|
z-index:-1;
|
||||||
|
transition: ease 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cloud:after, .cloud:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
background: #FFF;
|
||||||
|
z-index: -1
|
||||||
|
}
|
||||||
|
|
||||||
|
.cloud:after {
|
||||||
|
width: 100px; height: 100px;
|
||||||
|
top: -50px; left: 50px;
|
||||||
|
|
||||||
|
border-radius: 100px;
|
||||||
|
-webkit-border-radius: 100px;
|
||||||
|
-moz-border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cloud:before {
|
||||||
|
width: 180px; height: 180px;
|
||||||
|
top: -90px; right: 50px;
|
||||||
|
|
||||||
|
border-radius: 200px;
|
||||||
|
-webkit-border-radius: 200px;
|
||||||
|
-moz-border-radius: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x1 {
|
||||||
|
top:-50px;
|
||||||
|
left:100px;
|
||||||
|
-webkit-transform: scale(0.3);
|
||||||
|
-moz-transform: scale(0.3);
|
||||||
|
transform: scale(0.3);
|
||||||
|
opacity: 0.9;
|
||||||
|
-webkit-animation: moveclouds 15s linear infinite;
|
||||||
|
-moz-animation: moveclouds 15s linear infinite;
|
||||||
|
-o-animation: moveclouds 15s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x1_5{
|
||||||
|
top:-80px;
|
||||||
|
left:250px;
|
||||||
|
-webkit-transform: scale(0.3);
|
||||||
|
-moz-transform: scale(0.3);
|
||||||
|
transform: scale(0.3);
|
||||||
|
-webkit-animation: moveclouds 17s linear infinite;
|
||||||
|
-moz-animation: moveclouds 17s linear infinite;
|
||||||
|
-o-animation: moveclouds 17s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x2 {
|
||||||
|
left: 250px;
|
||||||
|
top:30px;
|
||||||
|
-webkit-transform: scale(0.6);
|
||||||
|
-moz-transform: scale(0.6);
|
||||||
|
transform: scale(0.6);
|
||||||
|
opacity: 0.6;
|
||||||
|
-webkit-animation: moveclouds 25s linear infinite;
|
||||||
|
-moz-animation: moveclouds 25s linear infinite;
|
||||||
|
-o-animation: moveclouds 25s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x3 {
|
||||||
|
left: 250px; bottom: -70px;
|
||||||
|
|
||||||
|
-webkit-transform: scale(0.6);
|
||||||
|
-moz-transform: scale(0.6);
|
||||||
|
transform: scale(0.6);
|
||||||
|
opacity: 0.8;
|
||||||
|
|
||||||
|
-webkit-animation: moveclouds 25s linear infinite;
|
||||||
|
-moz-animation: moveclouds 25s linear infinite;
|
||||||
|
-o-animation: moveclouds 25s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x4 {
|
||||||
|
left: 470px; botttom: 20px;
|
||||||
|
|
||||||
|
-webkit-transform: scale(0.75);
|
||||||
|
-moz-transform: scale(0.75);
|
||||||
|
transform: scale(0.75);
|
||||||
|
opacity: 0.75;
|
||||||
|
|
||||||
|
-webkit-animation: moveclouds 18s linear infinite;
|
||||||
|
-moz-animation: moveclouds 18s linear infinite;
|
||||||
|
-o-animation: moveclouds 18s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x5 {
|
||||||
|
left: 200px; top: 300px;
|
||||||
|
|
||||||
|
-webkit-transform: scale(0.5);
|
||||||
|
-moz-transform: scale(0.5);
|
||||||
|
transform: scale(0.5);
|
||||||
|
opacity: 0.8;
|
||||||
|
|
||||||
|
-webkit-animation: moveclouds 20s linear infinite;
|
||||||
|
-moz-animation: moveclouds 20s linear infinite;
|
||||||
|
-o-animation: moveclouds 20s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes moveclouds {
|
||||||
|
0% {margin-left: 1000px;}
|
||||||
|
100% {margin-left: -1000px;}
|
||||||
|
}
|
||||||
|
@-moz-keyframes moveclouds {
|
||||||
|
0% {margin-left: 1000px;}
|
||||||
|
100% {margin-left: -1000px;}
|
||||||
|
}
|
||||||
|
@-o-keyframes moveclouds {
|
||||||
|
0% {margin-left: 1000px;}
|
||||||
|
100% {margin-left: -1000px;}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="clouds">
|
||||||
|
<div class="cloud x1"></div>
|
||||||
|
<div class="cloud x1_5"></div>
|
||||||
|
<div class="cloud x2"></div>
|
||||||
|
<div class="cloud x3"></div>
|
||||||
|
<div class="cloud x4"></div>
|
||||||
|
<div class="cloud x5"></div>
|
||||||
|
</div>
|
||||||
|
<div class='c'>
|
||||||
|
<div class='_404'>Error</div>
|
||||||
|
<hr>
|
||||||
|
<div class='_1'>{{ message }}</div>
|
||||||
|
<!--<div class='_2'>WAS NOT FOUND</div>-->
|
||||||
|
<a class='btn' href='/'>Go Back</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
app/results/templates/report.html
Normal file
8
app/results/templates/report.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
{% include "_table_report.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block jscript %}
|
||||||
|
{{ super() }}
|
||||||
|
{#<script src="{{ url_for('static', filename="js/report.js") }}"></script>#}
|
||||||
|
{% endblock %}
|
@@ -40,8 +40,24 @@ $(document).ready(function () {
|
|||||||
$(document).ajaxStop(function () {
|
$(document).ajaxStop(function () {
|
||||||
$("body").removeClass("ajaxLoading");
|
$("body").removeClass("ajaxLoading");
|
||||||
});
|
});
|
||||||
$('#compare').change(function() {
|
$('#compare').change(function () {
|
||||||
|
$.ajax({
|
||||||
|
type:'POST',
|
||||||
|
url:'/results/set_compare',
|
||||||
|
data: JSON.stringify({"compare": $("#compare").is(":checked")}),
|
||||||
|
contentType: "application/json",
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data){
|
||||||
|
if (data.success) {
|
||||||
enable_disable_best_buttons();
|
enable_disable_best_buttons();
|
||||||
|
} else {
|
||||||
|
alert(data.file);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
||||||
|
alert(XMLHttpRequest.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
enable_disable_best_buttons();
|
enable_disable_best_buttons();
|
||||||
});
|
});
|
||||||
@@ -55,18 +71,7 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function showFile(selectedFile) {
|
function showFile(selectedFile) {
|
||||||
var form = $(
|
location.href = "/results/show/" + selectedFile;
|
||||||
'<form action="/show" method="post">' +
|
|
||||||
'<input type="hidden" name="selected-file" value="' +
|
|
||||||
selectedFile +
|
|
||||||
'" />' +
|
|
||||||
'<input type="hidden" name="compare" value=' +
|
|
||||||
$("#compare").is(":checked") +
|
|
||||||
" />" +
|
|
||||||
"</form>"
|
|
||||||
);
|
|
||||||
$("body").append(form);
|
|
||||||
form.submit();
|
|
||||||
}
|
}
|
||||||
function excel() {
|
function excel() {
|
||||||
var checkbox = document.getElementsByName("selected_files");
|
var checkbox = document.getElementsByName("selected_files");
|
||||||
|
Reference in New Issue
Block a user