Mon apprentissage de python avec Ogame ^^

3 décembre 2009 par Gaëtan Pas de commentaires »

The kikoolol strike back !! Mon deuxième billets de la soirée …pour pas grand chose en fait.

J’ai voulu apprendre le langage python de façon plutôt ludique en créant un bot qui créer des batiments en boucle pour Ogame … rien d’illégal bien entendu ^^.
Dans le code Python qui va suivre, vous pourrez comprendre (ou pas) comment fonctionne :

  • Les requêtes HTTP en python avec des headers à partir de zéro
  • Les Threads pour les opérations en parallèle
  • Les Semaphores, pour éviter des requêtes en parallèle (pas apprécié par Ogame dans certain cas)

Pour l’utiliser, il suffit ensuite d’ajouter au source qui vont suivre :

  1. og = Ogame()
  2. og.setSessionCookie(
  3.  "le contenu du cookie phpsessid de votre univers",
  4.  "le contenu du cookie prssess de votre univers",
  5.  "le contenu du cookie loginC de votre univers",
  6.  "le parametre de l'url &session=…",
  7.  "uniXX.ogame.fr"votre#univers
  8. )
  9. Farmer.buildInChainsPlanets(og,["id planete","id planete"],[[4,1,2,4,1,2,4,1,2,4],[4,1,2,4,1,2,4,1,2,4]])

le premier paramètre de buildInChainsPlanets est l’objet og
le second est un tableau de string contenant l’id des planètes à « farmer »
le troisième est un tableau de tableau contenant les séquences des batiments à construire :
1 pour le metal 2 pour le cristal 3 pour le deuterium 4 pour l’electricite.

Et voilà … lorsque vous aurez conquis une planète rajoutez-là au tableau ainsi que la séquence de batiments que vous voulez, puis laissez tourner le script plusieurs jours (faite gaffe avec les sessions qui risque de changer si vous vous reconnectez avec votre navigateur).
» En lire plus:Mon apprentissage de python avec Ogame ^^

Checker la validité d’une adresse mail en PHP via SMTP

3 décembre 2009 par Gaëtan Pas de commentaires »

plopinou …

Il arrive toujours un jour où l’on doit checker la validité d’une adresse mail de façon sûr (plus qu’une simple vérification sur la validité du nom de domaine).
Pour ce faire il faut directement se connecter sur le SMTP du domaine de l’adresse mail via un socket en PHP et envoyer l’adresse mail à checker.
» En lire plus:Checker la validité d’une adresse mail en PHP via SMTP

Mumuse avec GOLang …

1 décembre 2009 par Gaëtan 6 commentaires »

Depuis pas mal de temps déjà, Google a release un langage qui se veut simple, puissant … et tout et tout.

Pour savoir un peut ce que ça vaut, j’ai donc installé la bête, et fait un test basique : connexion HTTP/parsing regexp.

» En lire plus:Mumuse avec GOLang …

Virtualisation et tunnel : rajouter des PCs sur son réseau

24 novembre 2009 par Gaëtan Pas de commentaires »

Plopinou à tous …

Petite astuce toute simple, pour créer des tunnels et ainsi permettre à ses PCs virtuel (VMWare/VirtualBox) de communiquer en direct sur son réseau (enfin lorsque l’on a pas assez d’interface physique disponible … tout le monde n’en a pas 100 ^^).

Sous debian/ubuntu il faut faire un sudo apt-get install bridge-utils

Copiez les lignes suivantes dans un script nommé « tunnel.sh » (ou ce que vous voulez) :

