Add a skip button for the seeding and a progress bar, to be styled
This commit is contained in:
parent
7d594df524
commit
42e9855a08
4 changed files with 226 additions and 172 deletions
199
index.html
199
index.html
|
@ -5781,6 +5781,14 @@ body { font-family: Arial; background-image: url('images/diamonds.png'); height:
|
|||
#seedpoolarea { display: none; }
|
||||
#seedpooldisplay { font-family: monospace; font-size: 1em; width: 640px; padding: 15px 5px; word-wrap: break-word; }
|
||||
.seedpoint { width: 6px; height: 6px; display: block; border-radius: 3px; background-color: #80CF80; position: absolute; z-index: 10; }
|
||||
|
||||
#seedSkipper { font-size: 11px; text-align: center; line-height: 14px;}
|
||||
#generate #mousemovelimit { font-size: 16px; color: #FFF; }
|
||||
#rightArea { float: right; width: 170px; }
|
||||
#progress-bar { width: 170px; background:#99c31b; position: relative; margin-bottom: 20px; }
|
||||
#progress-bar-percentage { background:#ff952d; padding: 3px 0px; text-align: center; height: 18px; }
|
||||
#progress-bar-percentage span { display: inline-block; position: absolute; width: 100%; left: 0; }
|
||||
|
||||
#generate { font-size: 13px; text-align: left; position: relative; padding: 20px; border: 1px solid #BFBFBF; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; }
|
||||
#generate span { padding: 5px 5px 0 5px; }
|
||||
#generatekeyinput { position: relative; z-index: 20; }
|
||||
|
@ -6099,6 +6107,17 @@ body { font-family: Arial; background-image: url('images/diamonds.png'); height:
|
|||
<span id="generatelabelkeypress">OR type some random characters into this textbox</span> <input type="text" id="generatekeyinput" onkeypress="ninja.seeder.seedKeyPress(event);" /><br />
|
||||
<div id="seedpooldisplay"></div>
|
||||
|
||||
<div id="rightArea">
|
||||
<div id="progress-bar" class="fullyRounded">
|
||||
<div id="progress-bar-percentage" class="fullyRounded" style="width: 1%"><span id="mousemovelimit"> </span></div>
|
||||
</div>
|
||||
|
||||
<div id="seedSkipper">
|
||||
<a href="#" class="nicerButton" style="width: 100px;" onClick="ninja.seeder.seedCount = ninja.seeder.seedLimit; ninja.seeder.seed();">Skip »</a><br />
|
||||
<p>You may skip this step if you do not plan to use the random key generator.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="frontPageText">
|
||||
|
@ -7011,100 +7030,108 @@ ninja.publicKey = {
|
|||
};
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
ninja.seeder = {
|
||||
init: (function () {
|
||||
document.getElementById("generatekeyinput").value = "";
|
||||
})(),
|
||||
ninja.seeder = {
|
||||
init: (function () {
|
||||
document.getElementById("generatekeyinput").value = "";
|
||||
})(),
|
||||
|
||||
// number of mouse movements to wait for
|
||||
seedLimit: (function () {
|
||||
var num = Crypto.util.randomBytes(12)[11];
|
||||
return 200 + Math.floor(num);
|
||||
})(),
|
||||
// number of mouse movements to wait for
|
||||
seedLimit: (function () {
|
||||
var num = Crypto.util.randomBytes(12)[11];
|
||||
return 200 + Math.floor(num);
|
||||
})(),
|
||||
|
||||
seedCount: 0, // counter
|
||||
lastInputTime: new Date().getTime(),
|
||||
seedPoints: [],
|
||||
seedCount: 0, // counter
|
||||
lastInputTime: new Date().getTime(),
|
||||
seedPoints: [],
|
||||
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seed: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
var timeStamp = new Date().getTime();
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed mouse position X and Y when mouse movements are greater than 40ms apart.
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt16((evt.clientX * evt.clientY));
|
||||
ninja.seeder.showPoint(evt.clientX, evt.clientY);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seedKeyPress: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed key press character
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seed: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
var timeStamp = new Date().getTime();
|
||||
// seed a bunch (minimum seedLimit) of times
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt8(evt.which);
|
||||
var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
|
||||
SecureRandom.seedInt8(keyPressTimeDiff);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed mouse position X and Y when mouse movements are greater than 40ms apart.
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt16((evt.clientX * evt.clientY));
|
||||
ninja.seeder.showPoint(evt.clientX, evt.clientY);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
|
||||
showPool: function () {
|
||||
var poolHex;
|
||||
if (SecureRandom.poolCopyOnInit != null) {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
else {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
document.getElementById("mousemovelimit").innerHTML = (ninja.seeder.seedLimit - ninja.seeder.seedCount);
|
||||
},
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seedKeyPress: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed key press character
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
|
||||
var timeStamp = new Date().getTime();
|
||||
// seed a bunch (minimum seedLimit) of times
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt8(evt.which);
|
||||
var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
|
||||
SecureRandom.seedInt8(keyPressTimeDiff);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
|
||||
showPoint: function (x, y) {
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("class", "seedpoint");
|
||||
div.style.top = y + "px";
|
||||
div.style.left = x + "px";
|
||||
document.body.appendChild(div);
|
||||
ninja.seeder.seedPoints.push(div);
|
||||
},
|
||||
showPool: function () {
|
||||
var poolHex;
|
||||
if (SecureRandom.poolCopyOnInit != null) {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
else {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
document.getElementById("mousemovelimit").innerHTML = (ninja.seeder.seedLimit - ninja.seeder.seedCount);
|
||||
},
|
||||
|
||||
removePoints: function () {
|
||||
for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
|
||||
document.body.removeChild(ninja.seeder.seedPoints[i]);
|
||||
showPoint: function (x, y) {
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("class", "seedpoint");
|
||||
div.style.top = y + "px";
|
||||
div.style.left = x + "px";
|
||||
|
||||
// let's make the entropy 'points' grow and change color!
|
||||
percentageComplete = ninja.seeder.seedCount / ninja.seeder.seedLimit;
|
||||
document.getElementById("progress-bar-percentage").style.width=Math.ceil(percentageComplete*100)+"%";
|
||||
|
||||
// for some reason, appending these divs to an IOS device breaks clicking altogether (?)
|
||||
if (navigator.platform != 'iPad' && navigator.platform != 'iPhone' && navigator.platform != 'iPod') {
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
ninja.seeder.seedPoints.push(div);
|
||||
},
|
||||
|
||||
removePoints: function () {
|
||||
for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
|
||||
document.body.removeChild(ninja.seeder.seedPoints[i]);
|
||||
}
|
||||
ninja.seeder.seedPoints = [];
|
||||
}
|
||||
ninja.seeder.seedPoints = [];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ninja.qrCode = {
|
||||
// determine which type number is big enough for the input text length
|
||||
|
|
|
@ -157,6 +157,17 @@
|
|||
<span id="generatelabelkeypress">OR type some random characters into this textbox</span> <input type="text" id="generatekeyinput" onkeypress="ninja.seeder.seedKeyPress(event);" /><br />
|
||||
<div id="seedpooldisplay"></div>
|
||||
|
||||
<div id="rightArea">
|
||||
<div id="progress-bar" class="fullyRounded">
|
||||
<div id="progress-bar-percentage" class="fullyRounded" style="width: 1%"><span id="mousemovelimit"> </span></div>
|
||||
</div>
|
||||
|
||||
<div id="seedSkipper">
|
||||
<a href="#" class="nicerButton" style="width: 100px;" onClick="ninja.seeder.seedCount = ninja.seeder.seedLimit; ninja.seeder.seed();">Skip »</a><br />
|
||||
<p>You may skip this step if you do not plan to use the random key generator.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="frontPageText">
|
||||
|
|
|
@ -28,6 +28,14 @@ body { font-family: Arial; background-image: url('images/diamonds.png'); height:
|
|||
#seedpoolarea { display: none; }
|
||||
#seedpooldisplay { font-family: monospace; font-size: 1em; width: 640px; padding: 15px 5px; word-wrap: break-word; }
|
||||
.seedpoint { width: 6px; height: 6px; display: block; border-radius: 3px; background-color: #80CF80; position: absolute; z-index: 10; }
|
||||
|
||||
#seedSkipper { font-size: 11px; text-align: center; line-height: 14px;}
|
||||
#generate #mousemovelimit { font-size: 16px; color: #FFF; }
|
||||
#rightArea { float: right; width: 170px; }
|
||||
#progress-bar { width: 170px; background:#99c31b; position: relative; margin-bottom: 20px; }
|
||||
#progress-bar-percentage { background:#ff952d; padding: 3px 0px; text-align: center; height: 18px; }
|
||||
#progress-bar-percentage span { display: inline-block; position: absolute; width: 100%; left: 0; }
|
||||
|
||||
#generate { font-size: 13px; text-align: left; position: relative; padding: 20px; border: 1px solid #BFBFBF; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; }
|
||||
#generate span { padding: 5px 5px 0 5px; }
|
||||
#generatekeyinput { position: relative; z-index: 20; }
|
||||
|
|
|
@ -1,97 +1,105 @@
|
|||
ninja.seeder = {
|
||||
init: (function () {
|
||||
document.getElementById("generatekeyinput").value = "";
|
||||
})(),
|
||||
ninja.seeder = {
|
||||
init: (function () {
|
||||
document.getElementById("generatekeyinput").value = "";
|
||||
})(),
|
||||
|
||||
// number of mouse movements to wait for
|
||||
seedLimit: (function () {
|
||||
var num = Crypto.util.randomBytes(12)[11];
|
||||
return 200 + Math.floor(num);
|
||||
})(),
|
||||
// number of mouse movements to wait for
|
||||
seedLimit: (function () {
|
||||
var num = Crypto.util.randomBytes(12)[11];
|
||||
return 200 + Math.floor(num);
|
||||
})(),
|
||||
|
||||
seedCount: 0, // counter
|
||||
lastInputTime: new Date().getTime(),
|
||||
seedPoints: [],
|
||||
seedCount: 0, // counter
|
||||
lastInputTime: new Date().getTime(),
|
||||
seedPoints: [],
|
||||
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seed: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
var timeStamp = new Date().getTime();
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed mouse position X and Y when mouse movements are greater than 40ms apart.
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt16((evt.clientX * evt.clientY));
|
||||
ninja.seeder.showPoint(evt.clientX, evt.clientY);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seedKeyPress: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed key press character
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seed: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
var timeStamp = new Date().getTime();
|
||||
// seed a bunch (minimum seedLimit) of times
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt8(evt.which);
|
||||
var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
|
||||
SecureRandom.seedInt8(keyPressTimeDiff);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed mouse position X and Y when mouse movements are greater than 40ms apart.
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt16((evt.clientX * evt.clientY));
|
||||
ninja.seeder.showPoint(evt.clientX, evt.clientY);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
|
||||
showPool: function () {
|
||||
var poolHex;
|
||||
if (SecureRandom.poolCopyOnInit != null) {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
else {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
document.getElementById("mousemovelimit").innerHTML = (ninja.seeder.seedLimit - ninja.seeder.seedCount);
|
||||
},
|
||||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||||
seedKeyPress: function (evt) {
|
||||
if (!evt) var evt = window.event;
|
||||
// seeding is over now we generate and display the address
|
||||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.wallets.singlewallet.open();
|
||||
document.getElementById("generate").style.display = "none";
|
||||
document.getElementById("menu").style.visibility = "visible";
|
||||
ninja.seeder.removePoints();
|
||||
}
|
||||
// seed key press character
|
||||
else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
|
||||
var timeStamp = new Date().getTime();
|
||||
// seed a bunch (minimum seedLimit) of times
|
||||
SecureRandom.seedTime();
|
||||
SecureRandom.seedInt8(evt.which);
|
||||
var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
|
||||
SecureRandom.seedInt8(keyPressTimeDiff);
|
||||
ninja.seeder.seedCount++;
|
||||
ninja.seeder.lastInputTime = new Date().getTime();
|
||||
ninja.seeder.showPool();
|
||||
}
|
||||
},
|
||||
|
||||
showPoint: function (x, y) {
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("class", "seedpoint");
|
||||
div.style.top = y + "px";
|
||||
div.style.left = x + "px";
|
||||
document.body.appendChild(div);
|
||||
ninja.seeder.seedPoints.push(div);
|
||||
},
|
||||
showPool: function () {
|
||||
var poolHex;
|
||||
if (SecureRandom.poolCopyOnInit != null) {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
else {
|
||||
poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
|
||||
document.getElementById("seedpool").innerHTML = poolHex;
|
||||
document.getElementById("seedpooldisplay").innerHTML = poolHex;
|
||||
}
|
||||
document.getElementById("mousemovelimit").innerHTML = (ninja.seeder.seedLimit - ninja.seeder.seedCount);
|
||||
},
|
||||
|
||||
removePoints: function () {
|
||||
for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
|
||||
document.body.removeChild(ninja.seeder.seedPoints[i]);
|
||||
showPoint: function (x, y) {
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("class", "seedpoint");
|
||||
div.style.top = y + "px";
|
||||
div.style.left = x + "px";
|
||||
|
||||
// let's make the entropy 'points' grow and change color!
|
||||
percentageComplete = ninja.seeder.seedCount / ninja.seeder.seedLimit;
|
||||
document.getElementById("progress-bar-percentage").style.width=Math.ceil(percentageComplete*100)+"%";
|
||||
|
||||
// for some reason, appending these divs to an IOS device breaks clicking altogether (?)
|
||||
if (navigator.platform != 'iPad' && navigator.platform != 'iPhone' && navigator.platform != 'iPod') {
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
ninja.seeder.seedPoints.push(div);
|
||||
},
|
||||
|
||||
removePoints: function () {
|
||||
for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
|
||||
document.body.removeChild(ninja.seeder.seedPoints[i]);
|
||||
}
|
||||
ninja.seeder.seedPoints = [];
|
||||
}
|
||||
ninja.seeder.seedPoints = [];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ninja.qrCode = {
|
||||
// determine which type number is big enough for the input text length
|
||||
|
|
Loading…
Add table
Reference in a new issue