Welcome blash to the 2020s

master
Fabio Manganiello 2 months ago
parent aeecc9c6db
commit 8dadc0bf1f
  1. 16
      blash.css
  2. 0
      commands/cat.js
  3. 8
      commands/cd.js
  4. 6
      commands/chmod.js
  5. 0
      commands/clear.js
  6. 6
      commands/cp.js
  7. 0
      commands/echo.js
  8. 0
      commands/eval.js
  9. 0
      commands/find.js
  10. 0
      commands/grep.js
  11. 8
      commands/ln.js
  12. 9
      commands/logout.js
  13. 0
      commands/ls.js
  14. 0
      commands/man.js
  15. 6
      commands/mkdir.js
  16. 6
      commands/mv.js
  17. 12
      commands/nano.js
  18. 9
      commands/passwd.js
  19. 0
      commands/pwd.js
  20. 6
      commands/rm.js
  21. 5
      commands/rmdir.js
  22. 18
      commands/su.js
  23. 6
      commands/touch.js
  24. 7
      commands/useradd.js
  25. 6
      commands/userdel.js
  26. 6
      commands/users.js
  27. 0
      commands/wget.js
  28. 5
      commands/whoami.js
  29. 8
      index.html
  30. 103
      system/blash.js
  31. 7
      system/config.js

@ -4,7 +4,6 @@ body
color : #888;
font-family : Terminus, courier, monospace, fixed;
font-size : 13px;
tabindex : -1;
}
pre
@ -13,16 +12,7 @@ pre
font-size : 13px;
}
input.promptInput
{
background-color : black;
border : 0;
color : #888;
font-family : Terminus, courier, monospace, fixed;
font-size : 13px;
width : 500px;
}
input.promptInput,
input.password
{
background-color : black;
@ -31,6 +21,7 @@ input.password
font-family : Terminus, courier, monospace, fixed;
font-size : 13px;
width : 500px;
outline: none;
}
div#blashWindow
@ -41,7 +32,6 @@ div#blashWindow
/* padding : 10px; */
/* border : 1px solid #888; */
overflow : auto;
tabindex : -1;
}
span.directory
@ -57,13 +47,11 @@ span.link
a
{
color : green;
tabindex : -1;
}
a:visited
{
color : green;
tabindex : -1;
}
span.syntax