#!/bin/bash
  1. #
  2. #Usage : tunnel.sh
  3. #Create 1 bridge + 2 tap
  4. # ./tunnel.sh -d eth0 -n 0 -n 1
  5. #Remove bridge and 2 tap
  6. # ./tunnel.sh -s 0 -s 1 -r eth0
  7. createBridge() {
  8.  brctl addbr br0
  9.  brctl addif br0 $1
  10.  ifconfig $1 promisc
  11.  dhclient br0
  12. }
  13.  
  14. deleteBridge() {
  15.  ifconfig $1 -promisc
  16.  ifconfig br0 down
  17. }
  18.  
  19. createTunnel() {
  20.  openvpn –mktun –dev tap$1
  21.  ifconfig tap$1 up
  22.  brctl addif br0 tap$1
  23. }
  24.  
  25. deleteTunnel()
  26. {
  27.  ifconfig tap$1 down
  28.  brctl delif br0 tap$1
  29.  openvpn –rmtun –dev tap$1
  30. }
  31.  
  32. chmod 0666 /dev/net/tun
  33.  
  34. while getopts d:n:s:r: OPTION
  35. do
  36.  case $OPTION in
  37.   d)createBridge $OPTARG;;
  38.   n)createTunnel $OPTARG;;
  39.   s)deleteTunnel $OPTARG;;
  40.   r)deleteBridge $OPTARG;;
  41.  esac
  42. done

Avant de créer des tunnels, il faut créer un pont sur l’interface principal (eth0), ce qui donne :

sudo sh tunnel.sh -d eth0

Puis on peut créer plusieurs tunnels : tap0, tap1 et tap2 soit la commande suivante :

sudo sh tunnel.sh -n 0 -n 1 -n 2

On peut aussi vers les 2 à la suite (l’ordre est important … d’abord le pont ensuite les tunnels) :

sudo sh tunnel.sh -d eth0 -n 0 -n 1 -n 2

Ensuite, il suffit de choisir dans l’interface de configuration de réseau de Virtualbox/VMWare une connexion par pont/bridge :

tunnel

Pour détruire l’interface tap2 (après utilisation généralement … éteindre la machine virtuelle AVANT) :

sudo sh tunnel.sh -s 2

Pour enlever le bridge :

sudo sh tunnel.sh -r eth0

Et encore une fois … les deux à la fois ^^ (l’ordre est important … on détruit d’abord le tunnel avant d’éteindre le pont : d’où le -s d’abord, puis le -r ) :

sudo sh tunnel.sh -s 2 -r eth0

Et voilà c’est tout pour ce soir …

Utiliser Git pour gérer ses projets (mini mémo)

21 novembre 2009 par Gaëtan Pas de commentaires »

Petit mémo pour la gestion de projets via GIT, un gestionnaire de version (comme SVN, mais en mieux ;) ).

Pour ma part, depuis que je suis passé à GIT, je ne me vois plus bosser sur un SVN ^^. Les principaux points positifs de l’utilisation de GIT par rapport à l’utilisation de SVN sont (pour moi) :

  • Le fait qu’un dossier peut contenir plusieurs autres projets sous gestionnaire de révision (assez difficile à maintenir en SVN)
  • Le commit local, qui permet de ne pas à avoir à tout envoyer au serveur dès que l’on fait de grosse modifications (et devoir faire un revert sur le serveur si c’est pas bon), et aussi la possibilité donc de dev sans connexion au net en profitant d’un gestionnaire de révision
  • Le système de mise en ligne simplifié des projets (pas d’architecture super lourde à déployer comme pour SVN avec les modules dav/svn).
  • Plein d’autre choses encore à venir ;)

» En lire plus:Utiliser Git pour gérer ses projets (mini mémo)

Automatiser la récupération et la compilation du kernel et de son patch GrSec

31 octobre 2009 par Gaëtan 2 commentaires »

Plop à tous…

Petit truc de geek … un script pour automatiser la récupération du dernier kernel stable depuis le site kernel.org puis le dernier patch grsecurity à appliquer sur le kernel en question (qui sort généralement un jour après la release du kernel).
Sur ubuntu, il faut tout d’abord installer le paquet kernel-package :

sudo apt-get install kernel-package

