Merge branch 'unraid:master' into master

This commit is contained in:
Zack Spear
2023-10-11 20:12:49 -05:00
committed by GitHub
384 changed files with 10556 additions and 3049 deletions
@@ -6,7 +6,10 @@ cfg=/boot/config/plugins/dynamix.apcupsd/dynamix.apcupsd.cfg
[[ -f /var/run/apcupsd.pid || ! -f $cfg ]] && exit
# Read settings
source $cfg
. $cfg
# run & log functions
. /etc/rc.d/rc.runlog
# Apply settings
sed -i -e '/^NISIP/c\\NISIP 0.0.0.0' $conf
@@ -27,4 +30,4 @@ else
fi
# Start daemon
[[ $SERVICE == enable ]] && /etc/rc.d/rc.apcupsd start |& logger
[[ $SERVICE == enable ]] && /etc/rc.d/rc.apcupsd start |& log
@@ -368,7 +368,7 @@ class DockerTemplates {
@copy($iconRAM,$icon);
}
if ( !is_file($iconRAM) ) {
exec("/usr/bin/logger ".escapeshellarg("$imageName: Could not download icon $imgUrl"));
exec("logger -t webGUI -- \"$imageName: Could not download icon $imgUrl\"");
}
return (is_file($iconRAM)) ? str_replace($docroot, '', $iconRAM) : '';
@@ -20,6 +20,9 @@ require_once "$docroot/webGui/include/Secure.php";
$_SERVER['REQUEST_URI'] = 'plugins';
require_once "$docroot/webGui/include/Translations.php";
$tmpdir="/boot/deletemedowngrade.".uniqid();
mkdir($tmpdir);
exec("mv -f /boot/bz* $tmpdir");
exec("mv -f /boot/previous/* /boot");
$version = unscript(_var($_GET,'version'));
file_put_contents("$docroot/plugins/unRAIDServer/README.md","**"._('DOWNGRADE TO VERSION')." $version**");
@@ -151,7 +151,7 @@ function download($url, $name, &$error) {
// Deal with logging message.
//
function logger($message) {
shell_exec("logger $message");
exec("logger -t 'language-manager' -- \"$message\"");
}
// Interpret a language file
@@ -314,7 +314,7 @@ if ($method == 'install') {
copy($xml_file, $lang_file);
symlink($lang_file, $link_file);
write("language: $lang language pack installed\n");
logger("language: $lang language pack installed");
logger("$lang language pack installed");
// run hook scripts for post processing
post_hooks();
done(0);
@@ -396,7 +396,7 @@ if ($method == 'update') {
copy($xml_file, $lang_file);
symlink($lang_file, $link_file);
write("language: $lang language pack updated\n");
logger("language: $lang language pack updated");
logger("$lang language pack updated");
// run hook scripts for post processing
post_hooks();
done(0);
@@ -423,7 +423,7 @@ if ($method == 'remove') {
done(1);
}
write("language: $lang language pack removed\n");
logger("language: $lang language pack removed");
logger("$lang language pack removed");
// run hook scripts for post processing
post_hooks();
done(0);
@@ -44,7 +44,7 @@ foreach ($plugins as $plugin) {
$run = popen("$cmd $method $pluginArg",'r');
while (!feof($run)) {
$line .= fgetc($run);
if (in_array($line[-1],["\r","\n"])) {write($line); $line = '';}
if (!empty($line) && in_array($line[-1],["\r","\n"])) {write($line); $line = '';}
}
pclose($run);
write("\n");
@@ -154,7 +154,7 @@ function error_desc($code) {
case 2: return 'Parse error';
case 3: return 'File I/O error';
case 4: return 'Network failure';
case 5: return 'SSL verification failure';
case 5: return 'SSL verification failure - Check the date and time of your server in Settings - Date And Time';
case 6: return 'Username/password authentication failure';
case 7: return 'Protocol errors';
case 8: return 'Invalid URL / Server error response';
@@ -284,7 +284,7 @@ function filter_url($url) {
// Deal with logging message.
//
function logger($message) {
shell_exec("logger $message");
exec("logger -t 'plugin-manager' -- \"$message\"");
}
// Interpret a plugin file
@@ -382,12 +382,12 @@ function plugin($method, $plugin_file, &$error) {
// If file already exists, check the SHA256/MD5 (if supplied)
if (file_exists($name)) {
if ($file->SHA256) {
logger("plugin: checking: $name - SHA256");
logger("checking: $name - SHA256");
if (hash_file('sha256', $name) != $file->SHA256) {
unlink($name);
}
} elseif ($file->MD5) {
logger("plugin: checking: $name - MD5");
logger("checking: $name - MD5");
if (md5_file($name) != $file->MD5) {
unlink($name);
}
@@ -396,12 +396,12 @@ function plugin($method, $plugin_file, &$error) {
// If file already exists, do not overwrite
//
if (file_exists($name)) {
logger("plugin: skipping: $name already exists");
logger("skipping: $name already exists");
} elseif ($file->LOCAL) {
// Create the file
//
// for local file, just copy it
logger("plugin: creating: $name - copying LOCAL file $file->LOCAL");
logger("creating: $name - copying LOCAL file $file->LOCAL");
if (!copy($file->LOCAL, $name)) {
$error = "unable to copy LOCAL file: $name";
@unlink($name);
@@ -409,10 +409,10 @@ function plugin($method, $plugin_file, &$error) {
}
} elseif ($file->INLINE) {
// for inline file, create with inline contents
logger("plugin: creating: $name - from INLINE content");
logger("creating: $name - from INLINE content");
$contents = trim($file->INLINE).PHP_EOL;
if ($file->attributes()->Type == 'base64') {
logger("plugin: decoding: $name as base64");
logger("decoding: $name as base64");
$contents = base64_decode($contents);
if ($contents === false) {
$error = "unable to decode inline base64: $name";
@@ -426,20 +426,20 @@ function plugin($method, $plugin_file, &$error) {
}
} elseif ($file->URL) {
// for download file, download and maybe verify the file MD5
logger("plugin: creating: $name - downloading from URL $file->URL");
logger("creating: $name - downloading from URL $file->URL");
if ( (download($file->URL, $name, $error) === false) && (download(filter_url($file->URL), $name, $error) === false) ) {
@unlink($name);
return false;
}
if ($file->SHA256) {
logger("plugin: checking: $name - SHA256");
logger("checking: $name - SHA256");
if (hash_file('sha256', $name) != $file->SHA256) {
$error = "bad file SHA256: $name";
unlink($name);
return false;
}
} elseif ($file->MD5) {
logger("plugin: checking: $name - MD5");
logger("checking: $name - MD5");
if (md5_file($name) != $file->MD5) {
$error = "bad file MD5: $name";
unlink($name);
@@ -452,7 +452,7 @@ function plugin($method, $plugin_file, &$error) {
if ($file->attributes()->Mode) {
// if file has 'Mode' attribute, apply it
$mode = $file->attributes()->Mode;
logger("plugin: setting: $name - mode to $mode");
logger("setting: $name - mode to $mode");
if (!chmod($name, octdec($mode))) {
$error = "chmod failure: $name";
return false;
@@ -464,13 +464,13 @@ function plugin($method, $plugin_file, &$error) {
if ($file->attributes()->Run) {
$command = $file->attributes()->Run;
if ($name) {
logger(escapeshellarg("plugin: running: $command $name"));
logger("running: $command $name");
$retval = run("$command $name");
} elseif ($file->LOCAL) {
logger(escapeshellarg("plugin: running: $command $file->LOCAL"));
logger("running: $command $file->LOCAL");
$retval = run("$command $file->LOCAL");
} elseif ($file->INLINE) {
logger("plugin: running: 'anonymous'");
logger("running: 'anonymous'");
$name = '/tmp/inline.sh';
file_put_contents($name, $file->INLINE);
$retval = run("$command $name");
@@ -718,7 +718,7 @@ if ($method == 'install') {
if ($target != $plugin_file) copy($plugin_file, $target);
symlink($target, $symlink);
write("plugin: $plugin installed\n");
logger("plugin: $plugin installed");
logger("$plugin installed");
} else {
write("script: $plugin executed\n");
logger("script: $plugin executed");
@@ -835,7 +835,7 @@ if ($method == 'update') {
copy($plugin_file, $target);
symlink($target, $symlink);
write("plugin: $plugin updated\n");
logger("plugin: $plugin updated");
logger("$plugin updated");
// run hook scripts for post processing
post_hooks();
done(0);
@@ -867,7 +867,7 @@ if ($method == 'remove') {
// remove the plugin file
move($installed_plugin_file, "$boot-removed");
write("plugin: $plugin removed\n");
logger("plugin: $plugin removed");
logger("$plugin removed");
exec("/usr/local/sbin/update_cron");
// run hook scripts for post processing
post_hooks();
@@ -18,6 +18,7 @@ Markdown="false"
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
$cpus = cpu_list();
@@ -121,6 +122,7 @@ div.four label:nth-child(4n+4){float:none;clear:both}
div.four label.cpu1{width:32%}
div.four label.cpu2{width:26%}
div.template,div#dialogWindow,input#upload{display:none}
div.template,div#dialogWindow2,input#upload{display:none}
table.domdisk thead tr th:nth-child(1){width:56%!important}
table.domdisk thead tr th:nth-child(n+2){width:8%!important}
table.domdisk thead tr th:nth-child(1){padding-left:72px}
@@ -134,7 +136,7 @@ i.mover{margin-right:8px;display:none}
.dropdown-menu{z-index:10001}
</style>
<table id="kvm_table" class="tablesorter four shift">
<thead><tr><th class="th1"><a id="resetsort" class="nohand" onclick="resetSorting()" title="Reset sorting"><i class="fa fa-th-list"></i></a>_(Name)_</th><th class="th2">_(Description)_</th><th>_(CPUs)_</th><th>_(Memory)_</th><th>_(vDisks)_</th><th>_(Graphics)_</th><th class="th3">_(Autostart)_</th></tr></thead>
<thead><tr><th class="th1"><a id="resetsort" class="nohand" onclick="resetSorting()" title="Reset sorting"><i class="fa fa-th-list"></i></a>_(Name)_</th><th class="th2">_(Description)_</th><th>_(CPUs)_</th><th>_(Memory)_</th><th>_(vDisks / vCDs)_</th><th>_(Graphics)_</th><th class="th3">_(Autostart)_</th></tr></thead>
<tbody id="kvm_list"><tr><td colspan='8'></td></tr></tbody>
</table>
<input type="button" onclick="addVM()" id="btnAddVM" value="_(Add VM)_" style="display:none">
@@ -163,7 +165,54 @@ function resetSorting() {
function changemedia(uuid,dev,bus,file) {
if (file === "--select") getisoimage(uuid,dev,bus,file);
if (file === "--eject") ajaxVMDispatch({action:"change-media", uuid:uuid , cdrom:"" , dev:dev , bus:bus , file:file}, "loadlist");
}
function getisoimageboth(uuid,dev,bus,file,dev2,bus2,file2){
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
var match= ".iso";
var box = $("#dialogWindow");
box.html($("#templateISOboth").html());
box.find('#target').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match).attr('value', file).fileTreeAttach(null,null,function(path){
var bits = path.substr(1).split('/');
var auto = bits.length>3 ? '' : share;
box.find('#target').val(path+auto).change();
});
box.find('#target2').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match).attr('value', file2).fileTreeAttach(null,null,function(path){
var bits = path.substr(1).split('/');
var auto = bits.length>3 ? '' : share;
box.find('#target2').val(path+auto).change();
});
var height = 100;
box.dialog({
title: "Select ISOs for CDROMs",
resizable: false,
width: 600,
height: 300,
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
"_(Update)_": function(){
var target = box.find('#target');
if (target.length) {
target = target.val();
} else target = '';
var target2 = box.find('#target2');
if (target2.length) {
target2 = target2.val();
} else target2 = '';
box.find('#target').prop('disabled',true);
box.find('#target2').prop('disabled',true);
ajaxVMDispatch({action:"change-media-both", uuid:uuid , cdrom:"" , dev:dev , bus:bus , file:target, dev2:dev2 , bus2:bus2 , file2:target2}, "loadlist");
box.dialog('close');
},
"_(Cancel)_": function(){
box.dialog('close');
}
}
});
dialogStyle();
}
function getisoimage(uuid,dev,bus,file){
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
@@ -203,8 +252,220 @@ function getisoimage(uuid,dev,bus,file){
});
dialogStyle();
}
function VMClone(uuid, name){
//var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
var match= ".iso";
var box = $("#dialogWindow");
var height = 200;
box.html($("#templateClone").html());
box.find('#VMBeingCloned').html(name).change() ;
box.find('#target').val(name + "_clone") ;
document.getElementById("Free").checked = true ;
document.getElementById("Overwrite").checked = true ;
var Cancel = _("Cancel") ;
box.dialog({
title: "VM Clone",
resizable: false,
width: 600,
height: 500,
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
"_(Clone)_" : function(){
var target = box.find('#target');
if (target.length) {
target = target.val();
//if (!target ) {errorTarget(); return;}
} else target = '';
var clone = box.find("#target").prop('value') ;
x = box.find('#Start').prop('checked') ;
if (x) start = 'yes' ; else start = 'no' ;
x = box.find('#Edit').prop('checked') ;
if (x) edit = 'yes' ; else edit = 'no' ;
x = box.find('#Overwrite').prop('checked') ;
if (x) overwrite = 'yes' ; else overwrite = 'no' ;
x = box.find('#Free').prop('checked') ;
if (x) free = 'yes' ; else free = 'no' ;
scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone" , name:name ,clone:clone, overwrite:overwrite , edit:edit, start,start, free:free})) ;
openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist") ;
box.dialog('close');
},
"_(Cancel)_": function(){
box.dialog('close');
}
}
});
dialogStyle();
}
function selectsnapshot(uuid, name ,snaps, opt, getlist,state){
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
var match= ".iso";
var box = $("#dialogWindow2");
box.html($("#templatesnapshot"+opt).html());
var height = 200;
const Capopt = opt.charAt(0).toUpperCase() + opt.slice(1) ;
var optiontext = Capopt + " Snapshot" ;
box.find('#VMName').html(name) ;
box.find('#targetsnap').val(snaps) ;
box.find('#targetsnapl').html(snaps) ;
if (getlist) {
var only = 1 ;
if (opt == "remove") only = 0;
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-images", uuid:uuid , snapshotname:snaps, only:only}, function(data) {
if (data.html) {
box.find('#targetsnapimages').html(data.html) ;
}
},'json');
}
document.getElementById("targetsnaprmv").checked = true ;
document.getElementById("targetsnaprmvmeta").checked = true ;
document.getElementById("targetsnapkeep").checked = true ;
document.getElementById("targetsnapfspc").checked = true ;
box.dialog({
title: "_("+optiontext+ ")_",
resizable: false,
width: 600,
height: 500,
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
"_(Proceed)_": function(){
var target = box.find('#targetsnap');
if (target.length) {
target = target.val();
if (!target ) {errorTarget(); return;}
} else target = '';
var remove = 'yes'
var keep = 'yes'
var removemeta = 'yes'
var free = 'yes'
var desc = ''
box.find('#targetsnap').prop('disabled',true);
if (opt == "revert") {
var x = box.find('#targetsnaprmv').prop('checked') ;
if (x) remove = 'yes' ; else remove = 'no' ;
x = box.find('#targetsnaprmvmeta').prop('checked') ;
if (x) removemeta = 'yes' ; else removemeta = 'no' ;
x = box.find('#targetsnapkeep').prop('checked') ;
if (x) keep = 'yes' ; else keep = 'no' ;
}
if (opt == "create") {
var x = box.find('#targetsnapfspc').prop('checked') ;
if (x) free = 'yes' ; else free = 'no' ;
var desc = box.find("#targetsnapdesc").prop('value') ;
}
ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid , snapshotname:target , remove:remove, free:free ,removemeta:removemeta ,keep:keep, desc:desc} , "loadlist");
box.dialog('close');
},
"_(Cancel)_": function(){
box.dialog('close');
}
}
});
dialogStyle();
}
function selectblock(uuid, name ,snaps, opt, getlist,state){
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
var match= ".iso";
var box = $("#dialogWindow2");
box.html($("#templateblock").html());
var height = 200;
const Capopt = opt.charAt(0).toUpperCase() + opt.slice(1) ;
var optiontext = Capopt + " Block Devices" ;
box.find('#VMName').html(name) ;
box.find('#targetsnap').val(snaps) ;
box.find('#targetsnapl').html(snaps) ;
getlist = true ;
if (getlist) {
var only = 1 ;
if (opt == "remove") only = 0;
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-list", uuid:uuid }, function(data) {
if (data.html) {
var targetbase = document.getElementById("targetblockbase") ;
htmlstrbase = "<select class='targetblockbase' name='targetblockbase' id='targetblockbase'><option value='--base'>--base</option>" + data.html + "</select>"
htmlstrtop = "<select class='targetblocktop' name='targetblocktop' id='targetblocktop'><option value='--top'>--top</option>" + data.html + "</select>"
$("select.targetblockbase").replaceWith(htmlstrbase) ;
$("select.targetblocktop").replaceWith(htmlstrtop) ;
}
},'json');
}
document.getElementById("targetsnaprmv").checked = true ;
document.getElementById("targetsnaprmvmeta").checked = true ;
document.getElementById("targetsnapkeep").checked = true ;
document.getElementById("targetsnapfspc").checked = true ;
if (opt== "pull") {
$('.toprow').hide();
$('.targetpivotrow').hide();
$('.targetdeleterow').hide();
} else {
$('.toprow').show();
$('.targetpivotrow').show();
$('.targetdeleterow').show();
}
box.dialog({
title: "_("+optiontext+ ")_",
resizable: false,
width: 600,
height: 500,
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
_("Action")_: function(){
var target = box.find('#targetsnap');
if (target.length) {
target = target.val();
if (!target ) {errorTarget(); return;}
} else target = '';
var remove = 'yes'
var keep = 'yes'
var removemeta = 'yes'
var free = 'yes'
var delete_file = 'yes'
var pivot = 'yes'
var desc = ''
box.find('#targetsnap').prop('disabled',true);
if (opt == "create") {
var x = box.find('#targetsnapfspc').prop('checked') ;
if (x) free = 'yes' ; else free = 'no' ;
var desc = box.find("#targetsnapdesc").prop('value') ;
}
var targetbase = box.find("#targetblockbase").prop('value') ;
var targettop = box.find("#targetblocktop").prop('value') ;
x = box.find('#targetpivot').prop('checked') ;
if (x) pivot = 'yes' ; else pivot = 'no' ;
x = box.find('#targetdelete').prop('checked') ;
if (x) delete_file = 'yes' ; else delete_file = 'no' ;
Ajaxurl = "VMAjaxCall.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMajax.php&" + $.param({action:opt , name:name ,targetbase:targetbase, targettop:targettop , snapshotname:target , remove:remove, targetpivot:pivot ,removemeta:removemeta ,targetdelete:delete_file})) ;
openVMAction((Ajaxurl),"Block Commit", "dynamix.vm.manager", "loadlist") ;
box.dialog('close');
},
"_(Cancel)_": function(){
box.dialog('close');
}
}
});
dialogStyle();
}
function dialogStyle() {
$('.ui-dialog-titlebar-close').css({'background':'transparent','border':'none','font-size':'1.8rem','margin-top':'-14px','margin-right':'-18px'}).html('<i class="fa fa-times"></i>').prop('title',"_(Close)_").prop('onclick',null).off('click').click(function(){box.dialog('close');});
$('.ui-dialog-titlebar-close').css({'background':'transparent','border':'none','font-size':'1.8rem','margin-top':'-14px','margin-right':'-18px'}).html('<i class="fa fa-times"></i>').prop('title');
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
$('.ui-button-text').css({'padding':'0px 5px'});
@@ -304,5 +565,119 @@ $(function() {
<div markdown="1" id="templateISO" class="template">
_(ISO Image)_:
: <input type="text" id="target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
</div>
<div markdown="1" id="templateISOboth" class="template">
_(CD1 ISO Image)_:
: <input type="text" id="target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop=""><br>
_(CD2 ISO Image)_:
: <input type="text" id="target2" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
</div>
<div id="dialogWindow2"></div>
<div markdown="1" id="templatesnapshotcreate" class="template">
<table id='snapshot'>
<br><br>
<tr><td> _(VM Name)_:</td><td>
<label id="VMName"></label></td></tr>
<tr><td>_(Snapshot Name)_:</td><td>
<input type="text" id="targetsnap" autocomplete="off" spellcheck="false" value="--generate" onclick="this.select()">
_(Check free space)_:
<input type="checkbox" id="targetsnapfspc" checked></td></tr>
<tr><td>_(Description )_:</td><td>
<input type="text" id="targetsnapdesc" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
</table>
</div>
<div markdown="1" id="templatesnapshotrevert" class="template">
_(VM Name)_:
<label id="VMName"></label>
<br>
_(Snapshot Name)_:
<input type="text" id="targetsnap" hidden>
<label id="targetsnapl"></label><br>
_(Remove Images)_:
<input type="checkbox" id="targetsnaprmv" checked >
_(Remove Meta)_:
<input type="checkbox" id="targetsnaprmvmeta" checked>
<!--_(Keep snapshot)_:-->
<input type="checkbox" id="targetsnapkeep" hidden><br>
<label id="targetsnapimages"></label><br>
<div markdown="1" id="templatesnapshotremove" class="template" post>
_(!! Warning removing Snapshots can break the chain !!)_<br><br>
_(VM Name)_:
<label id="VMName"></label>
<br>
_(Snapshot Name)_:
<input type="text" id="targetsnap" hidden>
<label id="targetsnapl"></label><br>
<label id="targetsnapimages"></label><br>
<div markdown="1" id="templateblock" class="template">
_(VM Name)_:
<label id="VMName"></label>
<br>
_(Snapshot Name)_:
<input type="text" id="targetsnap" hidden>
<label id="targetsnapl"></label><br>
<br><br><br><br>
<table id='block'>
<tr><td>_(Base Image)_:</td><td>
<select class="targetblockbase" s>
</select></td></tr>
<tr name="toprow" class="toprow" ><td>_(Top Image )_:</td><td>
<select class="targetblocktop" name="targetblocktop" id="targetblocktop">
</select></td><td>
<tr name="targetpivotrow" class="targetpivotrow" ><td>_(Pivot)_:</td><td>
<input type="checkbox" id="targetpivot" checked></td></tr>
<tr name="targetdeleterow" class="targetdeleterow" ><td>_(Delete)_:</td><td>
<input type="checkbox" id="targetdelete" checked></td></tr>
</table>
<input type="checkbox" id="targetsnapkeep" hidden><br>
<label id="targetsnapimages"></label><br>
</div>
<div id="dialogWindow"></div>
<div markdown="1" id="templateClone" class="template">
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=1600">
<meta name="robots" content="noindex, nofollow">
<meta name="referrer" content="same-origin">
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
</head>
<body>
<br>
<table>
<tr><td>_(VM Being Cloned)_:</td>
<td><span id="VMBeingCloned"></span></td></tr>
<tr><td>_(New VM)_:</td>
<td><input type="text" id="target" autocomplete="off" spellcheck="false" value="" onclick="this.select()" ></td></tr>
<tr><td>_(Overwrite)_:</td>
<td><input type="checkbox" id="Overwrite" value="" ></td></tr>
<tr hidden><td>_(Start Cloned VM)_:</td>
<td><input type="checkbox" id="Start" value="" ></td></tr>
<tr hidden><td>_(Edit VM after clone)_:</td>
<td><input type="checkbox" id="Edit" value="" ></td></tr>
<tr><td>_(Check Free Space)_:</td>
<td><input type="checkbox" id="Free" value="" ></td></tr>
</table>
</body>
</html>
</div>
</div>
</div>
@@ -21,6 +21,7 @@ require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
$user_prefs = '/boot/config/plugins/dynamix.vm.manager/userprefs.cfg';
if (file_exists('/boot/config/plugins/dynamix.vm.manager/vmpreview')) $vmpreview = true ; else $vmpreview = false ;
$vms = $lv->get_domains();
if (empty($vms)) {
echo '<tr><td colspan="8" style="text-align:center;padding-top:12px">'._('No Virtual Machines installed').'</td></tr>';
@@ -51,6 +52,8 @@ foreach ($vms as $vm) {
$icon = $lv->domain_get_icon_url($res);
$image = substr($icon,-4)=='.png' ? "<img src='$icon' class='img'>" : (substr($icon,0,5)=='icon-' ? "<i class='$icon img'></i>" : "<i class='fa fa-$icon img'></i>");
$arrConfig = domain_to_config($uuid);
$snapshots = getvmsnapshots($vm) ;
$cdroms = $lv->get_cdrom_stats($res) ;
if ($state == 'running') {
$mem = $dom['memory']/1024;
} else {
@@ -101,7 +104,7 @@ foreach ($vms as $vm) {
}
unset($dom);
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ;
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log), $vmrcconsole);
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log), $vmrcconsole,$vmpreview);
$kvm[] = "kvm.push({id:'$uuid',state:'$state'});";
switch ($state) {
case 'running':
@@ -123,12 +126,33 @@ foreach ($vms as $vm) {
}
/* VM information */
if ($snapshots != null) $snapshotstr = _("(Snapshots :").count($snapshots).')' ; else $snapshotstr = _("(Snapshots :None)") ;
$cdbus = $cdbus2 = $cdfile = $cdfile2 = "" ;
$cdromcount = 0 ;
foreach ($cdroms as $arrCD) {
$disk = $arrCD['file'] ?? $arrCD['partition'];
$dev = $arrCD['device'];
$bus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
if ($dev == "hda") {
$cdbus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
$cdfile = $arrCD['file'] ?? $arrCD['partition'];
if ($cdfile != "") $cdromcount++ ;
}
if ($dev == "hdb") {
$cdbus2 = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
$cdfile2 = $arrCD['file'] ?? $arrCD['partition'];
if ($cdfile2 != "") $cdromcount++ ;
}
}
$changemedia = "getisoimageboth(\"{$uuid}\",\"hda\",\"{$cdbus}\",\"{$cdfile}\",\"hdb\",\"{$cdbus2}\",\"{$cdfile2}\")";
$cdstr = $cdromcount." / 2<a class='hand' title='$title' href='#' onclick='$changemedia'> <i class='fa fa-bullseye' ></i></a>";
echo "<tr parent-id='$i' class='sortable'><td class='vm-name' style='width:220px;padding:8px'><i class='fa fa-arrows-v mover orange-text'></i>";
echo "<span class='outer'><span id='vm-$uuid' $menu class='hand'>$image</span><span class='inner'><a href='#' onclick='return toggle_id(\"name-$i\")' title='click for more VM info'>$vm</a><br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)."</span></span></span></td>";
echo "<span class='outer'><span id='vm-$uuid' $menu class='hand'>$image</span><span class='inner'><a href='#' onclick='return toggle_id(\"name-$i\")' title='click for more VM info'>$vm</a><br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)." $snapshotstcount</span></span></span></td>";
echo "<td>$desc</td>";
echo "<td><a class='vcpu-$uuid' style='cursor:pointer'>$vcpu</a></td>";
echo "<td>$mem</td>";
echo "<td title='$diskdesc'>$disks</td>";
echo "<td title='$diskdesc'><span class='state' >$disks&nbsp;&nbsp;&nbsp;&nbsp;$cdstr<br>$snapshotstr</span></td>";
echo "<td>$graphics</td>";
echo "<td><input class='autostart' type='checkbox' name='auto_{$vm}' title=\""._('Toggle VM autostart')."\" uuid='$uuid' $autostart></td></tr>";
@@ -168,13 +192,13 @@ foreach ($vms as $vm) {
}
/* Display VM cdroms */
foreach ($lv->get_cdrom_stats($res) as $arrCD) {
foreach ($cdroms as $arrCD) {
$capacity = $lv->format_size($arrCD['capacity'], 0);
$allocation = $lv->format_size($arrCD['allocation'], 0);
$disk = $arrCD['file'] ?? $arrCD['partition'];
$disk = $arrCD['file'] ?? $arrCD['partition'] ?? "" ;
$dev = $arrCD['device'];
$bus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
$boot= $arrCD["boot order"];
$boot= $arrCD["boot order"] ?? "" ;
if ($boot < 1) $boot="Not set";
if ($disk != "" ) {
$title = _("Eject CD Drive").".";
@@ -214,12 +238,43 @@ foreach ($vms as $vm) {
}
}
}
} else {
}
else {
if ($gastate == "disconnected") echo "<tr><td>"._('Guest agent not installed')."</td><td></td><td></td><td></td></tr>";
else echo "<tr><td>"._('Guest not running')."</td><td></td><td></td><td></td><td></td></tr>";
}
echo "</tbody></table>";
echo "</td></tr>";
echo "</tbody>";
/* Display VM Snapshots */
if ($snapshots != null) {
$j=0 ;
$steps = array() ;
foreach($snapshots as $snap) {
if ($snap['parent'] == "" || $snap['parent'] == "Base") $j++;
$steps[$j] .= $snap['name'].';' ;
}
echo "<thead class='child' child-id='$i'><tr><th><i class='fa fa-clone'></i> <b>"._('Snapshots')."</b></th><th></th><th>"._('Date/Time')."</th><th>"._('Type')."</th><th>"._('Parent')."</th><th>"._('Memory')."</th></tr></thead>";
echo "<tbody class='child'child-id='$i'>";
foreach($steps as $stepsline)
{
$snapshotlist = explode(";",$stepsline) ;
$tab = "&nbsp;&nbsp;&nbsp;&nbsp;" ;
foreach($snapshotlist as $snapshotitem) {
if ($snapshotitem == "") continue ;
$snapshot = $snapshots[$snapshotitem] ;
$snapshotstate = _(ucfirst($snapshot["state"])) ;
$snapshotdesc = $snapshot["desc"] ;
$snapshotmemory = _(ucfirst($snapshot["memory"]["@attributes"]["snapshot"])) ;
$snapshotparent = $snapshot["parent"] ? $snapshot["parent"] : "None";
$snapshotdatetime = my_time($snapshot["creationtime"],"Y-m-d" )."<br>".my_time($snapshot["creationtime"],"H:i:s") ;
$snapmenu = sprintf("onclick=\"addVMSnapContext('%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,$snapshot["name"],$vmpreview);
echo "<tr><td><span id='vmsnap-$uuid' $snapmenu class='hand'>$tab|__&nbsp;&nbsp;<i class='fa fa-clone'></i></span>&nbsp;".$snapshot["name"]."</td><td>$snapshotdesc</td><td><span class='inner' style='font-size:1.1rem;'>$snapshotdatetime</span></td><td>$snapshotstate</td><td>$snapshotparent</td><td>$snapshotmemory</td></tr>";
$tab .="&nbsp;&nbsp;&nbsp;&nbsp;" ;
}
echo "</tbody>";
}
}
echo "</table>";
}
echo "\0".implode($kvm);
?>
@@ -265,6 +265,40 @@ case 'change-media':
: ['error' => "Change Media Failed"];
break;
case 'change-media-both':
requireLibvirt();
$res = $lv->get_domain_by_name($domName);
$cdroms = $lv->get_cdrom_stats($res) ;
$hda = $hdb = false ;
foreach ($lv->get_cdrom_stats($res) as $cd){
if ($cd['device'] == 'hda') $hda = true ;
if ($cd['device'] == 'hdb') $hdb = true ;
}
$file= $_REQUEST['file'];
if ($file != "" && $hda == false) {
$cmdstr = "virsh attach-disk '$domName' '$file' hda --type cdrom --targetbus sata --config" ;
} else {
if ($file == "") $cmdstr = "virsh change-media '$domName' hda --eject --current";
else $cmdstr = "virsh change-media '$domName' hda '$file'";
}
$rtn=shell_exec($cmdstr)
? ['success' => true]
: ['error' => "Change Media Failed"];
if (isset($rtn['error'])) return ;
$file2 = $_REQUEST['file2'];
if ($file2 != "" && $hdb == false) {
$cmdstr = "virsh attach-disk '$domName' '$file2' hdb --type cdrom --targetbus sata --config" ;
} else {
if ($file2 == "") $cmdstr = "virsh change-media '$domName' hdb --eject --current";
else $cmdstr = "virsh change-media '$domName' hdb '$file2' ";
}
$rtn=shell_exec($cmdstr)
? ['success' => true]
: ['error' => "Change Media Failed"];
break;
case 'memory-change':
requireLibvirt();
$arrResponse = $lv->domain_set_memory($domName, $_REQUEST['memory']*1024)
@@ -302,6 +336,40 @@ case 'snap-create':
: ['error' => $lv->get_last_error()];
break;
case 'snap-create-external':
requireLibvirt();
$arrResponse = vm_snapshot($domName,$_REQUEST['snapshotname'],$_REQUEST['desc'],$_REQUEST['free']) ;
break;
case 'snap-images':
requireLibvirt();
$html = vm_snapimages($domName,$_REQUEST['snapshotname'],$_REQUEST['only']) ;
$arrResponse = ['html' => $html , 'success' => true] ;
break;
case 'snap-list':
requireLibvirt();
$arrResponse = ($data = getvmsnapshots($domName))
? ['success' => true]
: ['error' => $lv->get_last_error()];
$datartn = "";
foreach($data as $snap=>$snapdetail) {
$snapshotdatetime = date("Y-m-d H:i:s",$snapdetail["creationtime"]) ;
$datartn .= "<option value='$snap'>$snap $snapshotdatetime</option>" ;
}
$arrResponse['html'] = $datartn ;
break;
case 'snap-revert-external':
requireLibvirt();
$arrResponse = vm_revert($domName,$_REQUEST['snapshotname'],$_REQUEST['remove'], $_REQUEST['removemeta']) ;
break;
case 'snap-remove-external':
requireLibvirt();
$arrResponse = vm_snapremove($domName,$_REQUEST['snapshotname']) ;
break;
case 'snap-delete':
requireLibvirt();
$arrResponse = $lv->domain_snapshot_delete($domName, $_REQUEST['snap'])
@@ -267,7 +267,7 @@
}
function config_to_xml($config) {
function config_to_xml($config,$vmclone = false) {
$domain = $config['domain'];
$media = $config['media'];
$nics = $config['nic'];
@@ -463,19 +463,26 @@
$usbstr = '';
if (!empty($usb)) {
foreach($usb as $i => $v){
$usbx = explode(':', $v);
if ($vmclone) $usbx = explode(':', $v['id']); else $usbx = explode(':', $v);
$startupPolicy = '' ;
if (isset($usbopt[$v])) {
if (isset($usbopt[$v]) && !$vmclone ) {
if (strpos($usbopt[$v], "#remove") == false) $startupPolicy = 'startupPolicy="optional"' ; else $startupPolicy = '' ;
}
}
if (isset($v["startupPolicy"]) && $vmclone ) {
if ($v["startupPolicy"] == "optional" ) $startupPolicy = 'startupPolicy="optional"' ; else $startupPolicy = '' ;
}
$usbstr .= "<hostdev mode='subsystem' type='usb'>
<source $startupPolicy>
<vendor id='0x".$usbx[0]."'/>
<product id='0x".$usbx[1]."'/>
</source>" ;
if (!empty($usbboot[$v])) {
if (!empty($usbboot[$v]) && !$vmclone ) {
$usbstr .= "<boot order='".$usbboot[$v]."'/>" ;
}
}
if (isset($v["usbboot"]) && $vmclone ) {
if ($v["usbboot"] != NULL) $usbstr .= "<boot order='".$v["usbboot"]."'/>" ;
}
$usbstr .= "</hostdev>";
}
}
@@ -774,17 +781,20 @@
if ($strAutoport == "yes") $strPort = $strWSport = "-1" ;
if (($gpu['copypaste'] == "yes") && ($strProtocol == "spice")) $vmrcmousemode = "<mouse mode='server'/>" ; else $vmrcmousemode = "" ;
if ($strProtocol == "spice") $virtualaudio = "spice" ; else $virtualaudio = "none" ;
$vmrc = "<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='$strProtocol' port='$strPort' autoport='$strAutoport' websocket='$strWSport' listen='0.0.0.0' $passwdstr $strKeyMap>
<graphics type='$strProtocol' sharePolicy='ignore' port='$strPort' autoport='$strAutoport' websocket='$strWSport' listen='0.0.0.0' $passwdstr $strKeyMap>
<listen type='address' address='0.0.0.0'/>
$vmrcmousemode
</graphics>
<video>
<model type='$strModelType'/>
</video>";
</video>
<audio id='1' type='$virtualaudio'/>";
if ($gpu['copypaste'] == "yes") {
if ($strProtocol == "spice") {
@@ -865,20 +875,23 @@
if (empty($pci_id) || in_array($pci_id, $pcidevs_used)) {
continue;
}
[$pci_bus, $pci_slot, $pci_function] = my_explode(":", str_replace('.', ':', $pci_id), 3);
if ($vmclone) [$pci_bus, $pci_slot, $pci_function] = my_explode(":", str_replace('.', ':', $pci_id['id']), 3);
else [$pci_bus, $pci_slot, $pci_function] = my_explode(":", str_replace('.', ':', $pci_id), 3);
$pcidevs .= "<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0000' bus='0x" . $pci_bus . "' slot='0x" . $pci_slot . "' function='0x" . $pci_function . "'/>
</source>" ;
if (!empty($pciboot[$pci_id])) {
if (!empty($pciboot[$pci_id]) && !$vmclone) {
$pcidevs .= "<boot order='".$pciboot[$pci_id]."'/>" ;
}
if (!empty($pci_id["boot"]) && $vmclone) {
$pcidevs .= "<boot order='".$pci_id["boot"]."'/>" ;
}
$pcidevs .= "</hostdev>";
$pcidevs_used[] = $pci_id;
if ($vmclone) $pcidevs_used[] = $pci_id['d']; else $pcidevs_used[] = $pci_id ;
}
}
@@ -1144,7 +1157,7 @@
$tmp = libvirt_domain_get_block_info($dom, $disks[$i]);
if ($tmp) {
$tmp['bus'] = $buses[$i];
$tmp["boot order"] = $boot[$i] ;
$tmp["boot order"] = $boot[$i] ?? "";
$ret[] = $tmp;
}
else {
@@ -1195,7 +1208,7 @@
if ($tmp) {
$tmp['bus'] = $disk->target->attributes()->bus->__toString();
$tmp["boot order"] = $disk->boot->attributes()->order ;
$tmp["boot order"] = $disk->boot->attributes()->order ?? "";
$tmp['serial'] = $disk->serial ;
// Libvirt reports 0 bytes for raw disk images that haven't been
@@ -1454,7 +1467,7 @@
function domain_change_xml($domain, $xml) {
$dom = $this->get_domain_object($domain);
if (!($old_xml = domain_get_xml($dom)))
if (!($old_xml = $this->domain_get_xml($dom)))
return $this->_set_last_error();
if (!libvirt_domain_undefine($dom))
return $this->_set_last_error();
@@ -1487,6 +1500,11 @@
return ($tmp) ? $tmp : $this->_set_last_error();
}
function get_interface_addresses($domain,$flag) {
$tmp = libvirt_domain_interface_addresses($domain,$flag);
return ($tmp) ? $tmp : $this->_set_last_error();
}
function get_node_device_res($res) {
if ($res == false)
return false;
@@ -1590,7 +1608,7 @@
if (!$dom)
return false;
$tmp = libvirt_domain_get_xml_desc($dom, $xpath);
$tmp = libvirt_domain_get_xml_desc($dom, 0);
return ($tmp) ? $tmp : $this->_set_last_error();
}
@@ -1854,6 +1872,48 @@
return false;
}
function nvram_create_snapshot($uuid,$snapshotname) {
// snapshot backup OVMF VARS if this domain had them
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd')) {
copy('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd', '/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd');
return true;
}
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd')) {
copy('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd', '/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd');
return true;
}
return false;
}
function nvram_revert_snapshot($uuid,$snapshotname) {
// snapshot backup OVMF VARS if this domain had them
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd')) {
copy('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd', '/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd');
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd') ;
return true;
}
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd')) {
copy('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd', '/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd');
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd') ;
return true;
}
return false;
}
function nvram_delete_snapshot($uuid,$snapshotname) {
// snapshot backup OVMF VARS if this domain had them
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd')) {
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd') ;
return true;
}
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd')) {
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd') ;
return true;
}
return false;
}
function is_dir_empty($dir) {
if (!is_readable($dir)) return NULL;
$handle = opendir($dir);
@@ -1992,7 +2052,7 @@
function domain_get_description($domain) {
$tmp = $this->get_xpath($domain, '//domain/description', false);
$var = $tmp[0];
$var = $tmp[0] ?? "";
unset($tmp);
return $var;
@@ -2194,33 +2254,34 @@
// Get any pci devices contained in the qemu args
$args = $this->get_xpath($domain, '//domain/*[name()=\'qemu:commandline\']/*[name()=\'qemu:arg\']/@value', false);
if (isset($args['num'])) {
for ($i = 0; $i < $args['num']; $i++) {
if (strpos($args[$i], 'vfio-pci') !== 0) {
continue;
}
for ($i = 0; $i < $args['num']; $i++) {
if (strpos($args[$i], 'vfio-pci') !== 0) {
continue;
}
$arg_list = explode(',', $args[$i]);
$arg_list = explode(',', $args[$i]);
foreach ($arg_list as $arg) {
$keypair = explode('=', $arg);
foreach ($arg_list as $arg) {
$keypair = explode('=', $arg);
if ($keypair[0] == 'host' && !empty($keypair[1])) {
$devid = 'pci_0000_' . str_replace([':', '.'], '_', $keypair[1]);
$tmp2 = $this->get_node_device_information($devid);
[$bus, $slot, $func] = my_explode(":", str_replace('.', ':', $keypair[1]), 3);
$devs[] = [
'domain' => '0x0000',
'bus' => '0x' . $bus,
'slot' => '0x' . $slot,
'func' => '0x' . $func,
'id' => $keypair[1],
'vendor' => $tmp2['vendor_name'],
'vendor_id' => $tmp2['vendor_id'],
'product' => $tmp2['product_name'],
'product_id' => $tmp2['product_id']
];
break;
if ($keypair[0] == 'host' && !empty($keypair[1])) {
$devid = 'pci_0000_' . str_replace([':', '.'], '_', $keypair[1]);
$tmp2 = $this->get_node_device_information($devid);
[$bus, $slot, $func] = my_explode(":", str_replace('.', ':', $keypair[1]), 3);
$devs[] = [
'domain' => '0x0000',
'bus' => '0x' . $bus,
'slot' => '0x' . $slot,
'func' => '0x' . $func,
'id' => $keypair[1],
'vendor' => $tmp2['vendor_name'],
'vendor_id' => $tmp2['vendor_id'],
'product' => $tmp2['product_name'],
'product_id' => $tmp2['product_id']
];
break;
}
}
}
}
@@ -2249,15 +2310,17 @@
$pid = $this->get_xpath($domain, $xpath.'product/@id', false);
$devs = [];
for ($i = 0; $i < $vid['num']; $i++) {
$dev = $this->_lookup_device_usb($vid[$i], $pid[$i]);
$devs[] = [
'id' => str_replace('0x', '', $vid[$i] . ':' . $pid[$i]),
'vendor_id' => $vid[$i],
'product_id' => $pid[$i],
'product' => $dev['product_name'],
'vendor' => $dev['vendor_name']
];
if (isset($vid['num'])) {
for ($i = 0; $i < $vid['num']; $i++) {
$dev = $this->_lookup_device_usb($vid[$i], $pid[$i]);
$devs[] = [
'id' => str_replace('0x', '', $vid[$i] . ':' . $pid[$i]),
'vendor_id' => $vid[$i],
'product_id' => $pid[$i],
'product' => $dev['product_name'],
'vendor' => $dev['vendor_name']
];
}
}
return $devs;
@@ -2291,7 +2354,7 @@
'mac' => $macs[$i],
'network' => $net[0],
'model' => $model[0],
'boot' => $boot[0]
'boot' => $boot[0] ?? ""
];
}
@@ -2469,6 +2532,12 @@
return ($tmp) ? $tmp : $this->_set_last_error();
}
//list all snapshots for domain
function domain_snapshot_get_xml($domain) {
$tmp = libvirt_domain_snapshot_get_xml($domain);
return ($tmp) ? $tmp : $this->_set_last_error();
}
// create a snapshot and metadata node for description
function domain_snapshot_create($domain) {
$this->domain_set_metadata($domain);
@@ -2478,10 +2547,9 @@
}
//delete snapshot and metadata
function domain_snapshot_delete($domain, $name) {
$this->snapshot_remove_metadata($domain, $name);
function domain_snapshot_delete($domain, $name, $flags=0) {
$name = $this->domain_snapshot_lookup_by_name($domain, $name);
$tmp = libvirt_domain_snapshot_delete($name);
$tmp = libvirt_domain_snapshot_delete($name,$flags);
return ($tmp) ? $tmp : $this->_set_last_error();
}
@@ -163,6 +163,7 @@ private static $encoding = 'UTF-8';
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
require_once "$docroot/webGui/include/Custom.php";
// Load emhttp variables if needed.
if (!isset($var)){
@@ -755,6 +756,15 @@ private static $encoding = 'UTF-8';
$arrWhitelistGPUClassIDregex = '/^(0001|03)/';
$arrWhitelistAudioClassIDregex = '/^(0403)/';
# "System peripheral [0880]" "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]" -pff "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]"
# typeid productid
# file is csv typeid:productid
#
if (is_file("/boot/config/VMPCIOverride.cfg")) {
$arrWhiteListOverride = str_getcsv(file_get_contents("/boot/config/VMPCIOverride.cfg")) ;
}
$arrWhiteListOverride[] = "0880:089a" ;
$arrValidPCIDevices = [];
exec("lspci -m -nn 2>/dev/null", $arrAllPCIDevices);
@@ -769,6 +779,9 @@ private static $encoding = 'UTF-8';
$boolBlacklisted = true;
}
$overrideCheck = "${arrMatch['typeid']}:${arrMatch['productid']}" ;
if (in_array($overrideCheck,$arrWhiteListOverride) ) $boolBlacklisted = false;
$strClass = 'other';
if (preg_match($arrWhitelistGPUClassIDregex, $arrMatch['typeid'])) {
$strClass = 'vga';
@@ -1203,6 +1216,7 @@ private static $encoding = 'UTF-8';
$arrDisks[] = [
'new' => $strPath,
'size' => '',
'driver' => $disk['type'],
'driver' => 'raw',
'dev' => $disk['device'],
'bus' => $disk['bus'],
@@ -1370,7 +1384,7 @@ private static $encoding = 'UTF-8';
$vendor=$USB->source->vendor->attributes()->id ;
$product=$USB->source->product->attributes()->id ;
$startupPolicy=$USB->source->attributes()->startupPolicy ;
$usbboot= $USB->boot->attributes()->order ;
$usbboot= $USB->boot->attributes()->order ?? "" ;
$id = str_replace('0x', '', $vendor . ':' . $product) ;
$found = false ;
foreach($arrValidUSBDevices as $key => $data) {
@@ -1420,7 +1434,7 @@ private static $encoding = 'UTF-8';
global $lv ;
$xml = new SimpleXMLElement($lv->domain_get_xml($res)) ;
$data = $xml->xpath('//channel/target[@name="org.qemu.guest_agent.0"]/@state') ;
$data = $data[0]->state ;
$data = $data[0]->state ?? null ;
return $data ;
}
@@ -1454,4 +1468,779 @@ private static $encoding = 'UTF-8';
if ($spicevmc || $qemuvdaagent) $copypaste = true ; else $copypaste = false ;
return $copypaste ;
}
function vm_clone($vm, $clone ,$overwrite,$start,$edit, $free, $waitID) {
global $lv,$domain_cfg ;
/*
Clone.
Stopped only.
Get new VM Name
Extract XML for VM to be cloned.
Check if directory exists.
Check for disk space
Stop VM Starting until clone is finished or fails.
Create new directory for Clone.
Update paths with new directory
Create new UUID
Create new MAC Address for NICs
Create VM Disks from source. Options full or Sparce. Method of copy?
release orginal VM to start.
If option to edit, show VMUpdate
*/
$uuid = $lv->domain_get_uuid($clone) ;
write("addLog\0".htmlspecialchars(_("Checking if clone exists")));
if ($uuid) { $arrResponse = ['error' => _("Clone VM name already inuse")]; return false ;}
#VM must be shutdown.
$res = $lv->get_domain_by_name($vm);
$dom = $lv->domain_get_info($res);
$state = $lv->domain_state_translate($dom['state']);
$vmxml = $lv->domain_get_xml($res) ;
file_put_contents("/tmp/cloningxml" ,$vmxml) ;
# if VM running shutdown. Record was running.
if ($state != 'shutoff') {write("addLog\0".htmlspecialchars(_("Shuting down $vm current $state"))); $arrResponse = $lv->domain_destroy($vm) ; }
# Wait for shutdown?
$disks =$lv->get_disk_stats($vm) ;
$capacity = 0 ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$pathinfo = pathinfo($file) ;
$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ;
$capacity = $capacity + $disk["capacity"] ;
}
$dirpath = $pathinfo["dirname"] ;
#Check free space.
write("addLog\0".htmlspecialchars("Checking for free space"));
$dirfree = disk_free_space($pathinfo["dirname"]) ;
$sourcedir = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($pathinfo["dirname"])." 2>/dev/null"));
$repdir = str_replace('/mnt/user/', "/mnt/$sourcedir/", $pathinfo["dirname"]);
$repdirfree = disk_free_space($repdir) ;
$reflink = true ;
$capacity *= 1 ;
if ($free == "yes" && $repdirfree < $capacity) { $reflink = false ;}
if ($free == "yes" && $dirfree < $capacity) { write("addLog\0".htmlspecialchars(_("Insufficent storage for clone"))); return false ;}
#Clone XML
$uuid = $lv->domain_get_uuid($vm) ;
$config=domain_to_config($uuid) ;
$config["domain"]["name"] = $clone ;
$config["domain"]["uuid"] = $lv->domain_generate_uuid() ;
foreach($config["nic"] as $index => $detail) {
$config["nic"][$index]["mac"] = $lv->generate_random_mac_addr() ;
}
$config["domain"]["type"] = "kvm";
$usbs = getVMUSBs($vmxml) ;
foreach($usbs as $i => $usb) {
if ($usb["checked"] == "checked") continue ;
unset($usbs[$i]) ;
}
$config["usb"] = $usbs ;
$files_exist = false ;
$files_clone = array() ;
foreach ($config["disk"] as $diskid => $disk) {
$file_clone[$diskid]["source"] = $config["disk"][$diskid]["new"] ;
$config["disk"][$diskid]["new"] = str_replace($vm,$clone,$config["disk"][$diskid]["new"]) ;
$pi = pathinfo($config["disk"][$diskid]["new"]) ;
$isdir = is_dir($pi['dirname']) ;
if (is_file($config["disk"][$diskid]["new"])) $file_exists = true ;
$file_clone[$diskid]["target"] = $config["disk"][$diskid]["new"] ;
}
$clonedir = $domain_cfg['DOMAINDIR'].$clone ;
if (!is_dir($clonedir)) {
mkdir($clonedir,0777,true) ;
chown($clonedir, 'nobody');
chgrp($clonedir, 'users');
}
write("addLog\0".htmlspecialchars("Checking for image files"));
if ($file_exists && $overwrite != "yes") { write("addLog\0".htmlspecialchars(_("New image file names exist and Overwrite is not allowed"))); return( false) ; }
#Create duplicate files.
foreach($file_clone as $diskid => $disk) {
$target = $disk['target'] ;
$source = $disk['source'] ;
if ($target == $source) { write("addLog\0".htmlspecialchars(_("New image file is same as old"))); return( false) ; }
$sourcerealdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($source)." 2>/dev/null"));
$reptgt = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $target);
$repsrc = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $source);
#var_dump($repsrc,$reptgt) ;
$cmdstr = "cp --reflink=always '$repsrc' '$reptgt'" ;
if ($reflink == true) { $refcmd = $cmdstr ; } else {$refcmd = false; }
$cmdstr = "rsync -ahPIXS --out-format=%f --info=flist0,misc0,stats0,name1,progress2 '$source' '$target'" ;
$error = execCommand_nchan($cmdstr,$path,$refcmd) ;
if (!$error) { write("addLog\0".htmlspecialchars("Image copied failed.")); return( false) ; }
}
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._("Completing Clone").": </legend><p class='logLine'></p><span id='wait-$waitID'></span></fieldset>");
write("addLog\0".htmlspecialchars("Creating new XML $clone"));
$xml = $lv->config_to_xml($config, true) ;
file_put_contents("/tmp/clonexml" ,$xml) ;
$rtn = $lv->domain_define($xml) ;
return($rtn) ;
}
function compare_creationtime($a, $b) {
return strnatcmp($a['creationtime'], $b['creationtime']);
}
function compare_creationtimelt($a, $b) {
return $a['creationtime'] < $b['creationtime'];
}
function getvmsnapshots($vm) {
$snaps=array() ;
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
$snaps = json_decode($snaps_json,true) ;
if (is_array($snaps)) uasort($snaps,'compare_creationtime') ;
return $snaps ;
}
function write_snapshots_database($vm,$name) {
global $lv ;
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
if (!is_dir($dbpath)) mkdir($dbpath) ;
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
$snaps = json_decode($snaps_json,true) ;
$snapshot_res=$lv->domain_snapshot_lookup_by_name($vm,$name) ;
$snapshot_xml=$lv->domain_snapshot_get_xml($snapshot_res) ;
$a = simplexml_load_string($snapshot_xml) ;
$a = json_encode($a) ;
$b= json_decode($a, TRUE);
$vmsnap = $b["name"] ;
$snaps[$vmsnap]["name"]= $b["name"];
$snaps[$vmsnap]["parent"]= $b["parent"] ;
$snaps[$vmsnap]["state"]= $b["state"];
$snaps[$vmsnap]["desc"]= $b["description"];
$snaps[$vmsnap]["memory"]= $b["memory"];
$snaps[$vmsnap]["creationtime"]= $b["creationTime"];
$disks =$lv->get_disk_stats($vm) ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$output = "" ;
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
foreach($output as $key => $line) {
$line=str_replace("image: ","",$line) ;
$output[$key] = $line ;
}
$snaps[$vmsnap]['backing'][$disk["device"]] = $output ;
$rev = "r".$disk["device"] ;
$reversed = array_reverse($output) ;
$snaps[$vmsnap]['backing'][$rev] = $reversed ;
}
$parentfind = $snaps[$vmsnap]['backing'][$disk["device"]] ;
$parendfileinfo = pathinfo($parentfind[1]) ;
$snaps[$vmsnap]["parent"]= $parendfileinfo["extension"];
$snaps[$vmsnap]["parent"] = str_replace("qcow2",'',$snaps[$vmsnap]["parent"]) ;
if (isset($parentfind[1]) && !isset($parentfind[2])) $snaps[$vmsnap]["parent"]="Base" ;
if (array_key_exists(0 , $b["disks"]["disk"])) $snaps[$vmsnap]["disks"]= $b["disks"]["disk"]; else $snaps[$vmsnap]["disks"][0]= $b["disks"]["disk"];
$value = json_encode($snaps,JSON_PRETTY_PRINT) ;
file_put_contents($dbpath."/snapshots.db",$value) ;
}
function refresh_snapshots_database($vm) {
global $lv ;
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
if (!is_dir($dbpath)) mkdir($dbpath) ;
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
$snaps = json_decode($snaps_json,true) ;
foreach($snaps as $vmsnap=>$snap)
$disks =$lv->get_disk_stats($vm) ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$output = "" ;
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
foreach($output as $key => $line) {
$line=str_replace("image: ","",$line) ;
$output[$key] = $line ;
}
$snaps[$vmsnap]['backing'][$disk["device"]] = $output ;
$rev = "r".$disk["device"] ;
$reversed = array_reverse($output) ;
$snaps[$vmsnap]['backing'][$rev] = $reversed ;
}
$parentfind = $snaps[$vmsnap]['backing'][$disk["device"]] ;
$parendfileinfo = pathinfo($parentfind[1]) ;
$snaps[$vmsnap]["parent"]= $parendfileinfo["extension"];
$snaps[$vmsnap]["parent"] = str_replace("qcow2",'',$snaps[$vmsnap]["parent"]) ;
if (isset($parentfind[1]) && !isset($parentfind[2])) $snaps[$vmsnap]["parent"]="Base" ;
$value = json_encode($snaps,JSON_PRETTY_PRINT) ;
$res = $lv->get_domain_by_name($vm);
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_create_snapshot($lv->domain_get_uuid($vm),$name) ;
#Remove any NVRAMs that are no longer valid.
# Get uuid
$vmuuid = $lv->domain_get_uuid($vm) ;
#Get list of files
#$filepath = "/etc/libvirt/qemu/nvram/'.$uuid*" ; #$snapshotname"
$filepath = "/etc/libvirt/qemu/nvram/$vmuuid*" ; #$snapshotname"
$nvram_files=glob($filepath) ;
foreach($nvram_files as $key => $nvram_file) {
if ($nvram_file == "/etc/libvirt/qemu/nvram/$vmuuid"."_VARS-pure-efi.fd" || $nvram_file == "/etc/libvirt/qemu/nvram/$vmuuid"."_VARS-pure-efi-tpm.fd" ) unset($nvram_files[$key]) ;
foreach ($snaps as $snapshotname => $snap) {
$tpmfilename = "/etc/libvirt/qemu/nvram/".$vmuuid.$snapshotname."_VARS-pure-efi-tpm.fd" ;
$nontpmfilename = "/etc/libvirt/qemu/nvram/".$vmuuid.$snapshotname."_VARS-pure-efi.fd" ;
if ($nvram_file == $tpmfilename || $nvram_file == $nontpmfilename ) {
unset($nvram_files[$key]) ;}
}
}
foreach ($nvram_files as $nvram_file) unlink($nvram_file) ;
file_put_contents($dbpath."/snapshots.db",$value) ;
}
function delete_snapshots_database($vm,$name) {
global $lv ;
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
$snaps = json_decode($snaps_json,true) ;
unset($snaps[$name]) ;
$value = json_encode($snaps,JSON_PRETTY_PRINT) ;
file_put_contents($dbpath."/snapshots.db",$value) ;
return true ;
}
function vm_snapshot($vm,$snapshotname, $snapshotdesc, $free = "yes", $memorysnap = "yes") {
global $lv ;
#Get State
$res = $lv->get_domain_by_name($vm);
$dom = $lv->domain_get_info($res);
$state = $lv->domain_state_translate($dom['state']);
#Get disks for --diskspec
$disks =$lv->get_disk_stats($vm) ;
$diskspec = "" ;
$capacity = 0 ;
if ($snapshotname == "--generate") $name= "S" . date("YmdHis") ; else $name=$snapshotname ;
if ($snapshotdesc != "") $snapshotdesc = " --description '$snapshotdesc'" ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$pathinfo = pathinfo($file) ;
$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ;
$diskspec .= " --diskspec '".$disk["device"]."',snapshot=external,file='".$filenew."'" ;
$capacity = $capacity + $disk["capacity"] ;
}
$dirpath = $pathinfo["dirname"] ;
#get memory
$mem = $lv->domain_get_memory_stats($vm) ;
$memory = $mem[6] ;
if ($memorysnap = "yes") $memspec = ' --memspec "'.$pathinfo["dirname"].'/memory'.$name.'.mem",snapshot=external' ; else $memspec = "" ;
$cmdstr = "virsh snapshot-create-as '$vm' --name '$name' $snapshotdesc --atomic" ;
if ($state == "running") {
$cmdstr .= " --live ".$memspec.$diskspec ;
$capacity = $capacity + $memory ;
} else {
$cmdstr .= " --disk-only ".$diskspec ;
}
#Check free space.
$dirfree = disk_free_space($pathinfo["dirname"]) ;
$capacity *= 1 ;
if ($free == "yes" && $dirfree < $capacity) { $arrResponse = ['error' => _("Insufficent Storage for Snapshot")]; return $arrResponse ;}
#Copy nvram
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_create_snapshot($lv->domain_get_uuid($vm),$name) ;
$xmlfile = $pathinfo["dirname"]."/".$name.".running" ;
file_put_contents("/tmp/xmltst", "$xmlfile" ) ;
if ($state == "running") exec("virsh dumpxml '$vm' > ".escapeshellarg($xmlfile),$outxml,$rtnxml) ;
$output= [] ;
$test = false ;
if ($test) exec($cmdstr." --print-xml 2>&1",$output,$return) ; else exec($cmdstr." 2>&1",$output,$return) ;
if (strpos(" ".$output[0],"error") ) {
$arrResponse = ['error' => substr($output[0],6) ] ;
} else {
$arrResponse = ['success' => true] ;
write_snapshots_database("$vm","$name") ;
#remove meta data
$ret = $lv->domain_snapshot_delete($vm, "$name" ,2) ;
}
return $arrResponse ;
}
function vm_revert($vm, $snap="--current",$action="no",$actionmeta = 'yes') {
global $lv ;
$snapslist= getvmsnapshots($vm) ;
$disks =$lv->get_disk_stats($vm) ;
switch ($snapslist[$snap]['state']) {
case "shutoff":
case "running":
#VM must be shutdown.
$res = $lv->get_domain_by_name($vm);
$dom = $lv->domain_get_info($res);
$state = $lv->domain_state_translate($dom['state']);
# if VM running shutdown. Record was running.
if ($state != 'shutdown') $arrResponse = $lv->domain_destroy($vm) ;
# Wait for shutdown?
# GetXML
$strXML= $lv->domain_get_xml($res) ;
$xmlobj = custom::createArray('domain',$strXML) ;
# Process disks and update path.
$disks=($snapslist[$snap]['disks']) ;
foreach ($disks as $disk) {
$diskname = $disk["@attributes"]["name"] ;
if ($diskname == "hda" || $diskname == "hdb") continue ;
$path = $disk["source"]["@attributes"]["file"] ;
if ($diskname == "hdc") {
$primarypathinfo = pathinfo($path) ;
$primarypath = $primarypathinfo['dirname'] ;
}
$item = array_search($path,$snapslist[$snap]['backing'][$diskname]) ;
$newpath = $snapslist[$snap]['backing'][$diskname][$item + 1];
$json_info = getDiskImageInfo($newpath) ;
foreach($xmlobj['devices']['disk'] as $ddk => $dd){
if ($dd['target']["@attributes"]['dev'] == $diskname) {
$xmlobj['devices']['disk'][$ddk]['source']["@attributes"]['file'] = "$newpath" ;
$xmlobj['devices']['disk'][$ddk]['driver']["@attributes"]['type'] = $json_info["format"] ;
}
}
}
$xml = custom::createXML('domain',$xmlobj)->saveXML();
$new = $lv->domain_define($xml);
if ($new)
$arrResponse = ['success' => true] ; else
$arrResponse = ['error' => $lv->get_last_error()] ;
# remove snapshot meta data and images for all snpahots.
foreach ($disks as $disk) {
$diskname = $disk["@attributes"]["name"] ;
if ($diskname == "hda" || $diskname == "hdb") continue ;
$path = $disk["source"]["@attributes"]["file"] ;
if (is_file($path) && $action == "yes") unlink("$path") ;
$item = array_search($path,$snapslist[$snap]['backing']["r".$diskname]) ;
$item++ ;
while($item > 0)
{
if (!isset($snapslist[$snap]['backing']["r".$diskname][$item])) break ;
$newpath = $snapslist[$snap]['backing']["r".$diskname][$item] ;
if (is_file($newpath) && $action == "yes") unlink("$newpath") ;
$item++ ;
}
}
uasort($snapslist,'compare_creationtimelt') ;
foreach($snapslist as $s) {
$name = $s['name'] ;
$xmlfile = $primarypath."/$name.running" ;
$memoryfile = $primarypath."/memory$name.mem" ;
if ($snapslist[$snap]['state'] == "running") {
# Set XML to saved XML
$xml = file_get_contents($xmlfile) ;
$xmlobj = custom::createArray('domain',$xml) ;
$xml = custom::createXML('domain',$xmlobj)->saveXML();
$rtn = $lv->domain_define($xml) ;
# Restore Memory.
$makerun = true ;
if ($makerun == true) exec("virsh restore ".escapeshellarg($memoryfile)) ;
#exec("virsh restore $memoryfile") ;
}
#Delete Metadata only.
if ($actionmeta == "yes") {
$ret = delete_snapshots_database("$vm","$name") ;
}
if (is_file($memoryfile) && $action == "yes") unlink($memoryfile) ;
if (is_file($xmlfile) && $action == "yes") unlink($xmlfile) ;
if ($s['name'] == $snap) break ;
}
#if VM was started restart.
if ($state == 'running' && $snapslist[$snap]['state'] != "running") {
$arrResponse = $lv->domain_start($vm) ;
}
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_revert_snapshot($lv->domain_get_uuid($vm),$name) ;
break ;
}
$arrResponse = ['success' => true] ;
return($arrResponse) ;
}
function vm_snapimages($vm, $snap, $only) {
global $lv ;
$snapslist= getvmsnapshots($vm) ;
$data = "<br><br>Images and metadata to remove if tickbox checked.<br>" ;
$disks =$lv->get_disk_stats($vm) ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$output = "" ;
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
foreach($output as $key => $line) {
$line=str_replace("image: ","",$line) ;
$output[$key] = $line ;
}
$snaps[$vm][$disk["device"]] = $output ;
$rev = "r".$disk["device"] ;
$reversed = array_reverse($output) ;
$snaps[$vm][$rev] = $reversed ;
$pathinfo = pathinfo($file) ;
$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ;
$diskspec .= " --diskspec ".$disk["device"].",snapshot=external,file=".$filenew ;
$capacity = $capacity + $disk["capacity"] ;
}
$snapdisks= $snapslist[$snap]['disks'] ;
foreach ($snapdisks as $diskkey => $snapdisk) {
$diskname = $snapdisk["@attributes"]["name"] ;
if ($diskname == "hda" || $diskname == "hdb") continue ;
$path = $snapdisk["source"]["@attributes"]["file"] ;
if (is_file($path)) $data .= "$path<br>" ;
$item = array_search($path,$snaps[$vm]["r".$diskname]) ;
$item++ ;
if ($only == 0) $item = 0 ;
while($item > 0)
{
if (!isset($snaps[$vm]["r".$diskname][$item])) break ;
$newpath = $snaps[$vm]["r".$diskname][$item] ;
if (is_file($path)) $data .= "$newpath<br>" ;
$item++ ;
}
}
$data .= "<br>Snapshots metadata to remove." ;
if ($only == 0) {
$data .= "<br>$snap";
} else {
uasort($snapslist,'compare_creationtimelt') ;
foreach($snapslist as $s) {
$name = $s['name'] ;
$data .= "<br>$name";
if ($s['name'] == $snap) break ;
}
}
return($data) ;
}
function vm_snapremove($vm, $snap) {
global $lv ;
$snapslist= getvmsnapshots($vm) ;
$res = $lv->get_domain_by_name($vm);
$dom = $lv->domain_get_info($res);
$disks =$lv->get_disk_stats($vm) ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$output = "" ;
exec("qemu-img info --backing-chain -U $file | grep image:",$output) ;
foreach($output as $key => $line) {
$line=str_replace("image: ","",$line) ;
$output[$key] = $line ;
}
$snaps[$vm][$disk["device"]] = $output ;
$rev = "r".$disk["device"] ;
$reversed = array_reverse($output) ;
$snaps[$vm][$rev] = $reversed ;
$pathinfo = pathinfo($file) ;
}
# GetXML
$strXML= $lv->domain_get_xml($res) ;
$xmlobj = custom::createArray('domain',$strXML) ;
# Process disks.
$disks=($snapslist[$snap]['disks']) ;
foreach ($disks as $disk) {
$diskname = $disk["@attributes"]["name"] ;
if ($diskname == "hda" || $diskname == "hdb") continue ;
$path = $disk["source"]["@attributes"]["file"] ;
$item = array_search($path,$snaps[$vm][$diskname]) ;
if ($item!==false) {
$data = ["error" => "Image currently active for this domain."] ;
return ($data) ;
}
}
$disks=($snapslist[$snap]['disks']) ;
foreach ($disks as $disk) {
$diskname = $disk["@attributes"]["name"] ;
if ($diskname == "hda" || $diskname == "hdb") continue ;
$path = $disk["source"]["@attributes"]["file"] ;
if (is_file($path)) {
if(!unlink("$path")) {
$data = ["error" => "Unable to remove image file $path"] ;
return ($data) ;
}
}
}
# Delete NVRAM
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_delete_snapshot($lv->domain_get_uuid($vm),$snap) ;
$ret = delete_snapshots_database("$vm","$snap") ;
if(!$ret)
$data = ["error" => "Unable to remove snap metadata $snap"] ;
else
$data = ["success => 'true"] ;
return($data) ;
}
function vm_blockcommit($vm, $snap ,$path,$base,$top,$pivot,$action) {
global $lv ;
/*
NAME
blockcommit - Start a block commit operation.
SYNOPSIS
blockcommit <domain> <path> [--bandwidth <number>] [--base <string>] [--shallow] [--top <string>] [--active] [--delete] [--wait] [--verbose] [--timeout <number>] [--pivot] [--keep-overlay] [--async] [--keep-relative] [--bytes]
DESCRIPTION
Commit changes from a snapshot down to its backing image.
OPTIONS
[--domain] <string> domain name, id or uuid
[--path] <string> fully-qualified path of disk
--bandwidth <number> bandwidth limit in MiB/s
--base <string> path of base file to commit into (default bottom of chain)
--shallow use backing file of top as base
--top <string> path of top file to commit from (default top of chain)
--active trigger two-stage active commit of top file
--delete delete files that were successfully committed
--wait wait for job to complete (with --active, wait for job to sync)
--verbose with --wait, display the progress
--timeout <number> implies --wait, abort if copy exceeds timeout (in seconds)
--pivot implies --active --wait, pivot when commit is synced
--keep-overlay implies --active --wait, quit when commit is synced
--async with --wait, don't wait for cancel to finish
--keep-relative keep the backing chain relatively referenced
--bytes the bandwidth limit is in bytes/s rather than MiB/s
blockcommit Debian --path /mnt/user/domains/Debian/vdisk1.S20230513120410qcow2 --verbose --pivot --delete
*/
# Error if VM Not running.
$snapslist= getvmsnapshots($vm) ;
$disks =$lv->get_disk_stats($vm) ;
foreach($disks as $disk) {
$path = $disk['file'] ;
$cmdstr = "virsh blockcommit '$vm' --path '$path' --verbose " ;
if ($pivot == "yes") $cmdstr .= " --pivot " ;
if ($action == "yes") $cmdstr .= " --delete " ;
# Process disks and update path.
$snapdisks=($snapslist[$snap]['disks']) ;
if ($base != "--base" && $base != "") {
#get file name from snapshot.
$snapdisks=($snapslist[$base]['disks']) ;
$basepath = "" ;
foreach ($snapdisks as $snapdisk) {
$diskname = $snapdisk["@attributes"]["name"] ;
if ($diskname != $disk['device']) continue ;
$basepath = $snapdisk["source"]["@attributes"]["file"] ;
}
if ($basepath != "") $cmdstr .= " --base '$basepath' ";
}
if ($top != "--top" && $top !="") {
#get file name from snapshot.
$snapdisks=($snapslist[$top]['disks']) ;
$toppath = "" ;
foreach ($snapdisks as $snapdisk) {
$diskname = $snapdisk["@attributes"]["name"] ;
if ($diskname != $disk['device']) continue ;
$toppath = $snapdisk["source"]["@attributes"]["file"] ;
}
if ($toppath != "") $cmdstr .= " --top '$toppath' ";
}
$error = execCommand_nchan($cmdstr,$path) ;
if (!$error) {
$arrResponse = ['error' => substr($output[0],6) ] ;
return($arrResponse) ;
} else {
$arrResponse = ['success' => true] ;
}
}
# Delete NVRAM
#if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_delete_snapshot($lv->domain_get_uuid($vm),$snap) ;
refresh_snapshots_database($vm) ;
$ret = $ret = delete_snapshots_database("$vm","$snap") ; ;
if($ret)
$data = ["error" => "Unable to remove snap metadata $snap"] ;
else
$data = ["success => 'true"] ;
return $data ;
}
function vm_blockpull($vm, $snap ,$path,$base,$top,$pivot,$action) {
global $lv ;
/*
NAME
blockpull - Populate a disk from its backing image.
SYNOPSIS
blockpull <domain> <path> [--bandwidth <number>] [--base <string>] [--wait] [--verbose] [--timeout <number>] [--async] [--keep-relative] [--bytes]
DESCRIPTION
Populate a disk from its backing image.
OPTIONS
[--domain] <string> domain name, id or uuid
[--path] <string> fully-qualified path of disk
--bandwidth <number> bandwidth limit in MiB/s
--base <string> path of backing file in chain for a partial pull
--wait wait for job to finish
--verbose with --wait, display the progress
--timeout <number> with --wait, abort if pull exceeds timeout (in seconds)
--async with --wait, don't wait for cancel to finish
--keep-relative keep the backing chain relatively referenced
--bytes the bandwidth limit is in bytes/s rather than MiB/s
*/
$snapslist= getvmsnapshots($vm) ;
$disks =$lv->get_disk_stats($vm) ;
foreach($disks as $disk) {
$file = $disk["file"] ;
$output = "" ;
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
foreach($output as $key => $line) {
$line=str_replace("image: ","",$line) ;
$output[$key] = $line ;
}
$snaps[$vm][$disk["device"]] = $output ;
$rev = "r".$disk["device"] ;
$reversed = array_reverse($output) ;
$snaps[$vm][$rev] = $reversed ;
}
$snaps_json=json_encode($snaps,JSON_PRETTY_PRINT) ;
$pathinfo = pathinfo($file) ;
$dirpath = $pathinfo["dirname"] ;
file_put_contents("$dirpath/image.tracker",$snaps_json) ;
foreach($disks as $disk) {
$path = $disk['file'] ;
$cmdstr = "virsh blockpull '$vm' --path '$path' --verbose --pivot --delete" ;
$cmdstr = "virsh blockpull '$vm' --path '$path' --verbose --wait " ;
# Process disks and update path.
$snapdisks=($snapslist[$snap]['disks']) ;
if ($base != "--base" && $base != "") {
#get file name from snapshot.
$snapdisks=($snapslist[$base]['disks']) ;
$basepath = "" ;
foreach ($snapdisks as $snapdisk) {
$diskname = $snapdisk["@attributes"]["name"] ;
if ($diskname != $disk['device']) continue ;
$basepath = $snapdisk["source"]["@attributes"]["file"] ;
}
if ($basepath != "") $cmdstr .= " --base '$basepath' ";
}
if ($action) $cmdstr .= " $action ";
$error = execCommand_nchan($cmdstr,$path) ;
if (!$error) {
$arrResponse = ['error' => substr($output[0],6) ] ;
return($arrResponse) ;
} else {
# Remove nvram snapshot
$arrResponse = ['success' => true] ;
}
}
refresh_snapshots_database($vm) ;
if($ret)
$data = ["error" => "Unable to remove snap metadata $snap"] ;
else
$data = ["success => 'true"] ;
return $data ;
}
function vm_blockcopy($vm,$path,$base,$top,$pivot,$action) {
/*
NAME
blockcopy - Start a block copy operation.
SYNOPSIS
blockcopy <domain> <path> [--dest <string>] [--bandwidth <number>] [--shallow] [--reuse-external] [--blockdev] [--wait] [--verbose] [--timeout <number>] [--pivot] [--finish] [--async] [--xml <string>] [--format <string>] [--granularity <number>] [--buf-size <number>] [--bytes] [--transient-job] [--synchronous-writes] [--print-xml]
DESCRIPTION
Copy a disk backing image chain to dest.
OPTIONS
[--domain] <string> domain name, id or uuid
[--path] <string> fully-qualified path of source disk
--dest <string> path of the copy to create
--bandwidth <number> bandwidth limit in MiB/s
--shallow make the copy share a backing chain
--reuse-external reuse existing destination
--blockdev copy destination is block device instead of regular file
--wait wait for job to reach mirroring phase
--verbose with --wait, display the progress
--timeout <number> implies --wait, abort if copy exceeds timeout (in seconds)
--pivot implies --wait, pivot when mirroring starts
--finish implies --wait, quit when mirroring starts
--async with --wait, don't wait for cancel to finish
--xml <string> filename containing XML description of the copy destination
--format <string> format of the destination file
--granularity <number> power-of-two granularity to use during the copy
--buf-size <number> maximum amount of in-flight data during the copy
--bytes the bandwidth limit is in bytes/s rather than MiB/s
--transient-job the copy job is not persisted if VM is turned off
--synchronous-writes the copy job forces guest writes to be synchronously written to the destination
--print-xml print the XML used to start the copy job instead of starting the job
*/
}
?>
@@ -62,7 +62,7 @@ function ajaxVMDispatchconsoleRV(params, spin){
}
},'json');
}
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, console="web"){
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, console="web", preview=false){
var opts = [];
var path = location.pathname;
var x = path.indexOf("?");
@@ -106,6 +106,12 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, c
e.preventDefault();
ajaxVMDispatch( {action:"domain-destroy", uuid:uuid}, "loadlist");
}});
opts.push({divider:true});
opts.push({text:_("Create Snapshot"), icon:"fa-clone", action:function(e) {
e.preventDefault();
selectsnapshot(uuid , name, "--generate" , "create",false,state) ;
}});
} else if (state == "pmsuspended") {
opts.push({text:_("Resume"), icon:"fa-play", action:function(e) {
e.preventDefault();
@@ -141,14 +147,26 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, c
ajaxVMDispatchconsoleRV({action:"domain-start-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
}});
}
}}
}
}
opts.push({divider:true});
if (log !== "") {
opts.push({text:_("Logs"), icon:"fa-navicon", action:function(e){e.preventDefault(); openTerminal('log',name,log);}});
}
opts.push({text:_("Edit"), icon:"fa-pencil", href:path+'/UpdateVM?uuid='+uuid});
if (state == "shutoff") {
opts.push({text:_("Clone"), icon:"fa-clone", action:function(e) {
e.preventDefault();
var clonename = VMClone(uuid,name) ;
}});
opts.push({divider:true});
opts.push({text:_("Create Snapshot"), icon:"fa-clone", action:function(e) {
e.preventDefault();
selectsnapshot(uuid , name, "--generate" , "create",false,state) ;
}});
opts.push({text:_("Remove VM"), icon:"fa-minus", action:function(e) {
e.preventDefault();
swal({
@@ -182,6 +200,50 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, c
}
context.attach('#vm-'+uuid, opts);
}
function addVMSnapContext(name, uuid, template, state, snapshotname, preview=false){
var opts = [];
var path = location.pathname;
var x = path.indexOf("?");
if (x!=-1) path = path.substring(0,x);
context.settings({right:false,above:false});
if (state == "running") {
opts.push({text:_("Revert snapshot"), icon:"fa-fast-backward", action:function(e) {
e.preventDefault();
selectsnapshot(uuid, name, snapshotname, "revert",true) ;
}});
opts.push({text:_("Block Commit"), icon:"fa-hdd-o", action:function(e) {
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
e.preventDefault();
selectblock(uuid, name, snapshotname, "commit",true) ;
}});
opts.push({text:_("Block Pull"), icon:"fa-hdd-o", action:function(e) {
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
e.preventDefault();
selectblock(uuid, name, snapshotname, "pull",true) ;
}});
if (preview) {
opts.push({text:_("Block Copy"), icon:"fa-stop", action:function(e) {
e.preventDefault();
ajaxVMDispatch({action:"domain-stop", uuid:uuid}, "loadlist");
}}); }
} else {
opts.push({text:_("Revert snapshot"), icon:"fa-fast-backward", action:function(e) {
e.preventDefault();
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
selectsnapshot(uuid, name, snapshotname, "revert",true) ;
}});
}
opts.push({text:_("Remove snapshot"), icon:"fa-trash", action:function(e) {
e.preventDefault();
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
selectsnapshot(uuid, name, snapshotname, "remove",true) ;
}});
context.attach('#vmsnap-'+uuid, opts);
}
function startAll() {
$('input[type=button]').prop('disabled',true);
for (var i=0,vm; vm=kvm[i]; i++) if (vm.state!='running') $('#vm-'+vm.id).parent().find('i').removeClass('fa-square').addClass('fa-refresh fa-spin');
@@ -225,3 +287,5 @@ function addVM() {
if (x!=-1) path = path.substring(0,x);
location = path+"/VMTemplates";
}
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Wrappers.php";
// add translations
$_SERVER['REQUEST_URI'] = '';
$login_locale = _var($display,'locale');
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
function write(...$messages){
$com = curl_init();
curl_setopt_array($com,[
CURLOPT_URL => 'http://localhost/pub/vmaction?buffer_length=1',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_RETURNTRANSFER => true
]);
foreach ($messages as $message) {
curl_setopt($com, CURLOPT_POSTFIELDS, $message);
curl_exec($com);
}
curl_close($com);
}
function execCommand_nchan($command,$idx) {
$waitID = mt_rand();
[$cmd,$args] = explode(' ',$command,2);
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._('Command execution')."</legend>".basename($cmd).' '.str_replace(" -","<br>&nbsp;&nbsp;-",htmlspecialchars($args))."<br><span id='wait-$waitID'>"._('Please wait')." </span><p class='logLine'></p></fieldset>","show_Wait\0$waitID");
write("addLog\0<br>") ;
write("addToID\0$idx\0 $action") ;
$proc = popen("$command 2>&1",'r');
while ($out = fgets($proc)) {
$out = preg_replace("%[\t\n\x0B\f\r]+%", '',$out);
if (substr($out,0,1) == "B") { ;
write("progress\0$idx\0".htmlspecialchars(substr($out,strrpos($out,"Block Pull")))) ;
} else echo write("addToID\0$idx\0 ".htmlspecialchars($out));
}
$retval = pclose($proc);
$out = $retval ? _('The command failed').'.' : _('The command finished successfully').'!';
write("stop_Wait\0$waitID","addLog\0<br><b>$out</b>");
return $retval===0;
}
#{action:"snap-", uuid:uuid , snapshotname:target , remove:remove, free:free ,removemeta:removemeta ,keep:keep, desc:desc}
#VM ID [ 99]: pull. .Block Pull: [ 0 %]Block Pull: [100 %].Pull complete.
$url = rawurldecode($argv[1]??'');
$waitID = mt_rand();
$style = ["<style>"];
$style[] = ".logLine{font-family:bitstream!important;font-size:1.2rem!important;margin:0;padding:0}";
$style[] = "fieldset.docker{border:solid thin;margin-top:8px}";
$style[] = "legend{font-size:1.1rem!important;font-weight:bold}";
$style[] = "</style>";
foreach (explode('&', $url) as $chunk) {
$param = explode("=", $chunk);
if ($param) {
${urldecode($param[0])} = urldecode($param[1]) ;
}
}
$id = 1 ;
write(implode($style)."<p class='logLine'></p>");
$process = " " ;
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._("Options for Block $action").": </legend><p class='logLine'></p><span id='wait-$waitID'>"._('Please wait')." </span></fieldset>");
write("addLog\0".htmlspecialchars("VMName $name "));
write("addLog\0".htmlspecialchars("SNAP $snapshotname "));
write("addLog\0".htmlspecialchars("Base $targetbase "));
if ($action == "commit") {
write("addLog\0".htmlspecialchars("Top $targettop "));
write("addLog\0".htmlspecialchars("Pivot $targetpivot "));
write("addLog\0".htmlspecialchars("Delete $targetdelete "));
}
switch ($action) {
case "commit":
vm_blockcommit($name,$snapshotname,$path,$targetbase,$targettop,$targetpivot,$targetdelete) ;
break ;
case "copy":
vm_blockcopy($name,$snapshotname,$path,$targetbase,$targettop,$pivot,' ') ;
break;
case "pull":
vm_blockpull($name,$snapshotname,$path,$targetbase,$targettop,$pivot,' ') ;
break ;
}
#execCommand_nchan("ls /") ;
write("stop_Wait\0$waitID") ;
write('_DONE_','');
?>
+108
View File
@@ -0,0 +1,108 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Wrappers.php";
// add translations
$_SERVER['REQUEST_URI'] = '';
$login_locale = _var($display,'locale');
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
require_once "$docroot/webGui/include/Helpers.php";
function write(...$messages){
$com = curl_init();
curl_setopt_array($com,[
CURLOPT_URL => 'http://localhost/pub/vmaction?buffer_length=1',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_RETURNTRANSFER => true
]);
foreach ($messages as $message) {
curl_setopt($com, CURLOPT_POSTFIELDS, $message);
curl_exec($com);
}
curl_close($com);
}
function execCommand_nchan($command,$idx,$refcmd=false) {
$waitID = mt_rand();
if ($refcmd) {
[$cmd,$args] = explode(' ',$refcmd,2);
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._('Command execution')."</legend>".basename($cmd).' '.str_replace(" -","<br>&nbsp;&nbsp;-",htmlspecialchars($args))."<br><span id='wait-$waitID'>"._('Please wait')." </span><p class='logLine'></p></fieldset>","show_Wait\0$waitID");
$rtn = exec("$refcmd 2>&1", $output,$return) ;
if ($return == 0) $reflinkok = true ; else {
$reflinkok = false ;
write("addLog\0<br><b>{$output[0]}</b>");
}
$out = $return ? _('The command failed revert to rsync')."." : _('The command finished successfully').'!';
write("stop_Wait\0$waitID","addLog\0<br><b>$out</b>");
}
if ($reflinkok) {
return true ;
} else {
$waitID = mt_rand();
[$cmd,$args] = explode(' ',$command,2);
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._('Command execution')."</legend>".basename($cmd).' '.str_replace(" -","<br>&nbsp;&nbsp;-",htmlspecialchars($args))."<br><span id='wait-$waitID'>"._('Please wait')." </span><p class='logLine'></p></fieldset>","show_Wait\0$waitID");
write("addToID\0$idx\0Cloning VM: ") ;
$proc = popen("$command 2>&1 &",'r');
while ($out = fread($proc,100)) {
$out = preg_replace("%[\t\n\x0B\f\r]+%", '',$out);
$out = trim($out) ;
$values = explode(' ',$out) ;
$string = _("Data copied: ").$values[0].' '._(" Percentage: ").$values[1].' '._(" Transfer Rate: ").$values[2].' '._(" Time remaining: ").$values[4].$values[5] ;
write("progress\0$idx\0".htmlspecialchars($string)) ;
if ($out) $stringsave=$string ;
}
$retval = pclose($proc);
write("progress\0$idx\0".htmlspecialchars($stringsave)) ;
$out = $retval ? _('The command failed').'.' : _('The command finished successfully').'!';
write("stop_Wait\0$waitID","addLog\0<br><b>$out</b>");
return $retval===0;
}
}
#{action:"snap-", uuid:uuid , snapshotname:target , remove:remove, free:free ,removemeta:removemeta ,keep:keep, desc:desc}
#VM ID [ 99]: pull. .Block Pull: [ 0 %]Block Pull: [100 %].Pull complete.
$url = rawurldecode($argv[1]??'');
$waitID = mt_rand();
$style = ["<style>"];
$style[] = ".logLine{font-family:bitstream!important;font-size:1.2rem!important;margin:0;padding:0}";
$style[] = "fieldset.docker{border:solid thin;margin-top:8px}";
$style[] = "legend{font-size:1.1rem!important;font-weight:bold}";
$style[] = "</style>";
foreach (explode('&', $url) as $chunk) {
$param = explode("=", $chunk);
if ($param) {
${urldecode($param[0])} = urldecode($param[1]) ;
}
}
$id = 1 ;
write(implode($style)."<p class='logLine'></p>");
$process = " " ;
$actiontxt = ucfirst($action) ;
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._("Options for $actiontxt").": </legend><p class='logLine'></p></fieldset>");
write("addLog\0".htmlspecialchars("Cloning $name to $clone"));
switch ($action) {
case "clone":
$rtn = vm_clone($name,$clone,$overwrite,$start,$edit,$free,$waitID) ;
break ;
}
write("stop_Wait\0$waitID") ;
if ($rtn) write('_DONE_',''); else write('_ERROR_','');
?>
@@ -1,10 +1,13 @@
#!/bin/sh
#!/bin/bash
# Intialize libvirt config storage
# Invoked by emhttp after mounting libvirt loopback but before starting libvirt.
# run & log functions
. /etc/rc.d/rc.runlog
# missing qemu directory would indicate new libvirt image file created
if [ ! -d /etc/libvirt/qemu ]; then
logger "initializing /etc/libvirt"
log "initializing /etc/libvirt"
# initialize with default settings
cp -rp /etc/libvirt-/* /etc/libvirt
# check if libvirt image file exists on USB flash
+2 -2
View File
@@ -568,8 +568,8 @@ function formatWarning(val) {
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Unclean shutdown detected)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will bring the array on-line)_.</td></tr>
<? elseif (missing_cache()):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Missing Cache disk)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)" disabled></td>
<td>**_(Start)_** _(will remove the missing cache disk and then bring the array on-line)_.
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Missing pool disk)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)" disabled></td>
<td>**_(Start)_** _(will remove the missing pool disk and then bring the array on-line)_.
<br><input type="checkbox" name="confirmStart" value="OFF" onclick="$('#cmdStart').prop('disabled',!arrayOps.confirmStart.checked)"><small>_(Yes, I want to do this)_</small></td></tr>
<? else:?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
File diff suppressed because it is too large Load Diff
+343
View File
@@ -0,0 +1,343 @@
Menu="Buttons:3a"
Title="File Manager"
Icon="icon-u-duplicate"
Code="e963"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$dfm = [
'browser' => $myPage['name']=='Browse',
'running' => file_exists('/var/tmp/file.manager.active'),
'jobs' => file_exists('/var/tmp/file.manager.jobs'),
'zfs' => is_executable('/usr/sbin/zfs')
];
if ($dfm['running'] || $dfm['browser']) eval('?>'.parse_file("$docroot/webGui/include/Templates.php"));
?>
<script>
function BrowseButton() {
location.replace('/<?=$task?>/Browse?dir=/mnt');
}
// Prototypes
String.prototype.dfm_patch = function(){return this.replace('rw','x+rw').replace('r-','wx+r').replace('--','rwx');}
String.prototype.dfm_proxy = function(){return this.replace('name','row');}
String.prototype.dfm_fetch = function(tag){return this.replace('check',tag);}
String.prototype.dfm_bring = function(tag){return this.replace('row',tag);}
String.prototype.dfm_strip = function(){return this.replace(/\/$/,'');}
String.prototype.dfm_quote = function(){return this.replace(/&#34;/g,'"');}
String.prototype.dfm_alter = function(...a){var t=this;for(var i=0;i<a.length;i+=2){t=t.replace(a[i],a[i+1]);} return t;}
String.prototype.dfm_build = function(){return this.replace(/\n(<!--!|!-->)\n/g,'');}
String.prototype.dfm_wedge = function(len){len=len||70;return this.length<=len ? this : this.slice(0,Math.round(len/2)-2)+'...'+this.slice(-1-Math.round(len/2));}
// General variables
const dfm = {window:null, dialog:false, running:false, previous:'', height:0, tsize:{0:0,1:6,2:3,3:3,4:3,11:2,12:2,14:0,15:3}};
var dfm_read = {};
function dfm_footer(action,text) {
switch (action) {
case 'show':
$('#countdown').show();
$('#user-notice').show();
break;
case 'hide':
$('#countdown').hide();
$('#user-notice').hide();
break;
case 'write':
if ($('#countdown').html()=='') $('#countdown').html('<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>');
$('#user-notice').html(text);
break;
case 'clear':
$('#countdown').html('');
$('#user-notice').html('');
break;
}
}
function dfm_done() {
dfm_footer('write',"<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
}
function dfm_minimize() {
dfm.window.dialog('close');
dfm_footer('show');
}
function dfm_close_button() {
$('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-window-minimize"></i>').prop({'title':"_(Minimize)_"}).prop('onclick',null).off('click').click(function(){dfm_minimize();}).show();
}
function dfm_htmlspecialchars(text) {
var map = {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'};
return text.replace(/[&<>"']/g,function(m){return map[m];});
}
function dfm_escapeHTML(name) {
const data = document.createElement('div');
const text = document.createTextNode(name);
data.appendChild(text);
return data.innerHTML;
}
function dfm_createSource(source) {
var select = dfm.window.find('#dfm_source');
if (Array.isArray(source)) {
for (var i=0,object; object=source[i]; i++) {
if (i < 10) {
select.html(select.html()+'<option'+(i==0?' selected':'')+'>'+object+'</option>');
} else {
select.html(select.html()+'<option>&lt;_(more)_&gt; ...</option>');
break;
}
}
} else {
select.html('<option selected>'+source+'</option>');
}
}
function dfm_showProgress(data) {
if (!data) return 0;
let file = null;
let text = data.split('\n');
let line = text[0].split('... ');
let strict = /^mnt|^boot/;
let footer = false;
if (text[0]=='#cat#') {
let loc = [], cat = [];
for (let i=1,row; row=text[i]; i++) {
if (!row) continue;
row = row.split('\0');
loc.push(row[0]);
cat.push(row[1].dfm_wedge(80));
}
if (cat.length > 0) {
dfm.window.find('.dfm_loc').html(loc.join('<br>'));
dfm.window.find('.dfm_text').html(cat.join('<br>'));
dfm.window.find('#dfm_files').html(loc.length+" "+"_(files)_");
}
return cat.length;
} else if (text.length==1) {
text = text[0].dfm_wedge(80);
footer = text.indexOf("_(Searching)_") != -1;
} else {
if (strict.test(text[1])) {
file = text[1];
text = dfm.previous;
} else {
file = line[1];
text = text[1].split(/\s+/);
text = "<i class='fa fa-circle-o-notch fa-spin dfm'></i>_(Completed)_: "+text[1]+",&nbsp;&nbsp;_(Speed)_: "+text[2]+",&nbsp;&nbsp;_(ETA)_: "+text[3];
dfm.previous = text;
footer = true;
}
}
if (file==null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
if (footer) dfm_footer('write',text);
return 0;
}
function dfm_fileManager(action) {
switch (action) {
case 'start':
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',true);
<?if ($dfm['browser']):?>
$('.dfm_control').prop('disabled',true);
$('.dfm_control.jobs').prop('disabled',$.cookie('dfm_control.jobs')?false:true);
<?endif;?>
if (!dfm.running) nchan_filemanager.start();
dfm.running = true;
break;
case 'stop':
if (dfm.running) nchan_filemanager.stop();
<?if ($dfm['browser']):?>
dfm.window.find('.dfm_text').removeClass('orange-text').html('');
$('.dfm_control.basic').prop('disabled',false);
$('.dfm_control.common').prop('disabled',$.cookie('dfm_control.common')?true:false);
<?endif;?>
dfm_footer('clear');
dfm.running = false;
break;
}
}
function dfm_makeDialog(open) {
if (open && dfm_read.action==15) {
dfm.window.dialog('open');
dfm_footer('hide');
return;
}
dfm.window = $('#dfm_dialogWindow');
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
var dfm_source = dfm_read.source.split('\r').slice(0,9);
switch (dfm_read.action) {
case 0: // create folder/object
dfm.window.html($('#dfm_templateCreateFolder').html());
dfm.height = 330;
break;
case 1: // delete folder/object
dfm.window.html($('#dfm_templateDeleteFolder').html());
dfm.height = 330;
break;
case 2: // rename folder/object
dfm.window.html($('#dfm_templateRenameFolder').html());
dfm.window.find('#dfm_target').val(dfm_read.target.strip().split('/').pop());
dfm.height = 330;
break;
case 3: // copy folder/object
dfm.window.html($('#dfm_templateCopyFolder').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 4: // move folder/object (rsync)
case 5: // move folder/object (mv)
dfm.window.html($('#dfm_templateMoveFolder').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 6: // delete file
dfm.window.html($('#dfm_templateDeleteFile').html());
dfm.height = 330;
break;
case 8: // copy file
dfm.window.html($('#dfm_templateCopyFile').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 9: // move file (rsync)
case 10: // move file (mv)
dfm.window.html($('#dfm_templateMoveFile').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true :false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 11: // change owner
dfm.window.html($('#dfm_templateChangeOwner').html());
dfm.window.find('#dfm_target').prop('disabled',true);
dfm.height = 330;
break;
case 12: // change permission
dfm.window.html($('#dfm_templateChangePermission').html());
dfm.window.find('#dfm_owner').prop('disabled',true);
dfm.window.find('#dfm_group').prop('disabled',true);
dfm.window.find('#dfm_other').prop('disabled',true);
dfm.height = 330;
break;
case 15: // search
dfm.window.html($('#dfm_templateSearch').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('.dfm_loc').html('&nbsp;').css({'line-height':'normal'});
dfm.window.find('.dfm_text').html('').css({'line-height':'normal'});
dfm.height = 630;
break;
}
dfm.window.find('#dfm_source').attr('size',Math.min(dfm.tsize[dfm_read.action],dfm_source.length));
dfm_createSource(dfm_source);
dfm.window.find('#dfm_sparse').prop('disabled',true);
dfm.window.find('#dfm_exist').prop('disabled',true);
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
dfm.window.dialog({
dialogClass: 'ui-dfm',
autoOpen: open||dfm.dialog,
title: dfm_read.title,
resizable: false,
width: 900,
height: dfm.height,
modal: true,
buttons: {
"_(Start)_": function(){
if (dfm_read.action==15) {
var dfm_target = dfm.window.find('#dfm_target').val();
dfm.window.find('.dfm_loc').html('&nbsp;');
dfm.window.find('.dfm_text').html("_(Running)_...");
dfm_footer('hide');
dfm_fileManager('start');
$.post('/webGui/include/Control.php',{mode:'file',action:15,title:encodeURIComponent(dfm_read.title),source:encodeURIComponent(dfm_read.source),target:encodeURIComponent(dfm_target),hdlink:'',sparse:'',exist:'',zfs:''});
} else {
return;
}
},
"_(Queue)_": function(){
return;
},
"_(Cancel)_": function(){
dfm_fileManager('stop');
dfm.window.dialog('destroy');
$.post('/webGui/include/Control.php',{mode:'file',action:99},function(){<?if ($dfm['browser']):?>setTimeout(loadList,500);<?endif;?>});
}
}
});
dfm_close_button();
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',true);
setTimeout(function(){$('.ui-dfm .ui-dialog-buttonset button:eq(2)').focus();});
if (open||dfm.dialog) dfm_footer('hide'); else dfm_footer('show');
}
function dfm_openDialog(open) {
$.post('/webGui/include/Control.php',{mode:'read'},function(data){
if (data) {
dfm_read = JSON.parse(data);
dfm_read.action = parseInt(dfm_read.action);
}
dfm_makeDialog(open);
});
}
var nchan_filemanager = new NchanSubscriber('/sub/filemanager',{subscriber:'websocket'});
nchan_filemanager.on('message', function(msg) {
let data = $.parseJSON(msg);
if (data.error) {
dfm_fileManager('stop');
dfm.window.find('.dfm_text').addClass('orange-text').html(data.error);
dfm.window.find('#dfm_target').prop('disabled',false);
dfm.window.find('#dfm_sparse').prop('disabled',false);
dfm.window.find('#dfm_exist').prop('disabled',false);
dfm.window.find('#dfm_owner').prop('disabled',false);
dfm.window.find('#dfm_group').prop('disabled',false);
dfm.window.find('#dfm_other').prop('disabled',false);
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',false);
} else {
let cat = dfm_showProgress(data.status);
if (data.done==1) {
setTimeout(function(){$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
switch (parseInt(queue)) {
case 0:
dfm_fileManager('stop');
dfm.window.dialog('destroy');
<?if ($dfm['browser']):?>
setTimeout(loadList);
<?endif;?>
break;
case 1:
<?if ($dfm['browser']):?>
$('.dfm_control.jobs').prop('disabled',true);
<?endif;?>
$.removeCookie('dfm_control.jobs');
case 2:
dfm_openDialog();
break;
}
})});
} else if (data.done==2) {
nchan_filemanager.stop();
dfm.running = false;
dfm.window.find('#dfm_target').prop('disabled',false).focus();
$('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',false);
if (cat==0) dfm.window.find('.dfm_text').html("_(No results found)_");
if ($('#user-notice:visible')) dfm_done();
}
}
});
<?if ($dfm['running']):?>
$(function(){
dfm_openDialog();
dfm_fileManager('start');
});
<?endif;?>
</script>
+90 -1
View File
@@ -22,6 +22,14 @@ function makeList($list) {
function sharename($share) {
return basename($share,'.cfg');
}
$subpools = array( "special", "logs", "dedup", "cache", "spares");
function isSubpool($name) {
global $subpools;
// pool name ending in any of these => zfs subpool
$tildaPosition = strpos($name, '~');
$subpool = ($tildaPosition!==false) ? substr($name, $tildaPosition+1) : false;
return ($subpool!==false && in_array($subpool, $subpools)) ? $subpool : false;
}
$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
?>
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
@@ -31,7 +39,7 @@ table.divider{margin-top:20px}
</style>
<script>
function validate(poolname) {
var valid = /^[a-z]([a-z0-9_-]*[a-z_-])*$/;
var valid = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/;
var reserved = [<?=makeList(explode(',',_var($var,'reservedNames')))?>];
var shares = [<?=makeList(array_map('sharename',glob('boot/config/shares/*.cfg',GLOB_NOSORT)))?>];
var pools = [<?=makeList($pools)?>];
@@ -82,6 +90,59 @@ function addPoolPopup() {
$(".ui-widget-content").css({'background':'<?=$bgcolor?>'});
$(".ui-button-text").css({'padding':'0px 5px'});
}
function removeOption(inputString,value) {
// Define a regular expression to match <option>...</option> substrings
const optionPattern = /<option .*?<\/option>/g;
// Replace all matching substrings that contain "value" with an empty string
const result = inputString.replace(optionPattern, (match) => {
if (match.includes(value)) {
return ''; // Remove the entire substring
} else {
return match; // Keep the substring as is
}
});
return result;
}
function addSubpoolPopup(poolname,currentsubpools) {
var popup = $('#dialogAddSubpool');
// Load popup with the template info
popup.html($("#templatePopupSubpool").html());
// Remove the options specifed by currentsubpools
if (currentsubpools.trim().length !== 0) {
var subpools = currentsubpools.split(',');
subpools.forEach(function(subpool) {
popup.html(function(index, oldHtml) {
return removeOption(oldHtml, subpool);
});
});
}
// Start Dialog section
popup.dialog({
title: "_(Add ZFS Subpool)_",
resizable: false,
width: 600,
modal: true,
show : {effect:'fade', duration:250},
hide : {effect:'fade', duration:250},
buttons: {
"_(Add)_": function() {
subpool=$(this).find('select[name="subpool"]').val();
$(this).find('input[name="poolName"]').val(poolname + "~" + subpool);
$(this).find('form').submit();
$(this).dialog('close');
},
"_(Cancel)_": function() {
$(this).dialog('close');
}
}
});
$(".ui-dialog .ui-dialog-titlebar").addClass('menu');
$('.ui-dialog .ui-dialog-titlebar-close').css({'display':'none'});
$(".ui-dialog .ui-dialog-title").css({'text-align':'center','width':'100%'});
$(".ui-dialog .ui-dialog-content").css({'padding-top':'15px','vertical-align':'bottom'});
$(".ui-widget-content").css({'background':'<?=$bgcolor?>'});
$(".ui-button-text").css({'padding':'0px 5px'});
}
<?if (_var($var,'fsState')=="Started"):?>
$('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
@@ -92,7 +153,11 @@ $('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
<?foreach ($pools as $pool):?>
<?if (isset($disks[$pool]['devices']) or _var($var,'fsState')=="Stopped"):?>
<table class="disk_status wide<?=$i?' divider':''?>">
<?if (isSubpool($pool)):?>
<thead></thead>
<?else:?>
<thead><tr><td>_(Device)_</td><td>_(Identification)_</td><td>_(Temp)_.</td><td>_(Reads)_</td><td>_(Writes)_</td><td>_(Errors)_</td><td>_(FS)_</td><td>_(Size)_</td><td>_(Used)_</td><td>_(Free)_</td></tr></thead>
<?endif;?>
<tbody id="pool_device<?=$i++?>">
<?foreach (cache_filter($disks) as $disk) if (prefix($disk['name'])==$pool) echo "<tr><td colspan='11'>&nbsp;</td></tr>"?>
</tbody>
@@ -109,6 +174,30 @@ $('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
_(Name)_:
: <input type="text" name="poolName" maxlength="40" value="<?=count($pools)==0?'cache':''?>">
_(Slots)_:
: <select name="poolSlots">
<?for ($n=1; $n<=_var($var,'MAX_CACHESZ',0); $n++):?>
<?=mk_option(1,$n,$n)?>
<?endfor;?>
</select>
</form>
</div>
<div id="dialogAddSubpool" style="display:none"></div>
<div id="templatePopupSubpool" style="display:none">
<form markdown="1" method="POST" action="/update.htm" target="progressFrame">
<input type="hidden" name="changeSlots" value="apply">
<input type="hidden" name="poolName" value="">
_(Name)_:
: <select name="subpool">
<?=mk_option("","special","special - Special Allocation Class")?>
<?=mk_option("","logs","logs - ZFS Intent Log")?>
<?=mk_option("","dedup","dedup - Deduplication Tables")?>
<?=mk_option("","cache","cache - Cache Devices")?>
<?=mk_option("","spares","spares - Hot Spares")?>
</select>
_(Slots)_:
: <select name="poolSlots">
<?for ($n=1; $n<=_var($var,'MAX_CACHESZ',0); $n++):?>
+2
View File
@@ -19,6 +19,8 @@ Tag="trophy"
**Community Applications** Copyright &copy; 2015-2023, Andrew Zawadzki
**GUI Search** Copyright &copy; 2021-2023, Andrew Zawadzki
The Software comprising the Unraid webGui, which is all files within this repository **except** for
files listed below, is licensed under GPL version 2.
+159
View File
@@ -55,6 +55,7 @@ exec("sed -ri 's/^\.logLine\{color:#......;/.logLine{color:$fgcolor;/' $docroot/
exec("/etc/rc.d/rc.docker status >/dev/null",$dummy,$dockerd);
exec("/etc/rc.d/rc.libvirt status >/dev/null",$dummy,$libvirtd);
$domain_cfg = parse_ini_file("/boot/config/domain.cfg");
$dockerd = $dockerd==0;
$libvirtd = $libvirtd==0;
$apcupsd = file_exists('/var/run/apcupsd.pid');
@@ -181,6 +182,7 @@ div.last{padding-bottom:12px}
div.leftside{float:left;width:66%}
div.rightside{float:right;margin:0;text-align:center}
div[id$=chart]{margin:-12px 8px -24px -18px}
div.template,div#dialogWindow,input#upload{display:none}
span.green,span.red,span.orange{padding-left:0}
span.ctrl{float:right;margin-top:0;margin-right:10px}
span.ctrl span{font-size:2rem!important}
@@ -814,6 +816,63 @@ var netchart = new ApexCharts(document.querySelector('#netchart'), options_net);
if ($.cookie('port_select')!=null && !ports.includes($.cookie('port_select'))) $.removeCookie('port_select');
var port_select = $.cookie('port_select')||ports[0];
function selectsnapshot(uuid, name ,snaps, opt, getlist){
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
var match= ".iso";
var box = $("#dialogWindow2");
box.html($("#templatesnapshot"+opt).html());
var height = 200;
const Capopt = opt.charAt(0).toUpperCase() + opt.slice(1);
var optiontext = Capopt + " Snapshot";
box.find('#VMName').html(name);
box.find('#targetsnap').val(snaps);
box.find('#targetsnapl').html(snaps);
if (getlist) {
var only = (opt == "remove") ? 0 : 1;
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-images", uuid:uuid, snapshotname:snaps, only:only}, function(data){if (data.html) box.find('#targetsnapimages').html(data.html);},'json');
}
document.getElementById("targetsnapfspc").checked = true;
box.dialog({
title: "_("+optiontext+ ")_",
resizable: false,
width: 600,
height: 500,
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
"_(Proceed)_": function(){
var target = box.find('#targetsnap');
if (target.length) {
target = target.val();
if (!target) {errorTarget(); return;}
} else target = '';
var remove = 'yes';
var removemeta = 'yes';
var keep = 'yes';
var free = 'yes';
var desc = '';
box.find('#targetsnap').prop('disabled',true);
if (opt == "revert") {
remove = box.find('#targetsnaprmv').prop('checked') ? 'yes' : 'no';
removemeta = box.find('#targetsnaprmvmeta').prop('checked') ? 'yes' : 'no';
keep = box.find('#targetsnapkeep').prop('checked') ? 'yes' : 'no';
}
if (opt == "create") {
free = box.find('#targetsnapfspc').prop('checked') ? 'yes' : 'no';
desc = box.find("#targetsnapdesc").prop('value');
}
ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid, snapshotname:target, remove:remove, free:free, desc:desc}, "loadlist");
box.dialog('close');
},
"_(Cancel)_": function(){
box.dialog('close');
}
}
});
dialogStyle();
}
function initCharts(clear) {
$.post('/webGui/include/InitCharts.php',{cmd:'get'},function(data) {
data = JSON.parse(data);
@@ -1504,4 +1563,104 @@ $(function() {
$.post('/webGui/include/InitCharts.php',{cmd:'set',data:JSON.stringify(data)});
});
});
function dialogStyle() {
$('.ui-dialog-titlebar-close').css({'background':'transparent','border':'none','font-size':'1.8rem','margin-top':'-14px','margin-right':'-18px'}).html('<i class="fa fa-times"></i>').prop('title');
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
$('.ui-button-text').css({'padding':'0px 5px'});
}
function VMClone(uuid, name){
//var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
var match= ".iso";
var box = $("#dialogWindow");
var height = 200;
box.html($("#templateClone").html());
box.find('#VMBeingCloned').html(name).change() ;
box.find('#target').val(name + "_clone") ;
document.getElementById("Free").checked = true ;
document.getElementById("Overwrite").checked = true ;
var Cancel = _("Cancel") ;
box.dialog({
title: "VM Clone",
resizable: false,
width: 600,
height: 500,
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
"_(Clone)_": function(){
var target = box.find('#target');
if (target.length) {
target = target.val();
//if (!target ) {errorTarget(); return;}
} else target = '';
var clone = box.find("#target").prop('value');
var start = box.find('#Start').prop('checked') ? 'yes' : 'no';
var edit = box.find('#Edit').prop('checked') ? 'yes' : 'no';
var overwrite = box.find('#Overwrite').prop('checked') ? 'yes' : 'no';
var free = box.find('#Free').prop('checked') ? 'yes' : 'no';
var scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free}));
openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist");
box.dialog('close');
},
"_(Cancel)_": function(){
box.dialog('close');
}
}
});
dialogStyle();
}
</script>
<div id="dialogWindow"></div>
<div markdown="1" id="templateClone" class="template">
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=1600">
<meta name="robots" content="noindex, nofollow">
<meta name="referrer" content="same-origin">
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
</head>
<body>
<br>
<table>
<tr><td>_(VM Being Cloned)_:</td>
<td><span id="VMBeingCloned"></span></td></tr>
<tr><td>_(New VM)_:</td>
<td><input type="text" id="target" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
<tr><td>_(Overwrite)_:</td>
<td><input type="checkbox" id="Overwrite" value="" ></td></tr>
<tr hidden><td>_(Start Cloned VM)_:</td>
<td><input type="checkbox" id="Start" value="" ></td></tr>
<tr hidden><td>_(Edit VM after clone)_:</td>
<td><input type="checkbox" id="Edit" value="" ></td></tr>
<tr><td>_(Check Free Space)_:</td>
<td><input type="checkbox" id="Free" value="" ></td></tr>
</table>
</body>
</html>
</div>
<div id="dialogWindow2"></div>
<div markdown="1" id="templatesnapshotcreate" class="template">
<table id='snapshot'>
<br><br>
<tr><td> _(VM Name)_:</td><td>
<label id="VMName"></label></td></tr>
<tr><td>_(Snapshot Name)_:</td><td>
<input type="text" id="targetsnap" autocomplete="off" spellcheck="false" value="--generate" onclick="this.select()">
_(Check free space)_:
<input type="checkbox" id="targetsnapfspc" checked></td></tr>
<tr><td>_(Description )_:</td><td>
<input type="text" id="targetsnapdesc" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
</table>
</div>
+66 -32
View File
@@ -80,6 +80,13 @@ function maintenance_mode() {
global $var;
return _var($var,'fsState')=="Started" && _var($var,'startMode')=="Maintenance" && _var($disk,'luksState',0)<=1;
}
function isSubpool($name) {
// pool name ending in any of these => zfs subpool
$subpools = array( "special", "logs", "dedup", "cache", "spares");
$tildaPosition = strpos($name, '~');
$subpool = ($tildaPosition!==false) ? substr($name, $tildaPosition+1) : false;
return ($subpool!==false && in_array($subpool, $subpools)) ? $subpool : false;
}
function isPool($name) {
global $pools;
return in_array($name,$pools);
@@ -220,8 +227,8 @@ function selectDiskFsWidth(num_devices,selected_width) {
} else {
var width, min_width;
if ($('#diskFsProfileZFS').val() == 'raidz1') min_width = 3;
else if ($('#diskFsProfileZFS').val() == 'raidz2') min_width = 4;
else if ($('#diskFsProfileZFS').val() == 'raidz3') min_width = 5;
else if ($('#diskFsProfileZFS').val() == 'raidz2') min_width = 3;
else if ($('#diskFsProfileZFS').val() == 'raidz3') min_width = 4;
for (width=min_width; width<=num_devices; width++) {
if ((num_devices % width) == 0) {
var groups = num_devices / width;
@@ -235,7 +242,7 @@ function selectDiskFsWidth(num_devices,selected_width) {
}
}
}
function selectDiskFsProfile(num_devices, width, init) {
function selectDiskFsProfile(num_slots, width, init) {
var t = init ? null : 'slow';
if (($('#diskFsType').val()||'').indexOf('auto') != -1) {
$('#diskFsProfileBTRFS').prop('disabled',true).hide();
@@ -260,7 +267,7 @@ function selectDiskFsProfile(num_devices, width, init) {
}
$('#diskFsProfileZFS').show();
$('#diskFsWidthZFS').show();
selectDiskFsWidth(num_devices, width);
selectDiskFsWidth(num_slots, width);
$('#compression').show(t);
<?if (diskType('Cache')):?>
$('#autotrim').show(t);
@@ -452,7 +459,7 @@ function updateMode(form,mode) {
$(form).find('input[name="#arg[3]"]').val(mode);
}
function validate(poolname) {
var valid = /^[a-z_]([a-z0-9_-]*[a-z_])*$/;
var valid = /^[a-z_]([a-z0-9~._-]*[a-z_])*$/;
var reserved = [<?=makeList(explode(',',_var($var,'reservedNames')))?>];
var shares = [<?=makeList(array_map('sharename',glob('boot/config/shares/*.cfg',GLOB_NOSORT)))?>];
var pools = [<?=makeList($pools)?>];
@@ -537,7 +544,7 @@ function eraseDisk(name) {
</script>
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="setFloor()">
<?if (_var($var,'fsState')=="Stopped" && isPool($name)):?>
<?if (_var($var,'fsState')=="Stopped" && isPool($name) && !isSubpool($name)):?>
_(Name)_:
: <a onclick="renamePoolPopup()" style="cursor:pointer" title="_(Rename Pool)_"><?=$name?></a>
@@ -556,7 +563,7 @@ _(Identification)_:
<?endif;?>
<?if (!$unassigned):?>
<?if (diskType('Data') || (diskType('Cache') && isPool(_var($disk,'name')))):?>
<?if (diskType('Data') || (diskType('Cache') && isPool($name) && !isSubpool($name))):?>
_(Comments)_:
: <input type="text" name="diskComment.<?=_var($disk,'idx',0)?>" maxlength="256" value="<?=htmlspecialchars(_var($disk,'comment'))?>">
@@ -569,11 +576,13 @@ _(Partition size)_:
_(Partition format)_:
: <?=_(_var($disk,'format'))?>
<?endif;?>
<?if (_var($var,'spinupGroups')=="yes" && diskType('Data','Parity')):?>
_(Spinup group(s))_:
: <input type="text" name="diskSpinupGroup.<?=_var($disk,'idx',0)?>" maxlength="256" value="<?=_var($disk,'spinupGroup')?>">
<?endif;?>
<?if (diskType('Data') || isPool($tag)):?>
_(Spin down delay)_:
: <select name="diskSpindownDelay.<?=_var($disk,'idx',0)?>">
<?=mk_option(_var($disk,'spindownDelay'), "-1", _('Use default'))?>
@@ -591,14 +600,12 @@ _(Spin down delay)_:
<?=mk_option(_var($disk,'spindownDelay'), "8", "8 "._('hours'))?>
<?=mk_option(_var($disk,'spindownDelay'), "9", "9 "._('hours'))?>
</select><span id="smart_selftest" class='orange-text'></span>
<?endif;?>
<?if (diskType('Data') || isPool($tag)):?>
_(File system status)_:
: <?=_(_var($disk,'fsStatus'))?>&nbsp;
<?$disabled = ((_var($var,'fsState')=="Stopped" && _var($var,'mdState')=="SWAP_DSBL") || _var($var,'fsState')=="Started" || _var($disk,'fsStatus')=='Mounted') || _var($disk,'uuid') ? "disabled" : ""?>
<?if (diskType('Data') || _var($disk,'slots',0)==1):?>
<?$disabled = (_var($var,'fsState')=="Stopped" && _var($disk,'uuid')) || (_var($var,'fsState')=="Started" && _var($disk,'fsStatus')=='Mounted') ? "disabled" : ""?>
<?if (diskType('Data') || (!isSubpool($name) && _var($disk,'slots',0)==1)):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=$disabled?>>
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
@@ -614,9 +621,9 @@ _(File system type)_:
:info_file_system_help:
<?elseif (_var($disk,'slots',0)>1):?>
<?elseif (!isSubpool($name) && _var($disk,'slots',0)>1):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
<?=mk_option(_var($disk,'fsType'), "btrfs", _('btrfs'))?>
@@ -625,26 +632,55 @@ _(File system type)_:
</select>
<select id="diskFsProfileBTRFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
<?=mk_option(_var($disk,'fsProfile'),"single", _('single'))?>
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
</select>
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
<?if (_var($disk,'devices',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
<?if ((_var($disk,'devices',0)%2)==0 || (_var($disk,'devices',0)%3)==0 || (_var($disk,'devices',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
<?if (_var($disk,'devices',0)>=5) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?if (_var($disk,'slots',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
<?if ((_var($disk,'slots',0)%2)==0 || (_var($disk,'slots',0)%3)==0 || (_var($disk,'slots',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
</select>
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
</select>
<?elseif (isSubpool($name)=="special" || isSubpool($name)=="logs" || isSubpool($name)=="dedup"):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
</select>
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsWidth(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?if (_var($disk,'slots',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
<?if ((_var($disk,'slots',0)%2)==0 || (_var($disk,'slots',0)%3)==0 || (_var($disk,'slots',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
</select>
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
</select>
<?elseif (isSubpool($name)=="cache"):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
</select>
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsWidth(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?if (_var($disk,'slots',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
</select>
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
</select>
<?elseif (isSubpool($name)=="spares"):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
</select>
<?endif;?>
<?if (isSubpool($name)===false):?>
<div markdown="1" id="compression" style="display:none">
_(Compression)_:
<?$disabled = _var($disk,'fsStatus')=='Mounted' ? "disabled" : ""?>
@@ -693,6 +729,7 @@ _(Critical disk utilization threshold)_ (%):
:info_critical_utilization_help:
<?endif;?>
<?endif;?>
&nbsp;
: <input type="submit" name="changeDisk" value="_(Apply)_" disabled><input type="button" id="doneButton" value="_(Done)_" onclick="done()">
@@ -973,7 +1010,7 @@ _(btrfs check status)_:
<?endif;?>
</form>
<?endif;?>
<?if (fsType('zfs')):?>
<?if (fsType('zfs') && !isSubpool($name)):?>
<div class="title nocontrol"><span class="left"><i class="title fa fa-info"></i>_(Pool Status)_</span></div>
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareFS(this,'zfs-scrub-<?=$tag?>','<?=$tag?>')">
<?if (_var($disk,'fsStatus')=="Mounted"):?>
@@ -1303,10 +1340,7 @@ $(function() {
}
});
}
var groups = <?=_var($disk,'fsGroups',0)?:0?>;
var width = <?=_var($disk,'fsWidth',0)?:0?>;
var devices = (groups==0 || width==0) ? <?=_var($disk,'devices',0)?:0?> : groups * width;
selectDiskFsProfile(devices,width,true);
selectDiskFsProfile(<?=_var($disk,'slots',0)?>,true);
<?if (fsType('btrfs')):?>
presetBTRFS(document.balance_schedule,'#balance-hour');
presetBTRFS(document.scrub_schedule,'#scrub-hour');
+129 -11
View File
@@ -19,6 +19,11 @@ Tag="icon-disk"
require_once "$docroot/webGui/include/Preselect.php";
$events = explode('|',$var['smEvents'] ?? $numbers);
$reply = '/var/tmp/luks.reply';
$keyfile = is_file($var['luksKeyfile']);
$encrypt = false;
foreach ($disks as $disk) if (isset($disk['fsType']) && strncmp($disk['fsType'],'luks:',5)===0) $encrypt = true;
function displayTemp($temp) {
global $display;
return (is_numeric($temp) && _var($display,'unit')=='F') ? round(9/5*$temp)+32 : $temp;
@@ -27,7 +32,11 @@ function displayTemp($temp) {
<style>
span.code{display:inline-block;width:186px}
</style>
<script>
function base64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
function doDispatch(form) {
var fields = {};
<?if (_var($display,'unit')=='F'):?>
@@ -55,11 +64,66 @@ function prepareDiskSettings(form) {
function setIndex(form) {
form.smIndex.value = form.smType.selectedIndex;
}
function prepareForm(form) {
<?if (!$keyfile):?>
form.oldluks.value = base64(form.oldtext.value);
form.oldtext.disabled = true;
form.oldfile.disabled = true;
<?endif;?>
form.newluks.value = base64(form.newtext.value);
form.newtext.disabled = true;
form.newcopy.disabled = true;
form.newfile.disabled = true;
}
function getFileContent(event,form,file) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){$(form).find('input[name="'+file+'"]').val(reader.result);};
reader.readAsDataURL(input.files[0]);
}
function selectInput(val,old) {
if (val=='text') {
if (old==true) {
$('div#oldfile').hide('slow');
$('div#oldtext').show('slow');
} else {
$('div#newfile').hide('slow');
$('div#newtext').show('slow');
$('input[name="newkey"]').prop('disabled',$('input[name="newtext"]').val()=='' || $('input[name="newtext"]').val()!=$('input[name="newcopy"]').val());
}
} else if (val=='file') {
if (old==true) {
$('div#oldtext').hide('slow');
$('div#oldfile').show('slow');
} else {
$('div#newtext').hide('slow');
$('div#newfile').show('slow');
$('input[name="newkey"]').prop('disabled',$('input[name="newfile"]').val()=='');
}
}
}
function showInput(show,old) {
if (old==true) {
var input = $('input[name="oldtext"]');
} else {
var input = $('input[name="newtext"],input[name="newcopy"]');
}
input.attr('type',show ? 'text' : 'password');
}
function checkInput(form) {
$(form).find('input[name="newkey"]').prop('disabled',form.newtext.value=='' || form.newtext.value!=form.newcopy.value);
}
<?if (is_file($reply)):?>
<?[$text,$type] = explode("\0",file_get_contents($reply)); unlink($reply);?>
$(function() {
swal({title:"_(Encryption Key Update)_",text:"<?=$text?>",html:true,type:"<?=$type?>",confirmButtonText:"_(Ok)_"});
});
<?endif;?>
</script>
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="doDispatch(this)">
_(Enable auto start)_:
: <select name="startArray" size="1">
: <select name="startArray">
<?=mk_option($var['startArray'], "no", _('No'))?>
<?=mk_option($var['startArray'], "yes", _('Yes'))?>
</select>
@@ -67,7 +131,7 @@ _(Enable auto start)_:
:disk_enable_autostart_help:
_(Default spin down delay)_:
: <select name="spindownDelay" size="1">
: <select name="spindownDelay">
<?=mk_option($var['spindownDelay'], "0", _('Never'))?>
<?=mk_option($var['spindownDelay'], "15", "15 "._('minutes'))?>
<?=mk_option($var['spindownDelay'], "30", "30 "._('minutes'))?>
@@ -86,7 +150,7 @@ _(Default spin down delay)_:
:disk_spindown_delay_help:
_(Enable spinup groups)_:
: <select name="spinupGroups" size="1">
: <select name="spinupGroups">
<?=mk_option($var['spinupGroups'], "no", _('No'))?>
<?=mk_option($var['spinupGroups'], "yes", _('Yes'))?>
</select>
@@ -94,7 +158,7 @@ _(Enable spinup groups)_:
:disk_spinup_groups_help:
_(Default file system)_:
: <select name="defaultFsType" size="1">
: <select name="defaultFsType">
<?=mk_option($var['defaultFsType'], "xfs", _('xfs'));?>
<?=mk_option($var['defaultFsType'], "zfs", _('zfs'));?>
<?=mk_option($var['defaultFsType'], "btrfs", _('btrfs'));?>
@@ -118,7 +182,7 @@ _(Tunable (poll_attributes))_:
:disk_tunable_poll_attributes_help:
_(Tunable (enable NCQ))_:
: <select name="queueDepth" size="1">
: <select name="queueDepth">
<?=mk_option($var['queueDepth'], "auto", _('Auto'))?>
<?=mk_option($var['queueDepth'], "1", _('No'))?>
</select>
@@ -131,7 +195,7 @@ _(Tunable (nr_requests))_:
:disk_tunable_nr_requests_help:
_(Tunable (scheduler))_:
: <select name="md_scheduler" size="1">
: <select name="md_scheduler">
<?=mk_option($var['md_scheduler'], "auto", _('Auto'))?>
<?=mk_option($var['md_scheduler'], "mq-deadline", _('mq-deadline'))?>
<?=mk_option($var['md_scheduler'], "kyber", _('kyber'))?>
@@ -157,7 +221,7 @@ _(Tunable (md_sync_limit))_:
:disk_tunable_md_sync_limit_help:
_(Tunable (md_write_method))_:
: <select name="md_write_method" size="1">
: <select name="md_write_method">
<?=mk_option($var['md_write_method'], "auto", _('Auto'))?>
<?=mk_option($var['md_write_method'], "0", _('read/modify/write'))?>
<?=mk_option($var['md_write_method'], "1", _('reconstruct write'))?>
@@ -189,8 +253,62 @@ _(Default critical disk temperature threshold)_ (&deg;<?=_var($display,'unit','C
: <input type="submit" name="changeDisk" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<div class="title"><span class="left"><i class="title fa fa-plus-square"></i>_(Global SMART Settings)_</span></div>
<?if ($encrypt && $var['fsState']=='Started'):?>
<div class="title"><span class="left"><i class="title fa fa-key"></i>_(Change Encryption Key)_</span></div>
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareForm(this)">
<input type="hidden" name="#file" value="">
<input type="hidden" name="#include" value="/webGui/include/update.encryption.php">
<input type="hidden" name="#reply" value="<?=$reply?>">
<input type="hidden" name="newdata" value="">
<input type="hidden" name="newluks" value="">
<?if (!$keyfile):?>
<input type="hidden" name="olddata" value="">
<input type="hidden" name="oldluks" value="">
<?endif;?>
_(Existing encryption key)_:
: <select name="oldinput" class="lock" onchange='selectInput(this.value,true)' <?=$keyfile?'disabled':''?>>
<?=mk_option(1,'text',_('Passphrase'))?>
<?=mk_option(1,'file',_('Keyfile'),$keyfile ? 'selected' : '')?>
</select><br>
<?if (!$keyfile):?>
<div markdown="1" id="oldtext">
_(Enter existing passphrase)_:
: <input type="password" name="oldtext" class="lock" maxlength="512" value="" autocomplete="off" spellcheck="false"><input name="showPass" type="checkbox" class="lock" onchange="showInput(this.checked,true)">_(show passphrase)_
</div>
<div markdown="1" id="oldfile" style="display:none">
_(Select existing keyfile)_:
: <input type="file" name="oldfile" class="lock" onchange="getFileContent(event,this.form,'olddata')">
</div>
<?endif;?>
_(Change encryption key)_:
: <select name="newinput" class="lock" onchange='selectInput(this.value,false)'>
<?=mk_option(1,'text',_('Passphrase'))?>
<?=mk_option(1,'file',_('Keyfile'))?>
</select><br>
<div markdown="1" id="newtext">
_(Type new passphrase)_:
: <input type="password" name="newtext" class="lock" maxlength="512" value="" autocomplete="off" spellcheck="false" onkeyup="checkInput(this.form)" placeholder="_(use printable characters only)_"><input name="showPass" type="checkbox" class="lock" onchange="showInput(this.checked,false)">_(show passphrase)_
_(Retype new passphrase)_:
: <input type="password" name="newcopy" class="lock" maxlength="512" value="" autocomplete="off" spellcheck="false" onkeyup="checkInput(this.form)">
</div>
<div markdown="1" id="newfile" style="display:none">
_(Select new keyfile)_:
: <input type="file" name="newfile" onchange="getFileContent(event,this.form,'newdata')">
</div>
&nbsp;
: <input type="submit" name="newkey" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?endif;?>
<div class="title"><span class="left"><i class="title fa fa-plus-square"></i>_(Global SMART Settings)_</span></div>
<form markdown="1" name="smart_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareDiskSettings(this)">
<input type="hidden" name="#file" value="/boot/config/smart-all.cfg">
<input type="hidden" name="#include" value="webGui/include/update.smart.php">
@@ -199,7 +317,7 @@ _(Default critical disk temperature threshold)_ (&deg;<?=_var($display,'unit','C
<input type="hidden" name="smEvents" value="">
<input type="hidden" name="smIndex" value="0">
_(Default SMART notification value)_:
: <select name="smSelect" size="1">
: <select name="smSelect">
<?=mk_option(_var($var,'smSelect'), "0", _('Raw'))?>
<?=mk_option(_var($var,'smSelect'), "1", _('Normalized'))?>
</select>
@@ -207,7 +325,7 @@ _(Default SMART notification value)_:
:disk_default_smart_notification_help:
_(Default SMART notification tolerance level)_:
: <select name="smLevel" size="1">
: <select name="smLevel">
<?=mk_option(_var($var,'smLevel'), "1.00", _('Absolute'))?>
<?=mk_option(_var($var,'smLevel'), "1.05", "5%")?>
<?=mk_option(_var($var,'smLevel'), "1.10", "10%")?>
@@ -220,7 +338,7 @@ _(Default SMART notification tolerance level)_:
:disk_default_smart_tolerance_help:
_(Default SMART controller type)_:
: <select name="smType" size="1" onchange="setIndex(this.form)">
: <select name="smType" onchange="setIndex(this.form)">
<?=mk_option(_var($var,'smType'), "", _('Automatic'))?>
<?=mk_option(_var($var,'smType'), "-d ata", "ATA")?>
<?=mk_option(_var($var,'smType'), "-d nvme", "NVMe")?>
+24 -27
View File
@@ -92,9 +92,31 @@ refresh(); // automatically include new ethernet ports
Array.prototype.same = function(){return this.sort().filter(function(v,i,o){return i&&v===o[i-1]?v:0;}).length;}
function prepareSettings(form) {
var metrics = [];
var metrics6 = [];
var bondnics = [], brnics = [];
for (var i=0,nic; nic=form.BONDNICS.options[i]; i++) {
if (nic.selected) {
bondnics.push(nic.value);
nic.selected = false;
}
}
nic = form.BONDNICS.options[0];
nic.value = bondnics.join(',');
nic.selected = true;
nic.disabled = false;
for (var i=0,nic; nic=form.BRNICS.options[i]; i++) {
if (nic.selected) {
brnics.push(nic.value);
nic.selected = false;
}
}
nic = form.BRNICS.options[0];
nic.value = form.BONDING.value=='yes' ? form.BONDNAME.value : brnics.join(',');
nic.selected = true;
nic.disabled = false;
if (brnics.length>1) form.BRSTP.value = 'yes';
if ($(form).find('input[name="#arg[1]"]').val()=='none') return true;
var metrics = [], metrics6 = [];
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val()>0) metrics.push($(this).val());});
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val()>0) metrics6.push($(this).val());});
if (metrics.same() || metrics6.same()) {
@@ -123,31 +145,6 @@ function prepareSettings(form) {
return false;
}
}
var member = '';
for (var i=0,item; item=form.BONDNICS.options[i]; i++) {
if (item.selected) {
if (member.length) member += ',';
member += item.value;
item.selected = false;
}
}
item = form.BONDNICS.options[0];
item.value = member;
item.selected = true;
item.disabled = false;
var member = '';
for (var i=0,item; item=form.BRNICS.options[i]; i++) {
if (item.selected) {
if (member.length) member += ',';
member += item.value;
item.selected = false;
}
}
item = form.BRNICS.options[0];
item.value = form.BONDING.value=='yes' ? form.BONDNAME.value : member;
item.selected = true;
item.disabled = false;
if (member.indexOf(',')>0) form.BRSTP.value = 'yes';
$(form).find('select[name^="PROTOCOL:"]').each(function() {
var protocol = $(this).val() || 'ipv4';
var i = $(this).attr('name').split(':')[1];
+30 -77
View File
@@ -14,59 +14,20 @@ Tag="server"
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
global $var ;
$theme = $display['theme'] ;
?>
<style>
table.t1{margin-top:0; border-collapse: collapse; border-spacing: 0;}
table tr td{padding:0 0 3px 0;margin:0}
table tr td.thin{line-height:8px;height:8px}
table.t1 tr>td{width: 1%; ; text-align:centre ;white-space: nowrap;}
table.t1 tr>td+td{width: 1%; white-space: nowrap; }
table.t1 tr>td+td+td{width:auto ; text-align:left;}
table.t1 tr>td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td+td+td+td+td+td{text-align:left;}
table.t1 tr>td+td+td+td+td+td+td+td+td+td+td+td+td{text-align:left;}
.tablesorter .filtered {
display: none;
}
<?if ($theme == "black"):?>
table.tablesorter tbody tr.alt-row {background-color:#212121;}
table.tablesorter tbody tr.normal-row {background-color:#1c1b1b;}
input.search {color:#f2f2f2;background-color:#1c1b1b;}
<?endif;?>
<?if ($theme == "white"):?>
table.tablesorter tbody tr.alt-row {background-color:#ededed;}
table.tablesorter tbody tr.normal-row {background-color:#f2f2f2;}
input.search {color:#1c1b1b;background-color:#f2f2f2;}
<?endif;?>
<?if ($theme == "gray"):?>
table.tablesorter tbody tr.alt-row {solid #0c0f0b;}
table.tablesorter tbody tr.normal-row {background-color:#1b1d1b;}
input.search {color:#606e7f;background-color:#1b1d1b;}
table.tablesorter thead th {color:#606e7f;background-color:#1b1d1b;}
div.tablesorter-header-inner {color:#606e7f;background-color:#1b1d1b;}
<?endif;?>
<?if ($theme == "azure"):?>
table.tablesorter tbody tr.alt-row {background-color:#e4e2e4; }
table.tablesorter tbody tr.normal-row {solid #f3f0f4;}
input.search {color:#606e7f;background-color:#e4e2e4;}
table.tablesorter thead th {color:#606e7f;background-color:#e4e2e4;}
div.tablesorter-header-inner {color:#606e7f;background-color:#e4e2e4;}
<?endif;?>
table.t1 tr td{padding:0 0 3px 0;margin:0}
table.t1 tr td.thin{line-height:8px;height:8px}
table.t1 tr>td{width:1%;text-align:centre;white-space: nowrap}
table.t1 tr>td+td{width:1%;white-space:nowrap}
table.t1 tr>td+td+td{width:auto;text-align:left}
table.t1 tr>td+td+td+td{text-align:left}
table.t1 tr>td+td+td+td+td{text-align:left}
.t1.tablesorter .filtered{display:none}
</style>
<script type="text/javascript" src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
<script type="text/javascript" src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
<script type="text/javascript">
function showDrivers(options, init = false) {
@@ -75,36 +36,32 @@ function showDrivers(options, init = false) {
$('#driversearch').prop('disabled', true);
$('#select').prop('disabled', true);
$('#rebuild').prop('disabled', true);
$.post('/webGui/include/SysDrivers.php',{table:'t1load',option:"all"},function(data){
clearTimeout(timers.refresh);
$("#t1").trigger("destroy");
$("#t1").trigger("destroy");
$('#t1').html(data.html);
$('#t1').tablesorter({
sortList:[[0,0]],
sortAppend:[[0,0]],
widgets: ['stickyHeaders','filter', 'zebra'],
widgetOptions: {
// on black and white, offset is height of #menu
// on azure and gray, offset is height of #header
stickyHeaders_offset: ( $('#menu').height() < 50 ) ? $('#menu').height() : $('#header').height(),
filter_columnFilters: false,
zebra : [ "normal-row", "alt-row" ]
}
sortList:[[0,0]],
sortAppend:[[0,0]],
widgets: ['stickyHeaders','filter', 'zebra'],
widgetOptions: {
// on black and white, offset is height of #menu
// on azure and gray, offset is height of #header
stickyHeaders_offset: ( $('#menu').height() < 50 ) ? $('#menu').height() : $('#header').height(),
filter_columnFilters: false,
zebra : [ "normal-row", "alt-row" ]
}
});
$('div.spinner.fixed').hide('slow');
$('#driversearch').prop('disabled', false);
$('#select').prop('disabled', false);
$('#rebuild').prop('disabled', data.init);
},"json");
} else {
filter = [];
filterDrivers() ;
filterDrivers() ;
}
}
}
function filterDrivers() {
var totalColumns = $('#t1')[0].config.columns;
@@ -124,7 +81,7 @@ function showDriversupdate() {
$('#rebuild').prop('disabled', false);
showDrivers("all",true) ;
$('div.spinner.fixed').hide('slow');
}) ;
});
}
function textedit(module) {
@@ -132,11 +89,9 @@ function textedit(module) {
$('#text'+module).prop('disabled', false);
$('#save'+module).attr('hidden', false);
$('#text'+module).attr('hidden', false);
}
function removecfg(module)
{
function removecfg(module) {
swal({title:"_(Proceed)_?",text:"_(Remove custom modprobe.d configuration?)_: "+module,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) textsave(module, true); else return false;});
}
@@ -146,7 +101,7 @@ function textsave(module,remove = false) {
$('#save'+module).attr('hidden', true);
var x = (remove) ? "" : document.getElementById("text" + module).value;
$.post('/webGui/include/SysDrivers.php',{table:'update',module:module,conf:x},function(data){
if(data) {
if (data) {
formHasUnsavedChanges=false;
$('#text'+module).val(data.modprobe) ;
$('#status'+module).html(data.state) ;
@@ -159,24 +114,22 @@ function textsave(module,remove = false) {
if (data.supportpage == true) {
if (data.support == true) {
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='" + _("Support page")_ + "' class='fa fa-phone-square'></i></a>" ;
}
}
}
}
}
$('#t1').trigger("updateCell",[document.getElementById('text'+module), false, null]);
$('#t1').trigger("updateCell",[document.getElementById('status'+module), false, null]);
var message = "_(System Drivers)_: _(A reboot is required to apply changes)_";
addRebootNotice(message);
},"json");
},"json");
}
$('.tabs').append("<span class='status'><span class='lite label'>_(Select View)_:</span><select id='select' onchange='showDrivers(this.value)'><option value='all' >All Drivers</option><option value='inuse' selected >Inuse Drivers</option></select>");
showDrivers("all",true) ;
</script>
:sysdrivers_intro_help:
<form autocomplete="off" onsubmit="return false;"><span><input class="search" id="driversearch" type="search" placeholder="Search..." onchange="filterDrivers();"></span></form>
<pre><form id="sysdrivers" class="js-confirm-leave" onsubmit="return false"><table id='t1' class="t1 disk_status tablesorter " ><tr><td><div class="spinner"></div></td></tr></table></form></pre><br>
<form autocomplete="off" onsubmit="return false;"><span><input class="t1 search" id="driversearch" type="search" placeholder="Search..." onchange="filterDrivers();"></span></form>
<pre><form id="sysdrivers" class="js-confirm-leave" onsubmit="return false"><table id='t1' class="t1 disk_status tablesorter"><tr><td><div class="spinner"></div></td></tr></table></form></pre><br>
<input type="button" value="_(Done)_" onclick="done()"><input type="button" id="rebuild" value="_(Rebuild Modules)_" onclick="showDriversupdate()">
+14 -5
View File
@@ -18,19 +18,28 @@ Tag="list"
<?
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
$log = '/var/log/syslog';
$prev = '/boot/logs/syslog-previous';
$cfg = '/boot/config/rsyslog.cfg';
$max = 5000;
$select = [];
$logs = [];
if (file_exists($cfg)) {
$syslog = parse_ini_file($cfg);
if (isset($syslog['local_server']) && isset($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
if (!empty($syslog['local_server']) && !empty($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
natsort($logs);
$select[] = "<select onchange='showLog(this.value)'>";
$select[] = mk_option(1,$log,'syslog');
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
$select[] = "</select>";
}
}
if (file_exists($prev)) {
// add syslog-previous to front of logs array
array_unshift($logs, $prev);
}
if (count($logs)) {
// add syslog to front of logs array
array_unshift($logs, $log);
$select[] = "<select onchange='showLog(this.value)'>";
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
$select[] = "</select>";
}
$select = implode($select);
?>
<style>
+2 -2
View File
@@ -139,7 +139,7 @@ $dnsserver = _var($$ethX,'DNS_SERVER1');
$link = iflink($ethX);
$postUp0 = "$script add $link WireGuard-<wg> $server <port> <port> udp";
$postUp1 = "logger -t wireguard 'Tunnel WireGuard-<wg> started';$services";
$postUp1 = "logger -t wireguard -- 'Tunnel WireGuard-<wg> started';$services";
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE";
$postUp3 = "iptables -N WIREGUARD_DROP_<WG>;iptables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
$postUpX = "iptables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
@@ -149,7 +149,7 @@ $postUp36 = "ip6tables -N WIREGUARD_DROP_<WG>;ip6tables -A WIREGUARD -o $link -
$postUpX6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
$postUpZ6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT;ip6tables -A WIREGUARD_DROP_<WG> -j RETURN";
$postDown0 = "$script del $link <port> udp";
$postDown1 = "logger -t wireguard 'Tunnel WireGuard-<wg> stopped';$services";
$postDown1 = "logger -t wireguard -- 'Tunnel WireGuard-<wg> stopped';$services";
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
$postDown3 = "iptables -F WIREGUARD_DROP_<WG>;iptables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;iptables -X WIREGUARD_DROP_<WG>";
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
@@ -1,3 +1,7 @@
#!/bin/bash
/usr/bin/logger "Submitting SysDrivers Build"
/usr/local/emhttp/plugins/dynamix/include/SysDriversInit.php &> /dev/null &
# run & log functions
. /etc/rc.d/rc.runlog
log "Submitting SysDrivers Build"
/usr/local/emhttp/plugins/dynamix/include/SysDriversInit.php &>/dev/null &
+5 -5
View File
@@ -119,12 +119,12 @@ function verifyTwoFactorToken(string $username, string $token): bool {
// This should accept 200 or 204 status codes
if ($httpCode !== 200 && $httpCode !== 204) {
// Log error to syslog
exec("logger -t webGUI ".escapeshellarg("2FA code for {$username} is invalid, blocking access!"));
exec("logger -t webGUI -- \"2FA code for {$username} is invalid, blocking access!\"");
return false;
}
// Log success to syslog
exec("logger -t webGUI ".escapeshellarg("2FA code for {$username} is valid, allowing login!"));
exec("logger -t webGUI -- \"2FA code for {$username} is valid, allowing login!\"");
// Success
return true;
@@ -199,7 +199,7 @@ if (!empty($username) && !empty($password)) {
// Check if we're limited
if ($failCount >= $maxFails) {
if ($failCount == $maxFails) exec("logger -t webGUI ".escapeshellarg("Ignoring login attempts for {$username} from {$remote_addr}"));
if ($failCount == $maxFails) exec("logger -t webGUI -- \"Ignoring login attempts for {$username} from {$remote_addr}\"");
throw new Exception(_('Too many invalid login attempts'));
}
@@ -216,7 +216,7 @@ if (!empty($username) && !empty($password)) {
$_SESSION['unraid_user'] = $username;
session_regenerate_id(true);
session_write_close();
exec("logger -t webGUI ".escapeshellarg("Successful login user {$username} from {$remote_addr}"));
exec("logger -t webGUI -- \"Successful login user {$username} from {$remote_addr}\"");
// Redirect the user to the start page
header("Location: /".$var['START_PAGE']);
@@ -226,7 +226,7 @@ if (!empty($username) && !empty($password)) {
$error = $exception->getMessage();
// Log error to syslog
exec("logger -t webGUI ".escapeshellarg("Unsuccessful login user {$username} from {$remote_addr}"));
exec("logger -t webGUI -- \"Unsuccessful login user {$username} from {$remote_addr}\"");
appendToFile($failFile, $time."\n");
}
}
@@ -35,7 +35,7 @@ if (!empty($_POST['password']) && !empty($_POST['confirmPassword'])) {
}
// Error when attempting to set password
exec("logger -t webGUI ".escapeshellarg($VALIDATION_MESSAGES['saveError'] . " [REMOTE_ADDR]: {$REMOTE_ADDR}"));
exec("logger -t webGUI -- \"{$VALIDATION_MESSAGES['saveError']} [REMOTE_ADDR]: {$REMOTE_ADDR}\"");
return $POST_ERROR = $VALIDATION_MESSAGES['saveError'];
}
+61 -31
View File
@@ -12,25 +12,46 @@
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = '';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
function write(&$rows) {
if ($size = count($rows)) echo '<tbody>',implode(array_map(function($row){echo gzinflate($row);},$rows)),'</tbody>';
$rows = $size;
}
function validdir($dir) {
$path = realpath($dir);
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path : '';
}
function escapeQuote($data) {
return str_replace('"','&#34;',$data);
}
function add($number, $name, $single='', $plural='s') {
return $number.' '._($name.($number==1 ? $single : $plural));
}
function age($number,$time) {
return sprintf(_('%s '.($number==1 ? $time : $time.'s').' ago'),$number);
}
function my_age($time) {
if (!is_numeric($time)) $time = time();
$age = new DateTime('@'.$time);
$age = date_create('now')->diff($age);
if ($age->y > 0) return age($age->y,'year');
if ($age->m > 0) return age($age->m,'month');
if ($age->d > 0) return age($age->d,'day');
if ($age->h > 0) return age($age->h,'hour');
if ($age->i > 0) return age($age->i,'minute');
return age($age->s,'second');
}
function parent_link() {
global $dir,$path;
$parent = dirname($dir);
return $parent=='/' ? false : '<a href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($parent)).'">'._('Parent Directory').'</a>';
}
function my_devs(&$devs) {
function my_devs(&$devs,$name,$menu) {
global $disks,$lock;
$text = []; $i = 0;
foreach ($devs as $dev) {
@@ -38,66 +59,75 @@ function my_devs(&$devs) {
$text[$i] = '<a class="info" onclick="return false"><i class="lock fa fa-fw fa-hdd-o grey-text"></i></a>&nbsp;---';
} else {
switch ($disks[$dev]['luksState']??0) {
case 0: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-unlock-alt grey-text'></i><span>"._('Not encrypted')."</span></a>"; break;
case 1: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-unlock-alt green-text'></i><span>"._('Encrypted and unlocked')."</span></a>"; break;
case 2: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-lock red-text'></i><span>"._('Locked: missing encryption key')."</span></a>"; break;
case 3: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-lock red-text'></i><span>"._('Locked: wrong encryption key')."</span></a>"; break;
default: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-lock red-text'></i><span>"._('Locked: unknown error')."</span></a>"; break;
case 0: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-unlock-alt grey-text"></i><span>'._('Not encrypted').'</span></a>'; break;
case 1: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-unlock-alt green-text"></i><span>'._('Encrypted and unlocked').'</span></a>'; break;
case 2: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-lock red-text"></i><span>'._('Locked: missing encryption key').'</span></a>'; break;
case 3: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-lock red-text"></i><span>'._('Locked: wrong encryption key').'</span></a>'; break;
default: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-lock red-text"></i><span>'._('Locked: unknown error').'</span></a>'; break;
}
$text[$i] .= compress($dev,12,0);
$root = $dev=='flash' ? "/boot/$name" : "/mnt/$dev/$name";
$text[$i] .= '<span id="device_'.$i.'" class="hand" onclick="'.$menu.'(\''.$root.'\','.$i.')" oncontextmenu="'.$menu.'(\''.$root.'\','.$i.');return false">'.compress($dev,11,0).'</span></span>';
}
$i++;
}
return implode($text);
}
$dir = validdir(htmlspecialchars_decode(rawurldecode($_GET['dir'])));
if (!$dir) {echo '<tbody><tr><td></td><td></td><td colspan="6">',_('Invalid path'),'</td><td></td></tr></tbody>'; exit;}
extract(parse_plugin_cfg('dynamix',true));
$disks = parse_ini_file('state/disks.ini',true);
$shares = parse_ini_file('state/shares.ini',true);
$dir = realpath(htmlspecialchars_decode(rawurldecode($_GET['dir'])));
$path = unscript($_GET['path']);
$fmt = "%F {$display['time']}";
$dirs = $files = [];
$total = $objs = 0;
[$null,$root,$main,$rest] = my_explode('/',$dir,4);
[$null,$root,$main,$next,$rest] = my_explode('/',$dir,5);
$user = $root=='mnt' && in_array($main,['user','user0']);
$lock = $root=='mnt' ? ($main ?: '---') : ($root=='boot' ? _('flash') : '---');
$ishare = $root=='mnt' && (!$main || !$next || ($main=='rootshare' && !$rest));
$folder = $lock=='---' ? _('DEVICE') : ($ishare ? _('SHARE') : _('FOLDER'));
if ($user) {
exec("shopt -s dotglob; getfattr --no-dereference --absolute-names -n system.LOCATIONS ".escapeshellarg($dir)."/* 2>/dev/null",$tmp);
if ($user ) {
exec("shopt -s dotglob;getfattr --no-dereference --absolute-names -n system.LOCATIONS ".escapeshellarg($dir)."/* 2>/dev/null",$tmp);
for ($i = 0; $i < count($tmp); $i+=3) $set[basename($tmp[$i])] = explode('"',$tmp[$i+1])[1];
unset($tmp);
}
$stat = popen("shopt -s dotglob; stat -L -c'%F|%s|%Y|%n' ".escapeshellarg($dir)."/* 2>/dev/null",'r');
$stat = popen("shopt -s dotglob;stat -L -c'%F|%U|%A|%s|%Y|%n' ".escapeshellarg($dir)."/* 2>/dev/null",'r');
while (($row = fgets($stat))!==false) {
[$type,$size,$time,$name] = explode('|',rtrim($row,"\n"),4);
[$type,$owner,$perm,$size,$time,$name] = explode('|',rtrim($row,"\n"),6);
$dev = explode('/',$name,5);
$devs = explode(',',$user ? $set[basename($name)]??$shares[$dev[3]]['cachePool']??'' : $lock);
$objs++;
$text = [];
if ($type[0]=='d') {
$text[] = "<tr>";
$text[] = "<td data=''><div class='icon-dir'></div></td>";
$text[] = "<td><a href=\"/$path?dir=".rawurlencode(htmlspecialchars($name))."\">".htmlspecialchars(basename($name))."</a></td>";
$text[] = "<td data='0'>&lt;"._('FOLDER')."&gt;</td>";
$text[] = "<td data='$time'>".my_time($time,$fmt)."</td>";
$text[] = "<td class='loc'>".my_devs($devs)."</td>";
$text[] = "</tr>";
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
$text[] = '<td data=""><div class="icon-dir"></div></td>';
$text[] = '<td><a id="name_'.$objs.'" oncontextmenu="folderContextMenu(this.id,\'right\');return false" href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($name)).'">'.htmlspecialchars(basename($name)).'</a></td>';
$text[] = '<td id="owner_'.$objs.'">'.$owner.'</td>';
$text[] = '<td id="perm_'.$objs.'">'.$perm.'</td>';
$text[] = '<td data="0">&lt;'.$folder.'&gt;</td>';
$text[] = '<td data="'.$time.'"><span class="my_time">'.my_time($time,$fmt).'</span><span class="my_age" style="display:none">'.my_age($time).'</span></td>';
$text[] = '<td class="loc">'.my_devs($devs,$dev[3]??$dev[2],'deviceFolderContextMenu').'</td>';
$text[] = '<td><i id="row_'.$objs.'" data="'.escapeQuote($name).'" type="d" class="fa fa-plus-square-o" onclick="folderContextMenu(this.id,\'both\')" oncontextmenu="folderContextMenu(this.id,\'both\');return false">...</i></td></tr>';
$dirs[] = gzdeflate(implode($text));
} else {
$ext = strtolower(pathinfo($name,PATHINFO_EXTENSION));
$tag = count($devs)>1 ? 'warning' : '';
$text[] = "<tr>";
$text[] = "<td data='$ext'><div class='icon-file icon-$ext'></div></td>";
$text[] = "<td><a href=\"".htmlspecialchars($name)."\" download target=\"_blank\" class=\"".($tag?:'none')."\">".htmlspecialchars(basename($name))."</a></td>";
$text[] = "<td data='$size' class='$tag'>".my_scale($size,$unit)." $unit</td>";
$text[] = "<td data='$time' class='$tag'>".my_time($time,$fmt)."</td>";
$text[] = "<td class='loc $tag'>".my_devs($devs)."</td>";
$text[] = "</tr>";
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
$text[] = '<td class="ext" data="'.$ext.'"><div class="icon-file icon-'.$ext.'"></div></td>';
$text[] = '<td id="name_'.$objs.'" class="'.$tag.'" onclick="fileEdit(this.id)" oncontextmenu="fileContextMenu(this.id,\'right\');return false">'.htmlspecialchars(basename($name)).'</td>';
$text[] = '<td id="owner_'.$objs.'" class="'.$tag.'">'.$owner.'</td>';
$text[] = '<td id="perm_'.$objs.'" class="'.$tag.'">'.$perm.'</td>';
$text[] = '<td data="'.$size.'" class="'.$tag.'">'.my_scale($size,$unit).' '.$unit.'</td>';
$text[] = '<td data="'.$time.'" class="'.$tag.'"><span class="my_time">'.my_time($time,$fmt).'</span><span class="my_age" style="display:none">'.my_age($time).'</span></td>';
$text[] = '<td class="loc '.$tag.'">'.my_devs($devs,$dev[3]??$dev[2],'deviceFileContextMenu').'</td>';
$text[] = '<td><i id="row_'.$objs.'" data="'.escapeQuote($name).'" type="f" class="fa fa-plus-square-o" onclick="fileContextMenu(this.id,\'both\')" oncontextmenu="fileContextMenu(this.id,\'both\');return false">...</i></td></tr>';
$files[] = gzdeflate(implode($text));
$total += $size;
}
}
pclose($stat);
if ($link = parent_link()) echo "<tbody class='tablesorter-infoOnly'><tr><td><div><img src='/webGui/icons/folderup.png'></div></td><td>$link</td><td colspan='3'></td></tr></tbody>";
echo write($dirs),write($files),'<tfoot><tr><td></td><td colspan="4">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';
?>
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><div><img src="/webGui/icons/folderup.png"></div></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
echo write($dirs),write($files),'<tfoot><tr><td></td><td></td><td colspan="7">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';
?>
@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -14,7 +14,7 @@
// Color coding for syslog and disk log
$match =
[['class' => 'text',
'text' => ['to the standard error','non[ -]fatal error','correct gpt errors','error handler\b','(kernel|logger): [|+ #-.]','logger: (naming|log)','tainted: (host-cpu|high-privileges)','root: (>f|cd)\+\+\+\+','root: \.d\.\.t\.','(move: ){2}','kernel: ERST']
'text' => ['to the standard error','non[ -]fatal error','correct gpt errors','error handler\b','(kernel|logger): [|+ #-.]','logger: (naming|log)','tainted: (host-cpu|high-privileges)','root: (>f|cd)\+\+\+\+','root: \.d\.\.t\.','(move: ){2}','kernel: ERST','kernel: BTRFS info \(device \S+\):']
],
['class' => 'login',
'text' => ['(accepted|failed) password','sshd\[\d+\]:',' login user ']
+179
View File
@@ -0,0 +1,179 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = '';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
function age($number,$time) {
return sprintf(_('%s '.($number==1 ? $time : $time.'s').' ago'),$number);
}
function my_age($time) {
if (!is_numeric($time)) $time = time();
$age = new DateTime('@'.$time);
$age = date_create('now')->diff($age);
if ($age->y > 0) return age($age->y,'year');
if ($age->m > 0) return age($age->m,'month');
if ($age->d > 0) return age($age->d,'day');
if ($age->h > 0) return age($age->h,'hour');
if ($age->i > 0) return age($age->i,'minute');
return age($age->s,'second');
}
function validname($name) {
$path = realpath(dirname($name));
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path.'/'.basename($name) : '';
}
function escape($name) {return escapeshellarg(validname($name));}
function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',$name)) : escape($name);}
switch ($_POST['mode']) {
case 'upload':
$file = validname(htmlspecialchars_decode(rawurldecode($_POST['file'])));
if (!$file) die('stop');
$local = "/var/tmp/".basename($file).".tmp";
if ($_POST['start']==0) {
$my = pathinfo($file); $n = 0;
while (file_exists($file)) $file = $my['dirname'].'/'.preg_replace('/ \(\d+\)$/','',$my['filename']).' ('.++$n.')'.($my['extension'] ? '.'.$my['extension'] : '');
file_put_contents($local,$file);
// create file with proper permissions and owner
touch($file);
chgrp($file,'users');
chown($file,'nobody');
chmod($file,0666);
}
$file = file_get_contents($local);
if ($_POST['cancel']==1) {
delete_file($file);
die('stop');
}
if (file_put_contents($file,base64_decode($_POST['data']),FILE_APPEND)===false) {
delete_file($file);
die('error');
}
die();
case 'calc':
extract(parse_plugin_cfg('dynamix',true));
$source = explode("\n",htmlspecialchars_decode(rawurldecode($_POST['source'])));
[$null,$root,$main,$rest] = my_explode('/',$source[0],4);
if ($root=='mnt' && in_array($main,['user','user0'])) {
$disks = parse_ini_file('state/disks.ini',true);
$tag = implode('|',array_merge(['disk'],pools_filter($disks)));
$loc = array_filter(explode(',',preg_replace("/($tag)/",',$1',exec("shopt -s dotglob; getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($source)."/* 2>/dev/null"))));
} else {
$loc = [];
foreach ($source as $path) {
[$null,$root,$main,$rest] = my_explode('/',$path,4);
$loc[] = $root=='mnt' ? ($main ?: '---') : ($root=='boot' ? _('flash') : '---');
}
}
natcasesort($loc);
$awk = "awk 'BEGIN{ORS=\" \"}/Number of files|Total file size/{if(\$5==\"(reg:\")print \$4,\$8;if(\$5==\"(dir:\")print \$4,\$6;if(\$3==\"size:\")print \$4}'";
[$files,$dirs,$size] = explode(' ',str_replace([',',')'],'',exec("rsync --stats -naI ".quoted($source)." /var/tmp 2>/dev/null|$awk")));
$dirs = $dirs ?: 0;
$files -= $dirs;
$calc = [];
$calc[] = _('Name').": ".implode(', ',array_map('basename',$source));
$calc[] = _('Location').": ".implode(', ',array_unique($loc));
$calc[] = _('Last modified').': '.my_age(max(array_map('filemtime',$source)));
$calc[] = _('Total occupied space').": ".my_scale($size,$unit)." $unit";
$calc[] = sprintf(_("in %s folder".($dirs==1?'':'s')." and %s file".($files==1?'':'s')),my_number($dirs),my_number($files));
$calc = '<div style="text-align:left;margin-left:56px">'.implode('<br>',$calc).'</div>';
die($calc);
case 'home':
$source = explode("\n",htmlspecialchars_decode(rawurldecode($_POST['source'])));
$target = htmlspecialchars_decode(rawurldecode($_POST['target']));
$disks = parse_ini_file('state/disks.ini',true);
$tag = implode('|',array_merge(['disk'],pools_filter($disks)));
$loc1 = implode(',',array_unique(array_filter(explode(',',preg_replace("/($tag)/",',$1',exec("getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($source)." 2>/dev/null"))))));
$loc2 = exec("getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($target)." 2>/dev/null");
$home = $loc1==$loc2 ? '1' : '0';
die($home);
case 'jobs':
$jobs = [];
$file = '/var/tmp/file.manager.jobs';
$rows = file_exists($file) ? file($file,FILE_IGNORE_NEW_LINES) : [];
$job = 1;
for ($x = 0; $x < count($rows); $x+=9) {
$data = parse_ini_string(implode("\n",array_slice($rows,$x,9)));
$task = $data['task'];
$source = explode("\r",$data['source']);
$target = $data['target'];
$more = count($source) > 1 ? " (".sprintf("and %s more",count($source)-1).") " : "";
$jobs[] = '<i id="queue_'.$job.'" class="fa fa-fw fa-square-o blue-text job" onclick="selectOne(this.id,false)"></i>'._('Job')." [".sprintf("%'.04d",$job++)."] - $task ".$source[0].$more.($target ? " --> $target" : "");
}
$jobs = '<div id="dfm_joblist">'.implode("<br>",$jobs).'</div>';
die($jobs);
case 'edit':
$file = validname(rawurldecode($_POST['file']));
die($file ? file_get_contents($file) : '');
case 'save':
if ($file = validname(rawurldecode($_POST['file']))) file_put_contents($file,rawurldecode($_POST['data']));
die();
case 'stop':
$file = htmlspecialchars_decode(rawurldecode($_POST['file']));
delete_file("/var/tmp/$file.tmp");
die();
case 'start':
$active = '/var/tmp/file.manager.active';
$jobs = '/var/tmp/file.manager.jobs';
$start = '0';
if (file_exists($jobs)) {
exec("sed -n '2,9 p' $jobs > $active");
exec("sed -i '1,9 d' $jobs");
$start = filesize($jobs) > 0 ? '2' : '1';
if ($start=='1') delete_file($jobs);
}
die($start);
case 'undo':
$jobs = '/var/tmp/file.manager.jobs';
$undo = '0';
if (file_exists($jobs)) {
$rows = array_reverse(explode(',',$_POST['row']));
foreach ($rows as $row) {
$end = $row + 8;
exec("sed -i '$row,$end d' $jobs");
}
$undo = filesize($jobs) > 0 ? '2' : '1';
if ($undo=='1') delete_file($jobs);
}
die($undo);
case 'read':
$active = '/var/tmp/file.manager.active';
$read = file_exists($active) ? json_encode(parse_ini_file($active)) : '';
die($read);
case 'file':
$active = '/var/tmp/file.manager.active';
$jobs = '/var/tmp/file.manager.jobs';
$data[] = 'action="'.($_POST['action']??'').'"';
$data[] = 'title="'.rawurldecode($_POST['title']??'').'"';
$data[] = 'source="'.htmlspecialchars_decode(rawurldecode($_POST['source']??'')).'"';
$data[] = 'target="'.rawurldecode($_POST['target']??'').'"';
$data[] = 'H="'.(empty($_POST['hdlink']) ? '' : 'H').'"';
$data[] = 'sparse="'.(empty($_POST['sparse']) ? '' : '--sparse').'"';
$data[] = 'exist="'.(empty($_POST['exist']) ? '--ignore-existing' : '').'"';
$data[] = 'zfs="'.rawurldecode($_POST['zfs']??'').'"';
if (isset($_POST['task'])) {
// add task to queue
$task = rawurldecode($_POST['task']);
$data = "task=\"$task\"\n".implode("\n",$data)."\n";
file_put_contents($jobs,$data,FILE_APPEND);
} else {
// start operation
file_put_contents($active,implode("\n",$data));
}
die();
}
?>
@@ -71,6 +71,7 @@ html{font-size:<?=$display['font']?>%}
.upgrade_notice i{float:right;cursor:pointer}
.back_to_top{display:none;position:fixed;bottom:30px;right:12px;color:#e22828;font-size:2.5rem;z-index:999}
span.big.blue-text{cursor:pointer}
span.strong.tour{margin-left:5px;padding-left:0}
i.abortOps{font-size:2rem;float:right;margin-right:20px;margin-top:8px;cursor:pointer}
pre#swalbody p{margin-block-end:1em}
<?
@@ -342,6 +343,29 @@ function openDocker(cmd,title,plg,func,start=0,button=0) {
$('button.confirm').prop('disabled',button==0);
});
}
function openVMAction(cmd,title,plg,func,start=0,button=0) {
// start = 0 : run command only when not already running (default)
// start = 1 : run command unconditionally
// button = 0 : hide CLOSE button (default)
// button = 1 : show CLOSE button
nchan_vmaction.start();
$.post('/webGui/include/StartCommand.php',{cmd:cmd,start:start},function(pid) {
if (pid==0) {
nchan_vmaction.stop();
$('div.spinner.fixed').hide();
$(".upgrade_notice").addClass('alert');
return;
}
swal({title:title,text:"<pre id='swaltext'></pre><hr>",html:true,animation:'none',showConfirmButton:button!=0,confirmButtonText:"<?=_('Close')?>"},function(close){
nchan_vmaction.stop();
$('div.spinner.fixed').hide();
$('.sweet-alert').hide('fast').removeClass('nchan');
setTimeout(function(){bannerAlert("<?=_('Attention - operation continues in background')?> ["+pid.toString().padStart(8,'0')+"]<i class='fa fa-bomb fa-fw abortOps' title=\"<?=_('Abort background process')?>\" onclick='abortOperation("+pid+")'></i>",cmd,plg,func,start);});
});
$('.sweet-alert').addClass('nchan');
$('button.confirm').prop('disabled',button==0);
});
}
function abortOperation(pid) {
swal({title:"<?=_('Abort background operation')?>",text:"<?=_('This may leave an unknown state')?>",html:true,animation:'none',type:'warning',showCancelButton:true,confirmButtonText:"<?=_('Proceed')?>",cancelButtonText:"<?=_('Cancel')?>"},function(){
$.post('/webGui/include/StartCommand.php',{kill:pid},function() {
@@ -387,6 +411,14 @@ function openDone(data) {
}
return false;
}
function openError(data) {
if (data == '_ERROR_') {
$('div.spinner.fixed').hide();
$('button.confirm').text("<?=_('Error')?>").prop('disabled',false).show();
return true;
}
return false;
}
function showStatus(name,plugin,job) {
$.post('/webGui/include/ProcessStatus.php',{name:name,plugin:plugin,job:job},function(status){$(".tabs").append(status);});
}
@@ -739,7 +771,7 @@ unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt
// Build footer
annotate('Footer');
echo '<div id="footer"><span id="statusraid"><span id="statusbar">';
$progress = (_var($var,'fsProgress')!='')? "&bullet;<span class='blue strong'>{$var['fsProgress']}</span>" : '';
$progress = (_var($var,'fsProgress')!='')? "&bullet;<span class='blue strong tour'>{$var['fsProgress']}</span>" : '';
switch (_var($var,'fsState')) {
case 'Stopped':
echo "<span class='red strong'><i class='fa fa-stop-circle'></i> "._('Array Stopped')."</span>$progress"; break;
@@ -804,7 +836,7 @@ defaultPage.on('message', function(msg,meta) {
switch (ini['fsState']) {
case 'Stopped' : var status = "<span class='red strong'><i class='fa fa-stop-circle'></i> <?=_('Array Stopped')?></span>"; break;
case 'Started' : var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>"; break;
case 'Formatting': var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>&bullet;<span class='orange strong'><?=_('Formatting device(s)')?></span>"; break;
case 'Formatting': var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>&bullet;<span class='orange strong tour'><?=_('Formatting device(s)')?></span>"; break;
default : var status = "<span class='orange strong'><i class='fa fa-pause-circle'></i> "+_('Array '+ini['fsState'])+"</span>";
}
if (ini['mdResyncPos'] > 0) {
@@ -816,11 +848,11 @@ defaultPage.on('message', function(msg,meta) {
default : var action = '';
}
action += " "+(ini['mdResyncPos']/(ini['mdResyncSize']/100+1)).toFixed(1)+" %";
status += "&bullet;<span class='orange strong'>"+action.replace('.','<?=_var($display,'number','.,')[0]?>');
status += "&bullet;<span class='orange strong tour'>"+action.replace('.','<?=_var($display,'number','.,')[0]?>');
if (ini['mdResyncDt']==0) status += " &bullet; <?=_('Paused')?>";
status += "</span>";
}
if (ini['fsProgress']) status += "&bullet;<span class='blue strong'>"+_(ini['fsProgress'])+"</span>";
if (ini['fsProgress']) status += "&bullet;<span class='blue strong tour'>"+_(ini['fsProgress'])+"</span>";
$('#statusbar').html(status);
break;
case 2:
@@ -919,7 +951,54 @@ nchan_docker.on('message', function(data) {
}
box.scrollTop(box[0].scrollHeight);
});
var nchan_vmaction = new NchanSubscriber('/sub/vmaction',{subscriber:'websocket'});
nchan_vmaction.on('message', function(data) {
if (!data || openDone(data) || openError(data)) return;
var box = $('pre#swaltext');
data = data.split('\0');
switch (data[0]) {
case 'addLog':
var rows = document.getElementsByClassName('logLine');
if (rows.length) {
var row = rows[rows.length-1];
row.innerHTML += data[1]+'<br>';
}
break;
case 'progress':
var rows = document.getElementsByClassName('progress-'+data[1]);
if (rows.length) {
rows[rows.length-1].textContent = data[2];
}
break;
case 'addToID':
var rows = document.getElementById(data[1]);
if (rows === null) {
rows = document.getElementsByClassName('logLine');
if (rows.length) {
var row = rows[rows.length-1];
row.innerHTML += '<span id="'+data[1]+'">'+data[1]+': <span class="content">'+data[2]+'</span><span class="progress-'+data[1]+'"></span>.</span><br>';
}
} else {
var rows_content = rows.getElementsByClassName('content');
if (!rows_content.length || rows_content[rows_content.length-1].textContent != data[2]) {
rows.innerHTML += '<span class="content">'+data[2]+'</span><span class="progress-'+data[1]+'"></span>.';
}
}
break;
case 'show_Wait':
progress_span[data[1]] = document.getElementById('wait-'+data[1]);
progress_dots[data[1]] = setInterval(function(){if (((progress_span[data[1]].innerHTML += '.').match(/\./g)||[]).length > 9) progress_span[data[1]].innerHTML = progress_span[data[1]].innerHTML.replace(/\.+$/,'');},500);
break;
case 'stop_Wait':
clearInterval(progress_dots[data[1]]);
progress_span[data[1]].innerHTML = '';
break;
default:
box.html(box.html()+data[0]);
break;
}
box.scrollTop(box[0].scrollHeight);
});
var backtotopoffset = 250;
var backtotopduration = 500;
$(window).scroll(function() {
@@ -215,9 +215,9 @@ EOF
echo "${RET}"
} >>"${LOG}"
# if there was an error with the submission, log details and exit loop
[[ "${RET}" != *"retry_after"* ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" "Failed sending notification" && break
[[ "${RET}" != *"retry_after"* ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" -- "Failed sending notification" && break
# if retries exhausted, log failure
[[ "${i}" -eq "${MAX}" ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" "Failed sending notification - rate limited" && break
[[ "${i}" -eq "${MAX}" ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" -- "Failed sending notification - rate limited" && break
# we were rate limited, try again after a delay
sleep 1
done
@@ -32,7 +32,7 @@ function build_pages($pattern) {
foreach (glob($pattern,GLOB_NOSORT) as $entry) {
[$header, $content] = my_explode("\n---\n",file_get_contents($entry));
$page = @parse_ini_string($header);
if (!$page) {exec("logger -t 'webGUI' Invalid .page format: $entry"); continue;}
if (!$page) {exec("logger -t webGUI -- \"Invalid .page format: $entry\""); continue;}
$page['file'] = $entry;
$page['root'] = dirname($entry);
$page['name'] = basename($entry, '.page');
@@ -1,22 +1,19 @@
#!/usr/bin/php
<?php
function SysDriverslog($m, $type = "NOTICE") {
if ($type == "DEBUG" ) return NULL;
$m = print_r($m,true);
$m = str_replace("\n", " ", $m);
$m = str_replace('"', "'", $m);
$cmd = "/usr/bin/logger ".'"'.$m.'"'." -tSysDrivers";
exec($cmd);
if ($type == "DEBUG") return NULL;
$m = print_r($m,true);
$m = str_replace("\n", " ", $m);
$m = str_replace('"', "'", $m);
exec("logger -t webGUI -- \"$m\"");
}
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/SysDriversHelpers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
$kernel = shell_exec("uname -r") ;
$kernel = trim($kernel,"\n") ;
@@ -28,6 +25,6 @@ $arrModtoPlg = json_decode(file_get_contents("/tmp/modulestoplg.json") ,TRUE) ;
file_put_contents("/tmp/sysdrivers.init","1") ;
SysDriverslog("SysDrivers Build Starting") ;
modtoplg() ;
createlist() ;
createlist() ;
SysDriverslog("SysDrivers Build Complete") ;
?>
@@ -0,0 +1,367 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$dfm['hover'] = in_array($theme,['white','azure']) ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)';
$dfm['bgcolor'] = in_array($theme,['white','azure']) ? '#f2f2f2' : '#1c1c1c';
$dfm['fgcolor'] = in_array($theme,['white','azure']) ? '#1c1c1c' : '#f2f2f2';
$dfm['incolor'] = $theme!='gray' ? $dfm['bgcolor'] : '#121510';
?>
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
<style>
#countdown{float:left;margin-left:100px}
#user-notice{float:left}
div.dfm_info{position:absolute;bottom:4px;width:74%;margin-left:23%}
div.dfm_template{display:none}
div#dfm_dialogWindow{overflow-x:hidden}
div#dfm_dialogWindow dt{width:23%}
div#dfm_joblist{text-align:left;margin-top:20px;margin-left:56px}
span.dfm_filter{position:relative;margin-left:<?=$themes1?'12':'0'?>px;top:-<?=$themes1?'2':'8'?>px}
span.dfm_filter i{position:absolute;left:10px;top:<?=$themes1?'4':'8'?>px;font-size:1.4rem}
span.dfm_loc{display:inline-block}
span.dfm_text{display:inline-block;width:75%;white-space:normal}
span.dfm_device{display:inline-block;float:left}
span.dfm_percent{display:inline-block;width:40px}
span.dfm_speed{display:inline-block;margin-left:10px;width:140px}
input.dfm_filter{border:none;width:100px;background-color:<?=$dfm['incolor']?>;margin:-8px 0 0 0;padding-left:30px}
input.dfm_filter:focus{background-color:<?=$dfm['incolor']?>}
input#dfm_sparse,input#dfm_exist{margin-left:0}
input#dfm_target{color:<?=$dfm['fgcolor']?>;width:500px}
input#dfm_target+.fileTree{background:<?=$dfm['bgcolor']?>;width:500px;max-height:320px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
select.dfm{margin:0 40px 0 10px}
select#dfm_source{min-width:none;max-width:none;border:none;background-image:none;width:660px;cursor:default}
select#dfm_source option{background-color:transparent}
i.dfm{margin-right:8px}
i.dfm_filter{margin-top:-<?=$themes1?'2':'4'?>px}
i.job{cursor:pointer;font-size:1.8rem;vertical-align:middle}
.ui-dfm .ui-dialog-titlebar-close{background:transparent;border:none;font-size:1.8rem!important;margin-top:-14px!important;margin-right:-18px!important}
.ui-dfm .ui-dialog-titlebar-close:hover{background:transparent;color:#ff8c2f}
.ui-dfm .ui-dialog-title{text-align:center;width:100%;font-size:1.8rem}
.ui-dfm .ui-dialog-content{padding-top:15px;vertical-align:bottom}
.ui-dfm .ui-button-text{padding:0px 5px}
.ui-dfm .ui-dialog-buttonpane .ui-dialog-buttonset button[disabled],
.ui-dfm .ui-dialog-buttonpane .ui-dialog-buttonset button[disabled]:hover
{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
</style>
<div class="dfm_template">
<div id="dfm_dialogWindow"></div>
<input type="file" id="dfm_upload" value="" onchange="startUpload(this.files)" multiple>
<div markdown="1" id="dfm_templateCreateFolder">
&nbsp;
: &nbsp;
_(New folder name)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="">
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This creates a folder at the current level)_</div>
</div>
<div markdown="1" id="dfm_templateDeleteFolder">
_(Folder name)_:
: <span id="dfm_source"></span>
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i><?=_("This deletes the folder and all its content")?></div>
</div>
<div markdown="1" id="dfm_templateRenameFolder">
_(Current folder name)_:
: <span id="dfm_source"></span>
&nbsp;
: _(rename to)_ ...
_(New folder name)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="">
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This renames the folder to the new name)_</div>
</div>
<div markdown="1" id="dfm_templateCopyFolder">
_(Source folder)_:
: <span id="dfm_source"></span>
&nbsp;
: _(copy to)_ ...
_(Target folder)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="HIDE_FILES_FILTER" data-pickmatch="" data-pickroot="" data-picktop="">
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i><?=_("This copies the folder and all its content to another folder")?></div>
</div>
<div markdown="1" id="dfm_templateMoveFolder">
_(Source folder)_:
: <span id="dfm_source"></span>
&nbsp;
: _(move to)_ ...
_(Target folder)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="HIDE_FILES_FILTER" data-pickmatch="" data-pickroot="" data-picktop="">
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i><?=_("This moves the folder and all its content to another folder")?></div>
</div>
<div markdown="1" id="dfm_templateDeleteFile">
_(File name)_:
: <span id="dfm_source"></span>
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This deletes the selected file)_</div>
</div>
<div markdown="1" id="dfm_templateRenameFile">
_(Current file name)_:
: <span id="dfm_source"></span>
&nbsp;
: _(rename to)_ ...
_(New file name)_:
: <input type="text" id="dfm_target" autocomplete="off" value="">
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This renames the selected file)_</div>
</div>
<div markdown="1" id="dfm_templateCopyFile">
_(Source file)_:
: <span id="dfm_source"></span>
&nbsp;
: _(copy to)_ ...
_(Target file)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This copies the selected file)_</div>
</div>
<div markdown="1" id="dfm_templateMoveFile">
_(Source file)_:
: <span id="dfm_source"></span>
&nbsp;
: _(move to)_ ...
_(Target file)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This moves the selected file)_</div>
</div>
<div markdown="1" id="dfm_templateDeleteObject">
_(Source)_:
: <select id="dfm_source"></select>
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This deletes all selected sources)_</div>
</div>
<div markdown="1" id="dfm_templateRenameObject">
_(Source)_:
: <span id="dfm_source"></span>
&nbsp;
: _(rename to)_ ...
_(Target)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="">
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This renames the selected source)_</div>
</div>
<div markdown="1" id="dfm_templateCopyObject">
_(Source)_:
: <select id="dfm_source"></select>
&nbsp;
: _(copy to)_ ...
_(Target)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This copies all the selected sources)_</div>
</div>
<div markdown="1" id="dfm_templateMoveObject">
_(Source)_:
: <select id="dfm_source"></select>
&nbsp;
: _(move to)_ ...
_(Target)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This moves all the selected sources)_</div>
</div>
<div markdown="1" id="dfm_templateChangeOwner">
_(Source)_:
: <select id="dfm_source"></select>
&nbsp;
: _(change owner)_ ...
_(New owner)_:
: <select id="dfm_target">
<?foreach ($users as $user) echo mk_option(0,$user['name'],$user['name']);
echo mk_option(0,'nobody','nobody');
?></select>
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This changes the owner of the source recursively)_</div>
</div>
<div markdown="1" id="dfm_templateChangePermission">
_(Source)_:
: <select id="dfm_source"></select>
&nbsp;
: _(change permission)_ ...
_(New permission)_:
: <input type="hidden" id="dfm_target" value="">
_(Owner)_:<select id="dfm_owner" class="narrow dfm">
<?=mk_option(0,'u-rwx',_('No Access'))?>
<?=mk_option(0,'u-wx+r',_('Read-only'))?>
<?=mk_option(0,'u-x+rw',_('Read/Write'))?>
</select>
_(Group)_:<select id="dfm_group" class="narrow dfm">
<?=mk_option(0,'g-rwx',_('No Access'))?>
<?=mk_option(0,'g-wx+r',_('Read-only'))?>
<?=mk_option(0,'g-x+rw',_('Read/Write'))?>
</select>
_(Other)_:<select id="dfm_other" class="narrow dfm">
<?=mk_option(0,'o-rwx',_('No Access'))?>
<?=mk_option(0,'o-wx+r',_('Read-only'))?>
<?=mk_option(0,'o-x+rw',_('Read/Write'))?>
</select>
&nbsp;
: <span class="dfm_text"></span>
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This changes the permission of the source recursively)_</div>
</div>
<div markdown="1" id="dfm_templateSearch">
_(Source)_:
: <select id="dfm_source"></select>
_(Search pattern)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value=""><span id="dfm_files"></span>
<span class="dfm_loc">&nbsp;</span>
: <span class="dfm_text"></span>
</div>
<div id="dfm_templateEditFile">
<!--!
<style>div#dfm_editor{position:absolute;top:0;bottom:0;left:0;right:0}</style>
<div id="dfm_editor"></div>
<script src="<?autov('/plugins/dynamix.file.manager/javascript/ace/ace.js')?>"></script>
<script src="<?autov('/plugins/dynamix.file.manager/javascript/ace/ext-modelist.js')?>"></script>
<script>
function getMode(file){
var modelist = require('ace/ext/modelist');
return modelist.getModeForPath(file).mode;
}
var source = "{$0}";
var editor = ace.edit('dfm_editor');
editor.session.setMode(getMode(source));
editor.setOptions({
showPrintMargin:false,
fontSize:13,
fontFamily:'bitstream',
theme:'ace/theme/<?if (in_array($theme,['black','gray'])):?>tomorrow_night<?else:?>tomorrow<?endif;?>'
});
timers.editor = setTimeout(function(){$('div.spinner.fixed').show();},500);
$.post('/plugins/dynamix.file.manager/include/Control.php',{mode:'edit',file:encodeURIComponent(source)},function(data){
clearTimeout(timers.editor);
$('div.spinner.fixed').hide();
editor.session.setValue(data);
});
</script>
!-->
</div>
<div id="dfm_templateViewFile">
<!--!
<img id="dfm_viewer" href="{$0}">
<script src="<?autov('/plugins/dynamix.file.manager/javascript/EZView.js')?>"></script>
<script>
$('#dfm_viewer').EZView();
$('#dfm_viewer').click();
</script>
!-->
</div>
<div id="dfm_templateJobs">
<!--!
<style>div#dfm_jobs{position:absolute;top:0;bottom:0;left:0;right:0;line-height:3rem}</style>
<div id="dfm_jobs"></div>
<script>
$.post('/plugins/dynamix.file.manager/include/Control.php',{mode:'jobs'},function(jobs){
$('#dfm_jobs').html(jobs);
});
</script>
!-->
</div>
</div>
+5 -5
View File
@@ -74,14 +74,14 @@ function ipaddr($ethX='eth0', $prot=4) {
global $$ethX;
switch (_var($$ethX,'PROTOCOL:0')) {
case 'ipv4':
return $$ethX['IPADDR:0'];
return _var($$ethX,'IPADDR:0');
case 'ipv6':
return $$ethX['IPADDR6:0'];
return _var($$ethX,'IPADDR6:0');
case 'ipv4+ipv6':
switch ($prot) {
case 4: return $$ethX['IPADDR:0'];
case 6: return $$ethX['IPADDR6:0'];
default:return [$$ethX['IPADDR:0'],$$ethX['IPADDR6:0']];}
case 4: return _var($$ethX,'IPADDR:0');
case 6: return _var($$ethX,'IPADDR6:0');
default:return [_var($$ethX,'IPADDR:0'),_var($$ethX,'IPADDR6:0')];}
default:
return _var($$ethX,'IPADDR:0');
}
@@ -1,5 +1,5 @@
<?PHP
/* Copyright 2005-2020, Lime Technology
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -10,14 +10,15 @@
*/
?>
<?
/* This file provides basic local setup for php cli and is
* named in /etc/php/php.ini like this:
* auto_prepend_file="/usr/local/emhttp/webGui/include/local_prepend.php"
*/
// This file provides basic local setup for php cli and is
// named in /etc/php/php.ini like this:
// auto_prepend_file="/usr/local/emhttp/webGui/include/local_prepend.php"
function csrf_terminate($reason) {
shell_exec("logger error: " . escapeshellarg($_SERVER['REQUEST_URI']) . ": $reason csrf_token");
exit;
exec("logger -t webGUI -- \"error: {$_SERVER['REQUEST_URI']} - {$reason} csrf_token\"");
exit;
}
putenv('PATH=.:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin');
chdir('/usr/local/emhttp');
setlocale(LC_ALL,'en_US.UTF-8');
@@ -28,14 +29,14 @@ ini_set("session.use_strict_mode", "1");
// ini_set("session.cookie_samesite", $secure?'Strict':'Lax');
ini_set("session.cookie_samesite", 'Lax');
if (array_key_exists('HTTP_HOST', $_SERVER)) {
session_name("unraid_".md5(strstr($_SERVER['HTTP_HOST'].':', ':', true)));
session_name("unraid_".md5(strstr($_SERVER['HTTP_HOST'].':', ':', true)));
}
session_set_cookie_params(0, '/', null, $secure, true);
if ($_SERVER['SCRIPT_NAME'] != '/login.php' && $_SERVER['SCRIPT_NAME'] != '/auth-request.php' && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($var)) $var = parse_ini_file('state/var.ini');
if (!isset($var['csrf_token'])) csrf_terminate("uninitialized");
if (!isset($_POST['csrf_token'])) csrf_terminate("missing");
if ($var['csrf_token'] != $_POST['csrf_token']) csrf_terminate("wrong");
unset($_POST['csrf_token']);
if (!isset($var)) $var = parse_ini_file('state/var.ini');
if (!isset($var['csrf_token'])) csrf_terminate("uninitialized");
if (!isset($_POST['csrf_token'])) csrf_terminate("missing");
if ($var['csrf_token'] != $_POST['csrf_token']) csrf_terminate("wrong");
unset($_POST['csrf_token']);
}
?>
@@ -0,0 +1,115 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Wrappers.php";
$save = false;
$disks = parse_ini_file('state/disks.ini',true);
$newkey = parse_ini_file('state/var.ini')['luksKeyfile'] ?: '/root/keyfile';
$oldkey = dirname($newkey).'/oldfile';
$delkey = !is_file($newkey);
$crypto = [];
foreach (glob('/dev/disk/by-id/*CRYPT-LUKS*',GLOB_NOSORT) as $disk) {
$disk = explode('-',$disk);
$crypto[] = array_pop($disk);
}
if (count($crypto)==0) die();
function delete_file(...$file) {
array_map('unlink',array_filter($file,'is_file'));
}
function removeKey($key,$disk) {
$match = $slots = 0;
$dump = popen("cryptsetup luksDump /dev/$disk",'r');
while (($row = fgets($dump))!==false) {
if (strncmp($row,'Version:',8)==0) {
switch (trim(explode(':',$row)[1])) {
case 1: $match = '/^Key Slot \d+: ENABLED$/'; break;
case 2: $match = '/^\s+\d+: luks2$/'; break;
}
}
if ($match && preg_match($match,$row)) $slots++;
}
pclose($dump);
if ($slots > 1) exec("cryptsetup luksRemoveKey /dev/$disk $key &>/dev/null");
}
function diskname($name) {
global $disks;
foreach ($disks as $disk) if (strncmp($name,$disk['device'],strlen(disk['device']))==0) return $disk['name'];
return $name;
}
function reply($text,$type) {
global $oldkey,$newkey,$delkey;
$reply = _var($_POST,'#reply');
if (realpath(dirname($reply))=='/var/tmp') file_put_contents($reply,$text."\0".$type);
delete_file($oldkey);
if (_var($_POST,'newinput','text')=='text' || $delkey) delete_file($newkey);
die();
}
if (isset($_POST['oldinput'])) {
switch ($_POST['oldinput']) {
case 'text':
file_put_contents($oldkey,base64_decode(_var($_POST,'oldluks')));
break;
case 'file':
file_put_contents($oldkey,base64_decode(explode(';base64,',_var($_POST,'olddata','x;base64,'))[1]));
break;
}
} else {
if (is_file($newkey)) copy($newkey,$oldkey);
}
if (is_file($oldkey)) {
$disk = $crypto[0]; // check first disk only (key is the same for all disks)
exec("cryptsetup luksOpen --test-passphrase --key-file $oldkey /dev/$disk &>/dev/null",$null,$error);
} else $error = 1;
if ($error > 0) reply(_('Incorrect existing key'),'warning');
if (isset($_POST['newinput'])) {
switch ($_POST['newinput']) {
case 'text':
file_put_contents($newkey,base64_decode(_var($_POST,'newluks')));
$luks = 'luksKey';
$data = _var($_POST,'newluks');
break;
case 'file':
file_put_contents($newkey,base64_decode(explode(';base64,',_var($_POST,'newdata','x;base64,'))[1]));
$luks = 'luksKey=&luksKeyfile';
$data = $newkey;
break;
}
$good = $bad = [];
foreach ($crypto as $disk) {
exec("cryptsetup luksAddKey --key-file $oldkey /dev/$disk $newkey &>/dev/null",$null,$error);
if ($error==0) $good[] = $disk; else $bad[] = diskname($disk);
}
if (count($bad)==0) {
// all okay, remove the old key
foreach ($good as $disk) removeKey($oldkey,$disk);
exec("emcmd 'changeDisk=apply&$luks=$data'");
reply(_('Key successfully changed'),'success');
} else {
// something went wrong, restore key
foreach ($good as $disk) removeKey($newkey,$disk);
reply(_('Changing key failed for disks').': '.implode(' ',$bad),'error');
}
}
reply(_('Missing new key'),'warning');
?>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/ext/beautify",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";function i(e,t){return e.type.lastIndexOf(t+".xml")>-1}var r=e("../token_iterator").TokenIterator;t.singletonTags=["area","base","br","col","command","embed","hr","html","img","input","keygen","link","meta","param","source","track","wbr"],t.blockTags=["article","aside","blockquote","body","div","dl","fieldset","footer","form","head","header","html","nav","ol","p","script","section","style","table","tbody","tfoot","thead","ul"],t.formatOptions={lineBreaksAfterCommasInCurlyBlock:!0},t.beautify=function(e){var n=new r(e,0,0),s=n.getCurrentToken(),o=e.getTabString(),u=t.singletonTags,a=t.blockTags,f=t.formatOptions||{},l,c=!1,h=!1,p=!1,d="",v="",m="",g=0,y=0,b=0,w=0,E=0,S=0,x=0,T,N=0,C=0,k=[],L=!1,A,O=!1,M=!1,_=!1,D=!1,P={0:0},H=[],B=!1,j=function(){l&&l.value&&l.type!=="string.regexp"&&(l.value=l.value.replace(/^\s*/,""))},F=function(){var e=d.length-1;for(;;){if(e==0)break;if(d[e]!==" ")break;e-=1}d=d.slice(0,e+1)},I=function(){d=d.trimRight(),c=!1};while(s!==null){N=n.getCurrentTokenRow(),k=n.$rowTokens,l=n.stepForward();if(typeof s!="undefined"){v=s.value,E=0,_=m==="style"||e.$modeId==="ace/mode/css",i(s,"tag-open")?(M=!0,l&&(D=a.indexOf(l.value)!==-1),v==="</"&&(D&&!c&&C<1&&C++,_&&(C=1),E=1,D=!1)):i(s,"tag-close")?M=!1:i(s,"comment.start")?D=!0:i(s,"comment.end")&&(D=!1),!M&&!C&&s.type==="paren.rparen"&&s.value.substr(0,1)==="}"&&C++,N!==T&&(C=N,T&&(C-=T));if(C){I();for(;C>0;C--)d+="\n";c=!0,!i(s,"comment")&&!s.type.match(/^(comment|string)$/)&&(v=v.trimLeft())}if(v){s.type==="keyword"&&v.match(/^(if|else|elseif|for|foreach|while|switch)$/)?(H[g]=v,j(),p=!0,v.match(/^(else|elseif)$/)&&d.match(/\}[\s]*$/)&&(I(),h=!0)):s.type==="paren.lparen"?(j(),v.substr(-1)==="{"&&(p=!0,O=!1,M||(C=1)),v.substr(0,1)==="{"&&(h=!0,d.substr(-1)!=="["&&d.trimRight().substr(-1)==="["?(I(),h=!1):d.trimRight().substr(-1)===")"?I():F())):s.type==="paren.rparen"?(E=1,v.substr(0,1)==="}"&&(H[g-1]==="case"&&E++,d.trimRight().substr(-1)==="{"?I():(h=!0,_&&(C+=2))),v.substr(0,1)==="]"&&d.substr(-1)!=="}"&&d.trimRight().substr(-1)==="}"&&(h=!1,w++,I()),v.substr(0,1)===")"&&d.substr(-1)!=="("&&d.trimRight().substr(-1)==="("&&(h=!1,w++,I()),F()):s.type!=="keyword.operator"&&s.type!=="keyword"||!v.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)?s.type==="punctuation.operator"&&v===";"?(I(),j(),p=!0,_&&C++):s.type==="punctuation.operator"&&v.match(/^(:|,)$/)?(I(),j(),v.match(/^(,)$/)&&x>0&&S===0&&f.lineBreaksAfterCommasInCurlyBlock?C++:(p=!0,c=!1)):s.type==="support.php_tag"&&v==="?>"&&!c?(I(),h=!0):i(s,"attribute-name")&&d.substr(-1).match(/^\s$/)?h=!0:i(s,"attribute-equals")?(F(),j()):i(s,"tag-close")?(F(),v==="/>"&&(h=!0)):s.type==="keyword"&&v.match(/^(case|default)$/)&&B&&(E=1):(I(),j(),h=!0,p=!0);if(c&&(!s.type.match(/^(comment)$/)||!!v.substr(0,1).match(/^[/#]$/))&&(!s.type.match(/^(string)$/)||!!v.substr(0,1).match(/^['"@]$/))){w=b;if(g>y){w++;for(A=g;A>y;A--)P[A]=w}else g<y&&(w=P[g]);y=g,b=w,E&&(w-=E),O&&!S&&(w++,O=!1);for(A=0;A<w;A++)d+=o}s.type==="keyword"&&v.match(/^(case|default)$/)?B===!1&&(H[g]=v,g++,B=!0):s.type==="keyword"&&v.match(/^(break)$/)&&H[g-1]&&H[g-1].match(/^(case|default)$/)&&(g--,B=!1),s.type==="paren.lparen"&&(S+=(v.match(/\(/g)||[]).length,x+=(v.match(/\{/g)||[]).length,g+=v.length),s.type==="keyword"&&v.match(/^(if|else|elseif|for|while)$/)?(O=!0,S=0):!S&&v.trim()&&s.type!=="comment"&&(O=!1);if(s.type==="paren.rparen"){S-=(v.match(/\)/g)||[]).length,x-=(v.match(/\}/g)||[]).length;for(A=0;A<v.length;A++)g--,v.substr(A,1)==="}"&&H[g]==="case"&&g--}s.type=="text"&&(v=v.replace(/\s+$/," ")),h&&!c&&(F(),d.substr(-1)!=="\n"&&(d+=" ")),d+=v,p&&(d+=" "),c=!1,h=!1,p=!1;if(i(s,"tag-close")&&(D||a.indexOf(m)!==-1)||i(s,"doctype")&&v===">")D&&l&&l.value==="</"?C=-1:C=1;l&&u.indexOf(l.value)===-1&&(i(s,"tag-open")&&v==="</"?g--:i(s,"tag-open")&&v==="<"?g++:i(s,"tag-close")&&v==="/>"&&g--),i(s,"tag-name")&&(m=v),T=N}}s=l}d=d.trim(),e.doc.setValue(d)},t.commands=[{name:"beautify",description:"Format selection (Beautify)",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]}); (function() {
window.require(["ace/ext/beautify"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/code_lens",["require","exports","module","ace/line_widgets","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/editor","ace/config"],function(e,t,n){"use strict";function u(e){var t=e.$textLayer,n=t.$lenses;n&&n.forEach(function(e){e.remove()}),t.$lenses=null}function a(e,t){var n=e&t.CHANGE_LINES||e&t.CHANGE_FULL||e&t.CHANGE_SCROLL||e&t.CHANGE_TEXT;if(!n)return;var r=t.session,i=t.session.lineWidgets,s=t.$textLayer,a=s.$lenses;if(!i){a&&u(t);return}var f=t.$textLayer.$lines.cells,l=t.layerConfig,c=t.$padding;a||(a=s.$lenses=[]);var h=0;for(var p=0;p<f.length;p++){var d=f[p].row,v=i[d],m=v&&v.lenses;if(!m||!m.length)continue;var g=a[h];g||(g=a[h]=o.buildDom(["div",{"class":"ace_codeLens"}],t.container)),g.style.height=l.lineHeight+"px",h++;for(var y=0;y<m.length;y++){var b=g.childNodes[2*y];b||(y!=0&&g.appendChild(o.createTextNode("\u00a0|\u00a0")),b=o.buildDom(["a"],g)),b.textContent=m[y].title,b.lensCommand=m[y]}while(g.childNodes.length>2*y-1)g.lastChild.remove();var w=t.$cursorLayer.getPixelPosition({row:d,column:0},!0).top-l.lineHeight*v.rowsAbove-l.offset;g.style.top=w+"px";var E=t.gutterWidth,S=r.getLine(d).search(/\S|$/);S==-1&&(S=0),E+=S*l.characterWidth,g.style.paddingLeft=c+E+"px"}while(h<a.length)a.pop().remove()}function f(e){if(!e.lineWidgets)return;var t=e.widgetManager;e.lineWidgets.forEach(function(e){e&&e.lenses&&t.removeLineWidget(e)})}function l(e){e.codeLensProviders=[],e.renderer.on("afterRender",a),e.$codeLensClickHandler||(e.$codeLensClickHandler=function(t){var n=t.target.lensCommand;if(!n)return;e.execCommand(n.id,n.arguments),e._emit("codeLensClick",t)},i.addListener(e.container,"click",e.$codeLensClickHandler,e)),e.$updateLenses=function(){function o(){var r=n.selection.cursor,i=n.documentToScreenRow(r),o=n.getScrollTop(),u=t.setLenses(n,s),a=n.$undoManager&&n.$undoManager.$lastDelta;if(a&&a.action=="remove"&&a.lines.length>1)return;var f=n.documentToScreenRow(r),l=e.renderer.layerConfig.lineHeight,c=n.getScrollTop()+(f-i)*l;u==0&&o<l/4&&o>-l/4&&(c=-l),n.setScrollTop(c)}var n=e.session;if(!n)return;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var i=e.codeLensProviders.length,s=[];e.codeLensProviders.forEach(function(e){e.provideCodeLenses(n,function(e,t){if(e)return;t.forEach(function(e){s.push(e)}),i--,i==0&&o()})})};var n=s.delayedCall(e.$updateLenses);e.$updateLensesOnInput=function(){n.delay(250)},e.on("input",e.$updateLensesOnInput)}function c(e){e.off("input",e.$updateLensesOnInput),e.renderer.off("afterRender",a),e.$codeLensClickHandler&&e.container.removeEventListener("click",e.$codeLensClickHandler)}var r=e("../line_widgets").LineWidgets,i=e("../lib/event"),s=e("../lib/lang"),o=e("../lib/dom");t.setLenses=function(e,t){var n=Number.MAX_VALUE;return f(e),t&&t.forEach(function(t){var r=t.start.row,i=t.start.column,s=e.lineWidgets&&e.lineWidgets[r];if(!s||!s.lenses)s=e.widgetManager.$registerLineWidget({rowCount:1,rowsAbove:1,row:r,column:i,lenses:[]});s.lenses.push(t.command),r<n&&(n=r)}),e._emit("changeFold",{data:{start:{row:n}}}),n},t.registerCodeLensProvider=function(e,t){e.setOption("enableCodeLens",!0),e.codeLensProviders.push(t),e.$updateLensesOnInput()},t.clear=function(e){t.setLenses(e,null)};var h=e("../editor").Editor;e("../config").defineOptions(h.prototype,"editor",{enableCodeLens:{set:function(e){e?l(this):c(this)}}}),o.importCssString("\n.ace_codeLens {\n position: absolute;\n color: #aaa;\n font-size: 88%;\n background: inherit;\n width: 100%;\n display: flex;\n align-items: flex-end;\n pointer-events: none;\n}\n.ace_codeLens > a {\n cursor: pointer;\n pointer-events: auto;\n}\n.ace_codeLens > a:hover {\n color: #0000ff;\n text-decoration: underline;\n}\n.ace_dark > .ace_codeLens > a:hover {\n color: #4e94ce;\n}\n","codelense.css",!1)}); (function() {
window.require(["ace/ext/code_lens"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},this.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},this.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},this.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},this.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},this.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},this.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},this.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},this.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r}}).call(r.prototype),t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})}); (function() {
window.require(["ace/ext/elastic_tabstops_lite"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
; (function() {
window.require(["ace/ext/error_marker"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/hardwrap",["require","exports","module","ace/range","ace/editor","ace/config"],function(e,t,n){"use strict";function i(e,t){function m(e,t,n){if(e.length<t)return;var r=e.slice(0,t),i=e.slice(t),s=/^(?:(\s+)|(\S+)(\s+))/.exec(i),o=/(?:(\s+)|(\s+)(\S+))$/.exec(r),u=0,a=0;o&&!o[2]&&(u=t-o[1].length,a=t),s&&!s[2]&&(u||(u=t),a=t+s[1].length);if(u)return{start:u,end:a};if(o&&o[2]&&o.index>n)return{start:o.index,end:o.index+o[2].length};if(s&&s[2])return u=t+s[2].length,{start:u,end:u+s[3].length}}var n=t.column||e.getOption("printMarginColumn"),i=t.allowMerge!=0,s=Math.min(t.startRow,t.endRow),o=Math.max(t.startRow,t.endRow),u=e.session;while(s<=o){var a=u.getLine(s);if(a.length>n){var f=m(a,n,5);if(f){var l=/^\s*/.exec(a)[0];u.replace(new r(s,f.start,s,f.end),"\n"+l)}o++}else if(i&&/\S/.test(a)&&s!=o){var c=u.getLine(s+1);if(c&&/\S/.test(c)){var h=a.replace(/\s+$/,""),p=c.replace(/^\s+/,""),d=h+" "+p,f=m(d,n,5);if(f&&f.start>h.length||d.length<n){var v=new r(s,h.length,s+1,c.length-p.length);u.replace(v," "),s--,o--}else h.length<a.length&&u.remove(new r(s,h.length,s,a.length))}}s++}}function s(e){if(e.command.name=="insertstring"&&/\S/.test(e.args)){var t=e.editor,n=t.selection.cursor;if(n.column<=t.renderer.$printMarginColumn)return;var r=t.session.$undoManager.$lastDelta;i(t,{startRow:n.row,endRow:n.row,allowMerge:!1}),r!=t.session.$undoManager.$lastDelta&&t.session.markUndoGroup()}}var r=e("../range").Range,o=e("../editor").Editor;e("../config").defineOptions(o.prototype,"editor",{hardWrap:{set:function(e){e?this.commands.on("afterExec",s):this.commands.off("afterExec",s)},value:!1}}),t.hardWrap=i}); (function() {
window.require(["ace/ext/hardwrap"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/menu_tools/settings_menu.css",["require","exports","module"],function(e,t,n){n.exports="#ace_settingsmenu, #kbshortcutmenu {\n background-color: #F7F7F7;\n color: black;\n box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);\n padding: 1em 0.5em 2em 1em;\n overflow: auto;\n position: absolute;\n margin: 0;\n bottom: 0;\n right: 0;\n top: 0;\n z-index: 9991;\n cursor: default;\n}\n\n.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {\n box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);\n background-color: rgba(255, 255, 255, 0.6);\n color: black;\n}\n\n.ace_optionsMenuEntry:hover {\n background-color: rgba(100, 100, 100, 0.1);\n transition: all 0.3s\n}\n\n.ace_closeButton {\n background: rgba(245, 146, 146, 0.5);\n border: 1px solid #F48A8A;\n border-radius: 50%;\n padding: 7px;\n position: absolute;\n right: -8px;\n top: -8px;\n z-index: 100000;\n}\n.ace_closeButton{\n background: rgba(245, 146, 146, 0.9);\n}\n.ace_optionsMenuKey {\n color: darkslateblue;\n font-weight: bold;\n}\n.ace_optionsMenuCommand {\n color: darkcyan;\n font-weight: normal;\n}\n.ace_optionsMenuEntry input, .ace_optionsMenuEntry button {\n vertical-align: middle;\n}\n\n.ace_optionsMenuEntry button[ace_selected_button=true] {\n background: #e7e7e7;\n box-shadow: 1px 0px 2px 0px #adadad inset;\n border-color: #adadad;\n}\n.ace_optionsMenuEntry button {\n background: white;\n border: 1px solid lightgray;\n margin: 0px;\n}\n.ace_optionsMenuEntry button:hover{\n background: #f0f0f0;\n}"}),define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom","ace/ext/menu_tools/settings_menu.css"],function(e,t,n){"use strict";var r=e("../../lib/dom"),i=e("./settings_menu.css");r.importCssString(i,"settings_menu.css",!1),n.exports.overlayPage=function(t,n,r){function o(e){e.keyCode===27&&u()}function u(){if(!i)return;document.removeEventListener("keydown",o),i.parentNode.removeChild(i),t&&t.focus(),i=null,r&&r()}function a(e){s=e,e&&(i.style.pointerEvents="none",n.style.pointerEvents="auto")}var i=document.createElement("div"),s=!1;return i.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; "+(t?"background-color: rgba(0, 0, 0, 0.3);":""),i.addEventListener("click",function(e){s||u()}),document.addEventListener("keydown",o),n.addEventListener("click",function(e){e.stopPropagation()}),i.appendChild(n),document.body.appendChild(i),t&&t.blur(),{close:u,setIgnoreFocusOut:a}}}),define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../../lib/keys");n.exports.getEditorKeybordShortcuts=function(e){var t=r.KEY_MODS,n=[],i={};return e.keyBinding.$handlers.forEach(function(e){var t=e.commandKeyBinding;for(var r in t){var s=r.replace(/(^|-)\w/g,function(e){return e.toUpperCase()}),o=t[r];Array.isArray(o)||(o=[o]),o.forEach(function(e){typeof e!="string"&&(e=e.name),i[e]?i[e].key+="|"+s:(i[e]={key:s,command:e},n.push(i[e]))})}}),n}}),define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"],function(e,t,n){"use strict";function i(t){if(!document.getElementById("kbshortcutmenu")){var n=e("./menu_tools/overlay_page").overlayPage,r=e("./menu_tools/get_editor_keyboard_shortcuts").getEditorKeybordShortcuts,i=r(t),s=document.createElement("div"),o=i.reduce(function(e,t){return e+'<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'+t.command+"</span> : "+'<span class="ace_optionsMenuKey">'+t.key+"</span></div>"},"");s.id="kbshortcutmenu",s.innerHTML="<h1>Keyboard Shortcuts</h1>"+o+"</div>",n(t,s)}}var r=e("../editor").Editor;n.exports.init=function(e){r.prototype.showKeyboardShortcuts=function(){i(this)},e.commands.addCommands([{name:"showKeyboardShortcuts",bindKey:{win:"Ctrl-Alt-h",mac:"Command-Alt-h"},exec:function(e,t){e.showKeyboardShortcuts()}}])}}); (function() {
window.require(["ace/ext/keybinding_menu"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var n=e.editor,r=e.getAccelKey();if(r){var n=e.editor,i=e.getDocumentPosition(),s=n.session,o=s.getTokenAt(i.row,i.column);t.previousLinkingHover&&t.previousLinkingHover!=o&&n._emit("linkHoverOut"),n._emit("linkHover",{position:i,token:o}),t.previousLinkingHover=o}else t.previousLinkingHover&&(n._emit("linkHoverOut"),t.previousLinkingHover=!1)}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("../editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}}),t.previousLinkingHover=!1}); (function() {
window.require(["ace/ext/linking"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;var r;/\^/.test(n)?r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$":r="^.*\\.("+n+")$",this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ABC:["abc"],ActionScript:["as"],ADA:["ada|adb"],Alda:["alda"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],Apex:["apex|cls|trigger|tgr"],AQL:["aql"],AsciiDoc:["asciidoc|adoc"],ASL:["dsl|asl|asl.json"],Assembly_x86:["asm|a"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],BibTeX:["bib"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp|ino"],C9Search:["c9search_results"],Cirru:["cirru|cr"],Clojure:["clj|cljs"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],Crystal:["cr"],CSharp:["cs"],Csound_Document:["csd"],Csound_Orchestra:["orc"],Csound_Score:["sco"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Drools:["drl"],Edifact:["edi"],Eiffel:["e|ge"],EJS:["ejs"],Elixir:["ex|exs"],Elm:["elm"],Erlang:["erl|hrl"],Forth:["frt|fs|ldr|fth|4th"],Fortran:["f|f90"],FSharp:["fsi|fs|ml|mli|fsx|fsscript"],FSL:["fsl"],FTL:["ftl"],Gcode:["gcode"],Gherkin:["feature"],Gitignore:["^.gitignore"],Glsl:["glsl|frag|vert"],Gobstones:["gbs"],golang:["go"],GraphQLSchema:["gql"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],Haskell_Cabal:["cabal"],haXe:["hx"],Hjson:["hjson"],HTML:["html|htm|xhtml|vue|we|wpy"],HTML_Elixir:["eex|html.eex"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Io:["io"],Ion:["ion"],Jack:["jack"],Jade:["jade|pug"],Java:["java"],JavaScript:["js|jsm|jsx|cjs|mjs"],JEXL:["jexl"],JSON:["json"],JSON5:["json5"],JSONiq:["jq"],JSP:["jsp"],JSSM:["jssm|jssm_state"],JSX:["jsx"],Julia:["jl"],Kotlin:["kt|kts"],LaTeX:["tex|latex|ltx|bib"],Latte:["latte"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],Log:["log"],LogiQL:["logic|lql"],Logtalk:["lgt"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],Markdown:["md|markdown"],Mask:["mask"],MATLAB:["matlab"],Maze:["mz"],MediaWiki:["wiki|mediawiki"],MEL:["mel"],MIPS:["s|asm"],MIXAL:["mixal"],MUSHCode:["mc|mush"],MySQL:["mysql"],Nginx:["nginx|conf"],Nim:["nim"],Nix:["nix"],NSIS:["nsi|nsh"],Nunjucks:["nunjucks|nunjs|nj|njk"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],PartiQL:["partiql|pql"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],PHP_Laravel_blade:["blade.php"],Pig:["pig"],PLSQL:["plsql"],Powershell:["ps1"],Praat:["praat|praatscript|psc|proc"],Prisma:["prisma"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Puppet:["epp|pp"],Python:["py"],QML:["qml"],R:["r"],Raku:["raku|rakumod|rakutest|p6|pl6|pm6"],Razor:["cshtml|asp"],RDoc:["Rd"],Red:["red|reds"],RHTML:["Rhtml"],Robot:["robot|resource"],RST:["rst"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SaC:["sac"],SASS:["sass"],SCAD:["scad"],Scala:["scala|sbt"],Scheme:["scm|sm|rkt|oak|scheme"],Scrypt:["scrypt"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Slim:["slim|skim"],Smarty:["smarty|tpl"],Smithy:["smithy"],snippets:["snippets"],Soy_Template:["soy"],Space:["space"],SPARQL:["rq"],SQL:["sql"],SQLServer:["sqlserver"],Stylus:["styl|stylus"],SVG:["svg"],Swift:["swift"],Tcl:["tcl"],Terraform:["tf","tfvars","terragrunt"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],TSX:["tsx"],Turtle:["ttl"],Twig:["twig|swig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs|vb"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],VHDL:["vhd|vhdl"],Visualforce:["vfp|component|page"],Wollok:["wlk|wpgm|wtest"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],XQuery:["xq"],YAML:["yaml|yml"],Zeek:["zeek|bro"],Django:["html"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C and C++",Csound_Document:"Csound Document",Csound_Orchestra:"Csound",Csound_Score:"Csound Score",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",HTML_Elixir:"HTML (Elixir)",FTL:"FreeMarker",PHP_Laravel_blade:"PHP (Blade Template)",Perl6:"Perl 6",AutoHotKey:"AutoHotkey / AutoIt"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}}); (function() {
window.require(["ace/ext/modelist"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/ext/rtl",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";function s(e,t){var n=t.getSelection().lead;t.session.$bidiHandler.isRtlLine(n.row)&&n.column===0&&(t.session.$bidiHandler.isMoveLeftOperation&&n.row>0?t.getSelection().moveCursorTo(n.row-1,t.session.getLine(n.row-1).length):t.getSelection().isEmpty()?n.column+=1:n.setPosition(n.row,n.column+1))}function o(e){e.editor.session.$bidiHandler.isMoveLeftOperation=/gotoleft|selectleft|backspace|removewordleft/.test(e.command.name)}function u(e,t){var n=t.session;n.$bidiHandler.currentRow=null;if(n.$bidiHandler.isRtlLine(e.start.row)&&e.action==="insert"&&e.lines.length>1)for(var r=e.start.row;r<e.end.row;r++)n.getLine(r+1).charAt(0)!==n.$bidiHandler.RLE&&(n.doc.$lines[r+1]=n.$bidiHandler.RLE+n.getLine(r+1))}function a(e,t){var n=t.session,r=n.$bidiHandler,i=t.$textLayer.$lines.cells,s=t.layerConfig.width-t.layerConfig.padding+"px";i.forEach(function(e){var t=e.element.style;r&&r.isRtlLine(e.row)?(t.direction="rtl",t.textAlign="right",t.width=s):(t.direction="",t.textAlign="",t.width="")})}function f(e){function n(e){var t=e.element.style;t.direction=t.textAlign=t.width=""}var t=e.$textLayer.$lines;t.cells.forEach(n),t.cellCache.forEach(n)}var r=[{name:"leftToRight",bindKey:{win:"Ctrl-Alt-Shift-L",mac:"Command-Alt-Shift-L"},exec:function(e){e.session.$bidiHandler.setRtlDirection(e,!1)},readOnly:!0},{name:"rightToLeft",bindKey:{win:"Ctrl-Alt-Shift-R",mac:"Command-Alt-Shift-R"},exec:function(e){e.session.$bidiHandler.setRtlDirection(e,!0)},readOnly:!0}],i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{rtlText:{set:function(e){e?(this.on("change",u),this.on("changeSelection",s),this.renderer.on("afterRender",a),this.commands.on("exec",o),this.commands.addCommands(r)):(this.off("change",u),this.off("changeSelection",s),this.renderer.off("afterRender",a),this.commands.off("exec",o),this.commands.removeCommands(r),f(this.renderer)),this.renderer.updateFull()}},rtl:{set:function(e){this.session.$bidiHandler.$isRtl=e,e?(this.setOption("rtlText",!1),this.renderer.on("afterRender",a),this.session.$bidiHandler.seenBidi=!0):(this.renderer.off("afterRender",a),f(this.renderer)),this.renderer.updateFull()}}})}); (function() {
window.require(["ace/ext/rtl"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event");t.contextMenuHandler=function(e){var t=e.target,n=t.textInput.getElement();if(!t.selection.isEmpty())return;var i=t.getCursorPosition(),s=t.session.getWordRange(i.row,i.column),o=t.session.getTextRange(s);t.session.tokenRe.lastIndex=0;if(!t.session.tokenRe.test(o))return;var u="\x01\x01",a=o+" "+u;n.value=a,n.setSelectionRange(o.length,o.length+1),n.setSelectionRange(0,0),n.setSelectionRange(0,o.length);var f=!1;r.addListener(n,"keydown",function l(){r.removeListener(n,"keydown",l),f=!0}),t.textInput.setInputHandler(function(e){if(e==a)return"";if(e.lastIndexOf(a,0)===0)return e.slice(a.length);if(e.substr(n.selectionEnd)==a)return e.slice(0,-a.length);if(e.slice(-2)==u){var r=e.slice(0,-2);if(r.slice(-1)==" ")return f?r.substring(0,n.selectionEnd):(r=r.slice(0,-1),t.session.replace(s,r),"")}return e})};var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{spellcheck:{set:function(e){var n=this.textInput.getElement();n.spellcheck=!!e,e?this.on("nativecontextmenu",t.contextMenuHandler):this.removeListener("nativecontextmenu",t.contextMenuHandler)},value:!0}})}); (function() {
window.require(["ace/ext/spellcheck"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./editor").Editor,u=e("./virtual_renderer").VirtualRenderer,a=e("./edit_session").EditSession,f=function(e,t,n){this.BELOW=1,this.BESIDE=0,this.$container=e,this.$theme=t,this.$splits=0,this.$editorCSS="",this.$editors=[],this.$orientation=this.BESIDE,this.setSplits(n||1),this.$cEditor=this.$editors[0],this.on("focus",function(e){this.$cEditor=e}.bind(this))};(function(){r.implement(this,s),this.$createEditor=function(){var e=document.createElement("div");e.className=this.$editorCSS,e.style.cssText="position: absolute; top:0px; bottom:0px",this.$container.appendChild(e);var t=new o(new u(e,this.$theme));return t.on("focus",function(){this._emit("focus",t)}.bind(this)),this.$editors.push(t),t.setFontSize(this.$fontSize),t},this.setSplits=function(e){var t;if(e<1)throw"The number of splits have to be > 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splits<this.$editors.length&&this.$splits<e)t=this.$editors[this.$splits],this.$container.appendChild(t.container),t.setFontSize(this.$fontSize),this.$splits++;while(this.$splits<e)this.$createEditor(),this.$splits++}else while(this.$splits>e)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();return t.setUndoManager(n),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=r+"px",n.container.style.top="0px",n.container.style.left=i*r+"px",n.container.style.height=t+"px",n.resize()}else{var s=t/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=e+"px",n.container.style.top=i*s+"px",n.container.style.left="0px",n.container.style.height=s+"px",n.resize()}}}).call(f.prototype),t.Split=f}),define("ace/ext/split",["require","exports","module","ace/split"],function(e,t,n){"use strict";n.exports=e("../split")}); (function() {
window.require(["ace/ext/split"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/static.css",["require","exports","module"],function(e,t,n){n.exports=".ace_static_highlight {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;\n font-size: 12px;\n white-space: pre-wrap\n}\n\n.ace_static_highlight .ace_gutter {\n width: 2em;\n text-align: right;\n padding: 0 3px 0 0;\n margin-right: 3px;\n contain: none;\n}\n\n.ace_static_highlight.ace_show_gutter .ace_line {\n padding-left: 2.6em;\n}\n\n.ace_static_highlight .ace_line { position: relative; }\n\n.ace_static_highlight .ace_gutter-cell {\n -moz-user-select: -moz-none;\n -khtml-user-select: none;\n -webkit-user-select: none;\n user-select: none;\n top: 0;\n bottom: 0;\n left: 0;\n position: absolute;\n}\n\n\n.ace_static_highlight .ace_gutter-cell:before {\n content: counter(ace_line, decimal);\n counter-increment: ace_line;\n}\n.ace_static_highlight {\n counter-reset: ace_line;\n}\n"}),define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text","ace/ext/static.css","ace/config","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";function f(e){this.type=e,this.style={},this.textContent=""}var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=e("./static.css"),o=e("../config"),u=e("../lib/dom"),a=e("../lib/lang").escapeHTML;f.prototype.cloneNode=function(){return this},f.prototype.appendChild=function(e){this.textContent+=e.toString()},f.prototype.toString=function(){var e=[];if(this.type!="fragment"){e.push("<",this.type),this.className&&e.push(" class='",this.className,"'");var t=[];for(var n in this.style)t.push(n,":",this.style[n]);t.length&&e.push(" style='",t.join(""),"'"),e.push(">")}return this.textContent&&e.push(this.textContent),this.type!="fragment"&&e.push("</",this.type,">"),e.join("")};var l={createTextNode:function(e,t){return a(e)},createElement:function(e){return new f(e)},createFragment:function(){return new f("fragment")}},c=function(){this.config={},this.dom=l};c.prototype=i.prototype;var h=function(e,t,n){var r=e.className.match(/lang-(\w+)/),i=t.mode||r&&"ace/mode/"+r[1];if(!i)return!1;var s=t.theme||"ace/theme/textmate",o="",a=[];if(e.firstElementChild){var f=0;for(var l=0;l<e.childNodes.length;l++){var c=e.childNodes[l];c.nodeType==3?(f+=c.data.length,o+=c.data):a.push(f,c)}}else o=e.textContent,t.trim&&(o=o.trim());h.render(o,i,s,t.firstLineNumber,!t.showGutter,function(t){u.importCssString(t.css,"ace_highlight"),e.innerHTML=t.html;var r=e.firstChild.firstChild;for(var i=0;i<a.length;i+=2){var s=t.session.doc.indexToPosition(a[i]),o=a[i+1],f=r.children[s.row];f&&f.appendChild(o)}n&&n()})};h.render=function(e,t,n,i,s,u){function c(){var r=h.renderSync(e,t,n,i,s);return u?u(r):r}var a=1,f=r.prototype.$modes;typeof n=="string"&&(a++,o.loadModule(["theme",n],function(e){n=e,--a||c()}));var l;return t&&typeof t=="object"&&!t.getTokenizer&&(l=t,t=l.path),typeof t=="string"&&(a++,o.loadModule(["mode",t],function(e){if(!f[t]||l)f[t]=new e.Mode(l);t=f[t],--a||c()})),--a||c()},h.renderSync=function(e,t,n,i,o){i=parseInt(i||1,10);var u=new r("");u.setUseWorker(!1),u.setMode(t);var a=new c;a.setSession(u),Object.keys(a.$tabStrings).forEach(function(e){if(typeof a.$tabStrings[e]=="string"){var t=l.createFragment();t.textContent=a.$tabStrings[e],a.$tabStrings[e]=t}}),u.setValue(e);var f=u.getLength(),h=l.createElement("div");h.className=n.cssClass;var p=l.createElement("div");p.className="ace_static_highlight"+(o?"":" ace_show_gutter"),p.style["counter-reset"]="ace_line "+(i-1);for(var d=0;d<f;d++){var v=l.createElement("div");v.className="ace_line";if(!o){var m=l.createElement("span");m.className="ace_gutter ace_gutter-cell",m.textContent="",v.appendChild(m)}a.$renderLine(v,d,!1),v.textContent+="\n",p.appendChild(v)}return h.appendChild(p),{css:s+n.cssText,html:h.toString(),session:u}},n.exports=h,n.exports.highlight=h}); (function() {
window.require(["ace/ext/static_highlight"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/lang"),s=function(e,t){this.element=r.createElement("div"),this.element.className="ace_status-indicator",this.element.style.cssText="display: inline-block;",t.appendChild(this.element);var n=i.delayedCall(function(){this.updateStatus(e)}.bind(this)).schedule.bind(null,100);e.on("changeStatus",n),e.on("changeSelection",n),e.on("keyboardActivity",n)};(function(){this.updateStatus=function(e){function n(e,n){e&&t.push(e,n||"|")}var t=[];n(e.keyBinding.getStatusText(e)),e.commands.recording&&n("REC");var r=e.selection,i=r.lead;if(!r.isEmpty()){var s=e.getSelectionRange();n("("+(s.end.row-s.start.row)+":"+(s.end.column-s.start.column)+")"," ")}n(i.row+":"+i.column," "),r.rangeCount&&n("["+r.rangeCount+"]"," "),t.pop(),this.element.textContent=t.join("")}}).call(s.prototype),t.StatusBar=s}); (function() {
window.require(["ace/ext/statusbar"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/ext/themelist",["require","exports","module"],function(e,t,n){"use strict";var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["IPlastic"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["SQL Server","sqlserver","light"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Dracula","","dark"],["Cobalt","cobalt","dark"],["Gruvbox","gruvbox","dark"],["Green on Black","gob","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Nord Dark","nord_dark","dark"],["One Dark","one_dark","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})}); (function() {
window.require(["ace/ext/themelist"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang");t.$detectIndentation=function(e,t){function c(e){var t=0;for(var r=e;r<n.length;r+=e)t+=n[r]||0;return t}var n=[],r=[],i=0,s=0,o=Math.min(e.length,1e3);for(var u=0;u<o;u++){var a=e[u];if(!/^\s*[^*+\-\s]/.test(a))continue;if(a[0]==" ")i++,s=-Number.MAX_VALUE;else{var f=a.match(/^ */)[0].length;if(f&&a[f]!=" "){var l=f-s;l>0&&!(s%l)&&!(f%l)&&(r[l]=(r[l]||0)+1),n[f]=(n[f]||0)+1}s=f}while(u<o&&a[a.length-1]=="\\")a=e[u++]}var h=r.reduce(function(e,t){return e+t},0),p={score:0,length:0},d=0;for(var u=1;u<12;u++){var v=c(u);u==1?(d=v,v=n[1]?.9:.8,n.length||(v=0)):v/=d,r[u]&&(v+=r[u]/h),v>p.score&&(p={score:v,length:u})}if(p.score&&p.score>1.4)var m=p.length;if(i>d+1){if(m==1||d<i/4||p.score<1.8)m=undefined;return{ch:" ",length:m}}if(d>i+1)return{ch:" ",length:m}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t&&t.trimEmpty?-1:0,s=[],o=-1;t&&t.keepCursorPosition&&(e.selection.rangeCount?e.selection.rangeList.ranges.forEach(function(e,t,n){var r=n[t+1];if(r&&r.cursor.row==e.cursor.row)return;s.push(e.cursor)}):s.push(e.selection.getCursor()),o=0);var u=s[o]&&s[o].row;for(var a=0,f=r.length;a<f;a++){var l=r[a],c=l.search(/\s+$/);a==u&&(c<s[o].column&&c>i&&(c=s[o].column),o++,u=s[o]?s[o].row:-1),c>i&&n.removeInLine(a,c,l.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t==" "?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c<h;c++){var p=a[c],d=p.match(/^\s*/)[0];if(d){var v=e.$getStringScreenWidth(d)[0],m=Math.floor(v/s),g=v%s,y=f[m]||(f[m]=r.stringRepeat(o,m));y+=l[g]||(l[g]=r.stringRepeat(" ",g)),y!=d&&(u.removeInLine(c,0,d.length),u.insertInLine({row:c,column:0},y))}}e.setTabSize(n),e.setUseSoftTabs(t==" ")},t.$parseStringArg=function(e){var t={};/t/.test(e)?t.ch=" ":/s/.test(e)&&(t.ch=" ");var n=e.match(/\d+/);return n&&(t.length=parseInt(n[0],10)),t},t.$parseArg=function(e){return e?typeof e=="string"?t.$parseStringArg(e):typeof e.text=="string"?t.$parseStringArg(e.text):e:{}},t.commands=[{name:"detectIndentation",description:"Detect indentation from content",exec:function(e){t.detectIndentation(e.session)}},{name:"trimTrailingSpace",description:"Trim trailing whitespace",exec:function(e,n){t.trimTrailingSpace(e.session,n)}},{name:"convertIndentation",description:"Convert indentation to ...",exec:function(e,n){var r=t.$parseArg(n);t.convertIndentation(e.session,r.ch,r.length)}},{name:"setIndentation",description:"Set indentation",exec:function(e,n){var r=t.$parseArg(n);r.length&&e.session.setTabSize(r.length),r.ch&&e.session.setUseSoftTabs(r.ch==" ")}}]}); (function() {
window.require(["ace/ext/whitespace"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/abc_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:["zupfnoter.information.comment.line.percentage","information.keyword","in formation.keyword.embedded"],regex:"(%%%%)(hn\\.[a-z]*)(.*)",comment:"Instruction Comment"},{token:["information.comment.line.percentage","information.keyword.embedded"],regex:"(%%)(.*)",comment:"Instruction Comment"},{token:"comment.line.percentage",regex:"%.*",comment:"Comments"},{token:"barline.keyword.operator",regex:"[\\[:]*[|:][|\\]:]*(?:\\[?[0-9]+)?|\\[[0-9]+",comment:"Bar lines"},{token:["information.keyword.embedded","information.argument.string.unquoted"],regex:"(\\[[A-Za-z]:)([^\\]]*\\])",comment:"embedded Header lines"},{token:["information.keyword","information.argument.string.unquoted"],regex:"^([A-Za-z]:)([^%\\\\]*)",comment:"Header lines"},{token:["text","entity.name.function","string.unquoted","text"],regex:"(\\[)([A-Z]:)(.*?)(\\])",comment:"Inline fields"},{token:["accent.constant.language","pitch.constant.numeric","duration.constant.numeric"],regex:"([\\^=_]*)([A-Ga-gz][,']*)([0-9]*/*[><0-9]*)",comment:"Notes"},{token:"zupfnoter.jumptarget.string.quoted",regex:'[\\"!]\\^\\:.*?[\\"!]',comment:"Zupfnoter jumptarget"},{token:"zupfnoter.goto.string.quoted",regex:'[\\"!]\\^\\@.*?[\\"!]',comment:"Zupfnoter goto"},{token:"zupfnoter.annotation.string.quoted",regex:'[\\"!]\\^\\!.*?[\\"!]',comment:"Zupfnoter annoation"},{token:"zupfnoter.annotationref.string.quoted",regex:'[\\"!]\\^\\#.*?[\\"!]',comment:"Zupfnoter annotation reference"},{token:"chordname.string.quoted",regex:'[\\"!]\\^.*?[\\"!]',comment:"abc chord"},{token:"string.quoted",regex:'[\\"!].*?[\\"!]',comment:"abc annotation"}]},this.normalizeRules()};s.metaData={fileTypes:["abc"],name:"ABC",scopeName:"text.abcnotation"},r.inherits(s,i),t.ABCHighlightRules=s}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/abc",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/abc_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./abc_highlight_rules").ABCHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="%",this.$id="ace/mode/abc",this.snippetFileId="ace/snippets/abc"}.call(u.prototype),t.Mode=u}); (function() {
window.require(["ace/mode/abc"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/ada_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="abort|else|new|return|abs|elsif|not|reverse|abstract|end|null|accept|entry|select|access|exception|of|separate|aliased|exit|or|some|all|others|subtype|and|for|out|synchronized|array|function|overriding|at|tagged|generic|package|task|begin|goto|pragma|terminate|body|private|then|if|procedure|type|case|in|protected|constant|interface|until||is|raise|use|declare|range|delay|limited|record|when|delta|loop|rem|while|digits|renames|with|do|mod|requeue|xor",t="true|false|null",n="count|min|max|avg|sum|rank|now|coalesce|main",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]}};r.inherits(s,i),t.AdaHighlightRules=s}),define("ace/mode/ada",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/ada_highlight_rules","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./ada_highlight_rules").AdaHighlightRules,o=e("../range").Range,u=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="--",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*(begin|loop|then|is|do)\s*$/);o&&(r+=n)}return r},this.checkOutdent=function(e,t,n){var r=t+n;return r.match(/^\s*(begin|end)$/)?!0:!1},this.autoOutdent=function(e,t,n){var r=t.getLine(n),i=t.getLine(n-1),s=this.$getIndent(i).length,u=this.$getIndent(r).length;if(u<=s)return;t.outdentRows(new o(n,0,n+2,0))},this.$id="ace/mode/ada"}.call(u.prototype),t.Mode=u}); (function() {
window.require(["ace/mode/ada"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/aql_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="for|return|filter|search|sort|limit|let|collect|asc|desc|in|into|insert|update|remove|replace|upsert|options|with|and|or|not|distinct|graph|shortest_path|outbound|inbound|any|all|none|at least|aggregate|like|k_shortest_paths|k_paths|all_shortest_paths|prune|window",t="true|false",n="to_bool|to_number|to_string|to_array|to_list|is_null|is_bool|is_number|is_string|is_array|is_list|is_object|is_document|is_datestring|typename|json_stringify|json_parse|concat|concat_separator|char_length|lower|upper|substring|left|right|trim|reverse|contains|log|log2|log10|exp|exp2|sin|cos|tan|asin|acos|atan|atan2|radians|degrees|pi|regex_test|regex_replace|like|floor|ceil|round|abs|rand|sqrt|pow|length|count|min|max|average|avg|sum|product|median|variance_population|variance_sample|variance|percentile|bit_and|bit_or|bit_xor|bit_negate|bit_test|bit_popcount|bit_shift_left|bit_shift_right|bit_construct|bit_deconstruct|bit_to_string|bit_from_string|first|last|unique|outersection|interleave|in_range|jaccard|matches|merge|merge_recursive|has|attributes|keys|values|unset|unset_recursive|keep|keep_recursive|near|within|within_rectangle|is_in_polygon|distance|fulltext|stddev_sample|stddev_population|stddev|slice|nth|position|contains_array|translate|zip|call|apply|push|append|pop|shift|unshift|remove_value|remove_values|remove_nth|replace_nth|date_now|date_timestamp|date_iso8601|date_dayofweek|date_year|date_month|date_day|date_hour|date_minute|date_second|date_millisecond|date_dayofyear|date_isoweek|date_isoweekyear|date_leapyear|date_quarter|date_days_in_month|date_trunc|date_round|date_add|date_subtract|date_diff|date_compare|date_format|date_utctolocal|date_localtoutc|date_timezone|date_timezones|fail|passthru|v8|sleep|schema_get|schema_validate|shard_id|call_greenspun|version|noopt|noeval|not_null|first_list|first_document|parse_identifier|current_user|current_database|collection_count|pregel_result|collections|document|decode_rev|range|union|union_distinct|minus|intersection|flatten|is_same_collection|check_document|ltrim|rtrim|find_first|find_last|split|substitute|ipv4_to_number|ipv4_from_number|is_ipv4|md5|sha1|sha512|crc32|fnv64|hash|random_token|to_base64|to_hex|encode_uri_component|soundex|assert|warn|is_key|sorted|sorted_unique|count_distinct|count_unique|levenshtein_distance|levenshtein_match|regex_matches|regex_split|ngram_match|ngram_similarity|ngram_positional_similarity|uuid|tokens|exists|starts_with|phrase|min_match|bm25|tfidf|boost|analyzer|cosine_similarity|decay_exp|decay_gauss|decay_linear|l1_distance|l2_distance|minhash|minhash_count|minhash_error|minhash_match|geo_point|geo_multipoint|geo_polygon|geo_multipolygon|geo_linestring|geo_multilinestring|geo_contains|geo_intersects|geo_equals|geo_distance|geo_area|geo_in_range",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"//.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]},this.normalizeRules()};r.inherits(s,i),t.AqlHighlightRules=s}),define("ace/mode/aql",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/aql_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./aql_highlight_rules").AqlHighlightRules,o=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(o,i),function(){this.lineCommentStart="//",this.$id="ace/mode/aql"}.call(o.prototype),t.Mode=o}); (function() {
window.require(["ace/mode/aql"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/batchfile_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"keyword.command.dosbatch",regex:"\\b(?:append|assoc|at|attrib|break|cacls|cd|chcp|chdir|chkdsk|chkntfs|cls|cmd|color|comp|compact|convert|copy|date|del|dir|diskcomp|diskcopy|doskey|echo|endlocal|erase|fc|find|findstr|format|ftype|graftabl|help|keyb|label|md|mkdir|mode|more|move|path|pause|popd|print|prompt|pushd|rd|recover|ren|rename|replace|restore|rmdir|set|setlocal|shift|sort|start|subst|time|title|tree|type|ver|verify|vol|xcopy)\\b",caseInsensitive:!0},{token:"keyword.control.statement.dosbatch",regex:"\\b(?:goto|call|exit)\\b",caseInsensitive:!0},{token:"keyword.control.conditional.if.dosbatch",regex:"\\bif\\s+not\\s+(?:exist|defined|errorlevel|cmdextversion)\\b",caseInsensitive:!0},{token:"keyword.control.conditional.dosbatch",regex:"\\b(?:if|else)\\b",caseInsensitive:!0},{token:"keyword.control.repeat.dosbatch",regex:"\\bfor\\b",caseInsensitive:!0},{token:"keyword.operator.dosbatch",regex:"\\b(?:EQU|NEQ|LSS|LEQ|GTR|GEQ)\\b"},{token:["doc.comment","comment"],regex:"(?:^|\\b)(rem)($|\\s.*$)",caseInsensitive:!0},{token:"comment.line.colons.dosbatch",regex:"::.*$"},{include:"variable"},{token:"punctuation.definition.string.begin.shell",regex:'"',push:[{token:"punctuation.definition.string.end.shell",regex:'"',next:"pop"},{include:"variable"},{defaultToken:"string.quoted.double.dosbatch"}]},{token:"keyword.operator.pipe.dosbatch",regex:"[|]"},{token:"keyword.operator.redirect.shell",regex:"&>|\\d*>&\\d*|\\d*(?:>>|>|<)|\\d*<&|\\d*<>"}],variable:[{token:"constant.numeric",regex:"%%\\w+|%[*\\d]|%\\w+%"},{token:"constant.numeric",regex:"%~\\d+"},{token:["markup.list","constant.other","markup.list"],regex:"(%)(\\w+)(%?)"}]},this.normalizeRules()};s.metaData={name:"Batch File",scopeName:"source.dosbatch",fileTypes:["bat"]},r.inherits(s,i),t.BatchFileHighlightRules=s}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/batchfile",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/batchfile_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./batchfile_highlight_rules").BatchFileHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="::",this.blockComment="",this.$id="ace/mode/batchfile"}.call(u.prototype),t.Mode=u}); (function() {
window.require(["ace/mode/batchfile"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/mode/bibtex_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:/@Comment\{/,stateName:"bibtexComment",push:[{token:"comment",regex:/}/,next:"pop"},{token:"comment",regex:/\{/,push:"bibtexComment"},{defaultToken:"comment"}]},{token:["keyword","text","paren.lparen","text","variable","text","keyword.operator"],regex:/(@String)(\s*)(\{)(\s*)([a-zA-Z]*)(\s*)(=)/,push:[{token:"paren.rparen",regex:/\}/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen","text","variable","text","keyword.operator"],regex:/(@String)(\s*)(\()(\s*)([a-zA-Z]*)(\s*)(=)/,push:[{token:"paren.rparen",regex:/\)/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen"],regex:/(@preamble)(\s*)(\()/,push:[{token:"paren.rparen",regex:/\)/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen"],regex:/(@preamble)(\s*)(\{)/,push:[{token:"paren.rparen",regex:/\}/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen","text","support.class"],regex:/(@[a-zA-Z]+)(\s*)(\{)(\s*)([\w-]+)/,push:[{token:"paren.rparen",regex:/\}/,next:"pop"},{token:["variable","text","keyword.operator"],regex:/([a-zA-Z0-9\!\$\&\*\+\-\.\/\:\;\<\>\?\[\]\^\_\`\|]+)(\s*)(=)/,push:[{token:"text",regex:/(?=[,}])/,next:"pop"},{include:"#misc"},{include:"#integer"},{defaultToken:"text"}]},{token:"punctuation",regex:/,/},{defaultToken:"text"}]},{defaultToken:"comment"}],"#integer":[{token:"constant.numeric.bibtex",regex:/\d+/}],"#misc":[{token:"string",regex:/"/,push:"#string_quotes"},{token:"paren.lparen",regex:/\{/,push:"#string_braces"},{token:"keyword.operator",regex:/#/}],"#string_braces":[{token:"paren.rparen",regex:/\}/,next:"pop"},{token:"invalid.illegal",regex:/@/},{include:"#misc"},{defaultToken:"string"}],"#string_quotes":[{token:"string",regex:/"/,next:"pop"},{include:"#misc"},{defaultToken:"string"}]},this.normalizeRules()};r.inherits(s,i),t.BibTeXHighlightRules=s}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/bibtex",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/bibtex_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./bibtex_highlight_rules").BibTeXHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o};r.inherits(u,i),function(){this.$id="ace/mode/bibtex"}.call(u.prototype),t.Mode=u}); (function() {
window.require(["ace/mode/bibtex"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
@@ -0,0 +1,7 @@
define("ace/mode/c9search_highlight_rules",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";function o(e,t){try{return new RegExp(e,t)}catch(n){}}var r=e("../lib/oop"),i=e("../lib/lang"),s=e("./text_highlight_rules").TextHighlightRules,u=function(){this.$rules={start:[{tokenNames:["c9searchresults.constant.numeric","c9searchresults.text","c9searchresults.text","c9searchresults.keyword"],regex:/(^\s+[0-9]+)(:)(\d*\s?)([^\r\n]+)/,onMatch:function(e,t,n){var r=this.splitRegex.exec(e),i=this.tokenNames,s=[{type:i[0],value:r[1]},{type:i[1],value:r[2]}];r[3]&&(r[3]==" "?s[1]={type:i[1],value:r[2]+" "}:s.push({type:i[1],value:r[3]}));var o=n[1],u=r[4],a,f=0;if(o&&o.exec){o.lastIndex=0;while(a=o.exec(u)){var l=u.substring(f,a.index);f=o.lastIndex,l&&s.push({type:i[2],value:l});if(a[0])s.push({type:i[3],value:a[0]});else if(!l)break}}return f<u.length&&s.push({type:i[2],value:u.substr(f)}),s}},{regex:"^Searching for [^\\r\\n]*$",onMatch:function(e,t,n){var r=e.split("\x01");if(r.length<3)return"text";var s,u,a=0,f=[{value:r[a++]+"'",type:"text"},{value:u=r[a++],type:"text"},{value:"'"+r[a++],type:"text"}];r[2]!==" in"&&f.push({value:"'"+r[a++]+"'",type:"text"},{value:r[a++],type:"text"}),f.push({value:" "+r[a++]+" ",type:"text"}),r[a+1]?(s=r[a+1],f.push({value:"("+r[a+1]+")",type:"text"}),a+=1):a-=1;while(a++<r.length)r[a]&&f.push({value:r[a],type:"text"});u&&(/regex/.test(s)||(u=i.escapeRegExp(u)),/whole/.test(s)&&(u="\\b"+u+"\\b"));var l=u&&o("("+u+")",/ sensitive/.test(s)?"g":"ig");return l&&(n[0]=t,n[1]=l),f}},{regex:"^(?=Found \\d+ matches)",token:"text",next:"numbers"},{token:"string",regex:"^\\S:?[^:]+",next:"numbers"}],numbers:[{regex:"\\d+",token:"constant.numeric"},{regex:"$",token:"text",next:"start"}]},this.normalizeRules()};r.inherits(u,s),t.C9SearchHighlightRules=u}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/folding/c9search",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/^(\S.*:|Searching for.*)$/,this.foldingStopMarker=/^(\s+|Found.*)$/,this.getFoldWidgetRange=function(e,t,n){var r=e.doc.getAllLines(n),s=r[n],o=/^(Found.*|Searching for.*)$/,u=/^(\S.*:|\s*)$/,a=o.test(s)?o:u,f=n,l=n;if(this.foldingStartMarker.test(s)){for(var c=n+1,h=e.getLength();c<h;c++)if(a.test(r[c]))break;l=c}else if(this.foldingStopMarker.test(s)){for(var c=n-1;c>=0;c--){s=r[c];if(a.test(s))break}f=c}if(f!=l){var p=s.length;return a===o&&(p=s.search(/\(Found[^)]+\)$|$/)),new i(f,p,l,0)}}}.call(o.prototype)}),define("ace/mode/c9search",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/c9search_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/c9search"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./c9search_highlight_rules").C9SearchHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/c9search").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u};r.inherits(a,i),function(){this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/c9search"}.call(a.prototype),t.Mode=a}); (function() {
window.require(["ace/mode/c9search"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/cirru_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"constant.numeric",regex:/[\d\.]+/},{token:"comment.line.double-dash",regex:/--/,next:"comment"},{token:"storage.modifier",regex:/\(/},{token:"storage.modifier",regex:/,/,next:"line"},{token:"support.function",regex:/[^\(\)"\s{}\[\]]+/,next:"line"},{token:"string.quoted.double",regex:/"/,next:"string"},{token:"storage.modifier",regex:/\)/}],comment:[{token:"comment.line.double-dash",regex:/ +[^\n]+/,next:"start"}],string:[{token:"string.quoted.double",regex:/"/,next:"line"},{token:"constant.character.escape",regex:/\\/,next:"escape"},{token:"string.quoted.double",regex:/[^\\"]+/}],escape:[{token:"constant.character.escape",regex:/./,next:"string"}],line:[{token:"constant.numeric",regex:/[\d\.]+/},{token:"markup.raw",regex:/^\s*/,next:"start"},{token:"storage.modifier",regex:/\$/,next:"start"},{token:"variable.parameter",regex:/[^\(\)"\s{}\[\]]+/},{token:"storage.modifier",regex:/\(/,next:"start"},{token:"storage.modifier",regex:/\)/},{token:"markup.raw",regex:/^ */,next:"start"},{token:"string.quoted.double",regex:/"/,next:"string"}]}};r.inherits(s,i),t.CirruHighlightRules=s}),define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),define("ace/mode/cirru",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/cirru_highlight_rules","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./cirru_highlight_rules").CirruHighlightRules,o=e("./folding/coffee").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="--",this.$id="ace/mode/cirru"}.call(u.prototype),t.Mode=u}); (function() {
window.require(["ace/mode/cirru"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/cobol_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="ACCEPT|MERGE|SUM|ADD||MESSAGE|TABLE|ADVANCING|MODE|TAPE|AFTER|MULTIPLY|TEST|ALL|NEGATIVE|TEXT|ALPHABET|NEXT|THAN|ALSO|NO|THEN|ALTERNATE|NOT|THROUGH|AND|NUMBER|THRU|ANY|OCCURS|TIME|ARE|OF|TO|AREA|OFF|TOP||ASCENDING|OMITTED|TRUE|ASSIGN|ON|TYPE|AT|OPEN|UNIT|AUTHOR|OR|UNTIL|BEFORE|OTHER|UP|BLANK|OUTPUT|USE|BLOCK|PAGE|USING|BOTTOM|PERFORM|VALUE|BY|PIC|VALUES|CALL|PICTURE|WHEN|CANCEL|PLUS|WITH|CD|POINTER|WRITE|CHARACTER|POSITION||ZERO|CLOSE|POSITIVE|ZEROS|COLUMN|PROCEDURE|ZEROES|COMMA|PROGRAM|COMMON|PROGRAM-ID|COMMUNICATION|QUOTE|COMP|RANDOM|COMPUTE|READ|CONTAINS|RECEIVE|CONFIGURATION|RECORD|CONTINUE|REDEFINES|CONTROL|REFERENCE|COPY|REMAINDER|COUNT|REPLACE|DATA|REPORT|DATE|RESERVE|DAY|RESET|DELETE|RETURN|DESTINATION|REWIND|DISABLE|REWRITE|DISPLAY|RIGHT|DIVIDE|RUN|DOWN|SAME|ELSE|SEARCH|ENABLE|SECTION|END|SELECT|ENVIRONMENT|SENTENCE|EQUAL|SET|ERROR|SIGN|EXIT|SEQUENTIAL|EXTERNAL|SIZE|FLASE|SORT|FILE|SOURCE|LENGTH|SPACE|LESS|STANDARD|LIMIT|START|LINE|STOP|LOCK|STRING|LOW-VALUE|SUBTRACT",t="true|false|null",n="count|min|max|avg|sum|rank|now|coalesce|main",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"\\*.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]}};r.inherits(s,i),t.CobolHighlightRules=s}),define("ace/mode/cobol",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/cobol_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./cobol_highlight_rules").CobolHighlightRules,o=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(o,i),function(){this.lineCommentStart="*",this.$id="ace/mode/cobol"}.call(o.prototype),t.Mode=o}); (function() {
window.require(["ace/mode/cobol"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
define("ace/mode/csp_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e=this.createKeywordMapper({"constant.language":"child-src|connect-src|default-src|font-src|frame-src|img-src|manifest-src|media-src|object-src|script-src|style-src|worker-src|base-uri|plugin-types|sandbox|disown-opener|form-action|frame-ancestors|report-uri|report-to|upgrade-insecure-requests|block-all-mixed-content|require-sri-for|reflected-xss|referrer|policy-uri",variable:"'none'|'self'|'unsafe-inline'|'unsafe-eval'|'strict-dynamic'|'unsafe-hashed-attributes'"},"identifier",!0);this.$rules={start:[{token:"string.link",regex:/https?:[^;\s]*/},{token:"operator.punctuation",regex:/;/},{token:e,regex:/[^\s;]+/}]}};r.inherits(s,i),t.CspHighlightRules=s}),define("ace/mode/csp",["require","exports","module","ace/mode/text","ace/mode/csp_highlight_rules","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./text").Mode,i=e("./csp_highlight_rules").CspHighlightRules,s=e("../lib/oop"),o=function(){this.HighlightRules=i};s.inherits(o,r),function(){this.$id="ace/mode/csp"}.call(o.prototype),t.Mode=o}); (function() {
window.require(["ace/mode/csp"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More