@ -14,17 +14,13 @@
{
shell.auto_prompt_focus = false;
shell.auto_prompt_refresh = false;
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=gethome';
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader ( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader ( "Content-length", params.length );
http.setRequestHeader ( "Connection", "close" );
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -29,8 +29,7 @@
perms |= (( perm_string.match ( 'w' )) ? 1 : 0 );
resource = shell.expandPath ( resource );
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=chmod&resource=' + escape ( resource ) + '&perms=' + escape ( perms.toString() );
if ( userlist )
@ -41,9 +40,6 @@
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader( "Content-length", params.length );
http.setRequestHeader( "Connection", "close" );
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -45,16 +45,12 @@
shell.auto_prompt_refresh = false;
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=cp&src=' + escape ( src ) + '&dest=' + escape ( dest );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -49,18 +49,14 @@
link_type = 'local';
}
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
shell.auto_prompt_refresh = false;
link = shell.expandPath ( link );
params = 'action=link&resource=' + escape ( res ) + '&link=' + escape ( link ) + '&type=' + escape ( link_type );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader( "Content-length", params.length );
http.setRequestHeader( "Connection", "close" );
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -24,15 +24,12 @@
shell.user = shell.json.user;
document.cookie = '';
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=logout';
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader( "Content-length", params.length );
http.setRequestHeader( "Connection", "close" );
http.onreadystatechange = function ()
{
@ -45,9 +42,7 @@
http.send ( params );
shell.path = shell.json.basepath;
var json_config = window.location.href;
json_config = json_config.replace ( /\/([a-zA-Z_\.]+)$/, '/system/blash.json' );
var json_config = './system/config.js';
var http2 = new XMLHttpRequest();
http2.open ( "GET", json_config, true );

@ -17,16 +17,12 @@
shell.auto_prompt_refresh = false;
arg = shell.expandPath ( arg );
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=mkdir&dir=' + escape ( arg );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -45,16 +45,12 @@
shell.auto_prompt_refresh = false;
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=mv&src=' + escape ( src ) + '&dest=' + escape ( dest );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -39,17 +39,13 @@
}
}
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=getperms&resource=' +
( newfile ? escape ( parent_dir['path'] ) : escape ( arg ));
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader ("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader ("Content-length", params.length);
http.setRequestHeader ("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )
@ -395,16 +391,12 @@
"bufferSave" : function ()
{
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=set_content&file=' + escape ( shell.fname ) + '&content=' + escape ( document.getElementById ( 'editor_window' ).value );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader ("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader ("Content-length", params.length);
http.setRequestHeader ("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -53,8 +53,7 @@
{
shell.cmdOut.innerHTML = 'The passwords do not match';
} else {
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=changepwd&user=' + escape ( shell.newuser ) + '&newpass=' + md5 ( password.value );
if ( shell.curUser != 'root' )
@ -65,9 +64,6 @@
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )
@ -111,9 +107,6 @@
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader( "Content-length", params.length );
http.setRequestHeader( "Connection", "close" );
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -17,16 +17,12 @@
shell.auto_prompt_refresh = false;
arg = shell.expandPath ( arg );
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=rm&file=' + escape ( arg );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -17,15 +17,12 @@
shell.auto_prompt_refresh = false;
arg = shell.expandPath ( arg );
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=rmdir&dir=' + escape ( arg );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{

@ -55,15 +55,12 @@
if ( key == 13 && password.value.length > 0 )
{
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=login&user=' + escape ( shell.newuser ) + '&pass=' + md5 ( password.value );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader ( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader ( "Content-length", params.length );
http.setRequestHeader ( "Connection", "close" );
http.onreadystatechange = function ()
{
@ -78,8 +75,6 @@
var xml2 = new XMLHttpRequest();
xml2.open ( "POST", users_php, true );
xml2.setRequestHeader ( "Content-type", "application/x-www-form-urlencoded" );
xml2.setRequestHeader ( "Content-length", params.length );
xml2.setRequestHeader ( "Connection", "close" );
params = 'action=gethome';
xml2.onreadystatechange = function ()
@ -94,14 +89,9 @@
shell.user = shell.json.user;
}
shell.files_json = window.location.href;
if ( shell.has_users )
{
shell.files_json = shell.files_json.replace ( /\/([a-zA-Z_\.]+)$/, '/modules/users/files.php' );
} else {
shell.files_json = shell.files_json.replace ( /\/([a-zA-Z_\.]+)$/, '/system/files.json' );
}
shell.files_json = shell.has_users ?
'./modules/users/files.php' :
'./system/files.json';
var http3 = new XMLHttpRequest();
http3.open ( "GET", shell.files_json, true );

@ -17,16 +17,12 @@
shell.auto_prompt_refresh = false;
arg = shell.expandPath ( arg );
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=touch&file=' + escape ( arg );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -31,7 +31,6 @@
var key = ( evt.charCode ) ? evt.charCode : evt.keyCode;
var password = document.getElementsByName ( "password" )[0];
var repeatPassword = document.getElementsByName ( "repeatPassword" )[0];
var repeatPasswordText = document.getElementById ( "repeatPasswordText" );
if ( key == 13 && password.value.length > 0 )
{
@ -45,16 +44,12 @@
return false;
}
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=add&user=' + escape ( shell.newuser ) + '&pass=' + md5 ( password.value );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -15,16 +15,12 @@
shell.auto_prompt_refresh = false;
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=del&user=' + escape ( arg );
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -8,17 +8,13 @@
"action" : function ( arg )
{
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=list';
shell.auto_prompt_refresh = false;
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader( "Content-length", params.length );
http.setRequestHeader( "Connection", "close" );
http.onreadystatechange = function ()
{
if ( http.readyState == 4 && http.status == 200 )

@ -26,15 +26,12 @@
} else {
shell.auto_prompt_refresh = false;
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
params = 'action=getuser';
var http = new XMLHttpRequest();
http.open ( "POST", users_php, true );
http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
http.setRequestHeader( "Content-length", params.length );
http.setRequestHeader( "Connection", "close" );
http.onreadystatechange = function ()
{

@ -6,8 +6,12 @@
<link rel="stylesheet" href="blash.css" type="text/css">
</head>
<body onload="shell = new blash()">
<div id="blashWindow" onmouseup="shell.prompt.focus()">
<body
onload="shell = new blash()"
onready="shell.prompt.focus()"
onmouseup="shell.prompt.focus()"
>
<div id="blashWindow">
<span id="promptText" class="promptText"></span>
<input type="text" class="promptInput" name="blashPrompt" autocomplete="off" onkeydown="shell.getKey ( event )" onkeyup="this.focus()" onblur="return false"/>
<span id="blashCmdOut" class="blashCmdOut"/></span>

@ -2,8 +2,9 @@
* *
* blash - An AJAX CMS for browsing your web site like a shell *
* *
* by BlackLight <blacklight@autistici.org>, (C) 2010 *
* Web: http://0x00.ath.cx *
* by Fabio "BlackLight" Manganiello <info@fabiomanganiello.com> *
* (C) 2010, 2022 *
* Web: https://blash.fabiomanganiello.com *
* Released under GPL licence v.3 *
* *
*****************************************************************/
@ -50,7 +51,36 @@ function blash ()
this.promptText = document.getElementById ( "promptText" );
/** Input field used as prompt */
this.prompt = document.getElementsByName ( "blashPrompt" )[0];
this.prompt = document.body.querySelector ( "[name=blashPrompt]" );
this.getPrompt = function () {
let prompt = document.body.querySelector ( "[name=blashPrompt]" );
if (!prompt) {
prompt = document.createElement ( 'input' );
prompt.setAttribute ( 'name', 'blashPrompt' );
prompt.setAttribute ( 'type', 'text' );
prompt.setAttribute ( 'class', 'promptInput' );
prompt.setAttribute ( 'autocomplete', 'off' );
prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' );
prompt.setAttribute ( 'onkeyup', 'this.focus()' );
prompt.setAttribute ( 'onblur', 'return false' );
this.cmdOut = document.createElement ( 'div' );
this.cmdOut.setAttribute ( 'id', 'blashCmdOut' );
this.cmdOut.setAttribute ( 'class', 'blashCmdOut' );
this.cmdOut.innerHTML = '<br/>';
this.window.appendChild ( prompt );
this.window.appendChild ( this.cmdOut );
this.prompt = prompt
if ( this.auto_prompt_focus )
{
prompt.focus();
}
}
return prompt;
};
/** Counter of the open <span> tags when replacing the colours in the command prompt */
this.__open_spans = 0;
@ -73,9 +103,7 @@ function blash ()
this.loadCommand = function ( cmd )
{
var cmd_file = window.location.href;
cmd_file = cmd_file.replace ( /\/([a-zA-Z_\.]+)$/, '/commands/' + cmd + ".json" );
var cmd_file = './commands/' + cmd + '.js'
var http = new XMLHttpRequest();
http.open ( "GET", cmd_file, true );
@ -96,15 +124,11 @@ function blash ()
{
this.user = RegExp.$1;
var params = 'action=getuser';
var users_php = window.location.href;
users_php = users_php.replace ( /\/([a-zA-Z_\.]+)$/, '/modules/users/users.php' );
var users_php = './modules/users/users.php';
var xml = new XMLHttpRequest();
xml.open ( "POST", users_php, true );
xml.setRequestHeader ( "Content-type", "application/x-www-form-urlencoded" );
xml.setRequestHeader ( "Content-length", params.length );
xml.setRequestHeader ( "Connection", "close" );
xml.onreadystatechange = function ()
{
if ( xml.readyState == 4 && xml.status == 200 )
@ -123,8 +147,6 @@ function blash ()
var xml2 = new XMLHttpRequest();
xml2.open ( "POST", users_php, true );
xml2.setRequestHeader ( "Content-type", "application/x-www-form-urlencoded" );
xml2.setRequestHeader ( "Content-length", params.length );
xml2.setRequestHeader ( "Connection", "close" );
params = 'action=gethome';
xml2.onreadystatechange = function ()
@ -147,11 +169,9 @@ function blash ()
this.prompt.focus();
var json_config = window.location.href;
json_config = json_config.replace ( /\/([a-zA-Z_\.]+)$/, '/system/blash.json' );
var config_url = './system/config.js';
var http = new XMLHttpRequest();
http.open ( "GET", json_config, true );
http.open ( "GET", config_url, true );
http.onreadystatechange = function ()
{
@ -193,15 +213,7 @@ function blash ()
}
}
shell.files_json = window.location.href;
if ( shell.has_users )
{
shell.files_json = shell.files_json.replace ( /\/([a-zA-Z_\.]+)$/, '/modules/users/files.php' );
} else {
shell.files_json = shell.files_json.replace ( /\/([a-zA-Z_\.]+)$/, '/system/files.json' );
}
shell.files_json = shell.has_users ? './modules/users/files.php' : './system/files.json';
var http2 = new XMLHttpRequest();
http2.open ( "GET", shell.files_json, true );
@ -363,27 +375,7 @@ function blash ()
this.window.innerHTML += value + '<br/>' + out + text;
}
this.prompt = document.createElement ( 'input' );
this.prompt.setAttribute ( 'name', 'blashPrompt' );
this.prompt.setAttribute ( 'type', 'text' );
this.prompt.setAttribute ( 'class', 'promptInput' );
this.prompt.setAttribute ( 'autocomplete', 'off' );
this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' );
this.prompt.setAttribute ( 'onkeyup', 'this.focus()' );
this.prompt.setAttribute ( 'onblur', 'return false' );
this.cmdOut = document.createElement ( 'div' );
this.cmdOut.setAttribute ( 'id', 'blashCmdOut' );
this.cmdOut.setAttribute ( 'class', 'blashCmdOut' );
this.cmdOut.innerHTML = '<br/>';
this.window.appendChild ( this.prompt );
this.window.appendChild ( this.cmdOut );
if ( this.auto_prompt_focus )
{
this.prompt.focus();
}
this.prompt = this.getPrompt();
}
}
}
@ -400,7 +392,7 @@ function blash ()
var outDiv = document.createElement ( 'span' );
outDiv.innerHTML = text;
this.window.insertBefore ( outDiv, document.getElementsByName ( "blashPrompt" )[0] );
this.window.insertBefore ( outDiv, this.getPrompt() );
return false;
} else if ( key == 13 || key == 10 || ( key == 67 && evt.ctrlKey )) {
@ -735,14 +727,15 @@ function blash ()
if (( this.prompt = document.getElementById ( "promptText" )))
{
value = this.prompt.innerHTML + (( document.getElementsByName ( 'blashPrompt' )[0].value.length > 0 ) ?
' ' + document.getElementsByName ( 'blashPrompt' )[0].value : '' );
this.prompt.parentNode.removeChild ( document.getElementsByName ( 'blashPrompt' )[0] );
const prompt = this.getPrompt();
value = prompt.innerHTML + (( prompt.value.length > 0 ) ?
' ' + prompt.value : '' );
this.prompt.parentNode.removeChild ( prompt );
}
if ( document.getElementsByName ( 'blashPrompt' )[0] )
if ( this.getPrompt() )
{
document.getElementsByName ( 'blashPrompt' )[0].parentNode.removeChild ( document.getElementsByName ( 'blashPrompt' )[0] );
this.getPrompt().parentNode.removeChild ( this.getPrompt() );
}
if (( this.cmdOut = document.getElementById ( "blashCmdOut" )))
@ -963,9 +956,7 @@ function blash ()
*/
this.refreshFiles = function ()
{
var files_config = window.location.href;
files_config = files_config.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/files.php' );
var files_config = './modules/users/files.php';
var http = new XMLHttpRequest();
http.open ( "GET", files_config, true );

@ -4,13 +4,14 @@
{
"banner" : "blash version 0.1<br/>" +
"Copyright (C) 2010 BlackLight &lt;blacklight@autistici.org&gt;" +
"by Fabio \"BlackLight\" Manganiello &lt;info@fabiomanganiello.com&gt;>" +
"<br/>Copyright (C) 2010, 2022" +
"<br/>Licence GPLv3+: GNU GPL version 3 or later " +
"&lt;<a class=\"bannerLink\" href=\"http://gnu.org/licences/gpl.html\" target=\"_new\">" +
"http://gnu.org/licences/gpl.html</a>&gt;<br/>" +
"Source code available at <a class=\"bannerLink\" target=\"_new\" " +
"href=\"https://github.com/BlackLight/blash\">" +
"https://github.com/BlackLight/blash</a><br/><br/>" +
"href=\"https://git.platypush.tech/blacklight/blash\">" +
"https://git.platypush.tech/blacklight/blash</a><br/><br/>" +
"This is free software; you are free to change and " +
"redistribuite it.<br/>There is NO WARRANTY, to the " +
"extent permitted by law.<br/>" +
Loading…
Cancel
Save