Puis récupérer le script suivant (nommé chez moi recupKernel.pl dans la commande qui suivra) :

  1. #!/usr/bin/perl
  2. require HTTP::Request;
  3. use LWP::UserAgent;
  4.  
  5. my $kernelUrl = recupKernel();
  6. my $kernelVersion = recupKernelVersion($kernelUrl);
  7. my $grsecUrl = recupGrSec($kernelVersion);
  8. my $grsecName = recupGrSecName($grsecUrl);
  9. if($kernelUrl && $grsecUrl)
  10. {
  11.  print "Url du dernier kernel stable : $kernelUrl\n";
  12.  print "Version du kernel : $kernelVersion\n";
  13.  print "Url du dernier patch GrSec stable : $grsecUrl\n";
  14.  print "Nom du Patch : $grsecName\n";
  15.  print "Recuperation du kernel : \n";
  16.  my $rK = `wget $kernelUrl`;
  17.  
  18.  print "Recuperation du patch : \n";
  19.  my $rG = `wget $grsecUrl`;
  20.  print "Extraction des données et compilation\n";
  21.  my $dT = `tar -xjf *.tar.bz2 && patch -p0 > $grsecName`;
  22. }
  23.  
  24. sub recupKernel
  25. {
  26.  my $req = HTTP::Request->new(GET => "http://kernel.org/");
  27.  my $ua = LWP::UserAgent->new;
  28.  $ua->agent("Firefox/4.0");
  29.  my $res = $ua->request($req);
  30.  if ($res->is_success) {
  31.   my $text = $res->content;
  32.   my $recherche = '<table id="brbtable([\n\t\r\W\w]*?)</table>';
  33.   $text =~ m/($recherche)/gm;
  34.   return recupHrefUrl($2);
  35.  }
  36.  return '';
  37. }
  38. sub recupHrefUrl
  39. {
  40.  my $ret=$_[0];
  41.  my $recherche = 'href="([^"]*)';
  42.  $ret =~ m/($recherche)/gm;
  43.  return $2;
  44. }
  45.  
  46. sub recupKernelVersion
  47. {
  48.  my $ret=$_[0];
  49.  my $recherche = 'linux-([0-9]+.[0-9]+.[0-9]+.[0-9]+)';
  50.  $ret =~ m/($recherche)/gm;
  51.  return $2;
  52. }
  53.  
  54. sub recupGrSecName
  55. {
  56.  my $ret=$_[0];
  57.  my $recherche = '/(grsecurity.*.patch)';
  58.  $ret =~ m/($recherche)/gm;
  59.  return $2;
  60. }
  61.  
  62. sub recupGrSec
  63. {
  64.  my $kernelV = $_[0];
  65.  my $req = HTTP::Request->new(GET => "http://www.grsecurity.net/test.php");
  66.  my $ua = LWP::UserAgent->new;
  67.  $ua->agent("Firefox/4.0");
  68.  my $res = $ua->request($req);
  69.  if ($res->is_success) {
  70.   my $text = $res->content;
  71.   my $recherche = "href=\"(test/grsecurity-[.0-9]+-$kernelV-[0-9]+.patch)\"";
  72.   $text =~ m/($recherche)/gm;
  73.   return "http://www.grsecurity.net/$2";
  74.  }
  75.  return '';
  76. }

Il suffit ensuite d’executer la commande suivante :

  1. perl recupKernel.pl && cd linux-* && make menuconfig && make-kpkg clean && make-kpkg –initrd –append-to-version "LoupZeur-grsec" kernel_image

Ce qui générera un fichier .deb qu’il faudra installer par un bon vieux dpkg -i.

PS: Lors de l’execution de la commande make menuconfig, une fenetre « bleu » apparaitra, il faudra selectionner la menu « security », puis grsecurity et choisir le niveau de sécurité « HIGH ».

PS2: Il faut aussi bien entendu selectionner ou deselectionner tout les modules inutiles (genre usb, support agp et … ).

Exemple de Bot d’Authentification et de clic en Php

