summaryrefslogtreecommitdiffstats
path: root/modules-available
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available')
-rw-r--r--modules-available/backup/page.inc.php1
-rw-r--r--modules-available/baseconfig/config.json3
-rw-r--r--modules-available/baseconfig/templates/_page.html2
-rw-r--r--modules-available/baseconfig_partitions_cdn/config.json4
-rw-r--r--modules-available/baseconfig_partitions_cdn/page.inc.php133
-rw-r--r--modules-available/baseconfig_partitions_cdn/templates/_page.html74
-rw-r--r--modules-available/dozmod/hooks/main-warning.inc.php11
-rw-r--r--modules-available/dozmod/lang/de/messages.json1
-rw-r--r--modules-available/dozmod/lang/en/messages.json1
-rw-r--r--modules-available/js_chart/clientscript.js11
-rw-r--r--modules-available/js_chart/config.json1
-rw-r--r--modules-available/js_circles/clientscript.js7
-rw-r--r--modules-available/js_circles/config.json1
-rw-r--r--modules-available/main/lang/de/global-tags.json2
-rw-r--r--modules-available/main/lang/de/template-tags.json8
-rw-r--r--modules-available/main/lang/en/global-tags.json2
-rw-r--r--modules-available/main/lang/en/template-tags.json8
-rw-r--r--modules-available/main/page.inc.php44
-rw-r--r--modules-available/main/templates/messagebox-error.html1
-rw-r--r--modules-available/main/templates/messagebox-info.html1
-rw-r--r--modules-available/main/templates/messagebox-success.html1
-rw-r--r--modules-available/main/templates/messagebox-warning.html1
-rw-r--r--modules-available/main/templates/messagebox.html7
-rw-r--r--modules-available/main/templates/page-main.html31
-rw-r--r--modules-available/minilinux/hooks/main-warning.inc.php6
-rw-r--r--modules-available/minilinux/lang/de/messages.json3
-rw-r--r--modules-available/minilinux/lang/en/messages.json3
-rw-r--r--modules-available/serversetup-bwlp/config.json (renamed from modules-available/serversetup/config.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/de/messages.json (renamed from modules-available/serversetup/lang/de/messages.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/de/module.json (renamed from modules-available/serversetup/lang/de/module.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/de/template-tags.json (renamed from modules-available/serversetup/lang/de/template-tags.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/en/messages.json (renamed from modules-available/serversetup/lang/en/messages.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/en/module.json (renamed from modules-available/serversetup/lang/en/module.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/en/template-tags.json (renamed from modules-available/serversetup/lang/en/template-tags.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/pt/messages.json (renamed from modules-available/serversetup/lang/pt/messages.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/pt/module.json (renamed from modules-available/serversetup/lang/pt/module.json)0
-rw-r--r--modules-available/serversetup-bwlp/lang/pt/template-tags.json (renamed from modules-available/serversetup/lang/pt/template-tags.json)0
-rw-r--r--modules-available/serversetup-bwlp/page.inc.php (renamed from modules-available/serversetup/page.inc.php)86
-rw-r--r--modules-available/serversetup-bwlp/templates/ipaddress.html (renamed from modules-available/serversetup/templates/ipaddress.html)7
-rw-r--r--modules-available/serversetup-bwlp/templates/ipxe.html70
-rw-r--r--modules-available/serversetup-bwlp/templates/ipxe_update.html (renamed from modules-available/serversetup/templates/ipxe_update.html)0
-rw-r--r--modules-available/serversetup/templates/ipxe-adv.html149
-rw-r--r--modules-available/serversetup/templates/ipxe-smp.html62
-rw-r--r--modules-available/statistics/config.json2
-rw-r--r--modules-available/statistics/page.inc.php2
-rw-r--r--modules-available/sysconfig/addmodule_branding.inc.php1
-rw-r--r--modules-available/sysconfig/addmodule_custommodule.inc.php1
-rw-r--r--modules-available/sysconfig/clientscript.js21
-rw-r--r--modules-available/sysconfig/hooks/main-warning.inc.php6
-rw-r--r--modules-available/sysconfig/inc/configmodule.inc.php2
-rw-r--r--modules-available/sysconfig/lang/de/messages.json27
-rw-r--r--modules-available/sysconfig/lang/en/messages.json27
-rw-r--r--modules-available/sysconfig/page.inc.php1
-rw-r--r--modules-available/syslog/clientscript.js8
-rw-r--r--modules-available/syslog/page.inc.php3
-rw-r--r--modules-available/syslog/style.css45
-rw-r--r--modules-available/systemstatus/config.json3
-rw-r--r--modules-available/systemstatus/page.inc.php4
-rw-r--r--modules-available/translation/page.inc.php3
-rw-r--r--modules-available/vmstore/hooks/main-warning.inc.php10
-rw-r--r--modules-available/vmstore/lang/de/messages.json3
-rw-r--r--modules-available/vmstore/lang/en/messages.json3
62 files changed, 505 insertions, 409 deletions
diff --git a/modules-available/backup/page.inc.php b/modules-available/backup/page.inc.php
index 9d253a1e..3f2388a5 100644
--- a/modules-available/backup/page.inc.php
+++ b/modules-available/backup/page.inc.php
@@ -27,7 +27,6 @@ class Page_Backup extends Page
if ($this->action === 'restore') {
Render::addTemplate('restore', $this->templateData);
} else {
- Render::addScriptBottom('fileselect');
Render::addTemplate('_page');
}
}
diff --git a/modules-available/baseconfig/config.json b/modules-available/baseconfig/config.json
index b72e9c23..9ce17b0d 100644
--- a/modules-available/baseconfig/config.json
+++ b/modules-available/baseconfig/config.json
@@ -1,4 +1,3 @@
{
- "category": "main.settings",
- "enabled": true
+ "category": "main.settings"
}
diff --git a/modules-available/baseconfig/templates/_page.html b/modules-available/baseconfig/templates/_page.html
index e8b85dd3..093cb10f 100644
--- a/modules-available/baseconfig/templates/_page.html
+++ b/modules-available/baseconfig/templates/_page.html
@@ -63,5 +63,5 @@
</div>
<button class="btn btn-primary" type="submit">{{lang_save}}</button>
<button class="btn btn-default" type="reset">{{lang_reset}}</button>
- <a class="btn btn-default" href="api.php?do=getconfig">Download</a>
+ <a class="btn btn-default" href="api.php?do=baseconfig">Download</a>
</form>
diff --git a/modules-available/baseconfig_partitions_cdn/config.json b/modules-available/baseconfig_partitions_cdn/config.json
new file mode 100644
index 00000000..a3036a56
--- /dev/null
+++ b/modules-available/baseconfig_partitions_cdn/config.json
@@ -0,0 +1,4 @@
+{
+ "category": "main.settings",
+ "dependencies": [ "baseconfig" ]
+} \ No newline at end of file
diff --git a/modules-available/baseconfig_partitions_cdn/page.inc.php b/modules-available/baseconfig_partitions_cdn/page.inc.php
new file mode 100644
index 00000000..b6ea869a
--- /dev/null
+++ b/modules-available/baseconfig_partitions_cdn/page.inc.php
@@ -0,0 +1,133 @@
+<?php
+
+class Page_BaseConfig_Partitions_CDN extends Page
+{
+
+ protected function doPreprocess()
+ {
+ User::load();
+
+ $action = Request::post('action');
+
+ if($action == 'new_partition') {
+ $this->addPartition();
+ }
+ if($action == 'reset') {
+ $this->resetConfig();
+ }
+
+ $deletePartition = Request::get('deletePartition');
+ if($deletePartition !== false) { // TODO: CSRF: Actions that change/update/delete anything should be POST
+ $this->deletePartition($deletePartition);
+ }
+
+ $this->updatePartitions();
+ }
+
+ protected function doRender()
+ {
+ if (!User::hasPermission('baseconfig_local')) {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=Main');
+ }
+
+ //loads partition settings
+ $partitions = array();
+ $res = Database::simpleQuery('SELECT id, partition_id, size, mount_point, options FROM setting_partition WHERE user=:user',
+ array( 'user' => User::getId() ));
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $partition = array(
+ 'id' => $row['id'],
+ 'partition_id' => $row['partition_id'],
+ 'size' => $row['size'],
+ 'mount_point' => $row['mount_point'],
+ 'options' => $row['options']
+ );
+ $partitions[] = $partition;
+ }
+
+ Render::addTemplate('_page', array(
+ 'partitions' => $partitions,
+ 'user' => User::getId()
+ ));
+ }
+
+ private function addPartition() {
+ $partId = Request::post('new-partition-id');
+ $partSize = Request::post('new-partition-size');
+ $partMountPoint = Request::post('new-partition-mount-point');
+ $partOptions = Request::post('new-partition-options');
+
+ if(strlen($partId) < 1 || strlen($partSize) < 1){
+ Message::addError('main.empty-field');
+ }else{
+ $data = array(
+ 'partition_id' => $partId,
+ 'size' => $partSize,
+ 'mount_point' => $partMountPoint,
+ 'options' => $partOptions,
+ 'user' => User::getId()
+ );
+ if (Database::exec('INSERT INTO setting_partition SET partition_id = :partition_id, size = :size,
+ mount_point = :mount_point, options = :options, user = :user ', $data) != 1) {
+ Util::traceError('Could not create new partition in DB');
+ }
+ }
+ Util::redirect('?do=BaseConfig');
+ }
+
+ private function deletePartition($id){
+ if(is_numeric($id)){
+ $data = array(
+ 'id' => $id,
+ 'user' => User::getId()
+ );
+ if (Database::exec('DELETE FROM setting_partition WHERE id = :id AND user = :user', $data) != 1) {
+ Util::traceError('Could not delete partition in DB');
+ }
+ }
+ Util::redirect('?do=BaseConfig');
+ }
+
+ private function updatePartitions(){
+ $partitions = array();
+ foreach($_POST as $key => $value){
+ if(substr($key,0,9) == 'partition'){
+ $id = substr($key,10,1);
+ $type = substr($key,12);
+ $partitions[$id][$type] = $value;
+ }
+ }
+
+ foreach($partitions as $key => $data){
+ $data = array(
+ 'id' => $key,
+ 'partition_id' => $data['partition_id'],
+ 'size' => $data['size'],
+ 'mount_point' => $data['mount_point'],
+ 'options' => $data['options'],
+ 'user' => User::getId()
+ );
+ Database::exec('UPDATE setting_partition SET partition_id=:partition_id, size=:size, mount_point=:mount_point,
+ options=:options WHERE id=:id AND user=:user;', $data);
+ }
+ if (!empty($partitions)) {
+ Message::addSuccess('partitions-updated');
+ Util::redirect('?do=BaseConfig');
+ }
+ }
+
+ private function resetConfig(){
+ $data = array(
+ 'user' => User::getId()
+ );
+ //Delete all config values
+ Database::exec('DELETE FROM setting_partition WHERE user = :user', $data);
+ //Create default partition values
+ Database::exec ( "INSERT INTO setting_partition SET partition_id = '44', size = '5G', mount_point = '/tmp', user = :user", $data );
+ Database::exec ( "INSERT INTO setting_partition SET partition_id = '43', size = '20G', mount_point = '/boot', options = 'bootable', user = :user", $data );
+ Database::exec ( "INSERT INTO setting_partition SET partition_id = '40', size = '20G', mount_point = '/cache/export/dnbd3', user = :user", $data );
+ Database::exec ( "INSERT INTO setting_partition SET partition_id = '41', size = '5G', mount_point = '/home', user = :user", $data );
+ Database::exec ( "INSERT INTO setting_partition SET partition_id = '82', size = '1G', user = :user", $data );
+ }
+} \ No newline at end of file
diff --git a/modules-available/baseconfig_partitions_cdn/templates/_page.html b/modules-available/baseconfig_partitions_cdn/templates/_page.html
new file mode 100644
index 00000000..ee764e37
--- /dev/null
+++ b/modules-available/baseconfig_partitions_cdn/templates/_page.html
@@ -0,0 +1,74 @@
+<h1>{{lang_partitioningManagement}}</h1>
+
+<form action="?do=BaseConfig_Partitions_CDN" method="post">
+ <input type="hidden" name="token" value="{{token}}">
+ <button class="btn btn-lg btn-primary" type="submit">{{lang_save}}</button>
+ <button class="btn btn-lg btn-primary" type="reset">{{lang_reset}}</button>
+ <a class="btn btn-lg btn-primary" href="#" onclick="saveConfig()">Download</a>
+</form>
+<div>
+<form method="post" action="?do=BaseConfig_Partitions_CDN">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="reset">
+ <button class="btn btn-default" type="submit" onclick="return confirm('{{lang_resetConfirm}}');">{{lang_resetDefault}}</button>
+</form>
+</div>
+
+<!-- Create Partition Window -->
+<form action="?do=BaseConfig_Partitions_CDN" method="post">
+ <div class="modal fade" id="add-partition" tabindex="-1" role="dialog">
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+ <div class="modal-header">{{lang_newPartition}}</div>
+ <div class="modal-body">
+
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_partitionId}}</span>
+ <input name="new-partition-id" class="form-control" type="text">
+ </div>
+ <p class="help-block">{{lang_helpId}}</p>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_partitionSize}}</span>
+ <input name="new-partition-size" class="form-control" type="text">
+ </div>
+ <p class="help-block">{{lang_helpSize}}</p>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_partitionMountPoint}}</span>
+ <input name="new-partition-mount-point" class="form-control" type="text">
+ </div>
+ <p class="help-block">{{lang_helpMountPoint}}</p>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_partitionOptions}}</span>
+ <input name="new-partition-options" class="form-control" type="text">
+ </div>
+ <p class="help-block">{{lang_helpOptions}}</p>
+ <input type="submit" class="btn btn-primary" value="{{lang_create}}">
+ </div>
+ <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
+ </div>
+ </div>
+ </div>
+ <input type="hidden" name="action" value="new_partition">
+ <input type="hidden" name="token" value="{{token}}">
+</form>
+<script type="text/javascript">
+ document.getElementById("cat-extra-6").innerHTML = "<div class='list-group'> <div class='list-group-item' style='background-color:#f5f5f5;color:#428bca;'> " +
+ "{{lang_catPartition}} <span style='display:inline-block; float: right; margin-top: -7px;'> <a class='btn btn-default ' data-toggle='modal' " +
+ "data-target='#add-partition'> <span class='glyphicon glyphicon-plus'></span> </a> </span> </div> {{#partitions}} <div class='list-group-item'> " +
+ "<div class='row'> <div class='col-md-1'> <input name='partition-{{id}}-partition_id' type='text' class='form-control' size='30' value='{{partition_id}}'" +
+ " placeholder='{{lang_partitionId}}' /> </div> <div class='col-md-1'> <input name='partition-{{id}}-size' type='text' class='form-control' size='30' " +
+ "value='{{size}}' placeholder='{{lang_partitionSize}}'/> </div> <div class='col-md-4'> <input name='partition-{{id}}-mount_point' type='text' " +
+ "class='form-control' size='30' value='{{mount_point}}' placeholder='{{lang_partitionMountPoint}}'/> </div> <div class='col-md-4'> <input " +
+ "name='partition-{{id}}-options' type='text' class='form-control' size='30' value='{{options}}' placeholder='{{lang_partitionOptions}}'/> </div> " +
+ "<div class='col-md-2'> <a class='btn btn-danger' href='?do=BaseConfig&deletePartition={{id}}&token={{token}}' ><span class='glyphicon glyphicon-trash'>" +
+ "</span> {{lang_delete}}</a> </div> </div> </div> {{/partitions}} </div> </div>";
+
+ function saveConfig(){
+ if(confirm('{{lang_confirm}}'))
+ window.location = 'api.php?do=baseconfig&user={{user}}&save=true';
+ else
+ window.location = 'api.php?do=baseconfig&user={{user}}';
+ }
+
+</script> \ No newline at end of file
diff --git a/modules-available/dozmod/hooks/main-warning.inc.php b/modules-available/dozmod/hooks/main-warning.inc.php
new file mode 100644
index 00000000..ffa87692
--- /dev/null
+++ b/modules-available/dozmod/hooks/main-warning.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+/*
+ * Show notification in main window if there are images that should be deleted and are waiting for confirmation
+ */
+
+$res = Database::queryFirst("SELECT Count(*) AS cnt FROM sat.imageversion WHERE deletestate = 'SHOULD_DELETE'", array(), true);
+if (isset($res['cnt']) && $res['cnt'] > 0) {
+ Message::addInfo('dozmod.images-pending-delete-exist', true, $res['cnt']);
+}
+unset($res);
diff --git a/modules-available/dozmod/lang/de/messages.json b/modules-available/dozmod/lang/de/messages.json
index d6e39cbf..7944ffae 100644
--- a/modules-available/dozmod/lang/de/messages.json
+++ b/modules-available/dozmod/lang/de/messages.json
@@ -1,4 +1,5 @@
{
"delete-images": "L\u00f6schung: {{0}}",
+ "images-pending-delete-exist": "Zur L\u00f6schung markierte Abbilder: {{0}}",
"mail-config-saved": "Mail-Konfiguration gespeichert"
} \ No newline at end of file
diff --git a/modules-available/dozmod/lang/en/messages.json b/modules-available/dozmod/lang/en/messages.json
index a3c94a56..6651e32e 100644
--- a/modules-available/dozmod/lang/en/messages.json
+++ b/modules-available/dozmod/lang/en/messages.json
@@ -1,4 +1,5 @@
{
"delete-images": "Delete: {{0}}",
+ "images-pending-delete-exist": "Images marked for deletion: {{0}}",
"mail-config-saved": "Mail config saved"
} \ No newline at end of file
diff --git a/modules-available/js_chart/clientscript.js b/modules-available/js_chart/clientscript.js
new file mode 100644
index 00000000..3a0a2c87
--- /dev/null
+++ b/modules-available/js_chart/clientscript.js
@@ -0,0 +1,11 @@
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 1.0.2
+ *
+ * Copyright 2015 Nick Downie
+ * Released under the MIT license
+ * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
+ */
+(function(){"use strict";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t["offset"+i]?t["offset"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,"Width"),n=this.height=i(t.canvas,"Height");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n<t.length;n++)i.apply(e,[t[n],n].concat(s))}else for(var o in t)i.apply(e,[t[o],o].concat(s))},o=s.clone=function(t){var i={};return n(t,function(e,s){t.hasOwnProperty(s)&&(i[s]=e)}),i},a=s.extend=function(t){return n(Array.prototype.slice.call(arguments,1),function(i){n(i,function(e,s){i.hasOwnProperty(s)&&(t[s]=e)})}),t},h=s.merge=function(){var t=Array.prototype.slice.call(arguments,0);return t.unshift({}),a.apply(null,t)},l=s.indexOf=function(t,i){if(Array.prototype.indexOf)return t.indexOf(i);for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1},r=(s.where=function(t,i){var e=[];return s.each(t,function(t){i(t)&&e.push(t)}),e},s.findNextWhere=function(t,i,e){e||(e=-1);for(var s=e+1;s<t.length;s++){var n=t[s];if(i(n))return n}},s.findPreviousWhere=function(t,i,e){e||(e=t.length);for(var s=e-1;s>=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=s.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=s.amd="function"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){return t%1!==0&&f(t)?t.toString().split(".")[1].length:0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),y=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},s.template=function(t,i){function e(t,i){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),-(s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)))},easeOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),s*Math.pow(2,-10*t)*Math.sin(2*(1*t-i)*Math.PI/e)+1)},easeInOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:2==(t/=.5)?1:(e||(e=.3*1.5),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),1>t?-.5*s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*t*t*(((i*=1.525)+1)*t-i):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=b(l):n.apply(o)};b(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent("on"+i,e):t["on"+i]=e}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+"px",i.canvas.style.height=s+"px",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+" "+t+"px "+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,i){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:C(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)<Math.pow(e,2)},draw:function(){if(this.display){var t=this.ctx;t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI),t.closePath(),t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.fillStyle=this.fillColor,t.fill(),t.stroke()}}}),e.Arc=e.Element.extend({inRange:function(t,i){var e=s.getAngleFromPoint(this,{x:t,y:i}),n=e.angle>=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin="bevel",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-n<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),t<this.yLabelWidth&&this.calculateXLabelRotation()},calculateXLabelRotation:function(){this.ctx.font=this.font;var t,i,e=this.ctx.measureText(this.xLabels[0]).width,s=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width;if(this.xScalePaddingRight=s/2+3,this.xScalePaddingLeft=e/2>this.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;i<this.valuesCount;i++)t=this.getPointPosition(i,d),e=this.ctx.measureText(C(this.templateString,{value:this.labels[i]})).width+5,0===i||i===this.valuesCount/2?(s=e/2,t.x+s>p&&(p=t.x+s,n=i),t.x-s<g&&(g=t.x-s,a=i)):i<this.valuesCount/2?t.x+e>p&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e<g&&(g=t.x-e,a=i);l=g,r=Math.ceil(p-this.width),o=this.getIndexAngle(n),h=this.getIndexAngle(a),c=r/Math.sin(o+Math.PI/2),u=l/Math.sin(h+Math.PI/2),c=f(c)?c:0,u=f(u)?u:0,this.drawingArea=d-(u+c)/2,this.setCenterPoint(u,c)},setCenterPoint:function(t,i){var e=this.width-i-this.drawingArea,s=t+this.drawingArea;this.xCenter=(s+e)/2,this.yCenter=this.height/2},getIndexAngle:function(t){var i=2*Math.PI/this.valuesCount;return t*i-Math.PI/2},getPointPosition:function(t,i){var e=this.getIndexAngle(t);return{x:Math.cos(e)*i+this.xCenter,y:Math.sin(e)*i+this.yCenter}},draw:function(){if(this.display){var t=this.ctx;if(n(this.yLabels,function(i,e){if(e>0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a<this.valuesCount;a++)s=this.getPointPosition(a,this.calculateCenterOffset(this.min+e*this.stepValue)),0===a?t.moveTo(s.x,s.y):t.lineTo(s.x,s.y);t.closePath(),t.stroke()}if(this.showLabels){if(t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop){var h=t.measureText(i).width;t.fillStyle=this.backdropColor,t.fillRect(this.xCenter-h/2-this.backdropPaddingX,o-this.fontSize/2-this.backdropPaddingY,h+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)}t.textAlign="center",t.textBaseline="middle",t.fillStyle=this.fontColor,t.fillText(i,this.xCenter,o)}}},this),!this.lineArc){t.lineWidth=this.angleLineWidth,t.strokeStyle=this.angleLineColor;for(var i=this.valuesCount-1;i>=0;i--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?"center":i===a?"center":a>i?"left":"right",t.textBaseline=r?"middle":l?"bottom":"top",t.fillText(this.labels[i],s.x,s.y)}}}}}),s.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define(function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].fillColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Bar",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing},calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<this.datasets.length;a++)for(i=0;i<this.datasets[a].bars.length;i++)if(this.datasets[a].bars[i].inRange(n.x,n.y))return e.each(this.datasets,o),s;return s},buildScale:function(t){var i=this,s=function(){var t=[];return i.eachBars(function(i){t.push(i.value)}),t},n={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(s(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(n,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new this.ScaleClass(n)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].bars.push(new this.BarClass({value:t,label:i,x:this.scale.calculateBarX(this.datasets.length,e,this.scale.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this.datasets.length),base:this.scale.endPoint,strokeColor:this.datasets[e].strokeColor,fillColor:this.datasets[e].fillColor}))
+},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.bars.shift()},this),this.update()},reflow:function(){e.extend(this.BarClass.prototype,{y:this.scale.endPoint,base:this.scale.endPoint});var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();this.chart.ctx;this.scale.draw(i),e.each(this.datasets,function(t,s){e.each(t.bars,function(t,e){t.hasValue()&&(t.base=this.scale.endPoint,t.transition({x:this.scale.calculateBarX(this.datasets.length,s,e),y:this.scale.calculateY(t.value),width:this.scale.calculateBarWidth(this.datasets.length)},i).draw())},this)},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Doughnut",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle)},this)}}),i.types.Doughnut.extend({name:"Pie",defaults:e.merge(s,{percentageInnerCutout:0})})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,bezierCurve:!0,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Line",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this),this.buildScale(t.labels),this.eachPoints(function(t,i){e.extend(t,{x:this.scale.calculateX(i),y:this.scale.endPoint}),t.save()},this)},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachPoints(function(t){t.save()}),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.datasets,function(t){e.each(t.points,function(t){t.inRange(s.x,s.y)&&i.push(t)})},this),i},buildScale:function(t){var s=this,n=function(){var t=[];return s.eachPoints(function(i){t.push(i.value)}),t},o={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(n(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.pointDotRadius+this.options.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(o,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new i.Scale(o)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:this.scale.calculateX(this.scale.valuesCount+1),y:this.scale.endPoint,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.points.shift()},this),this.update()},reflow:function(){var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();var s=this.chart.ctx,n=function(t){return null!==t.value},o=function(t,i,s){return e.findNextWhere(i,n,s)||t},a=function(t,i,s){return e.findPreviousWhere(i,n,s)||t};this.scale.draw(i),e.each(this.datasets,function(t){var h=e.where(t.points,n);e.each(t.points,function(t,e){t.hasValue()&&t.transition({y:this.scale.calculateY(t.value),x:this.scale.calculateX(e)},i)},this),this.options.bezierCurve&&e.each(h,function(t,i){var s=i>0&&i<h.length-1?this.options.bezierCurveTension:0;t.controlPoints=e.splineCurve(a(t,h,i),t,o(t,h,i),s),t.controlPoints.outer.y>this.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.y<this.scale.startPoint&&(t.controlPoints.outer.y=this.scale.startPoint),t.controlPoints.inner.y>this.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y<this.scale.startPoint&&(t.controlPoints.inner.y=this.scale.startPoint)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(h,function(t,i){if(0===i)s.moveTo(t.x,t.y);else if(this.options.bezierCurve){var e=a(t,h,i);s.bezierCurveTo(e.controlPoints.outer.x,e.controlPoints.outer.y,t.controlPoints.inner.x,t.controlPoints.inner.y,t.x,t.y)}else s.lineTo(t.x,t.y)},this),s.stroke(),this.options.datasetFill&&h.length>0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"PolarArea",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle),t.draw()},this),this.scale.draw()}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers;i.Type.extend({name:"Radar",defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1,scaleBeginAtZero:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:10,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this); \ No newline at end of file
diff --git a/modules-available/js_chart/config.json b/modules-available/js_chart/config.json
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/modules-available/js_chart/config.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/modules-available/js_circles/clientscript.js b/modules-available/js_circles/clientscript.js
new file mode 100644
index 00000000..0fc701eb
--- /dev/null
+++ b/modules-available/js_circles/clientscript.js
@@ -0,0 +1,7 @@
+/**
+ * circles - v0.0.6 - 2015-05-27
+ *
+ * Copyright (c) 2015 lugolabs
+ * Licensed
+ */
+!function(){"use strict";var a=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,1e3/60)},b=window.Circles=function(a){var b=a.id;if(this._el=document.getElementById(b),null!==this._el){this._radius=a.radius||10,this._duration=void 0===a.duration?500:a.duration,this._value=0,this._maxValue=a.maxValue||100,this._text=void 0===a.text?function(a){return this.htmlifyNumber(a)}:a.text,this._strokeWidth=a.width||10,this._colors=a.colors||["#EEE","#F00"],this._svg=null,this._movingPath=null,this._wrapContainer=null,this._textContainer=null,this._wrpClass=a.wrpClass||"circles-wrp",this._textClass=a.textClass||"circles-text",this._valClass=a.valueStrokeClass||"circles-valueStroke",this._maxValClass=a.maxValueStrokeClass||"circles-maxValueStroke",this._styleWrapper=a.styleWrapper===!1?!1:!0,this._styleText=a.styleText===!1?!1:!0;var c=Math.PI/180*270;this._start=-Math.PI/180*90,this._startPrecise=this._precise(this._start),this._circ=c-this._start,this._generate().update(a.value||0)}};b.prototype={VERSION:"0.0.6",_generate:function(){return this._svgSize=2*this._radius,this._radiusAdjusted=this._radius-this._strokeWidth/2,this._generateSvg()._generateText()._generateWrapper(),this._el.innerHTML="",this._el.appendChild(this._wrapContainer),this},_setPercentage:function(a){this._movingPath.setAttribute("d",this._calculatePath(a,!0)),this._textContainer.innerHTML=this._getText(this.getValueFromPercent(a))},_generateWrapper:function(){return this._wrapContainer=document.createElement("div"),this._wrapContainer.className=this._wrpClass,this._styleWrapper&&(this._wrapContainer.style.position="relative",this._wrapContainer.style.display="inline-block"),this._wrapContainer.appendChild(this._svg),this._wrapContainer.appendChild(this._textContainer),this},_generateText:function(){if(this._textContainer=document.createElement("div"),this._textContainer.className=this._textClass,this._styleText){var a={position:"absolute",top:0,left:0,textAlign:"center",width:"100%",fontSize:.7*this._radius+"px",height:this._svgSize+"px",lineHeight:this._svgSize+"px"};for(var b in a)this._textContainer.style[b]=a[b]}return this._textContainer.innerHTML=this._getText(0),this},_getText:function(a){return this._text?(void 0===a&&(a=this._value),a=parseFloat(a.toFixed(2)),"function"==typeof this._text?this._text.call(this,a):this._text):""},_generateSvg:function(){return this._svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this._svg.setAttribute("xmlns","http://www.w3.org/2000/svg"),this._svg.setAttribute("width",this._svgSize),this._svg.setAttribute("height",this._svgSize),this._generatePath(100,!1,this._colors[0],this._maxValClass)._generatePath(1,!0,this._colors[1],this._valClass),this._movingPath=this._svg.getElementsByTagName("path")[1],this},_generatePath:function(a,b,c,d){var e=document.createElementNS("http://www.w3.org/2000/svg","path");return e.setAttribute("fill","transparent"),e.setAttribute("stroke",c),e.setAttribute("stroke-width",this._strokeWidth),e.setAttribute("d",this._calculatePath(a,b)),e.setAttribute("class",d),this._svg.appendChild(e),this},_calculatePath:function(a,b){var c=this._start+a/100*this._circ,d=this._precise(c);return this._arc(d,b)},_arc:function(a,b){var c=a-.001,d=a-this._startPrecise<Math.PI?0:1;return["M",this._radius+this._radiusAdjusted*Math.cos(this._startPrecise),this._radius+this._radiusAdjusted*Math.sin(this._startPrecise),"A",this._radiusAdjusted,this._radiusAdjusted,0,d,1,this._radius+this._radiusAdjusted*Math.cos(c),this._radius+this._radiusAdjusted*Math.sin(c),b?"":"Z"].join(" ")},_precise:function(a){return Math.round(1e3*a)/1e3},htmlifyNumber:function(a,b,c){b=b||"circles-integer",c=c||"circles-decimals";var d=(a+"").split("."),e='<span class="'+b+'">'+d[0]+"</span>";return d.length>1&&(e+='.<span class="'+c+'">'+d[1].substring(0,2)+"</span>"),e},updateRadius:function(a){return this._radius=a,this._generate().update(!0)},updateWidth:function(a){return this._strokeWidth=a,this._generate().update(!0)},updateColors:function(a){this._colors=a;var b=this._svg.getElementsByTagName("path");return b[0].setAttribute("stroke",a[0]),b[1].setAttribute("stroke",a[1]),this},getPercent:function(){return 100*this._value/this._maxValue},getValueFromPercent:function(a){return this._maxValue*a/100},getValue:function(){return this._value},getMaxValue:function(){return this._maxValue},update:function(b,c){if(b===!0)return this._setPercentage(this.getPercent()),this;if(this._value==b||isNaN(b))return this;void 0===c&&(c=this._duration);var d,e,f,g,h=this,i=h.getPercent(),j=1;return this._value=Math.min(this._maxValue,Math.max(0,b)),c?(d=h.getPercent(),e=d>i,j+=d%1,f=Math.floor(Math.abs(d-i)/j),g=c/f,function k(b){if(e?i+=j:i-=j,e&&i>=d||!e&&d>=i)return void a(function(){h._setPercentage(d)});a(function(){h._setPercentage(i)});var c=Date.now(),f=c-b;f>=g?k(c):setTimeout(function(){k(Date.now())},g-f)}(Date.now()),this):(this._setPercentage(this.getPercent()),this)}},b.create=function(a){return new b(a)}}(); \ No newline at end of file
diff --git a/modules-available/js_circles/config.json b/modules-available/js_circles/config.json
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/modules-available/js_circles/config.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/modules-available/main/lang/de/global-tags.json b/modules-available/main/lang/de/global-tags.json
index 39236fd4..a8fa0034 100644
--- a/modules-available/main/lang/de/global-tags.json
+++ b/modules-available/main/lang/de/global-tags.json
@@ -2,8 +2,10 @@
"lang_back": "Zur\u00fcck",
"lang_cancel": "Abbrechen",
"lang_close": "Schlie\u00dfen",
+ "lang_days": "Tag(e)",
"lang_delete": "L\u00f6schen",
"lang_hint": "Hinweis",
+ "lang_hours": "Stunde(n)",
"lang_next": "Weiter",
"lang_save": "Speichern",
"lang_today": "Heute",
diff --git a/modules-available/main/lang/de/template-tags.json b/modules-available/main/lang/de/template-tags.json
index b299cbad..c11843a0 100644
--- a/modules-available/main/lang/de/template-tags.json
+++ b/modules-available/main/lang/de/template-tags.json
@@ -1,6 +1,5 @@
{
- "lang_bootMenuWarning": "Das Bootmen\u00fc ist veraltet oder wurde noch nicht generiert.",
- "lang_configure": "Konfigurieren",
+ "lang_goTo": "Gehe zu",
"lang_intro": "Dies ist die bwLehrpool Konfigurationsoberfl\u00e4che.",
"lang_introGuest": "Dies ist das Administrations-Interface der lokalen bwLehrpool-Installation. Bitte authentifizieren Sie sich, um Einstellungen vorzunehmen.",
"lang_language": "Sprachen",
@@ -8,16 +7,11 @@
"lang_loggedInSuffix": " ",
"lang_login": "Anmelden",
"lang_logout": "Abmelden",
- "lang_minilinuxMissing": "Wichtige Dateien der MiniLinux-Installation fehlen.",
"lang_needsSetup": "Einrichtung unvollst\u00e4ndig",
"lang_noExistingAccount": "Es existiert noch kein Administrator-Zugang f\u00fcr diesen Satelliten-Server.",
- "lang_numerOfImagesMarkedForDeletion": "Zur L\u00f6schung markierte Abbilder",
"lang_register": "Registrieren",
- "lang_systemConfiguration": "Systemkonfiguration",
- "lang_systemConfigurationNotChosen": "Es wurde noch keine Systemkonfiguration ausgew\u00e4hlt.",
"lang_toggleNavigation": "Navigation ein\/ausblenden",
"lang_translations": "\u00dcbersetzungen",
- "lang_vmLocationNotSet": "Es ist noch kein Speicherort f\u00fcr die Virtuellen Maschinen festgelegt.",
"lang_warning": "Warnung",
"lang_warningDebug": "Debugmodus aktiv!",
"lang_welcome": "Willkommen"
diff --git a/modules-available/main/lang/en/global-tags.json b/modules-available/main/lang/en/global-tags.json
index 10581ae2..181f600a 100644
--- a/modules-available/main/lang/en/global-tags.json
+++ b/modules-available/main/lang/en/global-tags.json
@@ -2,8 +2,10 @@
"lang_back": "Back",
"lang_cancel": "Cancel",
"lang_close": "Close",
+ "lang_days": "day(s)",
"lang_delete": "Delete",
"lang_hint": "Hint",
+ "lang_hours": "hour(s)",
"lang_next": "Next",
"lang_save": "Save",
"lang_today": "Today",
diff --git a/modules-available/main/lang/en/template-tags.json b/modules-available/main/lang/en/template-tags.json
index be03e53e..fcb34031 100644
--- a/modules-available/main/lang/en/template-tags.json
+++ b/modules-available/main/lang/en/template-tags.json
@@ -1,6 +1,5 @@
{
- "lang_bootMenuWarning": "The boot menu is outdated or has not been generated.",
- "lang_configure": "Configure",
+ "lang_goTo": "Gehe zu",
"lang_intro": "This is the bwLehrpool configuration interface.",
"lang_introGuest": "This is the administration interface of the local bwLehrpool intallation. Please authenticate yourself to adjust settings.",
"lang_language": "Language",
@@ -8,16 +7,11 @@
"lang_loggedInSuffix": " ",
"lang_login": "Login",
"lang_logout": "Logout",
- "lang_minilinuxMissing": "Important files from the mini Linux installation are missing.",
"lang_needsSetup": "Setup incomplete",
"lang_noExistingAccount": "No account has been created yet. Sign up to become the administrator.",
- "lang_numerOfImagesMarkedForDeletion": "Images marked for deletion",
"lang_register": "Register",
- "lang_systemConfiguration": "System Configuration",
- "lang_systemConfigurationNotChosen": "A system configuration has not been chosen yet.",
"lang_toggleNavigation": "toggle navigation",
"lang_translations": "Translations",
- "lang_vmLocationNotSet": "A location for the virtual machine is not set yet.",
"lang_warning": "Warning",
"lang_warningDebug": "Debug mode active!",
"lang_welcome": "Welcome"
diff --git a/modules-available/main/page.inc.php b/modules-available/main/page.inc.php
index 0a9acd81..bd50a5d1 100644
--- a/modules-available/main/page.inc.php
+++ b/modules-available/main/page.inc.php
@@ -3,24 +3,9 @@
class Page_Main extends Page
{
- private $sysconfig;
- private $minilinux;
- private $vmstore;
- private $ipxe;
- private $delPending;
-
protected function doPreprocess()
{
User::load();
- if (User::isLoggedIn()) {
- $this->sysconfig = !file_exists(CONFIG_HTTP_DIR . '/default/config.tgz');
- $this->minilinux = !file_exists(CONFIG_HTTP_DIR . '/default/kernel') || !file_exists(CONFIG_HTTP_DIR . '/default/initramfs-stage31') || !file_exists(CONFIG_HTTP_DIR . '/default/stage32.sqfs');
- $this->vmstore = !is_array(Property::getVmStoreConfig());
- $this->ipxe = !preg_match('/^\d+\.\d+\.\d+\.\d+$/', Property::getServerIp());
- Property::setNeedsSetup(($this->sysconfig || $this->minilinux || $this->vmstore || $this->ipxe) ? 1 : 0);
- $res = Database::queryFirst("SELECT Count(*) AS cnt FROM sat.imageversion WHERE deletestate = 'SHOULD_DELETE'", array(), true);
- $this->delPending = isset($res['cnt']) ? $res['cnt'] : 0;
- }
}
protected function doRender()
@@ -33,24 +18,21 @@ class Page_Main extends Page
}
// Logged in here
- // Load news
- $lines = array();
- $paginate = new Paginate("SELECT newsid, dateline, title, content FROM news ORDER BY dateline DESC", 10);
- $res = $paginate->exec();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- if(count($lines) >= 3) break;
- $lines[] = $row;
- }
-
Render::addTemplate('page-main', array(
- 'user' => User::getName(),
- 'sysconfig' => $this->sysconfig,
- 'minilinux' => $this->minilinux,
- 'vmstore' => $this->vmstore,
- 'ipxe' => $this->ipxe,
- 'delpending' => $this->delPending,
- 'news' => $lines
+ 'user' => User::getName()
));
+
+ // Warnings
+ $needSetup = false;
+ foreach (glob('modules/*/hooks/main-warning.inc.php') as $file) {
+ preg_match('#^modules/([^/]+)/#', $file, $out);
+ if (!Module::isAvailable($out[1]))
+ continue;
+ include $file;
+ }
+
+ // Update warning state
+ Property::setNeedsSetup($needSetup ? 1 : 0);
}
protected function doAjax()
diff --git a/modules-available/main/templates/messagebox-error.html b/modules-available/main/templates/messagebox-error.html
deleted file mode 100644
index 873716c9..00000000
--- a/modules-available/main/templates/messagebox-error.html
+++ /dev/null
@@ -1 +0,0 @@
-<div class="alert alert-danger"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> {{{message}}}</div>
diff --git a/modules-available/main/templates/messagebox-info.html b/modules-available/main/templates/messagebox-info.html
deleted file mode 100644
index eb9d518a..00000000
--- a/modules-available/main/templates/messagebox-info.html
+++ /dev/null
@@ -1 +0,0 @@
-<div class="alert alert-info"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> {{{message}}}</div>
diff --git a/modules-available/main/templates/messagebox-success.html b/modules-available/main/templates/messagebox-success.html
deleted file mode 100644
index 93674d69..00000000
--- a/modules-available/main/templates/messagebox-success.html
+++ /dev/null
@@ -1 +0,0 @@
-<div class="alert alert-success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> {{{message}}}</div>
diff --git a/modules-available/main/templates/messagebox-warning.html b/modules-available/main/templates/messagebox-warning.html
deleted file mode 100644
index b02e2e8a..00000000
--- a/modules-available/main/templates/messagebox-warning.html
+++ /dev/null
@@ -1 +0,0 @@
-<div class="alert alert-warning"><span class="glyphicon glyphicon-warning" aria-hidden="true"></span> {{{message}}}</div>
diff --git a/modules-available/main/templates/messagebox.html b/modules-available/main/templates/messagebox.html
new file mode 100644
index 00000000..45d5d8f6
--- /dev/null
+++ b/modules-available/main/templates/messagebox.html
@@ -0,0 +1,7 @@
+<div class="alert alert-{{type}}">
+ <span class="glyphicon glyphicon-{{icon}}" aria-hidden="true"></span>
+ {{#link}}
+ <a class="pull-right" href="?do={{link}}">{{lang_goTo}} &raquo;</a>
+ {{/link}}
+ {{{message}}}
+</div>
diff --git a/modules-available/main/templates/page-main.html b/modules-available/main/templates/page-main.html
index 39e4e74e..a0b2d3b0 100644
--- a/modules-available/main/templates/page-main.html
+++ b/modules-available/main/templates/page-main.html
@@ -3,34 +3,3 @@
<p>{{lang_intro}}</p>
</div>
-<ul class="list-group">
-{{#vmstore}}
- <li class="list-group-item list-group-item-text">
- {{lang_vmLocationNotSet}}
- <a class="btn btn-sm btn-primary" href="?do=VmStore">{{lang_configure}} &raquo;</a>
- </li>
-{{/vmstore}}
-{{#ipxe}}
- <li class="list-group-item list-group-item-text">
- {{lang_bootMenuWarning}}
- <a class="btn btn-sm btn-primary" href="?do=ServerSetup">{{lang_configure}} &raquo;</a>
- </li>
-{{/ipxe}}
-{{#minilinux}}
- <li class="list-group-item list-group-item-text">
- {{lang_minilinuxMissing}}
- <a class="btn btn-sm btn-primary" href="?do=MiniLinux">MiniLinux &raquo;</a>
- </li>
-{{/minilinux}}
-{{#sysconfig}}
- <li class="list-group-item list-group-item-text">
- {{lang_systemConfigurationNotChosen}}
- <a class="btn btn-sm btn-primary" href="?do=SysConfig">{{lang_systemConfiguration}} &raquo;</a>
- </li>
-{{/sysconfig}}
-{{#delpending}}
- <li class="list-group-item list-group-item-text">
- <a href="?do=DozMod">{{lang_numerOfImagesMarkedForDeletion}}: {{delpending}}</a>
- </li>
-{{/delpending}}
-</ul>
diff --git a/modules-available/minilinux/hooks/main-warning.inc.php b/modules-available/minilinux/hooks/main-warning.inc.php
new file mode 100644
index 00000000..2056bbbf
--- /dev/null
+++ b/modules-available/minilinux/hooks/main-warning.inc.php
@@ -0,0 +1,6 @@
+<?php
+
+if (!file_exists(CONFIG_HTTP_DIR . '/default/kernel') || !file_exists(CONFIG_HTTP_DIR . '/default/initramfs-stage31') || !file_exists(CONFIG_HTTP_DIR . '/default/stage32.sqfs')) {
+ Message::addError('minilinux.please-download-minilinux');
+ $needSetup = true;
+} \ No newline at end of file
diff --git a/modules-available/minilinux/lang/de/messages.json b/modules-available/minilinux/lang/de/messages.json
new file mode 100644
index 00000000..c91772c7
--- /dev/null
+++ b/modules-available/minilinux/lang/de/messages.json
@@ -0,0 +1,3 @@
+{
+ "please-download-minilinux": "Wichtige Dateien der MiniLinux-Installation fehlen."
+} \ No newline at end of file
diff --git a/modules-available/minilinux/lang/en/messages.json b/modules-available/minilinux/lang/en/messages.json
new file mode 100644
index 00000000..8d7fa76d
--- /dev/null
+++ b/modules-available/minilinux/lang/en/messages.json
@@ -0,0 +1,3 @@
+{
+ "please-download-minilinux": "Important files from the mini Linux installation are missing."
+} \ No newline at end of file
diff --git a/modules-available/serversetup/config.json b/modules-available/serversetup-bwlp/config.json
index f2abe27c..f2abe27c 100644
--- a/modules-available/serversetup/config.json
+++ b/modules-available/serversetup-bwlp/config.json
diff --git a/modules-available/serversetup/lang/de/messages.json b/modules-available/serversetup-bwlp/lang/de/messages.json
index cb0b229d..cb0b229d 100644
--- a/modules-available/serversetup/lang/de/messages.json
+++ b/modules-available/serversetup-bwlp/lang/de/messages.json
diff --git a/modules-available/serversetup/lang/de/module.json b/modules-available/serversetup-bwlp/lang/de/module.json
index eb777343..eb777343 100644
--- a/modules-available/serversetup/lang/de/module.json
+++ b/modules-available/serversetup-bwlp/lang/de/module.json
diff --git a/modules-available/serversetup/lang/de/template-tags.json b/modules-available/serversetup-bwlp/lang/de/template-tags.json
index bdbcb1ec..bdbcb1ec 100644
--- a/modules-available/serversetup/lang/de/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/de/template-tags.json
diff --git a/modules-available/serversetup/lang/en/messages.json b/modules-available/serversetup-bwlp/lang/en/messages.json
index d96be232..d96be232 100644
--- a/modules-available/serversetup/lang/en/messages.json
+++ b/modules-available/serversetup-bwlp/lang/en/messages.json
diff --git a/modules-available/serversetup/lang/en/module.json b/modules-available/serversetup-bwlp/lang/en/module.json
index aeea610c..aeea610c 100644
--- a/modules-available/serversetup/lang/en/module.json
+++ b/modules-available/serversetup-bwlp/lang/en/module.json
diff --git a/modules-available/serversetup/lang/en/template-tags.json b/modules-available/serversetup-bwlp/lang/en/template-tags.json
index af22081a..af22081a 100644
--- a/modules-available/serversetup/lang/en/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/en/template-tags.json
diff --git a/modules-available/serversetup/lang/pt/messages.json b/modules-available/serversetup-bwlp/lang/pt/messages.json
index 65745768..65745768 100644
--- a/modules-available/serversetup/lang/pt/messages.json
+++ b/modules-available/serversetup-bwlp/lang/pt/messages.json
diff --git a/modules-available/serversetup/lang/pt/module.json b/modules-available/serversetup-bwlp/lang/pt/module.json
index aeea610c..aeea610c 100644
--- a/modules-available/serversetup/lang/pt/module.json
+++ b/modules-available/serversetup-bwlp/lang/pt/module.json
diff --git a/modules-available/serversetup/lang/pt/template-tags.json b/modules-available/serversetup-bwlp/lang/pt/template-tags.json
index 3120c58c..3120c58c 100644
--- a/modules-available/serversetup/lang/pt/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/pt/template-tags.json
diff --git a/modules-available/serversetup/page.inc.php b/modules-available/serversetup-bwlp/page.inc.php
index c48ccd3d..9a040178 100644
--- a/modules-available/serversetup/page.inc.php
+++ b/modules-available/serversetup-bwlp/page.inc.php
@@ -3,10 +3,10 @@
class Page_ServerSetup extends Page
{
- private $mountIpxeTask;
private $taskStatus;
private $currentAddress;
private $currentMenu;
+ private $hasIpSet = false;
protected function doPreprocess()
{
@@ -19,14 +19,6 @@ class Page_ServerSetup extends Page
$this->currentMenu = Property::getBootMenu();
- if(Request::get('download') !== false){
- $this->downloadIpxe(Request::get('download'));
- }
-
- if(Request::get('defaultIpxe') !== false){
- $this->defaultIpxe(Request::get('defaultIpxe'));
- }
-
$action = Request::post('action');
if ($action === false) {
@@ -44,48 +36,30 @@ class Page_ServerSetup extends Page
// iPXE stuff changes
$this->updatePxeMenu();
}
-
- if($action === 'save-script') {
- // Save new iPXE script
- $this->updateIpxeScript();
- }
-
- if($action === 'default-script') {
- // Restore iPXE script to default
- $this->defaultIpxe();
- }
}
protected function doRender()
{
- Render::setTitle(Dictionary::translate('lang_serverConfiguration'));
$taskid = Request::any('taskid');
if ($taskid !== false && Taskmanager::isTask($taskid)) {
Render::addTemplate('ipxe_update', array('taskid' => $taskid));
}
- if (Request::get('advanced', 'false', 'string') === 'false') {
- Render::addTemplate('ipxe-smp');
- } else {
- Render::addTemplate('ipaddress', array(
- 'ips' => $this->taskStatus['data']['addresses']
- ));
- $data = $this->currentMenu;
- if (!isset($data['defaultentry']))
- $data['defaultentry'] = 'net';
- if ($data['defaultentry'] === 'net')
- $data['active-net'] = 'checked';
- if ($data['defaultentry'] === 'hdd')
- $data['active-hdd'] = 'checked';
- if ($data['defaultentry'] === 'custom')
- $data['active-custom'] = 'checked';
- //There is no $this->username and no pxe.embed, why do we need this?
- //Page won't load with lines below uncommented
- //$data['username'] = $this->username;
- //$data['script'] = file_get_contents("/opt/taskmanager/data/pxe.embed");
- Render::addTemplate('ipxe-adv', $data);
- }
+ Render::addTemplate('ipaddress', array(
+ 'ips' => $this->taskStatus['data']['addresses'],
+ 'chooseHintClass' => $this->hasIpSet ? '' : 'alert alert-danger'
+ ));
+ $data = $this->currentMenu;
+ if (!isset($data['defaultentry']))
+ $data['defaultentry'] = 'net';
+ if ($data['defaultentry'] === 'net')
+ $data['active-net'] = 'checked';
+ if ($data['defaultentry'] === 'hdd')
+ $data['active-hdd'] = 'checked';
+ if ($data['defaultentry'] === 'custom')
+ $data['active-custom'] = 'checked';
+ Render::addTemplate('ipxe', $data);
}
// -----------------------------------------------------------------------------------------------
@@ -112,6 +86,7 @@ class Page_ServerSetup extends Page
}
if ($this->currentAddress === $item['ip']) {
$item['default'] = true;
+ $this->hasIpSet = true;
}
$sortIp[] = $item['ip'];
}
@@ -162,33 +137,4 @@ class Page_ServerSetup extends Page
Util::redirect('?do=ServerSetup&taskid=' . $id);
}
- private function downloadIpxe($ipxe){
- $file = '/opt/taskmanager/data/ipxe/src/bin/ipxe.' . $ipxe;
- if (file_exists($file)) {
- header('Content-Description: File Transfer');
- header('Content-Type: application/octet-stream');
- header('Content-Disposition: attachment; filename='.basename($file));
- header('Expires: 0');
- header('Cache-Control: must-revalidate');
- header('Pragma: public');
- header('Content-Length: ' . filesize($file));
- ob_clean();
- flush();
- readfile($file);
- exit();
- }
- }
-
- private function updateIpxeScript(){
- $newScript = Request::post('custom-script');
- file_put_contents("/opt/taskmanager/data/pxe.embed",$newScript);
- Util::redirect('?do=ServerSetup');
- }
-
- private function defaultIpxe(){
- $default = file_get_contents("/opt/taskmanager/data/pxe_default.embed");
- $default = str_replace("{{ip}}", "http://" . Property::getServerIp(), $default);
- file_put_contents("/opt/taskmanager/data/pxe.embed",$default);
- Util::redirect('?do=ServerSetup');
- }
}
diff --git a/modules-available/serversetup/templates/ipaddress.html b/modules-available/serversetup-bwlp/templates/ipaddress.html
index e4c1fba9..0b3b2ed7 100644
--- a/modules-available/serversetup/templates/ipaddress.html
+++ b/modules-available/serversetup-bwlp/templates/ipaddress.html
@@ -1,12 +1,11 @@
-<a class="btn btn-default" href="?do=Serversetup&amp;advanced=false" role="button"><strong>{{lang_ipxeSmp}}</strong></a></br></br>
<div class="panel panel-default">
<div class="panel-heading">
{{lang_bootAddress}}
</div>
<div class="panel-body">
- <p>
+ <div class="{{chooseHintClass}}">
{{lang_chooseIP}}
- </p>
+ </div>
<form method="post" action="?do=ServerSetup">
<input type="hidden" name="action" value="ip">
<input type="hidden" name="token" value="{{token}}">
@@ -32,4 +31,4 @@
</p>
</form>
</div>
-</div>
+</div> \ No newline at end of file
diff --git a/modules-available/serversetup-bwlp/templates/ipxe.html b/modules-available/serversetup-bwlp/templates/ipxe.html
new file mode 100644
index 00000000..4539624b
--- /dev/null
+++ b/modules-available/serversetup-bwlp/templates/ipxe.html
@@ -0,0 +1,70 @@
+<form method="post" action="?do=ServerSetup">
+ <input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="display:none;">
+ <input type="password" name="password_fake" id="password_fake" value="" style="display:none;">
+ <input type="hidden" name="action" value="ipxe">
+ <input type="hidden" name="token" value="{{token}}">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_bootMenu}}
+ </div>
+ <div class="panel-body">
+ <p>
+ {{lang_bootInfo}}
+ </p>
+ <br>
+
+ <div class="form-group">
+ <strong>{{lang_bootBehavior}}</strong>
+ <div><label class="radio-inline"><input type="radio" name="defaultentry" value="net" {{active-net}}> bwLehrpool</label></div>
+ <div><label class="radio-inline"><input type="radio" name="defaultentry" value="hdd" {{active-hdd}}> {{lang_localHDD}}</label></div>
+ <div><label class="radio-inline"><input type="radio" name="defaultentry" value="custom" {{active-custom}}> {{lang_customEntry}} (&quot;custom&quot;)</label></div>
+ </div>
+
+ <div class="form-group">
+ <strong>{{lang_menuDisplayTime}}</strong>
+ <div class="input-group form-narrow">
+ <input type="text" class="form-control" name="timeout" value="{{timeout}}" pattern="\d+">
+ <span class="input-group-addon">{{lang_seconds}}</span>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <strong>{{lang_masterPassword}}</strong>
+ <div class="form-narrow">
+ <input type="{{password_type}}" class="form-control" name="masterpassword" value="{{masterpasswordclear}}">
+ </div>
+ <i>{{lang_masterPasswordHelp}}</i>
+ </div>
+
+ <div class="form-group">
+ <strong>{{lang_menuCustom}}</strong> <a class="btn btn-default btn-xs" data-toggle="modal" data-target="#help-custom"><span class="glyphicon glyphicon-question-sign"></span></a>
+ <textarea class="form-control" name="custom" rows="8">{{custom}}</textarea>
+ </div>
+ </div>
+
+ <div class="panel-footer">
+ <button class="btn btn-primary" name="action" value="ipxe">{{lang_bootMenuCreate}}</button>
+ </div>
+ </div>
+</form>
+
+<div class="modal fade" id="help-custom" tabindex="-1" role="dialog">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">{{lang_menuCustom}}</div>
+ <div class="modal-body">
+ {{lang_menuCustomHint1}}
+ <br>{{lang_example}}:
+ <pre>LABEL custom
+ MENU LABEL ^My Boot Entry
+ KERNEL http://1.2.3.4/kernel
+ INITRD http://1.2.3.4/initramfs-stage31
+ APPEND custom=option
+ IPAPPEND 3</pre>
+ {{lang_menuCustomHint2}} LABEL <strong>custom</strong>
+ {{lang_menuCustomHint3}}
+ </div>
+ <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
+ </div>
+ </div>
+</div>
diff --git a/modules-available/serversetup/templates/ipxe_update.html b/modules-available/serversetup-bwlp/templates/ipxe_update.html
index 9c598667..9c598667 100644
--- a/modules-available/serversetup/templates/ipxe_update.html
+++ b/modules-available/serversetup-bwlp/templates/ipxe_update.html
diff --git a/modules-available/serversetup/templates/ipxe-adv.html b/modules-available/serversetup/templates/ipxe-adv.html
deleted file mode 100644
index 00e9fd3a..00000000
--- a/modules-available/serversetup/templates/ipxe-adv.html
+++ /dev/null
@@ -1,149 +0,0 @@
-<div class="panel panel-default">
- <div class="panel-heading">
- {{lang_mountIpxe}}
- </div>
- <div class="panel-body">
- <p>{{lang_ipxeInfo}}</p>
- <label for="ext">{{lang_extension}}:</label>
- <select name="ext" class="form-control">
- <option value="kkpxe">.kkpxe</option>
- <option value="usb">.usb</option>
- <option value="iso">.iso</option>
- </select>
- <br>
- <form method="post" action="?do=ServerSetup" style="display:inline;">
- <input type="hidden" name="action" value="save-script">
- <input type="hidden" name="token" value="{{token}}">
-
- <label for="custom-script">{{lang_customScript}}</label>
- <textarea class="form-control" name="custom-script" rows="9" style="resize:none">{{script}}</textarea>
- <br>
- <input class="btn btn-default btn-sm" type="submit" value="{{lang_saveScript}}" />
- </form>
- <form method="post" action="?do=ServerSetup" style="display:inline;">
- <input type="hidden" name="action" value="default-script">
- <input type="hidden" name="token" value="{{token}}">
- <input class="btn btn-default btn-sm" type="submit" value="{{lang_restoreDefault}}" />
- </form>
- </div>
- <div class="panel-footer">
- <button id="mount-button" onclick="mountIpxe();" class="btn btn-primary" type="button" data-toggle="modal" data-target="#ipxe-modal" data-backdrop="static"> {{lang_compile}}
- </button>
- </div>
-</div>
-
-<form method="post" action="?do=ServerSetup">
- <input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="display:none;">
- <input type="password" name="password_fake" id="password_fake" value="" style="display:none;">
- <input type="hidden" name="action" value="ipxe">
- <input type="hidden" name="token" value="{{token}}">
- <div class="panel panel-default">
- <div class="panel-heading">
- {{lang_bootMenu}}
- </div>
- <div class="panel-body">
- <p>
- {{lang_bootInfo}}
- </p>
- <br>
-
- <div class="form-group">
- <strong>{{lang_bootBehavior}}</strong>
- <div><label class="radio-inline"><input type="radio" name="defaultentry" value="net" {{active-net}}> bwLehrpool</label></div>
- <div><label class="radio-inline"><input type="radio" name="defaultentry" value="hdd" {{active-hdd}}> {{lang_localHDD}}</label></div>
- <div><label class="radio-inline"><input type="radio" name="defaultentry" value="custom" {{active-custom}}> {{lang_customEntry}} (&quot;custom&quot;)</label></div>
- </div>
-
- <div class="form-group">
- <strong>{{lang_menuDisplayTime}}</strong>
- <div class="input-group form-narrow">
- <input type="text" class="form-control" name="timeout" value="{{timeout}}" pattern="\d+">
- <span class="input-group-addon">{{lang_seconds}}</span>
- </div>
- </div>
-
- <div class="form-group">
- <strong>{{lang_masterPassword}}</strong>
- <div class="form-narrow">
- <input type="{{password_type}}" class="form-control" name="masterpassword" value="{{masterpasswordclear}}">
- </div>
- <i>{{lang_masterPasswordHelp}}</i>
- </div>
-
- <div class="form-group">
- <strong>{{lang_menuCustom}}</strong> <a class="btn btn-default btn-xs" data-toggle="modal" data-target="#help-custom"><span class="glyphicon glyphicon-question-sign"></span></a>
- <textarea class="form-control" name="custom" rows="8">{{custom}}</textarea>
- </div>
- </div>
-
- <div class="panel-footer">
- <button class="btn btn-primary" name="action" value="ipxe">{{lang_bootMenuCreate}}</button>
- </div>
- </div>
-</form>
-
-<div class="modal fade" id="help-custom" tabindex="-1" role="dialog">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">{{lang_menuCustom}}</div>
- <div class="modal-body">
- {{lang_menuCustomHint1}}
- <br>{{lang_example}}:
- <pre>LABEL custom
- MENU LABEL ^My Boot Entry
- KERNEL http://1.2.3.4/kernel
- INITRD http://1.2.3.4/initramfs-stage31
- APPEND custom=option
- IPAPPEND 3</pre>
- {{lang_menuCustomHint2}} LABEL <strong>custom</strong>
- {{lang_menuCustomHint3}}
- </div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
- </div>
- </div>
-</div>
-
-<div class="modal fade" id="ipxe-modal" tabindex="-1" role="dialog" aria-labelledby="ipxe-modal-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
- <h4 class="modal-title" id="ipxe-modal-label">{{lang_compilingIpxe}}</h4>
- </div>
- <div class="modal-body" id="ipxe-modal-body">
-
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
- <button id="download-btn" type="button" class="btn btn-primary" disabled="disabled" onclick="downloadIpxe()">{{lang_download}}</button>
- </div>
- </div>
- </div>
-</div>
-
-<script>
- function mountIpxe() {
- document.getElementById('ipxe-modal-body').innerHTML = "<div class='alert alert-info' role='alert'>{{lang_ipxeWarning}}</div>"
- + "{{lang_loading}} <img src='fonts/loader.gif'/>";
- $("#download-btn").prop("disabled",true);
- var xmlhttp = new XMLHttpRequest();
- var extension = $("select[name=ext]").val();
- xmlhttp.open("GET","?do=ServerSetup&async=true&submitTask=true&extension=" + extension,true);
- xmlhttp.onreadystatechange= function() {
- if (xmlhttp.readyState==4 && xmlhttp.status==200) {
- var initResponse = xmlhttp.responseText;
- if(initResponse != "success")
- document.getElementById('ipxe-modal-body').innerHTML = initResponse;
- else {
- document.getElementById('ipxe-modal-body').innerHTML = "{{lang_success}}: ipxe." + extension;
- $("#download-btn").prop("disabled",false);
- }
- }
- }
- xmlhttp.send();
- }
-
- function downloadIpxe() {
- window.location = "?do=ServerSetup&download=" + $("select[name=ext]").val();
- }
-</script>
diff --git a/modules-available/serversetup/templates/ipxe-smp.html b/modules-available/serversetup/templates/ipxe-smp.html
deleted file mode 100644
index d126710c..00000000
--- a/modules-available/serversetup/templates/ipxe-smp.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<a class="btn btn-default" href="?do=Serversetup&amp;advanced=true" role="button"><strong>{{lang_ipxeAdv}}</strong></a></br></br>
-<div class="panel panel-default">
- <div class="panel-heading">
- {{lang_mountIpxe}}
- </div>
- <div class="panel-body">
- <p>{{lang_ipxeSmpInfo}}</p>
- <button id="mount-button" onclick="mountIpxe('iso');" class="btn btn-primary" type="button" data-toggle="modal" data-target="#ipxe-modal" data-backdrop="static"> {{lang_compileIso}}
- </button>
- <button id="mount-button" onclick="mountIpxe('usb');" class="btn btn-primary" type="button" data-toggle="modal" data-target="#ipxe-modal" data-backdrop="static"> {{lang_compileUsb}}
- </button>
- <br>
- </div>
-</div>
-
-
-<div class="modal fade" id="ipxe-modal" tabindex="-1" role="dialog" aria-labelledby="ipxe-modal-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
- <h4 class="modal-title" id="ipxe-modal-label">{{lang_compilingIpxe}}</h4>
- </div>
- <div class="modal-body" id="ipxe-modal-body">
-
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
- <button id="download-btn" type="button" class="btn btn-primary" disabled="disabled" onclick="downloadIpxe()">{{lang_download}}</button>
- </div>
- </div>
- </div>
-</div>
-
-<script>
- function mountIpxe(extension) {
- document.getElementById('ipxe-modal-body').innerHTML = "<div class='alert alert-info' role='alert'>{{lang_ipxeWarning}}</div>"
- + "{{lang_loading}} <img src='fonts/loader.gif'/>";
- $("#download-btn").prop("disabled",true);
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open("GET","?do=ServerSetup&async=true&submitTask=true&extension=" + extension,true);
- xmlhttp.onreadystatechange= function() {
- if (xmlhttp.readyState==4 && xmlhttp.status==200) {
- var initResponse = xmlhttp.responseText;
- if(initResponse != "success")
- document.getElementById('ipxe-modal-body').innerHTML = initResponse;
- else {
- document.getElementById('ipxe-modal-body').innerHTML = "{{lang_success}}: ipxe." + extension;
- document.getElementById('download-btn').setAttribute('onclick','downloadIpxe(\''+extension+'\')');
- $("#download-btn").prop("disabled",false);
- }
- }
- }
- xmlhttp.send();
- }
-
- function downloadIpxe(extension) {
- console.log("TESTE");
- console.log(extension);
- window.location = "?do=ServerSetup&download=" + extension;
- }
-</script>
diff --git a/modules-available/statistics/config.json b/modules-available/statistics/config.json
index b0123727..ab71ddbd 100644
--- a/modules-available/statistics/config.json
+++ b/modules-available/statistics/config.json
@@ -1,5 +1,5 @@
{
"category":"main.status",
- "enabled":"true",
+ "dependencies": [ "js_chart" ],
"permission":"0"
}
diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php
index f21f0db9..a896b7a6 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -49,7 +49,6 @@ class Page_Statistics extends Page
$this->showMachineList($filter, $argument);
return;
}
- Render::addScriptBottom('chart.min');
Render::openTag('div', array('class' => 'row'));
$this->showSummary();
$this->showMemory();
@@ -548,7 +547,6 @@ class Page_Statistics extends Page
Render::addTemplate('machine-usage', $spans);
// Any hdds?
if (!empty($hdds['hdds'])) {
- Render::addScriptBottom('chart.min');
Render::addTemplate('machine-hdds', $hdds);
}
// Client log
diff --git a/modules-available/sysconfig/addmodule_branding.inc.php b/modules-available/sysconfig/addmodule_branding.inc.php
index cb5609e6..84602614 100644
--- a/modules-available/sysconfig/addmodule_branding.inc.php
+++ b/modules-available/sysconfig/addmodule_branding.inc.php
@@ -9,7 +9,6 @@ class Branding_Start extends AddModule_Base
protected function renderInternal()
{
- Render::addScriptBottom('fileselect');
Render::addDialog(Dictionary::translate('config-module', 'branding_title'), false, 'branding-start', array(
'step' => 'Branding_ProcessFile',
'edit' => $this->edit ? $this->edit->id() : false
diff --git a/modules-available/sysconfig/addmodule_custommodule.inc.php b/modules-available/sysconfig/addmodule_custommodule.inc.php
index d08cc5fb..3f112c95 100644
--- a/modules-available/sysconfig/addmodule_custommodule.inc.php
+++ b/modules-available/sysconfig/addmodule_custommodule.inc.php
@@ -12,7 +12,6 @@ class CustomModule_Start extends AddModule_Base
protected function renderInternal()
{
Session::set('mod_temp', false);
- Render::addScriptBottom('fileselect');
Render::addDialog(Dictionary::translate('config-module', 'custom_title'), false, 'custom-upload', array(
'step' => 'CustomModule_ProcessUpload',
'edit' => $this->edit ? $this->edit->id() : false
diff --git a/modules-available/sysconfig/clientscript.js b/modules-available/sysconfig/clientscript.js
new file mode 100644
index 00000000..2a133353
--- /dev/null
+++ b/modules-available/sysconfig/clientscript.js
@@ -0,0 +1,21 @@
+
+function forceTable(t)
+{
+ var pwidth = t.parent().innerWidth();
+ var rows = t.find('tr');
+ var row = rows.first();
+ pwidth = Math.round(pwidth);
+ t.width(pwidth);
+ var sum = 0;
+ row.find('td').each(function() {
+ if (!$(this).hasClass('slx-width-ignore'))
+ sum += $(this).outerWidth(true);
+ });
+ var w = Math.round(pwidth - sum);
+ do {
+ rows.find('.slx-dyn-ellipsis').each(function() {
+ $(this).width(w).css('width', w + 'px').css('max-width', w + 'px');
+ });
+ w -= 3;
+ } while (t.width() > pwidth);
+}
diff --git a/modules-available/sysconfig/hooks/main-warning.inc.php b/modules-available/sysconfig/hooks/main-warning.inc.php
new file mode 100644
index 00000000..e5bc592f
--- /dev/null
+++ b/modules-available/sysconfig/hooks/main-warning.inc.php
@@ -0,0 +1,6 @@
+<?php
+
+if (!file_exists(CONFIG_HTTP_DIR . '/default/config.tgz')) {
+ Message::addError('sysconfig.no-noconfig-active', true);
+ $needSetup = true;
+} \ No newline at end of file
diff --git a/modules-available/sysconfig/inc/configmodule.inc.php b/modules-available/sysconfig/inc/configmodule.inc.php
index 7b92ff89..9fc3db21 100644
--- a/modules-available/sysconfig/inc/configmodule.inc.php
+++ b/modules-available/sysconfig/inc/configmodule.inc.php
@@ -118,7 +118,7 @@ abstract class ConfigModule
* Get module instances from module type.
*
* @param int $moduleType module type to get
- * @return array The requested modules from DB, or false on error
+ * @return \ConfigModule[] The requested modules from DB, or false on error
*/
public static function getAll($moduleType = false)
{
diff --git a/modules-available/sysconfig/lang/de/messages.json b/modules-available/sysconfig/lang/de/messages.json
index 7993babd..e6203d3d 100644
--- a/modules-available/sysconfig/lang/de/messages.json
+++ b/modules-available/sysconfig/lang/de/messages.json
@@ -1,20 +1,21 @@
{
+ "config-activated": "Konfiguration {{0}} wurde aktiviert",
+ "config-invalid": "Konfiguration mit ID {{0}} existiert nicht",
"invalid-action": "Ung\u00fcltige Aktion: {{0}}",
+ "missing-file": "Es wurde keine Datei ausgew\u00e4hlt!",
"missing-title": "Kein Titel eingegeben",
- "module-edited": "Modul wurde aktualisiert",
"module-added": "Modul erfolgreich hinzugef\u00fcgt",
- "replacing-config": "Ersetzen von Konfiguration {{0}}",
- "missing-file": "Es wurde keine Datei ausgew\u00e4hlt!",
- "unsuccessful-action": "Nicht erfolgreich",
- "upload-failed": "Upload schlug fehl: {{0}}",
- "remote-timeout": "Konnte Ressource {{0}} nicht herunterladen ({{1}})",
- "no-image": "Unter der angegebenen URL konnte kein SVG-Bild gefunden werden",
- "replacing-module": "Ersetzen von Modul {{0}}",
- "config-invalid": "Konfiguration mit ID {{0}} existiert nicht",
- "config-activated": "Konfiguration {{0}} wurde aktiviert",
- "module-rebuilt": "Modul wurde neu generiert",
+ "module-deleted": "Modul {{0}} wurde gel\u00f6scht",
+ "module-edited": "Modul wurde aktualisiert",
+ "module-in-use": "Modul {{0}} wird noch durch Konfiguration {{1}} verwendet",
"module-rebuild-failed": "Neubau des Moduls fehlgeschlagen",
"module-rebuilding": "Modul wird neu generiert",
- "module-in-use": "Modul {{0}} wird noch durch Konfiguration {{1}} verwendet",
- "module-deleted": "Modul {{0}} wurde gel\u00f6scht"
+ "module-rebuilt": "Modul wurde neu generiert",
+ "no-image": "Unter der angegebenen URL konnte kein SVG-Bild gefunden werden",
+ "no-noconfig-active": "Es wurde noch keine Systemkonfiguration ausgew\u00e4hlt.",
+ "remote-timeout": "Konnte Ressource {{0}} nicht herunterladen ({{1}})",
+ "replacing-config": "Ersetzen von Konfiguration {{0}}",
+ "replacing-module": "Ersetzen von Modul {{0}}",
+ "unsuccessful-action": "Nicht erfolgreich",
+ "upload-failed": "Upload schlug fehl: {{0}}"
} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/en/messages.json b/modules-available/sysconfig/lang/en/messages.json
index fc3c1160..a4aa8dc1 100644
--- a/modules-available/sysconfig/lang/en/messages.json
+++ b/modules-available/sysconfig/lang/en/messages.json
@@ -1,20 +1,21 @@
{
+ "config-activated": "Configuration {{0}} has been activated",
+ "config-invalid": "Configuration with id {{0}} does not exist",
"invalid-action": "Invalid action: {{0}}",
+ "missing-file": "There was no file selected!",
"missing-title": "No title given",
- "module-edited": "Module has been edited",
"module-added": "Module successfully added",
- "replacing-config": "Replace config {{0}}",
- "missing-file": "There was no file selected!",
- "unsuccessful-action": "Not successful",
- "upload-failed": "Upload failed: {{0}}",
- "remote-timeout": "Could not download resource {{0}} ({{1}})",
- "no-image": "Could not find an SVG-image at the given URL",
- "replacing-module": "Replace module {{0}}",
- "config-invalid": "Configuration with id {{0}} does not exist",
- "config-activated": "Configuration {{0}} has been activated",
- "module-rebuilt": "Module was rebuilt",
+ "module-deleted": "Module {{0}} was deleted",
+ "module-edited": "Module has been edited",
+ "module-in-use": "Module {{0}} is still used by Configuration {{1}}",
"module-rebuild-failed": "Rebuilding module failed",
"module-rebuilding": "Module is rebuilding...",
- "module-in-use": "Module {{0}} is still used by Configuration {{1}}",
- "module-deleted": "Module {{0}} was deleted"
+ "module-rebuilt": "Module was rebuilt",
+ "no-image": "Could not find an SVG-image at the given URL",
+ "no-noconfig-active": "No system configuration created\/selected yet.",
+ "remote-timeout": "Could not download resource {{0}} ({{1}})",
+ "replacing-config": "Replace config {{0}}",
+ "replacing-module": "Replace module {{0}}",
+ "unsuccessful-action": "Not successful",
+ "upload-failed": "Upload failed: {{0}}"
} \ No newline at end of file
diff --git a/modules-available/sysconfig/page.inc.php b/modules-available/sysconfig/page.inc.php
index 3f14a95d..efe34136 100644
--- a/modules-available/sysconfig/page.inc.php
+++ b/modules-available/sysconfig/page.inc.php
@@ -175,7 +175,6 @@ class Page_SysConfig extends Page
'modules' => $modules,
'havemodules' => (count($modules) > 0)
));
- Render::addScriptTop('custom');
Render::addFooter('<script> $(window).load(function (e) {
forceTable($("#modtable"));
forceTable($("#conftable"));
diff --git a/modules-available/syslog/clientscript.js b/modules-available/syslog/clientscript.js
new file mode 100644
index 00000000..3d652628
--- /dev/null
+++ b/modules-available/syslog/clientscript.js
@@ -0,0 +1,8 @@
+/*
+ * bootstrap-tagsinput v0.3.9 by Tim Schlechter
+ *
+ */
+!function(a){"use strict";function b(b,c){this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('<div class="bootstrap-tagsinput"></div>'),this.$input=a('<input size="'+this.inputSize+'" type="text" placeholder="'+this.placeholderText+'"/>').appendTo(this.$container),this.$element.after(this.$container),this.build(c)}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?h.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}var g={tagClass:function(){return"label label-info"},itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},freeInput:!0,maxTags:void 0,confirmKeys:[13],onTagExists:function(a,b){b.hide().fadeIn()}};b.prototype={constructor:b,add:function(b,c){var d=this;if(!(d.options.maxTags&&d.itemsArray.length>=d.options.maxTags||b!==!1&&!b)){if("object"==typeof b&&!d.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(d.isSelect&&!d.multiple&&d.itemsArray.length>0&&d.remove(d.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var f=b.split(",");if(f.length>1){for(var g=0;g<f.length;g++)this.add(f[g],!0);return c||d.pushVal(),void 0}}var h=d.options.itemValue(b),i=d.options.itemText(b),j=d.options.tagClass(b),k=a.grep(d.itemsArray,function(a){return d.options.itemValue(a)===h})[0];if(k){if(d.options.onTagExists){var l=a(".tag",d.$container).filter(function(){return a(this).data("item")===k});d.options.onTagExists(b,l)}}else{d.itemsArray.push(b);var m=a('<span class="tag '+e(j)+'">'+e(i)+'<span data-role="remove"></span></span>');if(m.data("item",b),d.findInputWrapper().before(m),m.after(" "),d.isSelect&&!a('option[value="'+escape(h)+'"]',d.$element)[0]){var n=a("<option selected>"+e(i)+"</option>");n.data("item",b),n.attr("value",h),d.$element.append(n)}c||d.pushVal(),d.options.maxTags===d.itemsArray.length&&d.$container.addClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemAdded",{item:b}))}}}},remove:function(b,c){var d=this;d.objectItems&&(b="object"==typeof b?a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==d.options.itemValue(b)})[0]:a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==b})[0]),b&&(a(".tag",d.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",d.$element).filter(function(){return a(this).data("item")===b}).remove(),d.itemsArray.splice(a.inArray(b,d.itemsArray),1)),c||d.pushVal(),d.options.maxTags>d.itemsArray.length&&d.$container.removeClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemRemoved",{item:b}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(),b.options.maxTags&&!this.isEnabled()&&this.enable()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;e.options=a.extend({},g,b);var h=e.options.typeahead||{};e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),c(e.options,"tagClass"),e.options.source&&(h.source=e.options.source),h.source&&a.fn.typeahead&&(d(h,"source"),e.$input.typeahead({source:function(b,c){function d(a){for(var b=[],d=0;d<a.length;d++){var g=e.options.itemText(a[d]);f[g]=a[d],b.push(g)}c(b)}this.map={};var f=this.map,g=h.source(b);a.isFunction(g.success)?g.success(d):a.when(g).then(d)},updater:function(a){e.add(this.map[a])},matcher:function(a){return-1!==a.toLowerCase().indexOf(this.query.trim().toLowerCase())},sorter:function(a){return a.sort()},highlighter:function(a){var b=new RegExp("("+this.query+")","gi");return a.replace(b,"<strong>$1</strong>")}})),e.$container.on("click",a.proxy(function(){e.$input.focus()},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus());break;default:e.options.freeInput&&a.inArray(b.which,e.options.confirmKeys)>=0&&(e.add(c.val()),c.val(""),b.preventDefault())}c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===g.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d){var e=[];return this.each(function(){var f=a(this).data("tagsinput");if(f){var g=f[c](d);void 0!==g&&e.push(g)}else f=new b(this,c),a(this).data("tagsinput",f),e.push(f),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?e.length>1?e:e[0]:e},a.fn.tagsinput.Constructor=b;var h=a("<div />");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
+/*
+//@ sourceMappingURL=bootstrap-tagsinput.min.js.map
+*/ \ No newline at end of file
diff --git a/modules-available/syslog/page.inc.php b/modules-available/syslog/page.inc.php
index ea73d1b9..486e0248 100644
--- a/modules-available/syslog/page.inc.php
+++ b/modules-available/syslog/page.inc.php
@@ -15,9 +15,6 @@ class Page_SysLog extends Page
protected function doRender()
{
- Render::setTitle('Client Log');
- Render::addScriptBottom('bootstrap-tagsinput.min');
-
if (isset($_GET['filter'])) {
$filter = $_GET['filter'];
$not = isset($_GET['not']) ? 'NOT' : '';
diff --git a/modules-available/syslog/style.css b/modules-available/syslog/style.css
new file mode 100644
index 00000000..98cfa7f3
--- /dev/null
+++ b/modules-available/syslog/style.css
@@ -0,0 +1,45 @@
+.bootstrap-tagsinput {
+ background-color: #fff;
+ border: 1px solid #ccc;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ display: inline-block;
+ padding: 4px 6px;
+ margin-bottom: 10px;
+ color: #555;
+ vertical-align: middle;
+ border-radius: 4px;
+ max-width: 100%;
+ line-height: 22px;
+}
+.bootstrap-tagsinput input {
+ border: none;
+ box-shadow: none;
+ outline: none;
+ background-color: transparent;
+ padding: 0;
+ margin: 0;
+ width: auto !important;
+ max-width: inherit;
+}
+.bootstrap-tagsinput input:focus {
+ border: none;
+ box-shadow: none;
+}
+.bootstrap-tagsinput .tag {
+ margin-right: 2px;
+ color: white;
+}
+.bootstrap-tagsinput .tag [data-role="remove"] {
+ margin-left: 8px;
+ cursor: pointer;
+}
+.bootstrap-tagsinput .tag [data-role="remove"]:after {
+ content: "x";
+ padding: 0px 2px;
+}
+.bootstrap-tagsinput .tag [data-role="remove"]:hover {
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
diff --git a/modules-available/systemstatus/config.json b/modules-available/systemstatus/config.json
index 650ab2fe..e78484d8 100644
--- a/modules-available/systemstatus/config.json
+++ b/modules-available/systemstatus/config.json
@@ -1,4 +1,5 @@
{
"category":"main.status",
- "enabled":"true"
+ "enabled":"true",
+ "dependencies": [ "js_circles" ]
}
diff --git a/modules-available/systemstatus/page.inc.php b/modules-available/systemstatus/page.inc.php
index 9f892957..cf80d1cc 100644
--- a/modules-available/systemstatus/page.inc.php
+++ b/modules-available/systemstatus/page.inc.php
@@ -29,8 +29,6 @@ class Page_SystemStatus extends Page
if (is_array($this->rebootTask) && isset($this->rebootTask['id'])) {
$data['rebootTask'] = $this->rebootTask['id'];
}
- Render::addScriptTop('custom');
- Render::addScriptBottom('circles.min');
Render::addTemplate('_page', $data);
}
@@ -184,7 +182,7 @@ class Page_SystemStatus extends Page
'uptime' => '???'
);
if (preg_match('/^(\d+)\D/', $uptime, $out)) {
- $data['uptime'] = floor($out[1] / 86400) . ' ' . Dictionary::translate('lang_days') . ', ' . floor(($out[1] % 86400) / 3600) . ' ' . Dictionary::translate('lang_hours'); // TODO: i18n
+ $data['uptime'] = floor($out[1] / 86400) . ' ' . Dictionary::translate('lang_days') . ', ' . floor(($out[1] % 86400) / 3600) . ' ' . Dictionary::translate('lang_hours');
}
$info = $this->sysInfo();
if (isset($info['MemTotal']) && isset($info['MemFree']) && isset($info['SwapTotal'])) {
diff --git a/modules-available/translation/page.inc.php b/modules-available/translation/page.inc.php
index 1fc3a0fe..5b2d24e1 100644
--- a/modules-available/translation/page.inc.php
+++ b/modules-available/translation/page.inc.php
@@ -721,6 +721,9 @@ class Page_Translation extends Page
$depth--;
}
}
+ // QnD special case for Message::add* using true as second param to add "go to" link.
+ if (preg_match('/^\s*,\s*true\b/i', $str))
+ return $count - 1;
return $count;
}
diff --git a/modules-available/vmstore/hooks/main-warning.inc.php b/modules-available/vmstore/hooks/main-warning.inc.php
new file mode 100644
index 00000000..ca2d1382
--- /dev/null
+++ b/modules-available/vmstore/hooks/main-warning.inc.php
@@ -0,0 +1,10 @@
+<?php
+
+/*
+ * Hook for main page: Show warning if vmstore not configured yet; set "warning" flag if so
+ */
+
+if (!is_array(Property::getVmStoreConfig())) {
+ Message::addError('vmstore.vmstore-not-configured', true); // Always specify module prefix since this is running in main
+ $needSetup = true; // Set $needSetup to true if you want a warning badge to appear in the menu
+}
diff --git a/modules-available/vmstore/lang/de/messages.json b/modules-available/vmstore/lang/de/messages.json
new file mode 100644
index 00000000..993d355d
--- /dev/null
+++ b/modules-available/vmstore/lang/de/messages.json
@@ -0,0 +1,3 @@
+{
+ "vmstore-not-configured": "Es ist noch kein Speicherort f\u00fcr die Virtuellen Maschinen festgelegt."
+} \ No newline at end of file
diff --git a/modules-available/vmstore/lang/en/messages.json b/modules-available/vmstore/lang/en/messages.json
new file mode 100644
index 00000000..9ac360eb
--- /dev/null
+++ b/modules-available/vmstore/lang/en/messages.json
@@ -0,0 +1,3 @@
+{
+ "vmstore-not-configured": "A location for the virtual machine is not set yet."
+} \ No newline at end of file