Avri Blog

Blog à l'avricot - Lord Of Castle, java, nosql, Utomia, AvriChat, javascript, Json, Css, Mootools, ajax, php...

Aller au contenu | Aller au menu | Aller à la recherche

Stop Bubble | Start

mercredi, décembre 21 2011

A primitive folder backup

Here is a simple way to backup a folder.
This shell make a tar of a folder and remove backup older than 10 days. Simple but usefull

shell
#!/bin/sh
NOW=$(date +"%Y-%m-%d")
SUFFIX="backup-nuxeo"
tar -czf "/srv/data/backup/$SUFFIX-$NOW.tar.gz"  /srv/data/app/nuxeo-dm-5.4.2-tomcat/nxserver/data/binaries

#Remove old backup files
find /srv/data/backup/ -ctime +10  -name "$SUFFIX*.tar.gz" -exec rm {} \;

cron :

shell
01 02 * * * /srv/data/backup/backup-nuxeo.sh

lundi, août 8 2011

hibernate delete all then re-insert - adding a @OrderColumn and updating db with python

Because we can have duplicated elements in a list, updating a List with hibernate will result to a full delete then re-insert. A complete explanation can be found here : Why Hibernate does "delete all then re-insert" - its not so strange A good solution is to use a Set or to add a index column to your List:

@JoinTable(name = "JOINTURE", joinColumns = @JoinColumn(name = "KEY_A"), inverseJoinColumns = @JoinColumn(name = "KEY_B"))
@ManyToMany(fetch = FetchType.LAZY)
@OrderColumn(name = "ORDERS_INDEX")
private List<MyObject> myList ;

Once the modification is done, you may need to initialize the existing entries. Here is a quick python script

#Pour installer MySQLdb : sudo apt-get install python-mysqldb
import MySQLdb
 
db=MySQLdb.connect(passwd="dev",db="mybb",host="localhost",user="dev")
#db.autocommit(1) 
 
db.query("""SELECT KEY_A, KEY_B from JOINTURE ORDER BY KEY_A""")
r=db.store_result()
 
id_A = 0 
i=0
while 1:
        row = r.fetch_row(how=1)
        if not row: 
                break
        row = row[0]
        i=i+1
        if id_A != row['KEY_A']:
                i=0 
                id_A=int(row['KEY_A']);
        try:
                c=db.cursor()
                c.execute("UPDATE JOINTURE set ORDERS_INDEX=%s where KEY_A=%s and KEY_B=%s", (i, id_A, int(row['KEY_B'])))
        except:
                print sys.exc_info()[1]
db.commit()

mardi, janvier 5 2010

cross domain communication with iframes