20 octobre 2009 par Gaëtan Pas de commentaires »

Bonjour à tous …

Aujourd’hui ze bot « cliqueur » ^^, il s’agit en fait d’un bot qui s’authentifie en POST, récupère le cookie et va en get sur un lien (le clic quoi).

A quoi ça peut bien servir ?

Pour ma part, c’était pour récupérer une clé pour la closed beta de HON (un Dota avec des binaires pour linux, fallait pas rater ça!!) sur le site de Alienware, le problème, c’est que les clés étaient censé être disponible soit très tard dans la soirée, soit très tôt dans la matinée, et comme je n’aimais pas l’idée de rester sur le site à poireauter, j’ai fait ce que tout programmeurs auraient fait ^^, un sympatique script …

Les actions à faire étaient :

  1. Regarder sur le site si le nombre de clés disponibles étaient supérieur à 0
  2. S’authentifier
  3. Récupérer les clés

Ce qui donne donc le script suivant en tâche Cron toutes les 5 minutes (fallait juste pas oublier de couper le script après réception des clés ^^) :

  1. <?php
  2. define("USERNAME","login");
  3. define("PASSWORD","pass");
  4. define("MAILADRES","mail@mail.com");
  5. $stringLoginPost="username=".USERNAME."&password=".PASSWORD;
  6.  
  7. /***********************************************DO NOT TOUCH**************************************************/
  8. $hon = file_get_contents("http://www.alienwarearena.com/event/hon-beta-giveaway/");
  9.  
  10. preg_match('|<h3[^>]*>Closed Beta Keys Remaining</h3>[\W\w]*<h1[^>]*>([0-9]+)</h1>|iU',$hon,$retour);
  11.  
  12. if($retour[1]!=0)
  13. {
  14.  $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
  15.  if(socket_connect($socket,"www.alienwarearena.com","80"))
  16.  {
  17.  //La requete de post pour ce logger
  18.   $postReq = "POST /cmd/account/login/ HTTP/1.1\r\n";
  19.   $postReq.= "Host: www.alienwarearena.com\r\n";
  20.   $postReq.= "Connection: Keep-Alive\r\n";//comme ça on se reconnecte direct ;) Pipelinning ROXX!!
  21.   $postReq.= "Content-type: application/x-www-form-urlencoded\r\n";
  22.   $postReq.= "Content-Length: ".strlen($stringLoginPost)."\r\n\r\n";
  23.   $postReq.= $stringLoginPost."\r\n";
  24.   socket_write($socket,$postReq);
  25.   socket_recv($socket,$retour,1024,0);
  26.  //la récupération de la valeur du cookie
  27.   preg_match("#Set-Cookie: PHPSESSID=([^;]*); path=/#",$retour,$tabRet);
  28.  //On va à la page de récupération des clés ^^
  29.   $getReq = "GET /cmd/account/get-beta-key/hon/ HTTP/1.1\r\n";
  30.   $getReq.= "Host: www.alienwarearena.com\r\n";
  31.   $getReq.= "Cookie: PHPSESSID=".$tabRet[1]."\r\n";
  32.   $getReq.= "Connection: Close\r\n\r\n";
  33.   socket_write($socket,$getReq);
  34.   socket_recv($socket,$retour,1024,0);
  35.  
  36.   mail(MAILADRES,"HON KEY!!","You got an HON KEY : ".$retour);
  37.  }
  38.         socket_close($socket);
  39. }
  40. ?>

Donc voilà … le script reste une idée (qui a fonctionné dans mon cas) à modifier selon les cas, avec curl ça aurait été plus court, mais faire mumuse avec les sockets ça n’a pas de prix …

Installer un donuts sur son G1 (CyanogenMod)

17 octobre 2009 par Gaëtan Pas de commentaires »

Bijour …

