Dev

Syslog LogAnalyzer with LDAP authentication

 

 

Adiscon is the company responsible for developping LogAnalyzer, a syslog (rsyslog, syslog-ng…) and/or flat file « analyzer ».
By analyzer, understand that it enables you to display the log in a meaningful way, splitting it depending on « views » and enabling real search filters.

If you don’t have the money for things liks Splunk and you are not convinces by other new projects using Rails, NoSQL and other tools that are a pain in the ass to install, you may fallback to LogAnalyzer.
Lire la suite de l’article »

WordPress NextGEN Gallery and GPS data

NextGen(eration) Gallery is a WordPress plugin from Alex Rabe. It provides image galleries, albums with great ease of administration.
As said by the author, it fills a gap in WordPress gallery systems.

It can handle « display » templates, which can be added to the plugin Views or simply in your theme. That’s what I’m working on right now for the Photo Theme I’m using in my new Photo Blog.
This way you don’t have to install another plugin and use hooks.

While it’s working well, it still have some features missing.

One of the missing stuffs is beeing able to display GPS data.
My photo blog have Geo-Tagged pictures. I want to be able to display them along with a google map image so my readers can see where it was taken. I also want to display some of the EXIF informations, like lense type, aperture, shutter speed and so on…

While some of them (most) are already handeled by the NextGen gallery, some of them are not.
NextGen Gallery is using the exif_read_data function to get the data from the file like :

  1. $this->exif_data = @exif_read_data($this->image->imagePath , 0, true );

Then, the RAW exif datas are separated in arrays. When trying to access the EXIF tags (using get_EXIF), only the part of the array under [EXIF] will be used. In fact this is partly false, as the get_EXIF function also dig under IFD0 and WINXP.
As the GPS data from my Nikon D700 are under the [GPS] array, there is no chance that NextGen gallery sees them even if you use the wordpress filter to add some new EXIF tags.

Then you only have one solution : check in the RAW meta-data or… change NextGen so it can handle them in the EXIF tags stored in the database.

So, my solution is divided in few parts :

  • Hardcode some new EXIF tags
  • get the GPS data inside get_EXIF
  • add a function to parse the GPS data and make them readable/usable by Google Map

Let’s do it :

Hardcode some new EXIF tags