Je suis tombé sur un hack intéressant pour faire du cross domaine.
L'idée est qu'une iframe (ou frame) peut modifier l'url d'une frame, qu'elle soit parent ou enfant, peut importe.
Plus intéressant : si vous rajoutez un identifiant (une ancre) à la fin du lien, la page n'est pas rechargée ! Il vous suffit donc de changer le hash l'url de iframe (ou de l'url parent) qui fait du cross domaine, et de checker régulièrement si celle-ci a changée :

  1. parent.document.location.hash+= '{votreBel:{objet = "JSON"}, ici="!"}'

et dans votre document principal vous n'avez plus qu'à récupérer la nouvelle url de l'element !

Hack parfois plus utile que celui qui consiste à charger votre page sur un domaine exterieur via des balises scripts ou des balises images
En effet ce genre de méthode :

  1. function callExternalScript(url){
  2. var n = document.createElement("script");
  3. n.setAttribute("type", "text/javascript");
  4. n.setAttribute("src", url);
  5. document.getElementsByTagName("head")[0].appendChild(n);
  6. }

Ne permet d'appeler une autre page uniquement en utilisant une méthode get.
Dans mon cas, c'est mauvais : la liste des paramètres à transférer peut être vraiment importante.
La solution des iframes permet de faire la même chose mais avec une méthode post.

En bref :

  • Balise script chargée dynamiquement : envoi limité par get, reception illimité
  • IFrame hack : envoi par post illimité, réponse passée dans l'url donc limitée...

A vous de choisir !
Plus d'infos ici :
Cross domain communication with iframe

mercredi, décembre 23 2009

XMLHttpRequest and eval vs Dynamic script loading (DSL)

You want to dynamicly load js files, but what's the best solution between an XMLHttpRequest + eval (the answer) and DSL solution ?

This is the first solution : DSL.
the dslTST.txt is a hudge js file : it's mootools core duplicatide many times (2.377 mo)
At the end of the file, we have the instruction : chrono.stop(0); which will stop the chrono.

  1. chrono.start(0);
  2. var DSLScript = document.createElement("script");
  3. DSLScript.src = "dslTEST.txt";
  4. DSLScript.type = "text/javascript";
  5. document.body.appendChild(DSLScript);

The first solution only timed during the evalution of the script by the browser.
At the top of the file, I add the instruction : chrono.start(0); which will start the chrono.

  1. var DSLScript = document.createElement("script");
  2. DSLScript.src = "dslTEST.txt";
  3. DSLScript.type = "text/javascript";
  4. document.body.appendChild(DSLScript);


The second solution :

  1. chrono.start(1) ;
  2. var myRequest = new Request({
  3. method: 'get',
  4. url: 'dslTEST.txt',
  5. onSuccess: function (responseText, responseXML) {
  6. eval (responseText) ;
  7. chrono.finish(1);
  8. }
  9. });
  10. myRequest.send();

The second solution timed during the eval() function :

  1. var myRequest = new Request({
  2. method: 'get',
  3. url: 'dslTEST.txt',
  4. onSuccess: function (responseText, responseXML) {
  5. chrono.start(1) ;
  6. eval (responseText) ;
  7. chrono.finish(1);
  8. }
  9. });
  10. myRequest.send();

The speed results are quite suprising (in ms) : benchmark_dynamic_script_loading_eval.PNG

So what's the conclusion ?
DSL seems to be faster for big files. (I have run the same tests with "small" files (e.g. 1x mootools core), and there is no real difference.)

Comparison DSL with XMLHttpRequest()

This method of loading Javascript code or data by dynamically creating new <script> tags in the header does have some advantages over XMLHttpRequest() calls:

  • Seems really faster for big files.
  • Can request a file from anywhere on the net, not just the server your page was loaded from (whithout cross-domain problems, but it can be fixed using other solution than XMLHttpRequest.
  • Works in IE even when ActiveX is turned off (though not when Javascript is turned off).
  • Works with a few older browsers that don't support XMLHttpRequest, like Opera 7 (though not Macintosh versions of IE).

There are also some modest disadvantages, including:

  • Returned data has to be formatted as Javascript code. XMLHttpRequest() can be used to fetch data in any format, XML, JSON, plain text, or whatever.
  • Can only do GET requests, not POST requests.
  • Whether the request is synchronous or asynchronous is pot luck, depending on the browser. With XMLHttpRequest() you can control this.
  • When fetching JSON data from an untrusted source, there is no possiblity of checking the data before feeding it to the Javascript parser. With XMLHttpRequest() you can parse the data with something like json2.js instead of eval() for secure parsing.

Conclusion inspired by this post.

mardi, avril 14 2009

script de benchmark

J'ai souvent envie de tester rapidement si telle ou telle fonction ou manière de faire en javascript est plus ou moins efficace.
Je me suis donc fait un petit script pour faire rapidement plusieurs mesures de temps en milisecondes.
L'utilisation est simple :

  1. chrono.start(0) ; //lance le chrono
  2. //bloc d'instruction à tester
  3. chrono.finish(0) ; //arrête le chrono
  4. chrono.getResult(0, 'idElementAffichage') ; //affiche le resultat, si 'idElementAffichage' n'est pas spécifié affiche une alerte

L'avantage est que le script vous calcul automatiquement une moyenne si vous mesurez plusieurs fois d'affilé le temps, et affiche la liste de tous les temps (utile pour verifié qu'il n'y ai pas de valeurs aberrantes).
Vous pouvez aussi prendre un nombre de mesures différentes infini si vous avez plusieurs fonctions à comparer (chrono.start(1) ; ... chrono.start(n) ;)

Script du chrono :

  1. <script type="text/javascript" >
  2. var Chrono = function (){
  3. this.listChrono = new Array() ;
  4. //on demarre le chrono
  5. this.start = function (_idChrono){
  6. //si c'est la premiere fois qu'on utilise le chrono on initialise la liste des resultats comme un array.
  7. if (typeof(this.listChrono[_idChrono]) == "undefined")
  8. this.listChrono[_idChrono] = new function () {
  9. this.resultat = new Array () ;
  10. };
  11. this.listChrono[_idChrono].dateInit = new Date () ;
  12. }
  13. //on arrete le chrono
  14. this.finish = function (_idChrono){
  15. this.listChrono[_idChrono].dateFin = new Date () ;
  16. }
  17. //on affiche le resultat et insere le resultat dans la liste
  18. this.getResult = function (_idChrono, _idElement)
  19. {
  20. var delta = 1000*(this.listChrono[_idChrono].dateFin.getUTCSeconds() - this.listChrono[_idChrono].dateInit.getUTCSeconds())
  21. +this.listChrono[_idChrono].dateFin.getUTCMilliseconds() - this.listChrono[_idChrono].dateInit.getUTCMilliseconds() ;
  22. //On ajoute le nouveau temps dans le tableau
  23. this.listChrono[_idChrono].resultat.push(delta);
  24. //on fait la moyenne avec les temps deja obtenu :
  25. var moyenne = 0;
  26. var liste = '' ;
  27. var nbreResultat = this.listChrono[_idChrono].resultat.length ;
  28. var i ;
  29. for(i=0;i<nbreResultat;i++){
  30. moyenne += this.listChrono[_idChrono].resultat[i] ;
  31. liste += this.listChrono[_idChrono].resultat[i]+', ' ;
  32. }
  33. moyenne = Math.round(moyenne/nbreResultat) ;
  34.  
  35. var result = 'Temps moyen :'+moyenne+' mili sec. (liste : '+liste+')' ;
  36.  
  37. if (_idElement == null || _idElement == "")
  38. alert(result);
  39. else
  40. $(_idElement).innerHTML = result ;
  41. }
  42. }
  43. </script>