Soon : alpha version of WebPyvotons

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 :

  • include CSS support and styles, use new icons
  • code cleanup and documentation
  • better error management
  • translation support
  • user groups
  • security improvements (especially against DOS attacks)
  • e-mailing support for account creation and voting opportunities
  • support for other database egines (e.g. sqllite)
  • server-side should be able to run under Apache (CGI, app server…)

 

Posted in Development, news | Leave a comment

Bibtex, latex, elsarticle and nodots : meaningless error message

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.

Posted in TechTips | 4 Comments

DroboFS : a php status page.

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.

edit:anonymized screenshots



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>
Posted in TechTips | Leave a comment

(Français) Le vacarme des bombes et le silence de la Gauche

Sorry, this entry is only available in Français.

Posted in Politics & society | 1 Comment

Download rtmp flash video from Linux

To watch a streaming flash video (rtmp streaming) from a tv website without the flash plugin, you can download the video to your computer like this :

  1. Open the web page with firefox. Right click and view the source of the page.
  2. Look for the “<embed>” markup of the video, such as <embed src=”http://site.tv/player.swf?admin=false&amp;autoPlay=true&amp;videorefFileUrl=http%3A%2F%2Fsite.tv%2Fvideos%2FmyFilm%2Cvideo.xml” […]>
  3. The URL of the XML file (in red here) contains the real reference to the video. So let’s copy it into the browser’s address bar, and replace the escaped characters by their values : http://site.tv/videos/myFilm,video.xml
  4. The XML file is now displayed in firefox. Look for the video itself (there might be more than one, for example SD or HD) and get its url. For example rtmp://site.tv/365/2744?lg=en
  5. Install flvstreamer (apt-get install flvstreamer in Ubuntu, urpmi flvstreamer in Mandriva and so on…)
  6. Run it with the rtmp URL : flvstreamer -o outputFile.flv -r “rtmp://site.tv/365/2744?lg=en
  7. If the download is not complete and you get the message ERROR: ReadPacket, failed to read RTMP packet header
    Download may be incomplete (downloaded about 57.20%), try resuming
    Just resume the download with the same command, plus the -e option :
    flvstreamer -e -o outputFile.flv -r “rtmp://site.tv/365/2744?lg=en”
  8. Repeat that last command as long as the file is not complete.
  9. Read the file with mplayer or vlc !
Posted in TechTips | Leave a comment

Automatic Synchronization between two backup NAS devices

Scenario

You have two NAS devices, for example two network hard drives (in my case Iomega StorCenter ix2). You want your users (Windows/Mac OS X/Linux) to be able to backup their data to one of them, and have a mirror of the backups on the second one (off-site backup). The setup does not need to be very secure, as this works on an internal network, so a password stored in clear text in a script is not a big deal.

Daily Synchronization by a Linux computer

Setup

Each user has an account and associated directory on Disk1. On Disk2, there is only one “Backups” directory. Windows share/CIFS/SMB is activated in both disks.
Here, both disks have DNS names “Disk1” and “Disk2”. You can use the IP address of the disks instead.
A backupUser user is declared on both disks, with reading rights only on all Disk1 directories, and all rights on Disk2 Backups directory.
On the Linux computer,  the directories /mnt/serv1 and /mnt/serv2 must be created.

Backup script

First, let’s make a small perl script backupNAS.pl to perform the backup :

#!/usr/bin/perl -w
#
# You need : - a backupUser with - all reading rights on all Disk1 directories
#                                                   - writing rights in Disk2/Backups
#           - the  Disk2/Backups directory must contain a file named AutoBackup
#

# Mounting Disk2 in /mnt/serv2
`umount /mnt/serv2; mount -t cifs -o user=backupUser,password="MyBackupPassword",iocharset=utf8,file_mode=0777,dir_mode=0777 //Disk2/Backups /mnt/serv2/`;
$err1 = $?;

# Check : There must be an "AutoBackup" file in the directory if the disk in mounted correctly
if ((not -e '/mnt/serv2/AutoBackup') or $err1 != 0){
	die "ERROR : cannot mount Disk2 !\n";
}

# Get the list of user directories in Disk1
@shareList1 = `smbclient -N -L //Disk1`;

# Filtering the list to get only the shared directories. Lines should look like 
# "        username        Disk  "
@reps1 = ();
print "Disk 1\n";
foreach $share1(@shareList1){
	chomp $share1;
	if ($share1 =~ /^\s+(\S+)\s+Disk\s+/){
		($name,) = $share1 =~ /^\s+(\S+)\s+Disk\s+/;
		push (@reps1, $name);
	}
}

# Each directory will be mounted then unmounted
foreach $rep1(@reps1){
	`umount /mnt/serv1`;
	`mount -t cifs -o user=backupUser,password="MyBackupPassword",ro,iocharset=utf8,file_mode=0444,dir_mode=0555,noperm //Disk1/$rep1 /mnt/serv1/`;
	if ($? != 0){
		print "ERROR : Directory //Disk1/$rep1 mount failed !\n";
		next;
	}
	print "SYNCHRO rsync /mnt/serv1/ /mnt/serv2/$rep1\n";
	print `rsync -rltpv --stats  /mnt/serv1/ /mnt/serv2/$rep1`; # --del if deleted files must be removed on Disk2 too
 }