In the file lib/meta.php, change the get_common_meta function so it look like :

  1. function get_common_meta() {
  2.                 global $wpdb;
  3.  
  4.                 $meta = array(
  5.                         ‘aperture’ => 0,
  6.                         ‘credit’ =>  »,
  7.                         ‘camera’ =>  »,
  8.                         ‘caption’ =>  »,
  9.                         ‘created_timestamp’ => 0,
  10.                         ‘copyright’ =>  »,
  11.                         ‘focal_length’ => 0,
  12.                         ‘iso’ => 0,
  13.                         ‘shutter_speed’ => 0,
  14.                         ‘flash’ => 0,
  15.                         ‘title’ =>  »,
  16.                         ‘altitude’ =>  »,
  17.                         ‘longitude’ =>  »,
  18.                         ‘latitude’ =>  »,
  19.                         ‘timestamp’ =>  »,
  20.                         ‘datestamp’ =>  »,
  21.                         ‘satellites’ =>  »,
  22.                         ‘direction’ =>  »,
  23.                         ‘lense’ =>  »,
  24.                         ‘keywords’ =>  »
  25.                 );

As you can see, I add all the GPS data, plus « lense », which is just a hook as the EXIF tag for the lense is actualy « UndefinedTag:0xA434″

You can also add the new tags in the i8n translation function

  1. function i8n_name($key) {
  2.  
  3.                 $tagnames = array(
  4.                 ‘aperture’                      => __(‘Aperture’,‘nggallery’),
  5.                 ‘credit’                        => __(‘Credit’,‘nggallery’),
  6.                 ‘camera’                        => __(‘Camera’,‘nggallery’),
  7.                 ‘caption’                       => __(‘Caption’,‘nggallery’),
  8.                 ‘created_timestamp’ => __(‘Date/Time’,‘nggallery’),
  9.                 ‘copyright’             => __(‘Copyright’,‘nggallery’),
  10.                 ‘focal_length’          => __(‘Focal length’,‘nggallery’),
  11.                 ‘iso’                           => __(‘ISO’,‘nggallery’),
  12.                 ‘shutter_speed’         => __(‘Shutter speed’,‘nggallery’),
  13.                 ‘title’                         => __(‘Title’,‘nggallery’),
  14.                 ‘author’                        => __(‘Author’,‘nggallery’),
  15.                 ‘tags’                          => __(‘Tags’,‘nggallery’),
  16.                 ‘subject’                       => __(‘Subject’,‘nggallery’),
  17.                 ‘make’                          => __(‘Make’,‘nggallery’),
  18.                 ‘status’                        => __(‘Edit Status’,‘nggallery’),
  19.                 ‘category’                      => __(‘Category’,‘nggallery’),
  20.                 ‘keywords’                      => __(‘Keywords’,‘nggallery’),
  21.                 ‘created_date’          => __(‘Date Created’,‘nggallery’),
  22.                 ‘created_time’          => __(‘Time Created’,‘nggallery’),
  23.                 ‘position’                      => __(‘Author Position’,‘nggallery’),
  24.                 ‘city’                          => __(‘City’,‘nggallery’),
  25.                 ‘location’                      => __(‘Location’,‘nggallery’),
  26.                 ‘state’                         => __(‘Province/State’,‘nggallery’),
  27.                 ‘country_code’          => __(‘Country code’,‘nggallery’),
  28.                 ‘country’                       => __(‘Country’,‘nggallery’),
  29.                 ‘headline’                      => __(‘Headline’,‘nggallery’),
  30.                 ‘credit’                        => __(‘Credit’,‘nggallery’),
  31.                 ‘source’                        => __(‘Source’,‘nggallery’),
  32.                 ‘copyright’                     => __(‘Copyright Notice’,‘nggallery’),
  33.                 ‘contact’                       => __(‘Contact’,‘nggallery’),
  34.                 ‘last_modfied’          => __(‘Last modified’,‘nggallery’),
  35.                 ‘tool’                          => __(‘Program tool’,‘nggallery’),
  36.                 ‘format’                        => __(‘Format’,‘nggallery’),
  37.                 ‘width’                         => __(‘Image Width’,‘nggallery’),
  38.                 ‘height’                        => __(‘Image Height’,‘nggallery’),
  39.                 ‘flash’                         => __(‘Flash’,‘nggallery’),
  40.                 ‘latitude’                      => __(‘Latitude’,‘nggallery’),
  41.                 ‘longitude’                     => __(‘Longitude’,‘nggallery’),
  42.                 ‘altitude’                      => __(‘Altitude’,‘nggallery’),
  43.                 ‘lense’                      => __(‘Lense’,‘nggallery’),
  44.                 );

get the GPS data inside get_EXIF

Now, every time you insert a new image or re-import the meta-data, the new tags will be asked. We need to change the get_EXIF function so it can find them.
Still in lib/meta.php, go down to the get_EXIF function and change it to  :

  1. function get_EXIF($object = false) {
  2.  
  3.                 if ( !$this->exif_data )
  4.                         return false;
  5.  
  6.                 if (!is_array($this->exif_array)){
  7.  
  8.                         $meta= array();
  9.  
  10.             if ( isset($this->exif_data[‘EXIF’]) ) {
  11.                 $exif = $this->exif_data[‘EXIF’];
  12.  
  13.                         if (!empty($exif[‘FNumber’]))
  14.                                 $meta[‘aperture’] = ‘F ‘ . round( $this->exif_frac2dec( $exif[‘FNumber’] ), 2 );
  15.                         if (!empty($exif[‘Model’]))
  16.                                 $meta[‘camera’] = trim( $exif[‘Model’] );
  17.                         if (!empty($exif[‘DateTimeDigitized’]))
  18.                                 $meta[‘created_timestamp’] = date_i18n(get_option(‘date_format’) . ‘ ‘ . get_option(‘time_format’), $this->exif_date2ts($exif[‘DateTimeDigitized’]));
  19.                         if (!empty($exif[‘FocalLength’]))
  20.                                 $meta[‘focal_length’] = $this->exif_frac2dec( $exif[‘FocalLength’] ) . __(‘ mm’,‘nggallery’);
  21.                         if (!empty($exif[‘ISOSpeedRatings’]))
  22.                                 $meta[‘iso’] = $exif[‘ISOSpeedRatings’];
  23.                         if (!empty($exif[‘ExposureTime’])) {
  24.                                  $meta[‘shutter_speed’]  = $this->exif_frac2dec ($exif[‘ExposureTime’]);
  25.                                  $meta[‘shutter_speed’]  =($meta[‘shutter_speed’] > 0.0 and $meta[‘shutter_speed’] < 1.0) ? ( ’1/’ . round( 1 / $meta[‘shutter_speed’], -1) ) : ($meta[‘shutter_speed’]);
  26.                                  $meta[‘shutter_speed’] .=  __(‘ sec’,‘nggallery’);
  27.                                 }
  28.                         //Bit 0 indicates the flash firing status
  29.                         if (!empty($exif[‘Flash’]))
  30.                                 $meta[‘flash’] =  ( $exif[‘Flash’] & 1 ) ? __(‘Fired’, ‘nggallery’) : __(‘Not fired’,‘ nggallery’);
  31.  
  32.                         if (!empty($exif[‘UndefinedTag:0xA434′]))
  33.                                 $meta[‘lense’] = $exif[‘UndefinedTag:0xA434′];
  34.             }
  35.  
  36.                         // additional information
  37.             if ( isset($this->exif_data[‘IFD0′]) ) {
  38.                         $exif = $this->exif_data[‘IFD0′];
  39.  
  40.                         if (!empty($exif[‘Model’]))
  41.                                 $meta[‘camera’] = $exif[‘Model’];
  42.                         if (!empty($exif[‘Make’]))
  43.                                 $meta[‘make’] = $exif[‘Make’];
  44.                         if (!empty($exif[‘ImageDescription’]))
  45.                                 $meta[‘title’] = utf8_encode($exif[‘ImageDescription’]);
  46.                         if (!empty($exif[‘Orientation’]))
  47.                                 $meta[‘Orientation’] = $exif[‘Orientation’];
  48.             }
  49.             // additional GPS information
  50.             if ( isset($this->exif_data[‘GPS’]) ) {
  51.                         $exif = $this->exif_data[‘GPS’];
  52.                         // send exif data to the function to get GPS on one line
  53.                         if (!empty($exif[‘GPSLatitudeRef’])) {
  54.                                 $GPS=self::get_Exif_GPS($exif, 1);
  55.                                 $meta[‘latitude’] = $GPS[‘latitude’];
  56.                                 $meta[‘longitude’] = $GPS[‘longitude’];
  57.                                 $meta[‘altitude’] = $GPS[‘altitude’]." metres";
  58.                                 $meta[‘timestamp’] = $GPS[‘timestamp’];
  59.                                 $meta[‘direction’] = $GPS[‘direction’];
  60.                                 if (!empty($exif[‘GPSSatellites’]))
  61.                                         $meta[‘satellites’] = $exif[‘GPSSatellites’];
  62.                                 if (!empty($exif[‘GPSDateStamp’]))
  63.                                         $meta[‘datestamp’] = $exif[‘GPSDateStamp’];
  64.                                 }
  65.             }

You can see two things here :
- if the meta asked is « lense », we look for the un-named attribute
- when we are done with EXIF and IFD0, we check in the GPS array

add a function to parse the GPS data and make them readable/usable by Google Map

Now we create the function to re-calculate the GPS coords. Create a function somewhere in the class. A good place is at the end of the lib/meta.php file, just before the last closing bracket.

  1. function get_Exif_GPS($exif, $assoc = false) {
  2.                 //get the Hemisphere multiplier
  3.                 $LatM = 1; $LongM = 1;
  4.                 if($exif["GPSLatitudeRef"] == ‘S’) {
  5.                         $LatM = -1;
  6.                         }
  7.                 if($exif["GPSLongitudeRef"] == ‘W’) {
  8.                         $LongM = -1;
  9.                         }
  10.  
  11.                 //get the GPS data
  12.                 $gps[‘LatDegree’]=$exif["GPSLatitude"][0];
  13.                 $gps[‘LatMinute’]=$exif["GPSLatitude"][1];
  14.                 $gps[‘LatgSeconds’]=$exif["GPSLatitude"][2];
  15.                 $gps[‘LongDegree’]=$exif["GPSLongitude"][0];
  16.                 $gps[‘LongMinute’]=$exif["GPSLongitude"][1];
  17.                 $gps[‘LongSeconds’]=$exif["GPSLongitude"][2];
  18.                 $gps[‘Altitude’]=$exif["GPSAltitude"];
  19.                 $gps[‘TimeHour’]=$exif["GPSTimeStamp"][0];
  20.                 $gps[‘TimeMin’]=$exif["GPSTimeStamp"][1];
  21.                 $gps[‘TimeSec’]=$exif["GPSTimeStamp"][2];
  22.                 $gps[‘direction’]=$exif["GPSImgDirection"];
  23.  
  24.                 //convert strings to numbers
  25.                 foreach($gps as $key => $value) {
  26.                         $pos = strpos($value, ‘/’);
  27.                         if($pos !== false) {
  28.                                 $temp = explode(‘/’,$value);
  29.                                 $gps[$key] = $temp[0] / $temp[1];
  30.                                 }
  31.                         }
  32.  
  33.                 //calculate the decimal degree
  34.                 $result[‘latitude’] = $LatM * ($gps[‘LatDegree’] + ($gps[‘LatMinute’] / 60) + ($gps[‘LatgSeconds’] / 3600));
  35.                 $result[‘longitude’] = $LongM * ($gps[‘LongDegree’] + ($gps[‘LongMinute’] / 60) + ($gps[‘LongSeconds’] / 3600));
  36.                 $result[‘altitude’] = $gps[‘Altitude’];
  37.                 $result[‘timestamp’] = $gps[‘TimeHour’].‘:’.$gps[‘TimeMin’].‘:’.$gps[‘TimeSec’];
  38.                 $result[‘direction’] = $gps[‘direction’];
  39.  
  40.                 if($assoc) {
  41.                         return $result;
  42.                         }
  43.  
  44.                 return json_encode($result);
  45.         }

Conclusion

Re-importing the meta-data of all your pictures should add the new stuffs.

I’v posted in the WordPress forum and asked for this to be added to the NextGen Gallery dev tree. Still have no answer for now. Maybe someone will come with a better code or better idea ?
I also asked for someone to check how GPS data are included in files from other brands as I can only tell for the Nikon’s D700.

jQuery tricks and notes

jQuery is a well known JavaScript « framework ». It have unique features for DOM manipulation and web page animations. Another one is MooTools, said to be better in animations.

When you’re on a webpage with sliding images (orbit, novo slider…), growing windows or overlays… you can be pretty sure they are using one of these frameworks. The latest versions of WordPress bundle jQuery. As I wanted a special theme for my photo-blog (not yet finished but can be seen here), I had to dig in jQuery.

While the jQuery basis is really simple, somehow well documented on their website and full of examples on the net, you still have tricks to know so your code is 100% efficient, bug free and more important cross browser compatible (I mean, compatible with IE 6/7).

I will reference here the pages/people talking of such hints, tricks and notes, and maybe give my own recommendations and discoveries.

First one is actualy mine, even if it’s obvious : install Firebug or enable Safari Developper options in your browser. This way, just right-clic on a part of a webpage and « Inspect » it.
Most of jQuery scripts are in « full text », not minified or obfuscated. Or, at least, you will find clues of the author, the licence… and be able to use it, copy/modify it or just be insipred.

Second one is a must-read when you already know the basis of jQuery. It’s a 14 point tricks/notes from Jeffrey Way and located at http://net.tutsplus.com

They also have two other interresting articles about Hidden Features and Animation.

I would also like to add two blogs/website of people providing great examples and tutorials for free :

More will come

Sending SMS from Nagios

logo

Sometimes you need to be able to send SMS from a computer. This is obvious when you’re talking of monitoring your servers. Email alerts are good, but what if you’re sleeping ?
I used to set up a SMS modem, with it’s own SIM card and subscription. This is really easy, using smsd daemon, to send SMS. Just put a formated file in a directory and bam!, you SMS is fired.
But what when you can’t set a SMS Modem in a datacenter ?

Then you have to use an online SMS provider.

  • Good
  • you just have to call an API to send a SMS

  • BAD
  • it’s not free (you pay per SMS when the modem can have an unlimited SMS sending subscription
    it is network dependant ; if you have a network failure, you will never be informed

    Lire la suite de l’article »

    computer stuffs…

    The main purpose of this blog is to act as a reminder, a todo. Here are things i’ve just found and needs a second look at, or more, a testing.

  • Human readable Glassfish Log
  • This is a shell (sh) script that should made things easier when having a look or doing a « tail -f » at Glassfish error logs.

  • Rajeshwar’s Weblog
  • This is a blog, lately talking about Glassfish V3 REST api implementation. As far as I know this is (still) not working with GF v2, which already have JMX and, if you’re a registered Sun user, SNMP. But worth having a look.

  • Beet
  • It seems to me that most of developpers are using Spring framework nowadays. This tool should enable them (or force them ?) to have a deeper look of what the framework is actualy doing. Seriously, comments welcome. May be the weapon of choice for sysadmins like me, dealing with developpers who hide behing their framework (like if the framework was an excuse… huhuhu).

  • PandoraFMS
  • Another monitoring software… well… to be tested.

  • Oracle Database-backed iGoogle Gadgets
  • An interesting thing you can do with Google’s API… It should with any database, but hey, a free software working with Oracle is worth beeing mentioned :)

  • Other Oracle related articles
  • Oracle TimesTen In-Memory Database
  • This is a PDF file dealing with TimesTen Database. This is a product newly (2 or 3 years) bought by Oracle, and well integrated. Embed the database close to the application, in the application server. Data are replicated at startup. You can choose which database, which table, which data using a filter, or even do transformations to the data. You select the synchronization frequency and there you go. I had a session OOW 2009 about that and how it was used to break a CDN application in two parts : one for slow data change (read/write to the DB) and one for massive fast queries on the delivery side. Ok, this use a lot of RAM… but RAM is cheap isn’t it ?

    Now we have some cool things to read and test, don’t we ? :)

    Un peu de lecture…

    Tutoriel sur l’injection SQL : http://st-curriculum.oracle.com/tutorial/SQLInjection/index.htm

    Oracle Performance Tuning Guide

    Un bon blog sur Oracle : http://sysdba.wordpress.com/ 

    A lire sur Python / Django :

    VirtuelEnv, qui permet de gerer des « package d’installation » de Python, et garder la distrib de base « propre »
    Un exemple d’utilisation de VirtualEnv
    Un autre blogger qui parle de VirtualEnv (lire les commentaires)

    Et n’oubliez pas d’installer easy_install :)

    Building MacPorts Py-Mysql on Leopard

    If you installed over your old Tiger or if you are new user, you may have experienced errors when trying to build py-mysql.Py-mysql is a Python module to connect to Mysql.I’m using it to have Django, the Python Web Framework, to connect to Mysql database. This is what I got when trying to install :  

    # port install py-mysql
    --->  Building py-mysql with target build
    Error: Target org.macports.build returned: shell command " cd "/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_python_py-mysql/work/MySQL-python-1.2.2" && /opt/local/bin/python2.4 setup.py build " returned error 1
    Command output: running build
    running build_py
    copying MySQLdb/release.py -> build/lib.macosx-10.3-ppc-2.4/MySQLdb
    running build_ext
    building '_mysql' extension
    /usr/bin/gcc-4.0 -fno-strict-aliasing -Wno-long-double -no-cpp-precomp -mno-fused-madd -fno-common -fno-common -dynamic -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -Dversion_info=(1,2,2,'final',0) -D__version__=1.2.2 -I/opt/local/include/mysql5/mysql -I/opt/local/Library/Frameworks/Python.framework/Versions/2.4/include/python2.4 -c _mysql.c -o build/temp.macosx-10.3-ppc-2.4/_mysql.o
    In file included from /opt/local/include/mysql5/mysql/mysql.h:47,
                     from _mysql.c:40:
    /usr/include/sys/types.h:92: error: duplicate 'unsigned'
    /usr/include/sys/types.h:92: error: two or more data types in declaration specifiers
    error: command '/usr/bin/gcc-4.0' failed with exit status 1
    
    Error: Status 1 encountered during processing.
    

    I tried to upgrade MacPorts… but I already had the latest.

    # port selfupdate
    
    MacPorts base version 1.600 installed
    
    Downloaded MacPorts base version 1.600
    
    The MacPorts installation is not outdated and so was not updated
    selfupdate done!

    I finaly found the solution on http://rob.cogit8.org/blog/2007/Nov/14/installing-django-leopard-mac-os-105/

    Google is everywhere

    Google Chart

    One new API from Google. This one allow you to create charts (graphiques, pour les francophones).

    Philippe Mougin is our guest and comes with a clean example with integration to Apple’s Cocoa programming. Check this here.

    Faire du python dans automator (Leopard)

    http://toxicsoftware.com/run-python-script

    Voila le site d’une personne qui a une solution. Cela interessera particulierement mon ami Akhen, qui fete son anniversaire demain. Tiens, c’est pour toi : http://toxicsoftware.com/run-python-script/

    une fiche memo pour Django

    C’est pas nouveau mais je viens de tomber la dessus. Ca peut etre pratique, surtout que je vais essayer de m’y remettre un peu…
    bref, c’est ici