Bé voilà, prochainement (voir depuis peu ^^) google a release sa nouvelle mise à jour de l’OS Android, avec pas mal de modifications dedans (plus rapide, bouffant moins de ressources, plus ergonomique, plus tout quoi …).

Etant très peu enclin à compiler la chose, je me suis tourné vers le mod de cyanogen qui publie toutes ses modifications dans un git en s’efforçant de suivre une idée : fournir quelques chose de « stable » pour l’instant que des béta ( ironie inside ^^), de sécurisé (utilisant un kernel à jour ^^ pas comme celui fournit par défaut par google), et avec plein de patch divers et variés (les principaux points forts son décrit ici).

Je ne vais pas décrire une énième fois l’ensemble des points forts d’android (on lit ça partout), je vais juste décrire les étapes d’une mise à jour/installation (sans perte de données, donc on garde gmail et compagnie ainsi que ses données : appli installé et …).

» En lire plus:Installer un donuts sur son G1 (CyanogenMod)

Tentative de Hack … quand les kikoolols attaquent!!!

11 octobre 2009 par Gaëtan Pas de commentaires »

Bijour …

Un truc assez amusant dernièrement, une tentative de hack de mon site … la deuxième attaque « importante » que mon site subit, la première avait fait planter ma base de donnée … prelude (couplé à MySQL) avait reporté les 100 000 alertes de ModSecurity (sûrement l’utilisation d’un soft genre Acunetix ou …) causant un DoS sur 2 jours le temps que la base de données sur mon RPS à 4Meg/s d’écriture de disque puisse écrire les données ^^ ou comment s’auto-détruire à cause de ses propres systèmes de sécurité en « période d’attaque » xD.

Depuis j’avais installé le mod_evasive pour blacklister les IP en cas d’accès répété dans des délais très court au service HTTP, et OSSEC qui a la capacité de bannir des IP en cas d’erreurs répétées sur différent services (ssh, http,…), histoire de limiter le spam dans ma base de données.

Et donc sur ce coup-ci, l’attaque a durée très peu de temps (environ 10 secondes) :
prelude-scan

Avant de se terminer par un sympatique ban ip :

ddos

Au passage je ferais remarquer à 82.246.200.104 (un freenaute) que mon blog utilise la dernière version de WordPress qui peut être facilement téléchargeable sur le net pour ensuite trouver des failles dans le site en local et pirater le site en question sans avoir à le scanner, donnant la possibilité pour le propriétaire de site web en question de découvrir la tentative d’attaque et éviter d’avoir son IP Fixe °(^.^)° publié sous le tag « kikoololz featured with scanner ».

Sinon, je recommande OSSEC comme IPS pour la protection de sites web, c’est assez sympa, on peut à la fois le coupler avec prelude-manager pour centraliser et visualiser l’ensemble des tentatives d’attaques sur une seule page web, envoyer un mail à l’admin (voir plusieurs en définissant des domaines d’expertises) et blacklister les attaques (même petites ^^ je me suis déjà fait ban de mon serveur en tentant une simple SQL Inj. dans l’url du blog … oui j’ai rien d’autre à faire).

Voilà pour ce sublime week-end …

Youtube et JavaFX via MediaView

11 octobre 2009 par Gaëtan Pas de commentaires »

Bijour …

Je suis encore et toujours en train de m’amuser avec JavaFX, et comme je suis un gros noob et que j’ai rien réussi à faire avec Jiwa (et que deezer ne me file toujours pas de clé pour leur API), j’ai décidé de me tourner vers Youtube qui fournit une API ( les clés pour leur API ne semblent pas à servir pour grand chose, l’essentiel de l’API (un fichier XML/ATOM) étant accessible sans être identifié …).

L’appli finale ressemble étrangement à celle crée pour Jiwa, à la seul différence qu’elle embarque un lecteur vidéo (depuis l’API 1.2.1 de javaFX il est possible de jouer des flux rtsp … le support est donc encore un peu chaotique (il manque des codec) : la vidéo joue sans le son ou l’inverse, le chargement du média s’effectue mais il n’arrive pas à le lire …, certaine fonction lié au média ne fonctionne pas (onStalled et onBuffering)).

