When trying to construct a head model for MRI studies, I did some experiments with coconuts.
Here are some images using BrainVisa/Anatomist for display of the acquisitions from a coconut still half full of juice.
When trying to construct a head model for MRI studies, I did some experiments with coconuts.
Here are some images using BrainVisa/Anatomist for display of the acquisitions from a coconut still half full of juice.
WordPress is used for a small website in my workplace. The server must use a proxy to connect to the web, and this is necessary for many plugins and for updates.
As explained in the documentation, the proxy is declared in wp-config.php
define('WP_PROXY_HOST', 'myCache.fr'); define('WP_PROXY_PORT', '3128');
Since 3.8.1, the Dashboard does not show any update available (even if now 3.9.1 is out). No error message is displayed either.
I had to run wireshark to see what was happening :
It seems that the proxy does not support HTTPS POST requests. So I had to find where the https URL was defined in WordPress. It turns out it is in wp-includes/update.php. But the URLs are defined as http, and the following code is used (in three different places) to convert it to https if ssl is available :
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) $url = set_url_scheme( $url, 'https' );
I thus commented those :
/**if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) $url = set_url_scheme( $url, 'https' );*/
And I could update the server. Of course, I will have to do that again after each update…
Five years ago I made backups of my data to three hard drives. When my desktop died, I used a small laptop where I could not copy the 1+Tb of data stored on the backups.
Last week, I tried to copy back all the data from my laptop and the old data from my Backups onto a new computer.
Of the three backup disks, one was completely dead (it did not even power up), the second one worked but contained only a partial backup (it was a smaller disk), and the last one was apparently unreadable.
When this disk was plugged in, ‘dmesg’ was printing ‘Read errors’ all over the place, and Linux did not detect any partition on the disk. I thought I had lost 1Tb of data…
Then I found this, this and this.
And here is how I got almost everything back :
[200135.764454] Buffer I/O error on device sdi, logical block 9464 [200160.490454] sd 9:0:0:0: [sdi] Unhandled sense code [200160.490457] sd 9:0:0:0: [sdi] [200160.490458] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [200160.490460] sd 9:0:0:0: [sdi] [200160.490461] Sense Key : Medium Error [current] [200160.490463] sd 9:0:0:0: [sdi] [200160.490465] Add. Sense: Data phase error [200160.490466] sd 9:0:0:0: [sdi] CDB: [200160.490467] Read(10): 28 00 00 01 27 c0 00 00 08 00 [200160.490472] end_request: I/O error, dev sdi, sector 75712
sudo dd if=/dev/sdi of=/home/myself/backupdisk.bin conv=noerror,sync
testdisk /home/myself/backupdisk.bin
sudo fdisk -lu /home/myself/backupdisk.bin Disk /home/myself/backupdisk.bin: 1000.2 GB, 1000204886016 bytes 255 têtes, 63 secteurs/piste, 121601 cylindres, total 1953525168 secteurs Unités = secteurs de 1 * 512 = 512 octets Taille de secteur (logique / physique) : 512 octets / 512 octets taille d'E/S (minimale / optimale) : 512 octets / 512 octets Identifiant de disque : 0x00000000 Périphérique Amorçage Début Fin Blocs Id. Système /home/myself/backupdisk.bin1 * 63 1953520064 976760001 83 Linux
sudo losetup -o 32256 /dev/loop0 /home/myself/backupdisk.bin
sudo fsck -y /dev/loop0 # This ends with : /dev/loop0: ***** FILE SYSTEM WAS MODIFIED ***** /dev/loop0 : 968660/122109952 files (3.9% non contiguous), 234454083/244190000 blocks
sudo mkdir /mnt/backupdisk sudo mount /dev/loop0 /mnt/backupdisk
sudo umount /mnt/backupdisk
sudo losetup -d /dev/loop0
Around 2010, while developping MRI sequences for brain imaging, we used an pineapple to test the effect of some parameters on the images.
Here are some images rendered with Anatomist (from a Philips 3 Tesla scanner). Most are T1-weighted 3D sequences, the most beautiful ones are T2 2D multi-slices sequences
[To be translated…]
Before each election in France, the largest political parties call for “tactical voting” (‘vote utile’, litterally ‘useful vote’) in the first round of our two-round elections to avoid a risk, e.g. the left being removed for the second round (like in Presidential elections of 2002 which saw a right/far-right second round) or the election of the left with a right majority as the vote is split between multiple right-wind candidates. The good citizen should thus vote for the main party of its side of the political spectrum.
Lastly in the 2014 local elections, the same idea took the form of “republican withdrawal” mostly defended by the parti socialiste : if the far right might win in the second round against a right-wing and a left-wing candidate (with just 34% of votes), the least successful in the first round should withdraw and ask voters to vote for the other. This idea was not really successful as it was not accepted by UMP (main right-wing party), so PS withdrew in favor of UMP when they had the lowest score, not the other way around.
Thus, largest political parties are blackmailing citizens : if you don’t vote for us, you may get the worst (far-right). How strange for the very idea of democracy ! Voters wouldn’t be free to vote for the party they like the most, but should feel responsible enough to support the major parties as a lesser evil. So “voting against” instead of “voting for”. Where is this coming from ?
In the current voting system (in France) if there are two left-wing candidates L1 and L2, a right-wing one R and a far-right one FR in the second round, if the results are 25.9%(L1), 26.1%(L2), 21%(R), 27%(FR), far-right will govern, despite the fact that 52% of voters wanted a left-wing candidate !
The solution is simple : changing the voting system !
There are numerous voting systems which don’t have this problem. I’ll present only one here : Instant run-off voting.
So, allowing voters to rank candidates allows a free expression of voters’opinion, without the fear of having cast a “wasted vote”, a vote without any influence on the choice of the winner because their preferred option lost the election.
It is of course possible to add a blank vote in the list, to express disatisfaction with all candidates, but to follow it by you ranking of the candidates, thus giving your voice for the “least bad”.
If there are solutions, why are they not implemented ? In fact they have been in many countries (Australia, New Zealand, Ireland, India…).
The main beneficiaries of the current system are the largest parties (PS and UMP in France), so it would be suprising that their members risk changing what works for them : they want to keep their seats in the Parliament (where they are dominant thanks to the voting system)
And that’s how you convert the diversity of opinions in a two-party system !
As a conclusion, here is a relevant excerpt of The Hitchiker’s Guide to the Galaxy by Douglas Adams :
On its world, the people are people. The leaders are lizards. The people hate the lizards and the lizards rule the people.”
“Odd,” said Arthur, “I thought you said it was a democracy.”
“I did,” said Ford. “It is.”
“So,” said Arthur,[…] “why don’t people get rid of the lizards?”
“It honestly doesn’t occur to them,” said Ford. “They’ve all got the vote, so they all pretty much assume that the government they’ve voted in more or less approximates to the government they want.”
“You mean they actually vote for the lizards?”
“Oh yes,” said Ford with a shrug, “of course.”
“But,” said Arthur,[…] “why?”
“Because if they didn’t vote for a lizard,” said Ford, “the wrong lizard might get in.
At last, I put online a web version of PyVotons!.
It is alpha software, not easy to run, lacking a lot of features.
You should read the Documentation page before trying to install it.
You need Python and python-openssl, on a system running on GNU/Linux.
Here it is :
Relatively easy thing to do, but I will keep this here if I need to do it again someday… Here is the code of a small bash script used to do that (not optimal, I know). But first, to get things started :
# Create a backup user to get read access to the database
mysql -u root -p
mysql> GRANT SELECT,RELOAD,LOCK TABLES ON *.* TO ‘backup_user’@’localhost’;
# Add the root user to the mysql group (as cron jobs run as root)
sudo usermod -a -G mysql root
# Allows read access to users of the mysql group for the directories of mysql data files
sudo find /var/lib/mysql -maxdepth 1 -type d -exec chmod g+r \{\} \;
# List all databases
mysql -u backup_user -B -e ‘show databases;’
# Backup one database
mysqlhotcopy -u backup_user databaseName /TheBackupDir/
# Backup all databases -> this does not work as some databases listed do not really exist !
for i in `mysql -u backup_user -B -e ‘show databases;’`; do echo $i; mysqlhotcopy -u backup_user “$i” /TheBackupDir/ ; done
On the samba share, create a directory WebServerBackup and in this directory, an empty file autoBackup to allow the script to confirm that the right directory is mounted before backing the database to it.
The samba share used here does not need a username or password, but adding user=”myuser”,password=”mypassword” to the list of options when mounting the share should work nicely in other cases.
The /var/www dir will be saved as is (no old versions) in the same directory and kept syncrhonized by rsync. A log will be written in /var/log/backup.log
Here is the script itself :
#!/bin/bash echo >> /var/log/backup.log echo >> /var/log/backup.log day=$(date +%d-%m-%Y_%Hh%M) # List of databases to backup. Unfortunately, # mysql -u backup_user -B -e 'show databases;' # lists system databases that cannot be saved. Using manual list instead in the for loop echo "-------------------------------------------------" >> /var/log/backup.log echo "Beginning WebServer Backup -> Launching backupWebsite.sh" >> /var/log/backup.log date -R >> /var/log/backup.log mount -t cifs -o iocharset=utf8,file_mode=0777,dir_mode=0777 //MySambaServer/MySambaShare /backupDisk if [ -f "/backupDisk/WebServerBackup/autoBackup" ] then rsync -rltp --del --stats /var/www /backupDisk/WebServerBackup/www >> /var/log/backup.log # --del mkdir "/backupDisk/WebServerBackup/mysql_$day" # Backup all databases for i in 'mybase' 'wordpress' 'mysql'; do echo $i; mysqlhotcopy -u backup_user "$i" "/backupDisk/WebServerBackup/mysql_$day" >> /var/log/backup.log ; done # Remove the old database backups (more than 30 days) find /backupDisk/WebServerBackup -maxdepth 1 -type d -name "mysql_*" -mtime +30 -exec rm -rf \{\} \; else echo "Echec du montage ! ***Pas de sauvegarde du serveur web !***" >> /var/log/backup.log fi umount /backupDisk echo "WebServer BACKUP FINISHED (in //MySambaServer/MySambaShare/WebServerBackup )" >> /var/log/backup.log date -R >> /var/log/backup.log echo "**************************************************" >> /var/log/backup.log
Finally, the script (executable, thanks to a sudo chmod a+x /usr/bin/backupWebsite.sh) is linked to from the directory /etc/cron.daily/ so it will launch automatically once a day. The .sh is removed in the link name as some versions of cron don’t execute .sh files.
sudo ln -s /usr/bin/backupWebsite.sh /etc/cron.daily/backupWebsite
After a few month of slumber, project PyVotons has awaken. It is now moving fast towards an alpha release on this website in the next few weeks.
This version should include account creation, poll creation, voter’s listings, voting page and finally poll’s result display.
Technical details : PyVotons contains a UI that runs in the client web browser (python compiled to javascript by Pyjamas) and a standalone HTTPS serveur (also using python) connected to a MySQL database to store user and poll data.
It should be the first usable web version of PyVotons but there will still be a lot on the TODO list :
Just in case this could help someone else, here is a small record about why using latex and bibtex with the Elsevier article class and bibliography style model4-names.bst may lead to some headaches…
First, just using
\documentclass{elsarticle}
and
\bibliographystyle{model4-names}
\bibliography{myBiblio}
does not display the name of authors and the date, but just a number [1].
Solution : \documentclass[authoryear]{elsarticle} (from the sample file at http://support.river-valley.com/wiki/index.php?title=Model-wise_bibliographic_style_files)
The problem with this solution is that the author’s names are full of dots in the reference section (Smith, S.J., for example, instead of Smith SJ).
The solution provided here is to use the numcompress.sty package like this : \usepackage[nodots]{numcompress}
There I got a puzzling error and could not find a solution (this is why I publish this) :
(./MyBiblio.bbl [12]
Runaway argument?
467, 469\@nil \else \ifx \next \@@@au \bibauthor {467, 469}\else 467,\ETC.
! Paragraph ended before \@@bibpages was complete.
<to be read again>
\par
l.514
?
In MyBiblio.bib file, some @article items were not well-defined. I had to change pages = {185,190} to a correct pages = {185–190}, and remove a pages={3} as it seems to confuse the numcompress package.
I recently bought a DroboFS for the storage needs of my lab. It is a nice piece of hardware but I was extremely surprised to see that the only way to configure it is the Drobo Dashboard, a Windows/Mac binary that must be plugged in the same network as the DroboFS (it sends broadcast packets to locate the DroboFS and it is impossible just to give it the IP address).
Why no web interface, such as the one on the Iomega StorCenter Ix2, a much cheaper network drive ?
A recent project to develop a webdashboard (by a user, not the company) exists, but to this day there is very little code available.
Based on his code, I wrote a PHP page (dirty code as I used PHP only once in the last 10 years) that displays the data I was able to get from the share configuration and status data of the Drobo.
I still cannot add users, allow them to change their own password, add a share and change user rights, but that’s a start !
Here is the source code in the hope it might be useful to someone else.
Known bug : if you did not define any users in your DroboFS the status display will fail.
To use it : activate DroboApps on your DroboFS (with Dashboard), install the Apache droboapp, create the file droboStatus.php in the /DroboApps/apache/www directory and fill it with the code that follows. To see the result, just go to http://droboIP:8080/droboStatus.php with your browser.
<html> <head> <title>PHP Test</title> </head> <body> <?php /* droboStatus;php : a simple php page to display the status of a DroboFS Copyright (C) 2011 Manik Bhattacharjee - manik-listes@altern.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /***************************** A short (and incomplete) XML parsing function **********************************************/ function parseBasicXML(&$sourcexml, $markOpen = "DRIShareConfig") { //echo "<br>Parsing...<br>"; $root = array(); $index = 0; // Searching for markups while (preg_match("/([^<]*)<([\s\w\/]+)>/", $sourcexml, $matches, PREG_OFFSET_CAPTURE) ) { //echo "WHILE "; $index = $index + 1; // For each markup $content = $matches[1][0]; $markup = $matches[2][0]; //echo strlen($sourcexml); //echo "$markup<br/>"; // Remove this part from the string $sourcexml = substr($sourcexml, strlen($markup) + 1 + $matches[2][1]); //echo "Match : $markup\n"; // 3 Cases : <Username>, </Username>, and <Username /> // Entering : call the function recursively, it will return a new node if (preg_match("/^\s*(\w+)\s*$/", $markup, $mark)){ //echo "New mark ".$mark[1]." <br>\n"; $root[$mark[1].$index] = parseBasicXML($sourcexml, $mark[1]); } // Open/Closed markup (e.g. <br /> : add it as a child with no value elseif (preg_match("/^\s*(\w+)\s*\/$/", $markup, $mark)){ $root[$mark[1].$index] = "novalue"; //echo "OpenClosed mark ".$mark[1]."<br>"; } // Closed Markup : if it really is our markOpen markup, return ! Otherwise, there is something very wrong ! elseif (preg_match("/^\s*\/\s*(\w+)\s*$/", $markup, $mark)){ if ($mark[1] === $markOpen){ //echo "Closing mark ".$mark[1]." with content $content<br>"; $root["content"] = $content; return $root; }else{ echo "Unexpected input $lt;/".$mark[1].", whereas $markOpen was expected."; } }else{ echo "Unidentified markup : $markup"; } //echo "<br>"; } return $root; } /********************************END XML Parsing function********************************************************************/ /***************************** Sub Functions for Drobo configuration Analysis****************************************************************/ function yesOrNo($val){ if($val == 0){ return "No";}else{return "Yes";} } function userRights($r){ if ($r == 0){ return "<font color=\"orange\">Read only</font>";}elseif($r == 1){ return "<font color=\"green\">Read/Write</font>";}else{return "Unknown rights !";} } function displayPassword($val){ return '***';} function displayUser($us){ echo "<tr><td><font color = \"blue\"><b>".$us['Username1']['content']."</b></font></td><td>".yesOrNo($us['ValidPassword3']['content'])."</td><td>".yesOrNo($us['EncryptedPassword4']['content'])."</td><td><font color=\"gray\">".displayPassword($us['Password2']['content'])."</font></td></tr>\n"; } function displayShare($sh){ // echo '<table border="1"><tr><td><b>ShareName<b></td><td>UserName</td><td>Rights</td><td>ShareState</td><td>TimeMachineEnabled</td><td>ShareMaxTMSizeGB</td><td>OldShareName</td></tr>'."\n"; echo "<tr bgcolor=\"#aaaaaa\"><td><font color = \"blue\"><b>".$sh['ShareName1']['content']."</b></font></td><td></td><td></td><td>".$sh['ShareState2']['content']."</td><td>".yesOrNo($sh['TimeMachineEnabled3']['content'])."</td><td>".$sh['ShareMaxTMSizeGB4']['content']."</td><td>".$sh['OldShareName6']."</td></tr>\n"; $su = $sh['ShareUsers5']; $index = 1; while($su["ShareUser$index"]){ echo '<tr><td></td><td><font color = "blue">'.$su["ShareUser$index"]['ShareUsername1']['content'].'</font></td><td>'.userRights($su["ShareUser$index"]['ShareUserAccess2']['content']).'</td><td></td><td></td><td></td><td></td></tr>'."\n"; $index = $index+1; } //echo "</table>\n"; } /**************************************End of Sub Functions for Drobo configuration Analysis**************************************************************/ /********************************** Drobo Configuration Analysis and display ******************************************************************/ function displayNASconf($nc){ // USERS echo "<h2><center>Users</center></h2>\n"; echo '<center><table border="1"><tr><td><b>UserName</b></td><td>Valid Password</td><td>Encrypted Password</td><td width = "50">Password</td></tr>'."\n"; $users = $nc["DRIShareConfig1"]["UserList2"]; $index = 1; while($users["User$index"]){ displayUser($users["User$index"]); $index = $index+1; } echo "</table></center>\n<br/><br/><br/><br/>\n"; // SHARES echo "<h2><center>Shares</center></h2>\n"; $shares = $nc["DRIShareConfig1"]['Shares3']; $index = 1; echo '<center><table border="1"><tr><td><b>ShareName<b></td><td>UserName</td><td>Rights</td><td>ShareState</td><td>TimeMachineEnabled</td><td>ShareMaxTMSizeGB</td><td>OldShareName</td></tr>'."\n"; while($shares["Share$index"]){ displayShare($shares["Share$index"]); echo "\n"; $index = $index+1; } echo "</table></center>\n<br/><br/><br/><br/>\n"; } /*********************************** End of Drobo Configuration Analysis and display ************************************************/ /******************************** Sub Functions for Drobo Status Analysis *******************************************************************/ function getCurrentStatus(){ //echo '<form><textarea cols="120" rows="40">'; $cfgServer = "localhost"; $cfgPort = 5000; $cfgTimeOut = 10; $drobofs = fsockopen($cfgServer, $cfgPort, $errno, $errstr, $cfgTimeOut); $statusxml = ""; if (!$drobofs) { echo "Connexion failed : $errstr\n"; } else { // read lines until end of "</ESATMUpdate>" is seen while (!feof($drobofs)) { $line = fgets($drobofs, 128); $statusxml = $statusxml.$line; if (strpos($line, "</ESATMUpdate>") === 0){ break;} } } if ($drobofs) { fclose($drobofs); } return parseBasicXML($statusxml); } function simpleString($val){ if ($val === 'novalue'){ return "undefined";}else{return $val['content'];} } function simpleMask($val){ return base_convert($val['content'], 10, 2).'b'; } // From http://code.google.com/p/drobowebdashboard/wiki/ESATMUpdate#ESATMUpdate/mStatus : should analyze the bitmask... function mStatus($val){ //$ret = $val['content'].' = '.base_convert($val['content'], 10, 2).'b -> '; $ret = ''; switch ($val['content']){ case 32768: return $ret.'<font style="BACKGROUND-COLOR: green" color="white">Everything ok, or undergoing relayout</font>'; case 32772: return $ret.'<font style="BACKGROUND-COLOR: yellow" color="black">Yellow capacity warning, replace first drive</font>'; case 32774: return $ret.'<font style="BACKGROUND-COLOR: red" color="white">Red capacity warning, replace first drive</font>'; case 32784: return $ret.'<font style="BACKGROUND-COLOR: red" color="white">Bad drive in 3rd bay</font>'; case 33344: return $ret.'<font style="BACKGROUND-COLOR: orange" color="black">Rebuilding</font>'; } $ret = $val['content'].' = '.base_convert($val['content'], 10, 2).'b -> '; return $ret.'<font color="red">UNKNOWN STATUS - please see http://code.google.com/p/drobowebdashboard/wiki/ESATMUpdate#ESATMUpdate/mStatus</font>'; } function capacity($val){ // Cannot just divide by 1024*1024*1024 because drobo's php does not support large numbers (above 2 Gb) : just remove the last digits for display $gb = substr($val['content'],0,-9); $tb = substr($val['content'],0,-12); return $gb.' Gb / '.$tb.' Tb.'; // return $val['content'].' bytes / '.$gb.' Gb / '.$tb.' Tb.'; } function emailConfig($val){ if ($val['content'] == 0){ return "Email alerts <b>not</b> enabled ";} elseif($val['content'] == 1) { return "Email alerts enabled ";} else {return 'Email alert : <b>unknown</b> status';} } function mFirmwareFeatureStates($val){ if($val['content'] == 6){ return '<b>Single redundancy</b>'; } elseif($val['content'] == 7){return '<b>Double redundancy</b>';}else{return '<b>Redundancy status unknown !</b>';} } function slotmStatus($val){ //$ret = $val['content'].' = '.base_convert($val['content'], 10, 2).'b -> '; $ret=""; switch ($val['content']){ case 1: return $ret.'<font color="white" style="BACKGROUND-COLOR: red">Solid red light (add/upgrade drive immediately)</font>'; case 2: return $ret.'<font color="black" style="BACKGROUND-COLOR: yellow">Solid yellow light (add/upgrade drive soon)</font>'; case 3: return $ret.'<font color="white" style="BACKGROUND-COLOR: green">Solid green light (everything ok)</font>'; case 4: return $ret.'<font color="yellow" style="BACKGROUND-COLOR: green">Blinking green/yellow light (relayout)</font>'; case 128: return $ret.'<font color="gray">No light (empty slot)</font>'; case 134: return $ret.'<font color="black" style="BACKGROUND-COLOR: red">Blinking red light (defective drive, replace immediately)</font>'; } return $ret.'<font color="red">UNKNOWN STATUS - please see http://code.google.com/p/drobowebdashboard/wiki/ESATMUpdate#ESATMUpdate/mSlotsExp/n/mStatus</font>'; } /****************************** End of sub Functions for Drobo Status Analysis *********************************************/ /*********************************** Drobo Status Analysis and display ************************************************/ function displayCurrentStatus($cs, $fullOrNot = 1){ $params = array('mESAUpdateSignature1' => array('?', 'simpleString'), 'mESAUpdateVersion2' => array('?', 'simpleString'), 'mESAUpdateSize3' => array('?', 'simpleString'), 'mESAID4' => array('? - serial number', 'simpleString'), 'mSerial5' => array('Serial number of the device ', 'simpleString'), 'mName6' => array('Name of the device', 'simpleString'), 'mVersion7' => array('Firmware version', 'simpleString'), 'mReleaseDate8' => array('Release date of the firmware ', 'simpleString'), 'mArch9' => array('Hardware architecture', 'simpleString'), 'mFirmwareFeatures10' => array('?', 'simpleString'), 'mFirmwareTestFeatures11' => array('?', 'simpleString'), 'mFirmwareTestState12' => array('?', 'simpleString'), 'mFirmwareTestValue13' => array('?', 'simpleString'), 'mStatus14' => array('Overall status of the device', 'mStatus'), 'mRelayoutCount15' => array('? (Speculation: number of relayouts in the device\'s history)', 'simpleString'), 'mTotalCapacityProtected16' => array('Total capacity', 'capacity'), 'mUsedCapacityProtected17' => array('Used capacity', 'capacity'), 'mFreeCapacityProtected18' => array('Free capacity', 'capacity'), 'mTotalCapacityUnprotected19' => array('?', 'capacity'), 'mUsedCapacityOS20' => array('?', 'capacity'), 'mYellowThreshold21' => array('Threshold of yellow warning about capacity, in 100th of a percent', 'simpleString'), 'mRedThreshold22' => array('Threshold of red warning about capacity, in 100th of a percent', 'simpleString'), 'mUseUnprotectedCapacity23' => array('?', 'capacity'), 'mRealTimeIntegrityChecking24' => array('?', 'simpleString'), 'mStoredFirmwareTestState25' => array('?', 'simpleString'), 'mStoredFirmwareTestValue26' => array('?', 'simpleString'), 'mDiskPackID27' => array('?', 'simpleString'), 'mDroboName28' => array('?', 'simpleString'), 'mConnectionType29' => array('?', 'simpleString'), 'mSlotCountExp30' => array('Maximum number of drive bays (slots)', 'simpleString'), 'mSlotsExp31' => array('Container tag for slots status', 'simpleString'), // SUBFUNCTION 'mLUNUpdates32' => array('Container tag for?', 'simpleString'), //SUBFUNCTION 'mFirmwareFeatureStates33' => array('?', 'mFirmwareFeatureStates'), 'mLUNCount34' => array('?', 'simpleString'), 'mMaxLUNs35' => array('?', 'simpleString'), 'mSledName36' => array('?', 'simpleString'), 'mSledVersion37' => array('?', 'simpleString'), 'mShareCount38' => array('?', 'simpleString'), 'mShareInfo39' => array('?', 'simpleString'), 'mSledStatus40' => array('?', 'simpleString'), 'mSledSerial41' => array('?', 'simpleString'), 'mDiskPackStatus42' => array('?', 'simpleString'), 'DNASStatus43' => array('?', 'simpleString'), 'DNASConfigVersion44' => array('?', 'simpleString'), 'DNASDroboAppsShared45' => array('? (Speculation: indicates whether DroboApps are enabled)', 'simpleString'), 'DNASDiskPackId46' => array('? (Speculation: unique ID for the disk pack) ', 'simpleString'), 'DNASFeatureTable47' => array('?', 'simpleString'), 'DNASEmailConfigEnabled48' => array('Indicates the state of email alerts', 'emailConfig'), 'content' => array('?', 'simpleString') ); $cs = $cs['ESATMUpdate1']; //Display slots $slots = $cs['mSlotsExp31']; $index = 0; if ($fullOrNot){ echo "<center><table border = \"1\">\n<tr><td><b>Slot number</b></td><td><b>Status</b></td><td><b>Capacity</b></td><td>Make</td><td>Model</td><td>ESAID</td></tr>\n"; }else{ echo "<center><table border = \"1\">\n<tr><td><b>Slot number</b></td><td><b>Status</b></td><td><b>Capacity</b></td></tr>\n"; } while($slots['n'.$index.($index+1)]){ $slot = $slots['n'.$index.($index+1)]; if ($fullOrNot){ echo '<tr><td>'.simpleString($slot[mSlotNumber1]).'</td><td>'.slotmStatus($slot[mStatus2]).'</td><td>'.capacity($slot[mPhysicalCapacity6]).'</td><td>'.simpleString($slot[mMake4]).'</td><td>'.simpleString($slot[mModel5]).'</td><td>'.simpleString($slot[mESAID3])."</td></tr>\n"; }else{ echo '<tr><td>'.simpleString($slot[mSlotNumber1]).'</td><td>'.slotmStatus($slot[mStatus2]).'</td><td>'.capacity($slot[mPhysicalCapacity6])."</td></tr>\n"; } $index = $index+1; } echo "</table></center>\n"; if ($fullOrNot){ // Display all parameters echo "<br><table border = \"1\">\n<tr><td>VarName</td><td>Comment</td><td>Value</td></tr>\n"; foreach ($cs as $key => $val) { if (!$params[$key][1]){ echo "<br><br><br>UNKNOWN param for $key !<br><br><br>"; } echo '<tr>'; echo "<td>$key</td><td>".$params[$key][0].'</td><td>'.$params[$key][1]($val).'</td>'; echo "</tr>\n"; } echo "</table>\n"; }else{ // Just display the comment and value for the most usefull items echo "<br><center><table border = \"1\">\n"; $keys = array('mName6', 'mStatus14', 'mTotalCapacityProtected16', 'mUsedCapacityProtected17', 'mFreeCapacityProtected18', 'mVersion7', 'DNASEmailConfigEnabled48'); foreach ($keys as $key){ echo '<tr><td>'.$params[$key][0].'</td><td>'.$params[$key][1]($cs[$key])."</td></tr>\n"; } echo "</table></center>\n"; } } /*********************************** End of Drobo Status Analysis and display ************************************************/ /****************************** THE PAGE CONTENT **********************************************************************/ // Parameter : full details or not ? if($_GET["full"]){ $full = 1;} else {$full = 0;} if ($full == 0){echo '<h3><a href="droboStatus.php?full=1">Display full details</a></h3>';}else{echo '<h3><a href="droboStatus.php">Display summary</a></h3>';} // Get the shares configuration exec("cat /mnt/DroboFS/System/DNAS/configs/shares.conf", $output); // Make one string from it $output = implode(" ", $output); // Parse and display it $nasconf = parseBasicXML($output); displayNASconf($nasconf); // Get the status from port 5000 and display it echo '<h2><center>Drobo Current Status</center></h2>'; displayCurrentStatus(getCurrentStatus(),$full); ?> </body> </html>