`umount /mnt/serv1`;
print "SERVER 1 : backup to DISK 2 is done !\n";

Cron script

Now, let’s create a small script that will call this one daily and log the results. Edit /etc/cron.daily/backupNAScall :

#!/bin/bash
echo >> /var/log/backupServers.log
echo >> /var/log/backupServers.log
echo "-------------------------------------------------" >> /var/log/backupServers.log
echo "Beginning BACKUP -> Launching backupNAS.pl" >> /var/log/backupServers.log
date -R >> /var/log/backupServers.log
perl /pathToScript/backupNAS.pl >> /var/log/backupServers.log

echo "BACKUP FINISHED" >> /var/log/backupServers.log
date -R >> /var/log/backupServers.log
echo "**************************************************" >> /var/log/backupServers.log

Now each day, the backup will start and detailled logs (including the date and time) will be stored in /var/log/backupServers.log !

From the NAS (in progress…)

Next step would be to remove the need for the linux computer entirely and execute this on the small linux system of the NAS disk. The following is specific to the NAS device (Iomega StorCenter ix2).
A ssh server can be activated on the NAS by going to the page https://myDiskAddress/support.html, then activating the access option.
When the disk has rebooted, you can connect to it with ssh root@myDiskAddress. The password is “soho” followed by the admin account password that was set up to access the web interface. With this, you have access to a small system (without perl or bash, just sh or ash – the previous code won’t work on this device “as is”. rsync is there, though).

In /etc/crontabs/root there is a warning :

# DO NOT SCHEDULE TASKS HERE (use sohoProcs.xml to schedule tasks)
The file /usr/local/cfg/sohoProcs.xml seems to be the right place for scheduled tasks. In it, we find commands like this :

<Program Name=”reportquota” Path=”/bin/sh”>
<Args>/usr/bin/reportquota</Args>
<SysOption Days=”1″ Scheduled=”1″ StartTime=”01:00″/>
</Program>

I did not try to add a custom command yet, but this should be the way to go…

This wiki might be helpful : http://ix2-200.wikidot.com/

Posted in TechTips | Leave a comment

PyVotons foundations

Incomplete translation

This text presents the main ideas that led to the creation of the PyVotons! project. It was written in february 2009, long before the first real move towards PyVotons.

The goal was to propose software tools for a group (at the time, a political party) in order to encourage initiatives and go towards collective propositions and decision-making.

DECISION software

Users

  • An wiki-like ID such as FirstnameLasname and a password
  • Optional personnal information
  • e-mail/phone/mobile : a way to get in touch
  • Usual availability dates for meetings (days of the week, time slots)

Polling software

This program will be used to choose a meeting date or to quickly take a simple decision in a small group, with a public voting system (anyone can see who votes for what).

  • doodle-like system
  • A user enter the question he/she wants to ask to a user groupe (When should we have this meeting ?)
  • he/she lists possible answers (12/02 5pm, 12/02 6pm, 17/02 8pm)
  • he/she sends a link to the poll page.
  • The programme creates a web page dispaying the question followed by possible answers. Each user enters its name then checks suitable answers.
  • At the end date, counting the number of checks gives the result of the poll
  • This can be extended to a larger variety of polls (select one from a list of answers, rate each possible answer…). It should still be very easy to use (not all users are familiar with the web); the user that wants to create a poll should see a list of typical polls and just choose the type he/she wants.

Messaging software

  • This allows to automatically (or not) send an e-mail following events on the site (poll newly opened, new proposition, opening of a vote, reminding the closing date of a vote, vote results published).
  • Having the option to send SMS (texts on mobile) would be a useful feature for those without computer or e-mail access, so that they are aware of the events on the site  (is there a free service that works with all phone providers ?)
  • It should be possible to opt out by message type, or to group messages (one per day, one per week).

Vote software

Submit one or more questions/propositions/candidates to a full-fledge vote or election.à un ou plusieurs tours

This must allow experimenting with multiple voting systems (ordering candidates by preference, rating propositions or just select he best one) using one or more rounds, anonymous or not (transparency for elected representative versus freedom of the vote with no supervision).

When creating a new election or a referendum, it must be possible to select one or more voting systems (if people are motivated enoiugh, we could compare the results of the vote according to the voting system).

Idea market software