La tête de l’application finale (super moche … encore un concept) :

youtubeFX

Néanmoins malgrès tout les problèmes du support vidéo streaming, l’effet escompté est bien là … la lecture de la vidéo bouffe beaucoup moins de ressource (faut dire que la vidéo est au format mpeg4-sp (176*140) pour les téléphones portable donc … ;) ).

La recherche des vidéos est effectuée en XML, j’aurais bien voulu utiliser l’objet AtomTask pour récupérer les données contenues dans le XML renvoyé par Youtube, mais malheureusement, dans leur API (celle de javaFX, pas de YouTube ^^), ils n’ont pas prévue qu’il puisse y avoir plusieurs médias dans le « content », donc j’ai du le parser à la main et faire un beau hack pour choper le flux.

Sur le plan technique, au lieu d’utiliser le MediaView, j’aurai pu utiliser la technique de Rakesh Menon en affichant une page web avec le player « chromeless de youtube » via l’API JS, mais ça aurait enlevé l’intêret de l’application puisque le but est de se débarasser du lecteur Flash.

Le temps de développement est super court (j’ai du mettre plus de temps à écrire l’article sur le blog qu’à developper l’appli ;) ), par contre, y’a déjà pas mal de hack pour rendre l’appli plus rapide/réactive, et il n’y a malheureusement aucune fonction qui permettent de déterminer si on charge la vidéo ou non (le onBuffering ne fonctionne pas :s).

Donc c’est assez naze d’avoir une appli de streaming sans état d’avancement dans le chargement du média mais comme y’a pas grand chose en français sur JavaFX et les média … je post le code (en espérant que le support de Java soit meilleur plus tard ^^) :

