Tuesday, November 30, 2010

HowTo randomly change fluxbox wallpaper every n minutes

Some weeks ago' I've discovered this fantastic WM (Windows Manager), thanks to Gentoo/Sabayon + GNOME dbus sessions problems with my Imac. I desired so much to learn something about portage and the gentoo world that I accepted going on without gnome. Fortunatelly.
Fluxbox is a very light and high configurable WM for X server, super super fast and with all such things one need to work fine (alt-tab to move around opened windows, a nice bar showing opened applications and so on). It doesn't have icons by default, but has an amazing menu totally and easily configurable showing up when clicking on the desktop.
Here I want to show how is possible to set a cronjob task that changes randomly the desktop wallpaper every 5 minutes.
FIRST: install feh
feh is a fast, lightweight image viewer, supporting many image formats that we'll use to show the wallpaper. So
$sudo emerge feh
SECOND: try it out
Open the ~/.fulxbox/menu file and add some wallpaper voices, like
[submenu] (Wallpaper)
[exec] (tamars) {fbsetbg -f /home/abidibo/Wallpapers/sabayon_t.png}
[exec] (minus_tamars) {fbsetbg -f /home/abidibo/Wallpapers/sabayon.png}
[exec] (matrix) {fbsetbg -f /home/abidibo/Wallpapers/sabayon_matrix.jpg}
[exec] (winzoz) {fbsetbg -f /home/abidibo/Wallpapers/winzoz.jpg}
[exec] (toilet) {fbsetbg -f /home/abidibo/Wallpapers/toilet.jpg}
[exec] (linuxVSwin) {fbsetbg -f /home/abidibo/Wallpapers/linuxvswin.jpg}
[end]
fbsetbg is a wrapper that searches for a image viewer in order to set the fulxbox background (in our case it'll use feh, but other programs may be used).
Now clicking on the desktop and selecting a wallpaper voice from the menu should change our fluxbox wallpaper, if not maybe there were some problems during the installation of feh, try solving them and continue.
THIRD: make a script that changes the background randomly
So put all the desired images inside a folder and then copy this code in a file that we'll call chgWallpaper.sh
#!/bin/bash
export DISPLAY=:0.0
fbsetbg -f /home/abidibo/Wallpapers/$(ls ~/Wallpapers | sort -R | tail -1)
Why we export the DISPLAY variable? Well, we always have to remember that the processes started by cron have no (or almost no) normal environment setup, and our script require this variable. So from terminal as normal user run
echo $DISPLAY
take the result and put it in place of :0.0
The second line of the script launches fbsetbg passing it one (tail -1) file randomly (sort -R) taken from the ~/Wallpapers directory (ls).
FOURTH: schedule the script with crontab
Now we have to schedule this script. My system has vixie-cron, many others uses crond, it's the same. We want to schedule the script as normal user (abidibo in my case), so
$sudo crontab -u abidibo -e
This commands opens your favourite editor, now we have to insert the job:
*/5 * * * * /bin/bash /home/abidibo/Scripts/chgWallpaper.sh
This way the script is run every 5 minutes. Now we save the file and exit and the new crontab is installed. We wait 5 minutes and our desktop background should change, if not go on reading.
TROUBLESHOOTING
If this doesn't work may be it happens something like what happened to me.
Read your system log file, in my case
$sudo vim /var/log/messages
and search for cron messages.
If you notice somithing like
Nov 30 14:35:01 localhost cron[7500]: (abidibo) CMD (bash /home/abidibo/Scripts/chgWallpaper.sh)
Nov 30 13:35:01 localhost postfix/postdrop[7511]: warning: unable to look up public/pickup: No such file or directory
Then you're welcome. Here we have a postfix problem, the pickup FIFO (files used by different processes to communicate) file is not present in your system, we have to create it, run
$sudo mkfifo /var/spool/postfix/public/pickup
$sudo /etc/init.d/postfix restart
And that should be fix it.
Now if it still doesn't work and your system log says something like
Nov 30 14:44:00 localhost postfix/local[7846]: fatal: open database /etc/mail/aliases.db: No such file or directory
you're welcome! It means you don't have that file. So you need to create it running the command
$sudo newaliases
$sudo /etc/init.d/postfix restart
Now cron may comunicate with you and send you emails that you may read by
$vim /var/mail/USERNAME
In my case cron was happy to say me such thing
From abidibo@abidibo-sabayon.localdomain  Tue Nov 30 15:29:01 2010
Return-Path: <abidibo@abidibo-sabayon.localdomain>
X-Original-To: abidibo
Delivered-To: abidibo@abidibo-sabayon.localdomain
Received: by abidibo-sabayon.localdomain (Postfix, from userid 1000)
         id 999DDD9E654; Tue, 30 Nov 2010 15:29:01 +0100 (CET)
From: root@abidibo-sabayon.localdomain (Cron Daemon)
To: abidibo@abidibo-sabayon.localdomain
Subject: Cron <abidibo@abidibo-sabayon> /bin/bash /home/abidibo/Scripts/chgWallpaper.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/abidibo>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=abidibo>
X-Cron-Env: <USER=abidibo>
Message-Id: <20101130142901.999DDD9E654@abidibo-sabayon.localdomain>
Date: Tue, 30 Nov 2010 15:29:01 +0100 (CET)

Error: Can't open display:
That led me to add  the "export DISPLAY=:0.0" line in my script (thing that you've already done).
That's all. Hasta la proxima siempre!

Thursday, October 28, 2010

Load local XML through AJAX request problems in IE

Have you got a simple html-js-xml project (doesn't need a server) that works locally on firefox but not in IE? You're welcome!
Understanding the problem
Let's see my example... I had an html document which only charges an external javascript which has the due to load an xml file representing a flowchart and simulate a navigation through the tree, with conditional steps and forwards steps.
Even if I'm a mootools lover, for this project I used jQuery because the mootools core 1.2.x xml loader doesn't work for IE in any case.
So I used jQuery ajax method to load the xml this way:
var xml = $.ajax({
    async: false,
    type:"GET",
    context: this,
    url: chart_path,
    dataType:"xml"
}).responseXML;
Now, I thought at my xml variable as a DOM object over which use all the traversing methods implemented by jQuery. That was true... in some cases.
The scenario
- Application hosted on a server
  works if visited with any browser and any OS
- Application hosted on my local server running on Ubuntu 9.04
  works if visited with any browser and any OS
- Application hosted on a PC with Windows XP not under a server
  works with firefox but not with IE
OH MY GOD
The answer
So at the end I gained the solution. The problem is that I was trying to get the responseXML from the ajax object, but without a server "telling" the browser that yes, that content is really an XML. Moreover (OH OH) IE is not so intelligent as to understand this things without help.
The solution
So what may we do? Simple. We get not the responseXML but the responseText and then load it using the loadXML method of the ActiveXObject. What follow is my example code
var xmltext = $.ajax({
    async: false,
    type:"GET",
    context: this,
    url: chart_path,
    dataType:"xml"
}).responseText;

if($.browser.msie) {
    xml = new ActiveXObject("Microsoft.XMLDOM");
    xml.loadXML(xmltext);
}
else {
    parser = new DOMParser();
    xml = parser.parseFromString(xmltext, "text/xml");
}
Now my xml variable is ready and contains the desired XML object.
Saludos

Wednesday, July 28, 2010

HowTo navigate through a tree without recursive methods (while loop instead)

-Hi,
today I was simply writing a local template in order to render a menu following the MVC pattern.
Now my local template system does not use a meta-language, but loops, if statements and so on are written directly in php, because I don't have enough time to write an interpreter.
So really I can use all php functionalities in my templates including recursive functions. But it's not the way I want to follow, moreover maybe some day I'll find the time to write my interpreter and then will be very easy to "convert" if statements and cycles, not so easy if not impossible to convert recursive functions.
Well, so the problem was the following:
I have a n-dimensional menu tree, and have to generate the classical html code for such a menu, that is something like:
<ul id="nav">
    <li>Voice1</li>
    <li>Voice2
        <ul>
            <li>Voice21</li>
            <li>Voice22</li>
        </ul>
    </li>
    <li>Voice3</li>
</ul>
So let's see HOW TO get this without recursion. The code is well commented, here it goes:
<?php

/*
 * Menu tree is represented by an n-dimensional array.
 * Array keys are the labels and array values are either a link
 * or a submenu (another array)
 */
$voices["Home"] = array("Home1" => array("Home11"=>"#"), "Home2"=>array("Home21"=>"#"));
$voices["News"] = array("News1" => "#", "News2"=>array("News21"=>"#"));
$voices[_("About")] = array("About1"=>array("About11"=>array("About111"=>"#", "About112"=>"#")), "About2"=>"#");
$voices[_("Services")] = '#';
$voices[_("Faq")] = '#';

/*
 *  INIT SOME VARIABLES
 */
// control the exit from the loop
$continue = true;
// this variables stores the branch currently analized
$parsed = $voices;         
// stores all the branches parsered, because the tree is navigated following a branch
// until the foil. So when returning on top levels the navigation must continue on
// branches interrupted earlier.
$tree = array();
// stores the last key of the current branch array
$last = null;

echo "<ul id=\"nav\">\n";

/*
 *  THE MAIN LOOP
 */
while($continue === true) {
    // if the value of the current element parsered is an array than has a submenu
    if(is_array(current($parsed))) {
        // echo the current voice and open a new submenu (ul)
        echo "<li><a href=\"#\">".key($parsed)."</a>\n<ul>\n";
        // we're going to begin navigate the branch ->
        // we store the branch we're leaving in the tree array
        $tree[] = $parsed;
        // the branch to analyze is now the submenu
        $parsed = current($parsed);
        // get the last key of the new branch
        end($parsed);
        $last = key($parsed);
        // reset the array pointer
        reset($parsed);
    }
    // else if the value of the current element is not an array (but a link)
    // and not false (i.e. after calling next on the last element of an array)
    elseif(current($parsed)!==false) {
        // echo the current voice
        echo "<li><a href=\"".current($parsed)."\">".key($parsed)."</a></li>\n";

        // if the voice printed is the last of its branch
        // than close the submenu and get the last branch stored in the
        // varable tree (the parent branch) as the one to follow parsering
        if(key($parsed)==$last) {
            echo "</ul></li>\n";
            $parsed = array_pop($tree);
        }
        // move the pointer to the next element
        next($parsed);
    }  
    // else the value of the current element is false -> we have already passed the last element
    // then we close the submenu and get the parent branch as the current one, passing to the next element
    else {
        echo "</ul></li>";
        $parsed = array_pop($tree);
        next($parsed);
    }

    // if we are navigating the first tree level and have passed through all them -> exit
    if(count($tree)==0 && current($parsed)==false) $continue = false;
}

echo "</ul>\n";
?>
Hasta la proxima!

Friday, July 9, 2010

Get MySQL table data structure with PHP

Hi, today I'll show how to retrieve informations about a MySQL table through php in order for example to create a php class making editable a table in an automatic way (that is: stupid class, i give you a name of a table and YOU have to create its backend for me). This work is done very well by the python framework Django for example.
Now, there are several ways to do so, I'll use the interrogation of the information_schema db.
Well, let's see the code. I post here a simple function, clearly the informations that may be retrieved are more than these.
function getTableStructure($dbname, $table) {
    $structure = array();
    $fields = array();

    $query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '$dbname' AND TABLE_NAME = '$table'";
    $res = mysql_query($query);

    while($row = mysql_fetch_array($res)) {
        $fields[$row['COLUMN_NAME']] = array(
            "order"=>$row['ORDINAL_POSITION'],
            "default"=>$row['COLUMN_DEFAULT'],
            "null"=>$row['IS_NULLABLE'],
            "type"=>$row['DATA_TYPE'],
            "max_length"=>$row['CHARACTER_MAXIMUM_LENGTH'],
            "key"=>$row['COLUMN_KEY'],
            "extra"=>$row['EXTRA']
        );
        if($row['COLUMN_KEY']=='PRI') $structure['primary_key'] = $row['COLUMN_NAME'];
    }
    $structure['fields'] = $fields;

    return $structure;

}

The important informations to do an auto-generation-form class are:
  • default: the default value (we may insert it as a default value in the input field of the form)
  • null: we may use it to decide whether a field must be compulsory or not
  • type: the must important: which form element we'll use? It depends on data type and ...
  • max_length: the maximum number of characters acceopted for the field
  • key: we may want to check for uniques keys etc...
  • extra: i think it's useful to know if a field is auto_increment because we may not make it editable
That's all falks, hasta la proxima!

Thursday, April 1, 2010

A mootools based horizontal scrollable list

Hi,
today I write about a nice javascript class that creates a typical horizontal scrollable list starting from an html unordered list. The final result is like many others in the web. The LI elements of a list are used to create the items of this scrollable list. The number of items visible at a time is a paramether, and if is greater than the maximum possible one, is reduced in order to get the items to stay in their space. The controller are two arrow buttons on the left and right of the slide. They have three states: ON, OFF and OVER controlled through javascript and personalizable by css. The width of the entire object and of the single item are needed, the height of the single item is not necessary because is calculated by javascript (through an iteration along all items), but clearly for a good result all items would rather have the same height.
Let's see the details now.
Imagine we have an unordered list where the LI elements are images set as css background of a DIV, for example:
<ul id="hlistVideo">
  <li>
    <div title="Durata: 00:00:10" style="background-color:#fff;background-image:url('upload/img/images.jpg'); background-position:center center;background-repeat:no-repeat; width:130px;height:100px;margin:10px;cursor:pointer;" /></div>
  </li>
  <li>
    <div title="Durata: 00:02:29" class="tooltip" style="background-color:#fff;background-image:url('upload/img/wildThings.png'); background-position:center center;background-repeat:no-repeat; width:130px;height:100px;margin:10px;cursor:pointer;" /></div>
  </li>
  <li>
    <div title="Durata: 00:02:18" class="tooltip" style="background-color:#fff;background-image:url('upload/img/trucker.png'); background-position:center center;background-repeat:no-repeat; width:130px;height:100px;margin:10px;cursor:pointer;" /></div>
  </li>
</ul>
Now, we want to transform it in a classical scrollable horizontal list, like the one represented in the image (the same one).
Well, here comes my mootools based javascript class which coupled with some css realizes it. First the code, then the usage
/*
 * hScrollingList class written by abidibo, 01/04/2010
 *
 * hScrollingList method: constructor
 *   Syntax
 *      var myInstance = new hScrollingList(list, vpItems, scrollableWidth, itemWidth, [options]);
 *   Arguments
 *      1. list - (string|Object) The UL element or its id attribute to be transformed
 *      2. vpItems - (int) The number of element showed in a viewport (the viewport changes (scrolls) when clicking on the arrows)
 *      3. scrollableWidth - (int) The width in px of the scrollable object
 *      4. itemWidth - (int) The width in px of a list element
 *    5. options - (object, optional) The options object.
 *   Options
 *    - id (string: default to null) The id of the object
 *      ........ maybe many more options in the future.........
 *
 */
var hScrollingList = new Class({

    Implements: [Options],
    options: {
        id: null
        // maybe more options in the future here
    },
        initialize: function(list, vpItems, scrollableWidth, itemWidth, options) {
  
        if($defined(options)) this.setOptions(options);

        this.list = $type(list)=='element'? list:$(list);
        this.listElements = this.list.getChildren('li');

        this.setWidths(scrollableWidth, itemWidth);
        this.vpItems = vpItems;
      
        this.setSlide();
        this.setStyles();  // vpItems property may change!
        this.setWrapper();

        this.vps = 1;
        this.tots = Math.ceil(this.listElements.length/this.vpItems);
        this.updateCtrl();
        this.tr = new Fx.Tween(this.slide, {
                'duration': 1000,
                'transition': 'quad:out',
                'onComplete' : function() {this.busy=false}.bind(this)
            });


    },
    setWidths: function(tw, iw) {
        this.width = tw;
        this.ctrlWidth = 24;
        this.cWidth = this.width - 2*this.ctrlWidth;
        this.iWidth = iw;
    },
    setSlide: function() {
        var clear = new Element('div', {'styles':{'clear':'both'}});
        this.slide = new Element('div', {
            'styles': {'position':'relative', 'width':'10000em', 'background-color':'#ccc'}  
        });
        this.slide.inject(this.list, 'before');
        this.slide.grab(this.list);
        clear.inject(this.slide, 'bottom');
    },
    setWrapper: function() {
        this.wrapper = new Element('div', {
                'styles':{'width': this.width}
        });      
        var ctrlHeight = this.listElements[0].getCoordinates().height;
        for(var i=1; i<this.listElements.length; i++)
            if(this.listElements[i].getCoordinates().height > ctrlHeight)
                ctrlHeight = this.listElements[i].getCoordinates().height;

        this.leftCtrl = new Element('div', {
            'styles': {'float': 'left', 'width': this.ctrlWidth+'px', 'height':ctrlHeight+'px'}
        })
        this.rightCtrl = new Element('div', {
            'styles': {'float': 'right', 'width': this.ctrlWidth+'px', 'height':ctrlHeight+'px'}      
        })
        this.itemContainer = new Element('div', {
            'styles': {'float': 'left', 'width': this.cWidth+'px', 'overflow':'hidden'}      
        })
        this.wrapper.adopt(this.leftCtrl, this.itemContainer, this.rightCtrl);
        this.wrapper.inject(this.slide, 'before');
        this.itemContainer.adopt(this.slide);
    },
    setStyles: function () {
        this.list.setStyles({'margin': '0', 'padding': '0', 'list-style-type':'none', 'list-style-position':'outside'});

        var esw = this.vpItems*this.iWidth;
        while(esw>this.cWidth) esw = --this.vpItems*this.iWidth;
        var margin = (this.cWidth - esw)/2;

        for(var i=0; i<this.listElements.length; i++) {
            var item = this.listElements[i];
            var r = i%this.vpItems;
            item.setStyles({
                'float':'left',
                'width': this.iWidth+'px',
                'margin-left': !i ? margin+'px' : r ? '0px' : 2*margin+'px'  
            })
        }
    },
    scroll: function(d) {
      
        if(this.busy) return false;

        this.busy = true;
        if(d=='right')
            this.tr.start('left', '-'+(this.cWidth*this.vps++)+'px');
        else if(d=='left')
            this.tr.start('left', '-'+(this.cWidth*(--this.vps-1))+'px');
  
        this.updateCtrl();
    },
    updateCtrl: function() {

        var lclass = this.vps == 1 ? 'leftCtrlOff':'leftCtrl';
        var rclass = this.vps == this.tots ? 'rightCtrlOff':'rightCtrl';
        this.leftCtrl.setProperty('class', lclass);          
        this.rightCtrl.setProperty('class', rclass);      

        if(this.vps==1) {
            this.leftCtrl.removeEvents('mouseover');
            this.leftCtrl.removeEvents('mouseout');
            this.leftCtrl.removeEvents('click');
            this.le = false;
        }
        else if(!this.le) {
            this.leftCtrl.addEvent('mouseover', function() {this.setProperty('class', 'leftCtrlOver')});
            this.leftCtrl.addEvent('mouseout', function() {this.setProperty('class', 'leftCtrl')});
            this.leftCtrl.addEvent('click', this.scroll.bind(this, 'left'));
            this.le = true;
        }

        if(this.vps == this.tots) {
            this.rightCtrl.removeEvents('mouseover');
            this.rightCtrl.removeEvents('mouseout');
            this.rightCtrl.removeEvents('click');
            this.re = false;
      
        }
        else if(!this.re) {
            this.rightCtrl.addEvent('mouseover', function() {this.setProperty('class', 'rightCtrlOver')});
            this.rightCtrl.addEvent('mouseout', function() {this.setProperty('class', 'rightCtrl')});
            this.rightCtrl.addEvent('click', this.scroll.bind(this, 'right'));
            this.re = true;
        }

    }
});
Now the css styles used in my example (if you wanna try this code remember to make your own arrows images)
div.leftCtrl {
    background: #b8b7b7 url('../img/arrowSX.png') no-repeat center center;
    cursor:pointer;
}
div.rightCtrl {
    background: #b8b7b7 url('../img/arrowDX.png') no-repeat center center;
    cursor:pointer;
}
div.leftCtrlOver {
    background: #929191 url('../img/arrowSX.png') no-repeat center center;
    cursor:pointer;
}
div.rightCtrlOver {
    background: #929191 url('../img/arrowDX.png') no-repeat center center;
    cursor:pointer;
}

div.leftCtrlOff {
    background: #b8b7b7 url('../img/arrowSX.png') no-repeat center center;
    opacity: 0.8;
    filter: alpha(opacity = 80);

}
div.rightCtrlOff {
    background: #b8b7b7 url('../img/arrowDX.png') no-repeat center center;
    opacity: 0.8;
    filter: alpha(opacity = 80);
}
Basically these css styles contains the three states of the two buttons: button ON, button OFF, and button OVER.
Now let's see how to use this class, very simple:
<script>var hList = new hScrollingList('hlistVideo', 5, 600, 150)</script>
So simply we instanciate the class hScrollingList, passing the paramethers:
  • 'hlistVideo': the id of the unordered list (we may pass even the DOM Object)
  • 5: the number of items 'for page', that is the number of elements in the viewport for each scrolling action
  • 600: the total width of the object
  • 150: the width of a single item (a LI element)
Observe that the class is able to auto-reduce the number of items 'for page', because it tries to put them in the space  allowed, and if thay can't stay correctly in the space their number is reduced by one untill they will.
So you only have to take this code, personalize the arrows images, the three states of the buttons through css and obtain your own personalized horizontal scrollable list.
For info or problems write at abidibo@gmail.com
Bye!