Le but ici est que chacun puisse lancer une proposition et que la sélection et les amendements de ces propositions se fassent par un processus collectif.

  • Proposer une proposition P
  • Commenter une P existante : critiquer ou au contraire aller dans le sens de la proposition
  • Noter une P (sur 20 par exemple)
  • Lier deux propositions (elles sont identiques, apparentées, l’une s’inspire de l’autre, ou c’est une nouvelle version de l’autre…)
  • Permettre la discussion (avec par exemple un forum lié à la P) pour faire évoluer une proposition et en créer une nouvelle intégrant le résultat de la discussion
  • Définir des thèmes et des mots-clés pour classer un peu les propositions
  • Pour chaque proposition, synthèse des arguments pour et contre
  • Moteur de recherche des propositions (éviter de proposer 10 fois la même, en trouver une apparentée). A ce niveau-là, ça devrait fonctionner un peu comme bugzilla
  • Amender ou fusionner des propositions : étiqueter comme anciennes les propositions obsolètes et en écrire une nouvelle liées aux anciennes
  • On peut éliminer les propositions anciennes (en les gardant dans un historique) quand elles sont remplacées par des propositions plus récentes
  • Une synthèse des propositions les mieux notées doit être générée périodiquement.
  • Les propositions qui sont remontées au-dessus d’un certain seuil (note + nombre de personnes ayant noté) doivent être soumises périodiquement au vote de tous avec l’application Vote
  • Les propositions soumises au vote seront étiquetées « rejetée » ou « acceptée » avec une référence au vote correspondant

Wiki de synthèse

Ce wiki doit être le lieu de synthèse de l’ensemble des propositions retenues. Elles doivent être listées et permettre d’élaborer des textes cohérents pour les articuler. (Inclusion de mediaWiki, ou MoinMoinWiki)

Base de connaissances Wiki

  • références à des livres, articles, réflexions
  • Le but est d’aider à comprendre le monde et d’avoir des arguments pour soutenir les discussions sur les propositions
  • (Inclusion de mediaWiki, ou MoinMoinWiki)

Forum et Discussion en ligne (« chat », IRC)

  • Le forum permet de discuter en ligne même quand les interlocuteurs n’ont pas de plages horaires communes disponibles : chacun écrit et lit quand il le souhaite, et les archives sont disponibles. (intégration de PhpBB par exemple…)
  • L’IRC permet de remplacer les réunions téléphoniques ou simplement de discuter en direct en mode texte. Les discussions peuvent être archivées. (serveur IRC quelconque).

Quelques remarques

Attention, tout ceci n’a pas pour but de supprimer les réunions et les contacts humains, mais de permettre au maximum de gens de proposer et de participer à la prise de décision, grâce aux technologies récentes. Pas de société des experts, autrement dit…

Les humains restant des humains il faudra trouver des méthodes de régulation pour éviter le spam, les guerres d’édition dans les wikis et le pouvoir trop important des modérateurs.

En gros, l’élaboration du programme devrait venir de propositions venues de tous, discutées sur les forums de discussion, par IRC et en réunion classique, notées, puis passées au vote, et enfin ajoutées dans le wiki de synthèse.

Posted in Documentation | Leave a comment

Unconditional basic income : debate notes

Translation in progress (questions are not translated yet)

Here are detailed notes I took during a presentation and debate about unconditional basic income, organized in Grenoble, France by les Alternatifs and la Fase on october 13, 2010. Continue reading

Posted in Politics & society | Leave a comment

Asus EEE 1005PX audio output

After installing Ubuntu 10.04 on a Asus EEE 1005PX netbook, the audio output jack did not work. When headphones were plugged in, the netbook speakers were cut off, but there was no sound at all in the headphones.

The solution was to add a line at the end of file /etc/modprobe.d/alsa-base.conf :
options snd-hda-intel model=lifebook

After the next reboot, the headphones worked perfectly.

Posted in TechTips | 4 Comments

General meeting for renewal : the Liberation forum in Grenoble

In the last three days, a convention was organized by the newspaper Liberation in Grenoble, combining conferences, debates and meetings between associations, French political figures, journalists and the public.

I went to a few conferences and a day of debate on the theme of democracy. The conferences were mildly interesting, especially because the number of questions was limited and the themes were not fully explored.

For example, the conference about democracy and Internet was just an hour-long talk between two European deputies, a sociologist and a communication coach for politicians. I was expecting a presentation of the role of Internet in the renewal of democracy, mostly in our western democracies.

For example, in 2005 a large debate opened about the European constitution referendum that was organized by citizen mostly outside political parties. The role of blogs, forums, wikis to summarize for/against arguments, all those new tools that allowed the citizen to get involved in the referendum.

Instead of that, most of the conference was dedicated to the use of Facebook and Twitter by politicians, how it could help them not loose contact with their electorate, in fact, the way these tools allow a new form of political communication and advertising.

There was a short mention of the role of Internet in the political contests in Tunisia and Egypt that lead to Ben Ali living the Tunisia.

Elected representatives feel often threatened by (and therefore, often block) the implication of citizens in decision-making processes. This was a theme discussed during the debate with interesting practical experiments by a mayor of a small city, and about a less satisfying experience in Grenoble linked to the “not in my backyard”.

The representativity of local citizen councils was also discussed, as most inhabitants going there are mostly retired and sometimes only the vocal opponents considering their local problems but not the larger picture.

A lot to think about !

Unfortunately, the last day was, for a “renewal” forum, a bit ironic : the conclusion was done by a group of old, white males. Journalists, politicians that have been ruling this country for years, speaking about renewal of the society !

Once more, the political parties, the main media are at not at the forefront, developing new ideas in the field of democracy, economy… This comes from associations, citizens, researchers.

Posted in Politics & society | Leave a comment