/*
  1.  * Main.fx
  2.  *
  3.  * Created on 9 oct. 2009, 20:18:51
  4.  */
  5.  
  6. package youtubefx;
  7.  
  8. import javafx.stage.Stage;
  9.  
  10. import javafx.scene.Scene;
  11. import javafx.scene.text.Text;
  12. import javafx.scene.media.MediaPlayer;
  13. import javafx.data.pull.PullParser;
  14. import javafx.io.http.HttpRequest;
  15. import javafx.data.pull.Event;
  16. import javafx.scene.control.Button;
  17. import javafx.scene.control.TextBox;
  18. import javafx.scene.layout.VBox;
  19. import javafx.scene.layout.HBox;
  20. import javafx.scene.control.ListView;
  21. import javafx.ext.swing.SwingListItem;
  22. import javafx.scene.input.MouseEvent;
  23. import javafx.scene.media.MediaView;
  24. import javafx.scene.media.Media;
  25. import javafx.scene.control.ProgressBar;
  26. import javafx.scene.Group;
  27. import javafx.scene.shape.Rectangle;
  28. import javafx.scene.paint.Color;
  29. import javafx.scene.CustomNode;
  30. import javafx.scene.Node;
  31.  
  32. /**
  33.  * @author Gaetan Grigis
  34.  */
  35. class Splash extends CustomNode {
  36.     var rect = Rectangle {x:0,y:0,width: 400,height: bind scene.height,fill: Color.BLACK};
  37.     var txt = Text{content: "Hello this is just a simple test to use MediaView\n"
  38.                           "and MediaPlayer with Youtube\n \n"
  39.                           "As the support of streaming by JavaFX is new\n"
  40.                           "sometimes it crash or doesn't work as expected\n"
  41.                           "because of unsupported codec (video or music\n"
  42.                           "isn't played in this case …)\n \n"
  43.                           "(Click somewhere here to close this …\n"
  44.                           "and try this …)",x: 50,y: 50,fill: Color.AQUAMARINE};
  45.     var groups = Group {
  46.         content: [rect,txt],
  47.         onMouseClicked: function( e: MouseEvent ):Void {rect.width=0;txt.content="";txt.x=0;txt.y=0}
  48.     }
  49.  
  50.     override function create():Node {return groups;}
  51. }
  52. var item : SwingListItem[] = [];
  53. var xml : PullParser = PullParser {documentType: PullParser.XML};
  54. var mus = [];
  55. //UI items
  56. var scene = Scene {width: 400,height: 250};
  57. var searchTxt = TextBox{width:bind (scene.width276),text: "Type your text .."};
  58. var searchBtn = Button{text: "Search",width: 100,action: function(){searchItem(searchTxt.text)};};
  59. var listView : ListView = ListView{width:bind (scene.width-176),height: bind (scene.height – searchTxt.height),items: bind item};
  60. var SearchBox = HBox {content: [searchTxt,searchBtn],width: bind scene.width};
  61. var PlayBox = VBox{content:[SearchBox,listView],width: bind (scene.width176),height: bind scene.height};
  62. var player = MediaPlayer{autoPlay:true};
  63. var info = Text {content: bind "{player.currentTime.toSeconds()}/{player.media.duration.toSeconds()} Sec.\nStatus : {player.status}\nClick on the progressBar\nif it doesn't start\n\tStatus 2 = playing\n\tStatus 0 = Loading/Crashed", };
  64. var pg = ProgressBar{progress: bind ProgressBar.computeProgress(player.media.duration.toSeconds(),player.currentTime.toSeconds()),onMouseClicked:function(e:MouseEvent){if(player.status!=2){player.play();}else{player.pause();}}};
  65. scene.content = HBox{content:[Splash{},PlayBox,VBox{content: [MediaView{visible:true, cache: true, mediaPlayer: player},info,pg]}]};
  66.  
  67. function searchItem(search: String)
  68. {
  69.     item = [];//on reset à la barbare ;)
  70.     var connexion : HttpRequest = HttpRequest {
  71.         method: HttpRequest.GET
  72.         location: "http://gdata.youtube.com/feeds/api/videos?v=2&amp;lr=en&amp;format=6&amp;orderby=published&amp;safeSearch=strict&amp;q={search}&amp;max-results=50"
  73.         onInput: function(is: java.io.InputStream) {
  74.             try {
  75.                 xml.input = is;
  76.                 var it = SwingListItem{};
  77.                 var i  = 0;
  78.                 xml.onEvent = function(event: Event) : Void{
  79.                     if( event.qname.prefix == "media" )
  80.                     {
  81.                         if(event.qname.name == "content" and event.typeName == "START_ELEMENT" and event.getAttributeValue("type") == "video/3gpp" )
  82.                         {
  83.                             //can't get the yt:format, so as we know that mpeg is second we just increment …
  84.                             it.value = event.getAttributeValue("url");
  85.                             i++;
  86.                         }
  87.                         if(event.qname.name == "title" and event.text!="" and event.typeName == "TEXT"){it.text = event.text;}
  88.                         if(it.text !="" and it.value!="" and i &gt; 1 ){
  89.                             insert it into item;it = SwingListItem{};
  90.                         }
  91.                     }
  92.                 };
  93.                 xml.parse();
  94.             } finally {is.close();}
  95.         }
  96.     };connexion.start();
  97. }
  98.  
  99. listView.onMouseClicked = function (e:MouseEvent):Void{
  100.     player.stop();
  101.     listView.disable=true;
  102.     //hack to stop playing while another is loading
  103.         player.media.source = null;
  104.         player.media = null;
  105.     player.media = Media{source:item[listView.selectedIndex].value.toString(),};
  106.     player.play();
  107.     listView.disable=false;
  108. }
  109. Stage {title: "ytFX",scene: scene,onClose:function(){player.pause();player.media.source = null;player.media = null;}}

Comme dit, le code est moche, y’a du hack partout plein de syntaxe différente pour des trucs similaires …