tag:blogger.com,1999:blog-22444933379246639222024-03-09T13:25:03.081+01:00Remy Saissy's blogUnknownnoreply@blogger.comBlogger17125tag:blogger.com,1999:blog-2244493337924663922.post-19709617169248270812013-08-11T19:43:00.000+02:002013-08-11T19:43:09.167+02:00New version of the MacOSX Cassandra Preferences PaneI've just released a new version of the MacOSX Cassandra Preferences Pane.<br />
<br />
What happened since the previous version?<br />
<br />
<ul>
<li>Bug fixes which prevented to use the preferences pane correctly</li>
<li>Support for arbitrary located Cassandra installation. Simply unpack your Cassandra zip and create a symlink from <your unpack path>/bin/cassandra to ~/bin/cassandra, and let the Preferences pane handle the rest</li>
<li>If you have a customized launchd plist, it will no longer be migrated. I don't think it was a meaningful feature but I'm sure it was a complex one to maintain. Feel free to let me know if you need it!</li>
</ul>
<br /><br />
The preferences pane is still not on the app store, if you already have the application, simply start it, the update will be downloaded automatically. Otherwise, you can go to GitHub: https://github.com/remysaissy/cassandra-macosx-prefspane to download it.<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-32624184451995387132013-03-03T12:52:00.001+01:002013-03-03T17:24:11.070+01:00CR du Hadoop User Group Paris du 26 Février sur Impala<br />
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Le HUG s'est déroulé dans les locaux d'AF83, dans le 2ème arrondissement Parisien.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Il n'y a eu qu'une seule présentation, celle de Marcel Kornacker Lead Architect chez Cloudera sur le projet <span class="il">Impala</span>.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">La présentation était très dense et portait sur <span class="il">Impala</span> aujourd'hui et dans un futur proche.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
Voici ce que j'en ai retenu.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"></span><br />
<a name='more'></a><br />
<span style="background-color: white;"><br /></span></div>
<h2>
<span style="background-color: white;">Impala</span></h2>
<h3>
<span style="background-color: white;">Qu'est ce qu'<span class="il">Impala</span> ?</span></h3>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><span class="il">Impala</span> est un projet OpenSource de Cloudera et non de la fondation Apache permettant de faire du requêtage SQL sur des jeux de données de type Big Data.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><span class="il">Impala</span> est adapté aussi bien à des traitements OLAP qu'OLTP et garantie des temps de réponse très rapides.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Niveau de maturité</span></h3>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">C'est aujourd'hui une bêta que Cloudera installe chez ses clients lorsque ces derniers veulent tester le produit et donner du feedback pour son amélioration.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><span class="il">Impala</span> n'est pas, aujourd'hui, prêt pour la production comme pour du POC.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Cependant, un premier palier déstabilisé sera franchi avec la sortie d'une version GA en Avril 2013.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Architecture</span></h3>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Dans <span class="il">Impala</span>, on distingue deux composants.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<h4>
<span style="background-color: white;">Le Statestore</span></h4>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">C'est ici que se trouvent les schéma des tables et que les agents <span class="il">impalas</span> (voir plus bas) s'enregistrent.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Le statestore exporte aussi une façade Thrift pour le contrôler à distance.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Au jour d'aujourd'hui, le statestore lit le contenu du NameNode et du Metastore de Hive.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Il ne s'agit pas d'une base de référence en ce sens qu'elle se construit sur la base à la fois du contenu du NameNode et des RegionServer HBase. Cloudera parle de soft-state.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Ainsi, il sera possible d'utiliser un statestore pour consolider les données se trouvant dans plusieurs clusters Hadoop et les requêtes SQL se répartiront entre les agents impalad des différents clusters en fonction du besoin.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<h4>
<span style="background-color: white;">Les agents Impalad</span></h4>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Installés sur chacun des noeuds Hadoop (HDFS ou HBase), ce composant assure à la fois le point d'entrée des requêtes SQL, le calcul du plan d'exécution et l'exécution des chunks.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Le résultat intermédiaire sur chaque agent est ensuite streamé sur le noeud à l'origine de la requête.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Le choix de l'agent qui peut traiter un bout de requête se fait en fonction de la localité de la donnée, comme pour Map Reduce donc.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Accès à <span class="il">Impala</span></span></h3>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Il y a deux modes d'accès à <span class="il">Impala</span> :</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"> - ODBC/JDBC</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"> - <span class="il">impala</span>-shell, qui se connecte à un agent impalad</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Aujourd'hui, on doit se connecter à un noeud en particulier. Il est prévu d'ajouter un mécanisme de load balancing afin de ne plus avoir à se soucier de la charge des agents.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">D'autre part, Kerberos est déjà supporté.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Stockage et formats supportés</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Il n'y a pas de contrainte particulière de stockage ni de format, le produit se voulant le plus ouvert possible.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">Ce qui est supporté aujourd'hui :</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"> - stockage RAW avec ou sans compression LZO</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"> - stockage SequenceFile ou RCFile avec Snappy ou GZip</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;">La version GA apportera entre autres le support pour les fichiers binaires Avro.</span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<span style="background-color: white;"><br /></span></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: 13px;">
<h3>
<span style="background-color: white;">Les performances</span></h3>
<div>
<span style="background-color: white;">Les performances sont un élément fondamental pour eux. <span class="il">Impala</span> est écrit en C++, ne repose pas sur MapReduce et les requêtes SQL soumises au moteur sont transformées en bytecode LLVM pour que ce dernier puisse générer au runtime le code exécutant l'opération SQL demandée.</span></div>
<div>
<span style="background-color: white;">Un autre point important est de réduire autant que possible l'empreinte mémoire des agents.</span></div>
<div>
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Un moteur SQL</span></h3>
<div>
<span style="background-color: white;"><span class="il">Impala</span> permet de requêter en SQL-92 avec globalement les même limitations que Hive plus le fait qu'aujourd'hui on ne peut pas faire d'opération de DDL.</span></div>
<div>
<span style="background-color: white;">Le support pour les opérations DDL arriveront courant 2013 de même que les opérations d'INSERT, de DELETE et d'UPDATE.</span></div>
<div>
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Limitations fonctionnelles actuelles</span></h3>
<div>
<span style="background-color: white;">Aujourd'hui, <span class="il">Impala</span> ne supporte pas d'UDF personnalisées, de Serdes, ni d'extension au delà de SQL tels que XPath, Json, …</span></div>
<div>
<span style="background-color: white;">De la même manière, une requête doit tenir en mémoire, les ORDER BY nécessitent une clause LIMIT, il n'y a pas de support les TOP-n et l'ordre des JOIN dépend de l'ordre dans la requête.</span></div>
<div>
<span style="background-color: white;">Ce sont là des points qui seront dépassés dans le courant de l'année 2013.</span></div>
<div>
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Quelques métriques de performances</span></h3>
<div>
<span style="background-color: white;">Sans avoir fait des tests poussés, les métriques suivantes ont été constatées :</span></div>
<div>
<span style="background-color: white;"> - Sur une petite table avec des données facilement compressible,le ratio de compression de Parquet par rapport à Snappy est de 15:1</span></div>
<div>
<span style="background-color: white;"> - <span class="il">Impala</span> est plus intensif en I/O que Hive. Sur certaines requêtes, les I/O peuvent être saturées</span></div>
<div>
<span style="background-color: white;"> - Sur des requêtes simples tenant sur la mémoire d'un seul noeud, un gain jusqu'à x100 a été constaté par rapport à Hive</span></div>
<div>
<span style="background-color: white;"> - Sur des requêtes plus complexe, le gain constaté est d'environ x2 à x3 par rapport à Hive</span></div>
<div>
<span style="background-color: white;"><br /></span></div>
<div>
<h2>
<span style="background-color: white;">Parquet</span></h2>
<div>
<span style="background-color: white;">Parquet est le successeur de Trevni, un format de stockage orienté colonne.</span></div>
<div>
<span style="background-color: white;">Il sert pour la sérialisation de :</span></div>
<div>
<span style="background-color: white;"> - Avro</span></div>
<div>
<span style="background-color: white;"> - Thrift</span></div>
<div>
<span style="background-color: white;"> - ProtoBuf</span></div>
<div>
<span style="background-color: white;">Le projet est OpenSource et conjointement développé par Cloudera et Twitter.</span></div>
<div>
<span style="background-color: white;">Parmi les fonctionnalités attendues se trouvent :</span></div>
<div>
<span style="background-color: white;"> - un nombre de colonne différent pour chaque ligne</span></div>
<div>
<span style="background-color: white;"> - les types natifs</span></div>
<div>
<span style="background-color: white;"> - l'indexation de pages pour accélérer les opérations de lookup</span></div>
<div>
<span style="background-color: white;"> - l'ajout de nouveaux encodages de types</span></div>
<div>
<span style="background-color: white;"> - la compression dictionnaire pour les valeurs à faible cardinalité</span></div>
<div>
<span style="background-color: white;"><br /></span></div>
<div>
<span style="background-color: white;">D'autre part, <span class="il">Impala</span> avec Parquet supportera les JOIN.</span></div>
</div>
<div>
<span style="background-color: white;"><br /></span></div>
<h3>
<span style="background-color: white;">Conclusion</span></h3>
<div>
<span style="background-color: white;">La vision que nous a exposé Marcel Kornacker pour <span class="il">Impala</span> peut se résumer ainsi :</span></div>
<div>
<span style="background-color: white;"> <span class="il">Impala</span> devra pouvoir être utilisé pour des requêtes exploratoires et de production sur le même cluster dans impact sur les jobs de production de ce cluster.</span></div>
</div>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2244493337924663922.post-88455869131105592752013-02-17T21:58:00.001+01:002013-02-17T21:58:32.552+01:00Using a 3G USB stick Vodafone Globetrotter K3760 - Option 431 on GNU/LinuxThese days, I need a 3G USB stick to access the internet.<br />
The USB stick provided by my company is a Vodafone Globetrotter K3760. It is actually the 3G card from Option N.V, the Option 431 model.<br />
<br />
When I tried to plug the stick in my Ubuntu, nothing happened. This was because UDEV actually didn't know the device yet.<br />
<br />
There is not a lot of comprehensive information on the internet about it (I haven't been able to find something at least), therefore here is, I hope, a simple and straightforward to get things up and running.<br />
<br />
It is a three steps process:<br />
<br />
<h3>
Add a new udev rule</h3>
<div>
Create a new rules file in the udev configuration directory.</div>
<div>
<i>sudo gedit /etc/udev/rules.d/vodafone.rules</i></div>
<div>
<br /></div>
<div>
<div>
Then, copy paste the following in the file:</div>
<div>
<br /></div>
<div>
<i># Option N.V. Globetrotter HSUPA Modem (K3760)</i></div>
<div>
<i>SUBSYSTEM=="usb", ATTR{idVendor}=="0af0", ATTR{idProduct}=="7501", RUN+="/usr/sbin/usb_modeswitch --default-vendor 0x0af0 --default-product 0x7501 --message-endpoint 0x01 --message-content 55534243785634120100000080000601000000000000000000000000000000"</i></div>
</div>
<div>
<br /></div>
<div>
Basically, it teaches udev about our device's idVendor and idProduct so it can recognize it and tell it to execute usb_modeswitch with some parameters specific to our 3G USB stick.</div>
<div>
<br /></div>
<div>
Therefore, if you have another 3G USB device, you need to find the good:</div>
<div>
<ul>
<li>idVendor</li>
<li>idProduct</li>
<li>message-endpoint (if there is one)</li>
<li>message-content</li>
</ul>
<div>
You can find a list of such informations in the usb_modeswitch sources or online here:</div>
<div>
<a href="http://www.draisberghof.de/usb_modeswitch/device_reference.txt">http://www.draisberghof.de/usb_modeswitch/device_reference.txt</a></div>
<div>
<br /></div>
<div>
Also, some devices may require to add <i>--reset-usb 1 </i>argument to the usb_modeswitch command line.</div>
</div>
<div>
Syslog is your best friend in this case.</div>
<div>
<br /></div>
<h3>
Restart the udev service</h3>
<div>
From a terminal, enter the following command:</div>
<div>
<i>sudo service udev restart</i></div>
<div>
<br /></div>
<div>
You can also restart your computer of course...</div>
<div>
<br /></div>
<h3>
Plug the 3G stick and configure the network manager</h3>
<div>
Once udev has been restarted, you can simply plug you 3G USB stick into your computer and wait for the PIN prompt.</div>
<div>
You can also configure a broadband access using the network manager since the device is now correctly detected.</div>
<div>
<br /></div>
<div>
Enjoy!</div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2244493337924663922.post-47307009599730980412012-11-04T20:48:00.001+01:002012-11-04T21:45:36.826+01:00Setting up unit tests in a Vala project using CMakeI've recently came across the issue of setting up unit tests in <a href="https://live.gnome.org/Vala/">Vala.</a><br />
Since I haven't found a lot of comprehensive documentation on the web to setup it, I share here my experience so it can be useful to somebody else (I hope). <br />
<br />
<a name='more'></a><br />
<br />
<h2>
Setting up a Vala project with CMake</h2>
The very first step is to setup the project.<br />
I use the following directory structure:<br />
<span style="font-size: x-small;"><i> +-- AUTHORS<br /> +-- ChangeLog<br /> +-- cmake</i></span><br />
<span style="font-size: x-small;"><i> |</i></span><br />
<span style="font-size: x-small;"><i> +-- vala</i></span><br />
<span style="font-size: x-small;"><i> |</i></span><br />
<span style="font-size: x-small;"><i> +-- <b>FindVala.cmake</b></i></span><br />
<span style="font-size: x-small;"><i> +-- <b>UseVala.cmake</b><br /> +-- <b>CMakeLists.txt </b></i></span><br />
<span style="font-size: x-small;"><i> +-- COPYING<br /> +--MAINTAINERS<br /> +--README<br /> +-- src</i></span><br />
<span style="font-size: x-small;"><i> |</i></span><br />
<span style="font-size: x-small;"><i> +-- <b>CMakeLists.txt </b> </i></span><br />
<span style="font-size: x-small;"><i> +-- myclass.vala<br /> +--tests</i></span><br />
<span style="font-size: x-small;"><i> |</i></span><br />
<span style="font-size: x-small;"><i> +-- <b>CMakeLists.txt</b></i></span><br />
<span style="font-size: x-small;"><i><b> </b> +-- testcase.vala</i></span> <br />
<span style="font-size: x-small;"><i> +-- test-main.vala</i></span><br />
<span style="font-size: x-small;"><i> +-- test-myclass.vala</i></span><br />
<br />
<h3>
The Vala extensions for CMake</h3>
In order to support Vala, you have to add the two files <i>FindVala.cmake</i> and <i>UseVala.cmake</i> in your source tree. They both come from the <a href="https://github.com/jakobwesthoff/Vala_CMake">Vala_CMake</a><br />
github project from Jakob Westhoff.<br />
<br />
<span style="font-size: x-small;"><i>$git clone <a href="https://github.com/jakobwesthoff/Vala_CMake">https://github.com/jakobwesthoff/Vala_CMake</a></i></span><br />
So you can also simply add an external reference in your SCM to pull the latest version.<br />
<br />
<h3>
The top level CMakeLists.txt file</h3>
Now it is time to add some configuration in our top level <i>CMakeLists.txt</i> file.<br />
The bare minimum for our project is:<br />
<br />
<span style="font-size: x-small;"><i>cmake_minimum_required (VERSION 2.8)<br />project (myproject)<br />enable_testing(true)<br /> </i></span><br />
<span style="font-size: x-small;"><i><b>list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/vala)</b><br /><br /><b>find_package(Vala "0.18.0" REQUIRED)<br />include(${VALA_USE_FILE})</b></i></span><br />
<br />
<span style="font-size: x-small;"><span style="font-size: x-small;"><i>add_subdirectory (src)<br />add_subdirectory (tests)</i></span></span><br />
As you can see, three lines are important for Vala support to be enabled.<br />
<ul>
<li><i>list()</i> tells cmake to load FindVala.cmake and UseVala.cmake</li>
<li><i>find_package()</i> tells cmake to check that vala in version 0.18.0 at least is available</li>
<li><i>include()</i> adds the required includes for compilation. </li>
</ul>
The <i>enabled_testing() </i>statement is necessary to tell cmake that we want to make unit tests on this project.<br />
<br />
<h3>
The src CMakeLists.txt file</h3>
The <i>CMakeLists.txt</i> file located in the src subdirectory contains the necessary for Vala to compile the final binary properly.<br />
The file looks like this:<br />
<br />
<span style="font-size: x-small;"><i>find_package(PkgConfig) <br /><br />pkg_check_modules(GLIB REQUIRED glib-2.0) <br />add_definitions(${GLIB_CFLAGS} ${GLIB_CFLAGS_OTHER}) <br />link_libraries(${GLIB_LIBRARIES})<br />link_directories(${GLIB_LIBRARY_DIRS})<br /><br /><b>vala_precompile</b>(VALA_C<br /> myclass.vala <br />PACKAGES<br /> glib-2.0<br /> posix<br />GENERATE_VAPI<br /> mybinary<br />GENERATE_HEADER<br /> mybinary<br />)<br /><br />add_executable(mybinary ${VALA_C})<br />add_library(mybinary-clib ${VALA_C})</i></span><br />
<br />
In this file, you use <i>pkg_check_modules()</i> for any required package that we can find later in the PACKAGES section of the <i>vala_precompile()</i> statement.<br />
<br />
If you use GIO, GEE or any other, simply replace GLIB_ by GIO_ or GEE_.<br />
<br />
Next you have to precompile your Vala sources in C sources.<br />
In order to do it, you use <i>vala_precompile()</i>.<br />
In this example, I asked to generate a .vapi file and two headers, a .h and an _internal.h.<br />
You can also use:<br />
<ul>
<li>CUSTOM_VAPIS and provide a list of the existing .vapi files to use during the precompilation</li>
<li>OPTIONS to pass options to the valac executable. Type valac --help to see available options</li>
</ul>
<br />
At this point, you can compile and run your program by typing:<br />
<span style="font-size: x-small;"><i>$cmake . && make</i></span><br />
<span style="font-size: x-small;"><i>$./src/mybinary</i></span><br />
<br />
<h3>
The tests CMakeLists.txt file</h3>
Now you can configure the <i>CMakeLists.txt</i> file which will compile the <i>unittests</i> program.<br />
<span style="font-size: x-small;"><i><br /></i></span>
<span style="font-size: x-small;"><i><b>enable_testing(true)</b></i></span><br />
<span style="font-size: x-small;"><i><b>set(LIBS ${LIBS} vignette-photo-thumbnailer-clib) </b> <br /><b>include_directories(. ../src)</b><br /><br />find_package(PkgConfig) <br />pkg_check_modules(GLIB REQUIRED glib-2.0) <br />add_definitions(${GLIB_CFLAGS} ${GLIB_CFLAGS_OTHER}) <br />link_libraries(${GLIB_LIBRARIES})<br />link_directories(${GLIB_LIBRARY_DIRS})<br /><br />vala_precompile(VALA_C</i></span><br />
<span style="font-size: x-small;"><i> testcase.vala<br /> test-main.vala<br /> test-myclass.vala<br />PACKAGES<br /> glib-2.0<br /> posix<br />)<br /><br />add_executable(unittests ${VALA_C})<br /><b>target_link_libraries(unittests ${LIBS})</b><br /><b>add_test(unittests ${CMAKE_CURRENT_BINARY_DIR}/unittests)</b></i></span><br />
<br />
As you can see, the <i>vala_precompile()</i> statement is still here. This is because your tests are written in Vala.<br />
<br />
The important things here are:<br />
<ul>
<li><i>enable_testing(true)</i> which is also present in the top level CMakeLists.txt</li>
<li><i>set()</i> which tell cmake to link your test binary with the static library version of the program to test</li>
<li><i>target_link_libraries()</i> links the static library <i>mybinary-clib.a</i> of our main program that we have generated in the src/CMakeLists.txt file</li>
<li><i>add_test()</i> makes cmake (and thus ctest) aware that the <i>unittests</i> binary is for testing purpose</li>
</ul>
<br />
Now you can run your tests by typing the following command:<br />
<span style="font-size: x-small;"><i>$cmake . && make</i></span><br />
<span style="font-size: x-small;"><i>$ctest </i> </span><br />
<br />
<h3>
Writing tests</h3>
<span style="font-weight: normal;"></span><br />
<span style="font-weight: normal;">To write tests, Vala can take advantage of the GLib which provides the GLib.Test namespace.</span><br />
<span style="font-weight: normal;"><br /></span>
<span style="font-weight: normal;">When using the GLib.Test namespace, you register your test suites in a main.</span><br />
<span style="font-weight: normal;">In our example, this is the <i>test-main.vala</i> file.</span><br />
<br />
<span style="font-weight: normal;"><span style="font-size: x-small;"><i>using GLib;<br /><br />public static int main(string[] args)<br />{<br /> Test.init(ref args); <br /> TestSuite.get_root().add_suite(new TestMyClass().get_suite());<br /> return Test.run();<br />}</i></span></span><br />
<span style="font-weight: normal;"><span style="font-size: x-small;"><i> </i></span> </span><br />
<span style="font-weight: normal;">Each suite is provided in a class. The test class contains the usual test cases along with the common <i>set_up()</i> and <i>tear_down()</i> methods.</span><br />
<span style="font-weight: normal;"><br /></span>
<span style="font-weight: normal;"><span style="font-size: x-small;"><i>using GLib;<br /><br />public class TestMyClass : MyProject.TestCase<br />{<br /><br /> public TestMyClass()<br /> {<br /> // assign a name for this class<br /> base("TestMyClass");<br /> // add test methods<br /> add_test("test_fail", test_fail);<br /> }<br /><br /> public override void set_up() <br /> {<br /> // setup your test<br /> }<br /><br /> public void test_fail()<br /> {<br /> // add your expressions<br /> assert(1 == 2);<br /> }<br /><br /> public override void tear_down() <br /> {<br /> // tear down your test<br /> }<br />}</i></span></span><br />
<span style="font-weight: normal;">You might be wondering what is that inherited <i>MyProject.TestCase</i> class. </span><br />
<span style="font-weight: normal;">The <i>GLib.Test</i> namespace provides function calls to create a test case and a test suite which is not convenient when manipulating classes.</span><br />
<span style="font-weight: normal;">The guys of the <a href="https://live.gnome.org/Libgee">libgee</a> provide a handful wrapper to let you simply inherits from a <i>Gee.TestCase</i> class.</span><br />
<span style="font-weight: normal;">Since I had some issues using this wrapper (maybe because my version of libgee is too old) and that the code is not that complicated, I simply copied and pasted it into my project.</span><br />
<span style="font-weight: normal;"><br /></span>
<span style="font-weight: normal;">This is the <i>testcase.vala</i> file.</span><br />
<span style="font-weight: normal;"><br /></span>
<span style="font-size: x-small;"><i>public abstract class MyProject.TestCase : Object <br />{ <br /> private GLib.TestSuite suite;<br /> private Adaptor[] adaptors = new Adaptor[0];<br /><br /> public delegate void TestMethod();<br /><br /> public TestCase(string name)<br /> {<br /> this.suite = new GLib.TestSuite(name);<br /> }<br /><br /> public void add_test(string name, owned TestMethod test) <br /> {<br /> var adaptor = new Adaptor(name, (owned)test, this);<br /> this.adaptors += adaptor;<br /><br /> this.suite.add(new GLib.TestCase(adaptor.name,<br /> adaptor.set_up,<br /> adaptor.run,<br /> adaptor.tear_down));<br /> }<br /><br /> public virtual void set_up() <br /> {<br /> }<br /><br /> public virtual void tear_down() <br /> {<br /> }<br /><br /> public GLib.TestSuite get_suite() <br /> {<br /> return this.suite;<br /> }<br /><br /> private class Adaptor <br /> {<br /><br /> public string name { get; private set; }<br /> private TestMethod test;<br /> private TestCase test_case;<br /><br /> public Adaptor(string name,<br /> owned TestMethod test,<br /> TestCase test_case) <br /> {<br /> this.name = name;<br /> this.test = (owned)test;<br /> this.test_case = test_case;<br /> }<br /><br /> public void set_up(void *fixture) <br /> {<br /> this.test_case.set_up();<br /> }<br /><br /> public void run(void *fixture) <br /> {<br /> this.test();<br /> }<br /><br /> public void tear_down(void *fixture) <br /> {<br /> this.test_case.tear_down();<br /> }<br /> }<br />}</i></span><br />
<br />
Now you can run your tests!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2244493337924663922.post-31964490297341329472012-09-15T10:18:00.001+02:002012-09-15T22:13:32.145+02:00Les leçons que je tire d'un startup weekend<br />
Ceci est un retour d'expérience sur un startup weekend auquel j'ai participé en Juin, à Paris.<br />
<br />
Initialement, j'étais venu en observateur, en curieux.<br />
Le startup weekend, pour ceux qui ne connaissent pas, c'est un weekend pour présenter un concept, le prototyper avec un business plan et présenter le résultat au bout de 48h. L'objectif est de convaincre le jury pour avoir l'opportunité de démarrer ensuite le projet avec un support des personnes de l'incubateur.<br />
<br />
<a name='more'></a><br />
Ce qui est génial, c'est que pendant ce weekend, les participants sont aidés par des ingénieurs de grands groupes et par des gens du business. Tout est donc fait pour vous permettre d'atteindre votre objectif.<br />
<br />
Après la présentation des projets, les participants discutent avec chaque porteur de projet et votent pour les projets qui leurs plaisent le plus. Cela permet d'éliminer les projets les moins prometteurs.<br />
<br />
Ensuite, c'est aux porteurs de projet de convaincre les personnes dont ils ont besoin pour monter leur équipe.<br />
Après avoir fait un petit tour des porteurs, je me suis finalement décidé à participer. A la base c'était pour permettre aux porteurs du projet de faire quelque chose ce weekend car ils ne parvenaient pas à trouver un développeur ios et leur projet était une application iPhone qui se trouve avoir été nommée Polagram.<br />
<br />
C'est ainsi que j'ai participé à ce startup weekend. Il a fallu recadrer de temps en temps, aider à "imposer" une décision sur le nom pour le produit, coder en avance pour montrer le travail implémenté et ainsi couper court aux discussions fonctionnelles stériles mais c'est normal, l'équipe ne se connaissait pas et la majorité ne connaissait pas non plus le développement de produit.<br />
En ayant un peu fait et connaissant les difficultés à prendre des décisions sur des points fonctionnels, je me suis donc permis de redonner du rythme lorsque c'était nécessaire.<br />
Globalement, le weekend fut très sympa et très agréable je dois dire.<br />
<br />
La bonne surprise, c'est qu'au terme du weekend, nous sommes arrivés deuxième. Notre présentatrice fut vraiment magistrale !<br />
Un des jurés avait aussi particulièrement apprécié la présentation, le design du produit... Il voulait savoir quand nous allions le sortir.<br />
En ce qui me concerne, j'étais assez chaud pour le faire. Finalement, le business model tournait tout seul ou presque (il fallait encore trouver un partenariat), était viable, et techniquement, le produit était à deux jours homme de développement d'être terminé.<br />
Rien à perdre, rien à gagner, une bonne occasion de livrer le projet donc ! Et puis, c'est l'esprit du startup weekend que les équipes qui réussissent lancent leur produit !<br />
<br />
Finalement, les porteurs du projet n'ont pas souhaité le lancer expliquant qu'ils devaient se concentrer sur leur startup actuelle.<br />
La majorité de l'équipe étant de leur avis, on a donc mis le projet en sommeil.<br />
<br />
Je me souviens que nous nous sommes revu quelques jours après car nous avions gagné un petit pécule que nous avons dépensé dans un resto. Restaurant pendant lequel j'ai compris que mes deux porteurs de projet n'avaient fait le weekend que pour recruter un dev ios... Manque de chance pour eux, je ne suis pas disponible.<br />
<br />
Un peu plus de deux mois après, de retour de vacances, toute l'ex-équipe reçoit un sympathique email d'un des deux porteurs de projet nous informant qu'ils se sont associés à une boite qui leur a redéveloppé l'application (à l'identique, j'ai vérifié) pendant l'été et que cette dernière sort bientôt sur l'appstore...<br />
Et ils n'étaient pas chaud deux mois avant pourtant. Que s'est il passé ? Mystère.<br />
<br />
Je suis super déçu.<br />
En tant que porteurs du projet, c'est à eux de prendre les décisions, c'est normal et sain. Mon point est sur la forme.<br />
Si ils avaient envoyé un email pour prévenir <i>avant</i> et <i>expliquer</i> pourquoi ils continuaient la route sans nous, ils auraient eu les sources (et auraient donc gagné du temps) et du support pour les comprendre.<br />
Pour ma part je n'aurai de toutes façons pas participé au projet car je n'ai finalement pas le temps et je pense que ça aurait aussi été le cas d'autres personnes dans l'équipe...<br />
<br />
Mes leçons de cette aventure :<br />
- Le startup weekend c'est fun, agréable, etc c'est aussi un lieu de recrutement pour les startups qui peuvent voir ce que valent les devs avant d'embaucher. J'aime. Avis aux amateurs !<br />
- Ce n'est pas forcément un lieu pour démarrer un business, mais c'est excellent pour y apprendre des choses et faire un d'entrainement à blanc.<br />
- Etre porteur d'un projet, c'est être responsable de décider mais aussi de communiquer, d'expliquer le <i>quoi</i> et le <i>pourquoi</i>, à son équipe de ce qui <i>va</i> se passer et pas ce qui a été fait sans que personne ne le sache. C'est compliqué et très humain donc.<br />
- Au terme du weekend, si l'équipe ne continue pas, les porteurs de projet doivent être clair sur le fait qu'ils continuent leur route comme ils l'entendent (l'équipe se dissout) et doivent s'assurer d'avoir tout le nécessaire pour cela (business plan, sources, présentation, ...)<br />
<br />
[1] Startup Weekend : <a href="http://startupweekend.org/">http://startupweekend.org/</a><br />
<div>
<br /></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-48961588321794394212012-08-01T16:32:00.002+02:002012-08-01T22:55:01.728+02:00Allowing installation of non Mac App Store applications on MacOSX 10.8 Mountain LionI've recently upgraded to Mountain Lion.<br />
Not that I was unhappy with Lion but I've got some feedbacks from developers telling me that there were issues installing one of my applications under Mountain Lion.<br />
<br />
Hopefully, there is a simple way to recover your liberty to install the software you want.<br />
<br />
<br />
<a name='more'></a><br />
<br />
<h3>
The guilty, GateKeeper</h3>
The latest MacOSX ships GateKeeper, a small piece of software which prevents users form installing software that do not come from the Mac App Store or is not signed by a registered developer.<br />
<br />
<h3>
What does GateKeeper do?</h3>
As long as I saw, GateKeeper doesn't check unix processes.<br />
This means that you can still use <i>homebrew </i>or <i>macports</i> to install for example Cassandra or Hadoop on your Mac.<br />
<br />
If you want to execute for example a System Preferences plugin, you need either get it from the Mac App Store or tell GateKeeper to allow Software from any source.<br />
<br />
<br />
But honestly, if you plan to use exclusively <i>homebrew</i> or <i>macports, </i>then you should seriously consider moving to a GNU/Linux distribution like Ubuntu since the Mac App Store and <i>homebrew</i>/<i>macports</i> stuff are much more developed for a long time there and do not link the user to an exclusive provider.<br />
<div>
<br /></div>
<br />
<h3>
How to tell GateKeeper to accept software from any source?</h3>
<div>
Fixing GateKeeper is pretty simple. Here is a 4-steps procedure to follow in order to achieve it.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4fUuffIIZjSwHsdxSrU8Z-sBWhhAp3W-nCMxroxJjnYqD-jBf__eAfj7I8CJO7D0YX3zWcSiGJl516u4Rxvu1oZk6G8sBzG5m84qZgRNQkngZTSnAxweXjBcpV91smlSu3sBzpjsMF7g/s1600/gatekeeper+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4fUuffIIZjSwHsdxSrU8Z-sBWhhAp3W-nCMxroxJjnYqD-jBf__eAfj7I8CJO7D0YX3zWcSiGJl516u4Rxvu1oZk6G8sBzG5m84qZgRNQkngZTSnAxweXjBcpV91smlSu3sBzpjsMF7g/s320/gatekeeper+1.png" width="320" /></a></div>
<div style="text-align: center;">
<i>Locate GateKeeper in the System Preferences.</i> </div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-DSKeiFu8oZ7fsICi0d0_aFM1zUelRTFNwTDuQI2IvjugTiM5hUYEPq00dySAn4A8sydw1icU1bh3LaNW3fM22M30BYeXJUF-e-_xXAzH9eEI4byvs807ZaVIgNOxtnjObps_kXj975E/s1600/gatekeeper+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-DSKeiFu8oZ7fsICi0d0_aFM1zUelRTFNwTDuQI2IvjugTiM5hUYEPq00dySAn4A8sydw1icU1bh3LaNW3fM22M30BYeXJUF-e-_xXAzH9eEI4byvs807ZaVIgNOxtnjObps_kXj975E/s320/gatekeeper+2.png" width="320" /></a></div>
<div style="text-align: center;">
<i>In General, unlock the preferences to change the settings.</i></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH3N9m3Ju__e6Wfm2HD-wLMx43Kp4jsUqcQI83rxbMyrBv5AzKRnZBEtklD63zK9JmEoGzd9f_dc71lXczJdaBsr9DdN7KIgHLiJh83Sw5Y6JdSBk_KjzCBXlJ3VU1JEohXZe8ykmvnCM/s1600/gatekeeper+3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH3N9m3Ju__e6Wfm2HD-wLMx43Kp4jsUqcQI83rxbMyrBv5AzKRnZBEtklD63zK9JmEoGzd9f_dc71lXczJdaBsr9DdN7KIgHLiJh83Sw5Y6JdSBk_KjzCBXlJ3VU1JEohXZe8ykmvnCM/s320/gatekeeper+3.png" width="320" /></a></div>
<div style="text-align: center;">
<i>We selection Anywhere and confirm to MacOSX that we want to <b>Allow From Anywhere.</b></i></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7yzamr0ZosToOXAgXNgsBWuwVwoN40MylK8TYuTQVoSsP1cA6B4Gq5b0DQ1DwpAuNoPiuqTQLTgNachrgoiSl_wvxb9dkdpHSmf8wk4mTAyZoynsAjUbW1HCBLlrZG_Ihsfv26fIjFqU/s1600/gatekeeper+4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7yzamr0ZosToOXAgXNgsBWuwVwoN40MylK8TYuTQVoSsP1cA6B4Gq5b0DQ1DwpAuNoPiuqTQLTgNachrgoiSl_wvxb9dkdpHSmf8wk4mTAyZoynsAjUbW1HCBLlrZG_Ihsfv26fIjFqU/s320/gatekeeper+4.png" width="320" /></a></div>
<div>
<div style="text-align: center;">
<i>Now, simply restore the locker to prevent further modifications of the settings.</i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
That's all! Now you have recovered your liberty to choose where you want to download software from.</div>
</div>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-80858775855946555432012-07-25T16:20:00.002+02:002012-11-12T22:42:10.217+01:00A Preferences Pane for Cassandra on MacOSX<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif; line-height: 18px;">In the previous blog post, I wrote about a useful piece of software (at least to me!), the MongoDB Preferences Pane for MacOSX.</span></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif; line-height: 18px;"><a href="http://www.blogger.com/goog_1311740376"><br /></a></span></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif; line-height: 18px;">Today is about the little brother, the Cassandra Preferences Pane for MacOSX.</span></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif; line-height: 18px;">Based on the same codebase , it shares the same set of functionalities.</span></div>
<div style="text-align: left;">
<a href="http://www.blogger.com/goog_1311740376"><span style="color: black; font-family: 'Trebuchet MS', sans-serif;"><br /></span></a></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif;"><span style="line-height: 18px;">It is available on Github:</span><span style="line-height: 18px;"> </span><span style="line-height: 18px;"><a href="https://github.com/remysaissy/cassandra-macosx-prefspane">https://github.com/remysaissy/cassandra-macosx-prefspane</a>.</span></span></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif;"><span style="line-height: 18px;">The latest version can be downloaded here: </span><a href="https://github.com/remysaissy/cassandra-macosx-prefspane/raw/master/download/Cassandra.prefPane.zip">https://github.com/remysaissy/cassandra-macosx-prefspane/raw/master/download/Cassandra.prefPane.zip</a></span></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Trebuchet MS', sans-serif;">If you read the MongoDB Preferences Pane announcement, you can stop reading this blog post here. The rest is the same since both share the same set of functionalities.</span></div>
<h3 style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; margin: 0px; position: relative;">
</h3>
<h3 style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; margin: 0px; position: relative;">
</h3>
<h3 style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; margin: 0px; position: relative;">
</h3>
<h2>
<a name='more'></a></h2>
<h2>
Prerequisites</h2>
<div style="line-height: 18px;">
<span style="font-family: 'Trebuchet MS', sans-serif;">This is only a preferences pane. It does not embed a Cassandra Server. Therefore, you first have to install Cassandra.</span></div>
<div style="line-height: 18px;">
<span style="font-family: 'Trebuchet MS', sans-serif;">A simple way to do it is using <a href="http://mxcl.github.com/homebrew/" style="text-decoration: none;" target="_blank">Homebrew</a></span></div>
<div style="line-height: 18px;">
<span style="font-family: 'Trebuchet MS', sans-serif;"><br /></span></div>
<div style="line-height: 18px;">
<i><span style="font-family: 'Trebuchet MS', sans-serif;">$brew install cassandra</span></i></div>
<div style="line-height: 18px;">
<br /></div>
<h2>
What can you do with it?</h2>
<span style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; line-height: 18px;">The emphasis has been put on the simplicity.</span><br />
<span style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; line-height: 18px;">Therefore the preferences pane shows the current running state of the Cassandra server along with a single button to start it.</span><br />
<br />
<span style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; line-height: 18px;">You can also check a checkbox if you want to have Cassandra always up and running.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiotfsGLvouLckfCwwwyXFd5FkA5Cxmwa7ICcXPMTjeHcudFbMKcPe5qNG2yOZ2lh4gyqhgi6LA5-Ka7MG98HMm6TRr9ofMgVRA3N9SqXxHGwcPS39Dooq9uaYWwBEUxYT8aCza3arFehQ/s1600/screenshot+started.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="color: black;"><img border="0" height="322" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiotfsGLvouLckfCwwwyXFd5FkA5Cxmwa7ICcXPMTjeHcudFbMKcPe5qNG2yOZ2lh4gyqhgi6LA5-Ka7MG98HMm6TRr9ofMgVRA3N9SqXxHGwcPS39Dooq9uaYWwBEUxYT8aCza3arFehQ/s640/screenshot+started.png" width="640" /></span></a></div>
<h2>
</h2>
<h2>
I don't speak english</h2>
<div style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; line-height: 18px;">
Nevermind, the preference pane comes in 5 flavors:</div>
<div style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; line-height: 18px;">
<ul style="line-height: 1.4; margin: 0.5em 0px; padding: 0px 2.5em;">
<li style="margin: 0px 0px 0.25em; padding: 0px;">English</li>
<li style="margin: 0px 0px 0.25em; padding: 0px;">French</li>
<li style="margin: 0px 0px 0.25em; padding: 0px;">Simplified Chinese</li>
<li style="margin: 0px 0px 0.25em; padding: 0px;">Spanish</li>
<li style="margin: 0px 0px 0.25em; padding: 0px;">Portugese</li>
</ul>
<div>
<br /></div>
</div>
<div style="font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; line-height: 18px;">
An auto update functionality has also been implemented so you won't have to worry about updating the software, just focus on your own goals!</div>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2244493337924663922.post-13588860296786787332012-07-22T14:35:00.001+02:002012-08-01T16:35:22.206+02:00A Preferences Pane for MongoDB Server on MacOSXThese last weeks, I have worked a bit with MongoDB.<br />
I work on a MacBook Pro laptop and in order to save my battery, I don't like having all my databases servers always up and running.<br />
Since I liked the MySQL Preferences Pane very much and there was nothing like that for MongoDB, I wrote it.<br />
<br />
It is available on Github: <a href="https://github.com/remysaissy/mongodb-macosx-prefspane">https://github.com/remysaissy/mongodb-macosx-prefspane</a>.<br />
The latest version can be downloaded here: <a href="https://github.com/remysaissy/mongodb-macosx-prefspane/raw/master/download/MongoDB.prefPane.zip">https://github.com/remysaissy/mongodb-macosx-prefspane/raw/master/download/MongoDB.prefPane.zip</a><br />
<h2>
<a name='more'></a></h2>
<h2>
Prerequisites</h2>
<div>
This is only a preferences pane. It does not embed a MongoDB Server. Therefore, you first have to install MongoDB.</div>
<div>
A simple way to do it is using <a href="http://mxcl.github.com/homebrew/" target="_blank">Homebrew</a></div>
<div>
<br /></div>
<div>
<i>brew install mongodb</i></div>
<div>
<br /></div>
<h2>
What can you do with it?</h2>
The emphasis has been put on the simplicity.<br />
Therefore the preferences pane shows the current running state of the MongoDB server along with a single button to start it.<br />
<br />
You can also check a checkbox if you want to have MongoDB always up and running.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH3i9F2pQkUVsz3R3fWmYnmpfhfrCkA1A1UZNz8WOzRyedW05pRKQhjR4EaxaYOJiM5Y6v7SQkRpXUTSjE25sz5q5KP3tbGvHeXeszwuge5-bamCzGKj_sdZ-elJuvqCSJ-IhrakZ6O_s/s1600/screenshot+started.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH3i9F2pQkUVsz3R3fWmYnmpfhfrCkA1A1UZNz8WOzRyedW05pRKQhjR4EaxaYOJiM5Y6v7SQkRpXUTSjE25sz5q5KP3tbGvHeXeszwuge5-bamCzGKj_sdZ-elJuvqCSJ-IhrakZ6O_s/s640/screenshot+started.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h2>
I don't speak english</h2>
<div>
Nevermind, the preference pane comes in 5 flavors:</div>
<div>
<ul>
<li>English</li>
<li>French</li>
<li>Simplified Chinese</li>
<li>Spanish</li>
<li>Portugese</li>
</ul>
<div>
<br /></div>
</div>
<div>
An auto update functionality has also been implemented so you won't have to worry about updating the software, just focus on your own goals!</div>
<div>
<br /></div>
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2244493337924663922.post-57279572978025530962012-06-19T14:11:00.001+02:002012-08-01T16:35:04.694+02:00Improve your efficiency with GMail's shortcutsThanks to a good friend, I've recently discovered a great feature in GMail: shortcuts.<br />
<div>
<br /></div>
<div>
I see you, you are thinking that I am talking about something that everybody already knows, blablabla.</div>
<div>
Well, maybe. But in my case, my knowledge of GMail's shortcuts was actually quite limited:</div>
<div>
<ul>
<li>'c' to compose a new email</li>
<li>'r' to reply</li>
<li>'a' to reply all</li>
<li>'f' to transfer</li>
</ul>
<div>
That's all. Yep, really.<br />
<br />
<a name='more'></a><br /></div>
</div>
<div>
What my friend showed me is the '?' key. When you press that key, an awesome list of very handful shortcuts appears. 'Esc' hides the dialog.</div>
<div>
Since I've discovered it, I am really much more productive using GMail. Actually, my favorite shortcuts are:</div>
<div>
<ul>
<li>'u' to go back to the conversations list</li>
<li>'s' to star a conversation</li>
<li>'e' to archive a conversation</li>
<li>'/' to search</li>
<li>'k'/'j' to go to the next / previous conversation</li>
<li>'Shift + t' to add a conversation to the task list</li>
<li>'g'+'l' to go write the name of the label you want to go into</li>
</ul>
<div>
<br /></div>
</div>
<div>
You can do much more like go in more standard labels (inbox, starred,...), make a phone call, search in chat conversations, select some messages, ... This is really easy, useful and it helps to work much faster!</div>
<div>
<br />
Thanks Google guys :).<br />
<br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2244493337924663922.post-90107720269742460802012-05-07T11:25:00.000+02:002012-05-07T11:26:44.357+02:00Export ACP from the Alfresco StoreHave you ever tried to export groups and people from an Alfresco Store?<br />
Everytime I do this, it is a pain in the ass. you have to shutdown the server and then struggle to find the right command line to perform the export.<br />
I get errors like javax.servlet exception or PermGen space and other ClassNotFound... It is a waste of time.<br />
Here is the command line I use. I tried to clean it as much as possible.<br />
It runs on an Ubuntu server with tomcat6 installed.<br />
<br />
<i>TOMCAT/webapps/alfresco/WEB-INF$sudo service tomcat6 stop</i><br />
<i># Wait a bit that tomcat has been really shutdown.</i><br />
<i>TOMCAT/webapps/alfresco/WEB-INF$</i><i>sudo java -XX:MaxPermSize=512m -classpath `locate servlet-api.jar`:classes/alfresco/module:classes:lib/* org.alfresco.tools.Export -user <MyUser> -pwd <MyPassword> -s workspace://SpacesStore -verbose -p /sys:system/sys:authorities -d /tmp authorities.xml</i><br />
<i>TOMCAT/webapps/alfresco/WEB-INF$</i><i>sudo service tomcat6 start</i><br />
<br />
The official wiki page should also now be up to date: http://wiki.alfresco.com/wiki/Export_and_Import#Export_Tool<br />
<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-85373953337284264872012-04-03T21:05:00.000+02:002012-04-03T21:18:17.516+02:00Solving the Property 'foo' is a DateTime property! CMIS issue with Chemistry and AlfrescoRecently, I worked on CMIS and Alfresco 4 for a client.<br />
It is a standard project. Everything is in Java with Maven. We developped an Alfresco custom model to fit the needs of the client...<br />
<br />
For interoperability purpose and to avoid too much extra coding on the Alfresco side, we decided to use CMIS...<br />
<br />
We ran into a <i>Property 'foo' is a DateTime property!</i> when trying to create a document using CMIS.<br />
I read message from people complaining about the issue on the web but no solution about how to fix it. Here is how to do it.<br />
<br />
<a name='more'></a><h2 style="font-weight: normal;">
<b>
The truth is in the source code </b></h2>
<br />
When you have a <i>Date</i> or a <i>DateTime</i> Java object, don't push it directly into Chemistry.<br />
Instead, you must wrap it into a <i>GregorianCalendar</i> object.<br />
<br />
The piece of code which teaches you about it is located in the Chemistry source code:<br />
<br />
<div style="font-family: inherit;">
<i>org.apache.chemistry.opencmis.client.runtime.repository.ObjectFactoryImpl.java:440:</i></div>
<span id="goog_743661590"></span><span id="goog_743661591"></span><a href="http://www.blogger.com/"></a><br />
<div class="highlight">
<pre><span style="font-family: "Courier New",Courier,monospace; font-size: small;"><i>} else if (definition instanceof PropertyDateTimeDefinition) {
if (firstValue == null) {
propertyData = bof.createPropertyDateTimeData(id, (List) null);
} else if (firstValue instanceof GregorianCalendar) {
propertyData = bof.createPropertyDateTimeData(id, (List) values);
} else {
throw new IllegalArgumentException("Property '" + id + "' is a DateTime property!");
}
}</i></span>
<div class="line" id="LC18">
</div>
</pre>
</div>
As you can see, whenever you send a <i>DateTime</i> or a <i>Date</i>, Chemistry tries to get a <i>GregorianCalendar</i> object.So all we have to do is to provide it such an object!<br />
<br />
<h2>
An example!</h2>
Consider the custom model below:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"><i><!-- Custom model name is myModel. --><br /><type name="mymodel:myContent"><br /> <title>Custom Content</title><br /> <parent>cm:content</parent><br /> <archive>true</archive><br /> <properties><br /> <property name="mymodel:registerDate"><br /> <type>d:date</type><br /> <mandatory>false</mandatory><br /> <index enabled="true"><br /> <atomic>true</atomic><br /> <stored>false</stored><br /> </index><br /> </property><br /> </properties><br /></type></i></span><br />
<br />
As you can see, we have a very simple custom type which adds only a <i>registerDate</i>.<br />
<br />
Now how would you create a document with the <i>registerDate</i> property through CMIS?<br />
<br />
Let's take the create a document example from the Apache Chemistry project website at: <a href="http://chemistry.apache.org/java/examples/example-create-update.html" target="_blank">http://chemistry.apache.org/java/examples/example-create-update.html </a>customized for our custom model.<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>// Initialization.</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>Folder parent = ....</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>String name = "myNewDocument.txt";</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>Date aRegisterDate = new Date();</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i><br /></i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>// properties </i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>// (minimal set: name and object type id)</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>Map<String, Object> properties = new HashMap<String, Object>();</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>properties.put(PropertyIds.OBJECT_TYPE_ID, "D:mymodel:myModel");</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>properties.put(PropertyIds.NAME, name);</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i><br /></i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>// The registerDate.</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>GregorianCalendar cal = new GregorianCalendar();</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>cal.setTime(aRegisterDate);</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>properties.put("mymodel:registerDate", cal);</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i><br /></i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>// content</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>byte[] content = "Hello World!".getBytes();</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>InputStream stream = new ByteArrayInputStream(content);</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(content.length), "text/plain", stream);</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i><br /></i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>// create a major version</i></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"><i>Document newDoc = parent.createDocument(properties, contentStream, VersioningState.MAJOR);</i></span></div>
<br />
<br />
As you can see, <i>registerDate</i> is a <i>GregorianCalendar</i> object. If you simply put the <i>aRegisterDate</i> object, you would have received the following exception message:<br />
Property <i>'mymodel:registerDate'</i> is a <i>DateTime</i> property is returned.<br />
<br />
But with the <i>GregorianCalendar</i> object instead, it works!<br />
<br />
<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-51456007950539130902012-02-26T16:48:00.001+01:002012-04-03T21:07:54.114+02:00Restoring the Apple's EFI on a MacBookPro with LinuxRecently, you installed GNU/Linux and deleted the /EFI/APPLE directory.<br />
But now, you need to boot from a USB key and holding the Option button no longer works! Even the recoveryHD USB doesn't work.<br />
Why? Because this code was located in /EFI/APPLE/.<br />
<br />
Here is how to restore it and why not, keep your EFI up to date on a macbook pro without having MacOSX installed.<br />
<a name='more'></a><br />
First, download the EFI update for your model: <br />
<a href="http://support.apple.com/kb/HT1237%20">http://support.apple.com/kb/HT1237 </a><br />
In my case, I have a MacBookPro8,2 so I downloaded
MBP81.0047.B27 (EFI 2.7).<br />
<br />
The DMG which is uncompressed is supposed to be moutabled under Linux using either:<br />
<i><b> </b>$sudo mount -t hfs -o loop myImage.dmg /mnt</i><br />
or<br />
<i>$sudo mount -t hfsplus -o loop myImage.dmg /mnt</i> <br />
<b><br /></b><br />
However, I was not able do it so I had to fallback to another MacOSX installation from which I retrieved the .pkg.<br />
Feel free to share yur experiences with DMGs under Linux! <br />
<br />
The .pkg file is actually a xar archive (<a href="http://linux.die.net/man/1/xar">http://linux.die.net/man/1/xar</a>).<br />
So, install xar and uncompress the .pkg using:<br />
<i>$xar -xf /mnt/MacBookProEFIUpdate.pkg</i><br />
<br />
In the uncompressed directory, the Payload file is actually a .tar.gz archive so uncompress it:<br />
<i>$tar zxf Payload</i><br />
<br />
Then go in the newly created System directory and follows subdirectories until you find a .scap file. It is named like <i>MBP81_0047_27B_LOCKED.scap</i>.<br />
Assuming your EFI partition is located at /boot/efi, copy this file to <i>/boot/efi/EFI/APPLE/FIRMWARE</i><br />
Do not forget to create the <i>/boot/efi/EFI/APPLE/EXTENSIONS</i> directory.<br />
<br />
You can reboot, it should work again!<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-87768562830426003652011-12-27T14:51:00.001+01:002012-04-03T21:19:16.523+02:00Importing photos from F-Spot in PicasaGnome users know F-spot, a photo management software for Gnome.<br />
I used to use F-Spot for a while and my photo library of almost 13 000 photos is organized with the following directories: <i>Year/Month/Day</i>.<br />
Importing all of this into Picasa could be as simple configuring Picasa to watch the old F-Spot photos directory.<br />
However, I wanted my photo library to fit Picasa's naming conventions which is one directory named <i>Year-Month-Day</i> and all the photos of that day inside.<br />
<br />
What follows is the code of a small Python script I wrote to do the job.<br />
<br />
<b></b><br />
<a name='more'></a><h2 style="font-weight: normal;">
<b>How to use the script?</b></h2>
<br />
- Copy paste the code in a file named <i>convert2picasa.py;</i><br />
- Put this file at the root of your old photo library;<br />
- Make the file executable with <i>chmod +x convert2picasa.py</i>.<br />
<br />
Run it in a terminal.<br />
Once finished, you will notice a new directory named Picasa in your old photo library. This is where all of your photos have been copied following the Picasa naming convention. Therefore you can now simply cut and paste its content in your Picasa library directory!<br />
<br />
<h3>
Convert2picasa.py</h3>
<pre>#!/usr/bin/env python
import os
import shutil
print 'Creating picasa output directory...'
try:
os.mkdir('picasa')
except OSError:
shutil.rmtree('picasa')
os.mkdir('picasa')
print 'Copying your Year/Month/Day organized photo library to a Year-Month-Day organized library into the picasa directory...'
for dirname, dirnames, filename in os.walk('.'):
dir_components = dirname.split('/')[1:]
if len(dir_components) == 3:
dest_dirname = '-'.join(dir_components)
dest_dirname = "./picasa/{0}".format(dest_dirname)
try:
os.mkdir(dest_dirname)
except OSError:
pass
finally:
print "Processing {0}...".format(dest_dirname)
for f in filename:
source_file = "{0}/{1}".format(dirname, f)
dest_file = "{0}/{1}".format(dest_dirname, f)
print "Copying {0} to {1}...".format(source_file, dest_file)
shutil.copy2(source_file, dest_file)
</pre>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-77827816169012935242011-10-28T10:40:00.001+02:002012-04-03T21:23:21.843+02:00How to implement an attribute in WebKit<br />
In a <a href="http://blog.remysaissy.com/2011/10/building-custom-webkit-for-your-macosx.html">previous article</a>, I explained how to build a custom WebKit for MacOSX.<br />
In this article, I will explain how to implement a custom attribute in WebKit.<br />
Please keep in mind that these articles reflect the current state of my explorations in the WebKit code so do not hesitate to share your thoughts and/or correct me if I'm wrong somewhere.<br />
<br />
<a name='more'></a><h2>
<span class="Apple-style-span" style="font-size: large;">The context</span></h2>
<br />
Imagine that for an obscure but good reason we want an attribute which set a custom attribute on a per <i>frame / iframe</i> tag basis.<br />
<br />
This <i>myattribute</i> attribute is expected to be an url. An example use would be:<br />
<br />
<i><iframe src="http://greatwebsite.com" </i><i>myattribute</i><i>="http://anothergreatwebsite.com" /></i><br />
<br />
<h2>
<span class="Apple-style-span" style="font-size: large;">How can we achieve this?</span></h2>
<br />
WebKit is made of three major projects<br />
<br />
<ul>
<li><i>WebKit:</i> The UI project;</li>
<li><i>JavaScriptCore:</i> Which contains the JavaScript engine code;</li>
<li><i>WebCore:</i> The backend library of WebKit. DOM related code is located here. </li>
</ul>
<br />
Basically, we want to add an attribute to the DOM so we will work on the WebCore project.<br />
<br />
The very first thing to do is to keep in mind the following sketch:<br />
<a href="http://www.webkit.org/coding/major-objects.html">http://www.webkit.org/coding/major-objects.html</a><br />
<br />
It is also important to know that during its build process, WebKit generates a certain amount of source code files among which an <i>HTMLNames.[h|cpp]</i> which is where constants for our new attributes will be.<br />
<br />
<h2 style="font-weight: normal;">
<b><span class="Apple-style-span" style="font-size: large;">Let's write some code!</span></b></h2>
<h3>
<b>Register for the code generation</b></h3>
To implement our new attribute to the source code generation, we must add it in the <i>html/HTMLAttributeNames.in</i> file which is a big flat file of all available attributes. One per line.<br />
<br />
At compile time, a constant <i>myattribute</i><i>Attr</i> will be added to the <i>HTMLNames</i> class thus allowing you to use it in other places of your code.<br />
<br />
<h3>
<b>Update the IDL</b></h3>
Then, have a look into the html directory. You will find one <i>.idl</i> file per HTML tag.<br />
<br />
IDL files define what is exposed by WebCore to JavaScript and other bindings. For more informations, you can read <a href="http://trac.webkit.org/wiki/IdlAttributes">http://trac.webkit.org/wiki/IdlAttributes</a> or you can also have a look at the W3C specification here: <a href="http://www.w3.org/TR/WebIDL/">http://www.w3.org/TR/WebIDL/</a>.<br />
<br />
So let's take the two .idl related to our tags <i>HTMLFrameElement.idl</i> and <i>HTMLIFrameElement.idl</i> and add the following line into then:<br />
<i>attribute [Reflect, URL] DOMString </i><i>myattribute</i><i>;</i><br />
<br />
<h3>
Write the custom setter to implement the custom behaviour</h3>
Now it is time to write some code that will be executed when the <i>myattribute</i> attribute will be set.<br />
<br />
Both <i>HTMLFrameElement</i> and <i>HTMLIFrameElement</i> classes have a common ancestor, <i>HTMLFrameElementBase</i>. This information is not in the .idl in which both inherits from <i>HTMLElement</i> but in the header files of both classes.<br />
<br />
Since we want our attribute to be available to both classes, let's implement our setter in <i>HTMLFrameElementBase</i>!<br />
<br />
To do it, add the following method declaration to <i>HTMLFrameElementBase.h</i>:<br />
<i>void setM</i><i>yattribute</i><i>(const AtomicString&);</i><br />
<br />
And in <i>HTMLFrameElementBase.cpp</i>, put the implementation of the method:<br />
<br />
<i>void HTMLFrameElementBase::setM</i><i>yattribute</i><i>(const AtomicString& str)</i><br />
<i>{</i><br />
<i> // Create a URL out of the referrer parameter and set it as the referrer of the current frame.</i><br />
<i> KURL url = str.isEmpty() ? KURL() : KURL(ParsedURLString, str.string());</i><br />
<i> // Do your stuff..</i><br />
<i>}</i><br />
<div>
<i><br /></i></div>
What kind of stuff can we do here?<br />
Well, almost anything you want!<br />
Looking at the <i>HTMLFrameElementBase</i> class header ancestors, you can do several things:<br />
<br />
<h3 style="font-weight: normal;">
<b>Control the FrameLoader</b></h3>
You have access to the <i>Frame</i> by which you have access to the <i>FrameLoader</i> (as shown in the the sketch at: <a href="http://www.webkit.org/coding/major-objects.html">http://www.webkit.org/coding/major-objects.html</a>).<br />
So for example, you could do the following:<br />
<i>contentFrame()->loader()->setOutgoingReferrer(url);</i><br />
in order to set a custom referrer.<br />
<br />
<h3 style="font-weight: normal;">
<b>Control the DOMWindow</b></h3>
You can also control the <i>DOMWindow</i> of the <i>Frame</i> or even the <i>Document...</i> You only have to look at what is available in these classes and use it!<br />
So for example you could do the following:<br />
<i>contentWindow()->setUrl(url);</i><br />
<br />
<h3 style="font-weight: normal;">
<b>Control another element in the Document</b></h3>
You can also access to another element in the DOM and then modify it.<br />
So for example you could do the following:<br />
<br />
<div class="p1">
<span class="s1"><span class="s1">Element *element = </span>contentDocument()-></span> getElementById(str);</div>
<div class="p1">
element->setIdAttribute("newId");</div>
<div class="p1">
<br /></div>
All of this look good. But if you run WebKit at this point, your custom setter will never be called. Why?<br />
Because we need to tell the parser that setting the <i>myattribute</i> attributes means calling our custom setter. This is done through the following method:<br />
<i> virtual void parseMappedAttribute(Attribute*);</i><br />
<br />
Add the following piece of code to <i>parseMappedAttribute(Attribute*)</i> in <i>HTMLFrameElementBase.cpp</i>:<br />
<br />
<i>if (attr->name() == </i><i>myattribute</i><i>Attr) {</i><br />
<i> setReferrer(attr->value()); </i><br />
<i>}</i><br />
<br />
This will cause your setter to be called when the attribute name will be the value of <i>myattribute</i><i>Attr</i>.<br />
<br />
Ok, you are ready to go! Compile your code, you can now load a webpage with your shiny new referrer attribute on an <i>iframe</i> tag!<br />
<br />
<h2 style="font-weight: normal;">
<b><span class="Apple-style-span" style="font-size: large;">Conclusion</span></b></h2>
Although WebKit might seems intimidating at first glance, in practice, it is mainly a great piece of software that is relatively easy to digg into… At least for such simple modifications.<br />
I'll try to keep you aware as I am discovering new existing stuffs about WebKit in my next articles.<br />
In the meantime, feel free to give me some feedback!<br />
<div>
<br /></div>
<div>
</div>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2244493337924663922.post-81601025054380213992011-10-20T11:23:00.000+02:002012-04-03T21:28:15.831+02:00Building a Custom WebKit for your MacOSX ApplicationI recently ran into the issue of how to build WebKit in order to include it in a MacOSX project.<br />
Even though it might look hard at first glance, it is actually a quite simple and straightforward process.<br />
Let's have a look at how you can do it.<br />
<a name='more'></a><br />
<h2>
<span class="Apple-style-span" style="font-size: large;">Installing XCode3</span></h2>
It might seems odd but presently WebKit does not compiles with XCode4, Therefore the first thing you need to do is to retrieve and install XCode3. XCode3 will be your compilation tool as well as your IDE for WebKit development.<br />
<br />
XCode3 is available in the Downloads section of the <a href="https://developer.apple.com/devcenter/mac/">Apple Mac Dev Center</a>.<br />
<br />
<h2>
<b><span class="Apple-style-span" style="font-size: large;">Retrieving the sources</span></b></h2>
Once you have installed the right devtools, you can retrieve the WebKit sources.<br />
Assuming you want the trunk, there is two ways to do it:<br />
<br />
<i>$svn checkout<a class="external" href="http://svn.webkit.org/repository/webkit/trunk" style="background-image: url(https://project.plizy.com/images/external.png); background-position: 0% 60%; background-repeat: no-repeat no-repeat; color: #2a5685; padding-left: 12px; text-decoration: none;">http://svn.webkit.org/repository/webkit/trunk</a> WebKit</i><br />
Retrieves the trunk of the subversion repository.<br />
<br />
<i>$curl -o WebKit-SVN-source.tar.bz<a class="external" href="http://nightly.webkit.org/files/WebKit-SVN-source.tar.bz2" style="background-image: url(https://project.plizy.com/images/external.png); background-position: 0% 60%; background-repeat: no-repeat no-repeat; color: #2a5685; padding-left: 12px; text-decoration: none;">http://nightly.webkit.org/files/WebKit-SVN-source.tar.bz2</a></i><br />
<i>$tar jxf WebKit-SVN-source.tar.bz2</i><br />
<div>
<br />
Retrieves and unpack the latest nightly build.</div>
Beware that these are not stable releases so some functionalities might be temporarily broken.<br />
<br />
<h2>
<b><span class="Apple-style-span" style="font-size: large;">Preparing the retrieved sources for building</span></b></h2>
What you want is to build WebKit and put the resulting <i>.framework</i> bundles in your application bundle's Frameworks directory.<br />
In order to do it, some preparation work is needed in the WebKit sources to ensure that the resulting dynamic libraries will be relocatable.<br />
<br />
<i>$cd WebKit/Source</i><br />
Go to the source directory of the WebKit repository. This is where WebCode, JavaScriptCore and WebKit are located.<br />
<br />
<i>$find . -type f -name 'project.pbxproj' -exec sed -i 's/INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)"/INSTALL_PATH = "@rpath"/g'</i><br />
Ensure that the <i>Installation Path</i> of dynamic libraries is relocatable otherwise you won't be able to include the built framework wherever you want to.<br />
<i>@rpath</i> is a special identifier in MacOSX linking tools used to make dynamic libraries location agnostic.<br />
<br />
<h2>
<b><span class="Apple-style-span" style="font-size: large;">Building the WebKit</span></b></h2>
This is probably the simplest part of the work. From the root directory of the repository, executes the following command:<br />
<i>$Tools/Scripts/build-webkit --release</i><br />
It build WebKit in release mode. Now you can a coffe since the building takes some time...<br />
<br />
Once done, we have some more work to do because <i>WebCore.framework</i> has to be included in <i>WebKit.framework.</i><br />
<i><br /></i><br />
<i>$cd WebKitBuild/Release</i><br />
Go into the built sources directory.<br />
<br />
<i>$mkdir WebKit.framework/Frameworks</i><br />
<i>$cp -R WebCore.framework </i><i>WebKit.framework/Frameworks/</i><br />
Copy the WebCore.framework in WebKit.framework so it can compile.<br />
<br />
<h2>
<b><span class="Apple-style-span" style="font-size: large;">Using WebKit in your project</span></b></h2>
Ok, now you are ready to use WebKit in your project. To do it, simply copy <i>WebKit.framework, </i><i>WebCore.framework,</i> <i>JavaScriptCore.framework, JavaScriptGlue.framework and WebKit2.framework</i> in your project <i>Frameworks </i>to use it!<br />
<br />
The only I still have at this point is that I need to have a duplicate <i>WebCore.framework</i> in both the Frameworks subdirectory of <i>WebKit.framework</i> bundle and a copy (which is also necessary in the final bundle) in the same directory than the others <i>.framework</i>.<br />
<br />
At last, before building your application, you will simply have to set the <i>Search Path </i>to point to the directory in your bundle where you have copied your frameworks (typically Frameworks).<br />
<div>
<br /></div>
<br />Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2244493337924663922.post-40898435964146241172011-06-01T00:23:00.000+02:002012-04-03T21:06:58.200+02:00How to create a UIImage with a gradient from one or more UIColorI recently needed to create a very specific progress bar not provided "as is" in the iOS SDK.<br />
"The progress bar have an evolving background, a text label in foreground and an animation as the download/upload progresses. It must also be possible to tap on the progress bar like on a button.".<br />
<br />
Solving this issue is pretty simple actually; you only need to use two overlapping buttons, one for the background and another for both the text label and the progression image. The latter has a clearColor background, at least for the "not yet filled" part of the progress image of course.<br />
<a name='more'></a><br />
The point of this article is to provide the piece of code which allowed me to create this progress image set on the foreground button.<br />
<br />
<i>/* Create a Core Graphics Image context with the width and height of the progress bar button</i><br />
<i> and push this context on the stack. At this point, the image is clearColored. */</i><br />
<br />
<i> UIGraphicsBeginImageContext(CGSizeMake(width, height)); </i><br />
<i> CGContextRef context = UIGraphicsGetCurrentContext(); </i><br />
<i> UIGraphicsPushContext(context); </i><br />
<i><br />
</i><br />
<i>/* Set the color to use for the fillRect method. Here we want a blue filling. */</i><br />
<i> CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);</i><br />
<i>/* Fill the Core Graphics Image with the color defined above given 'progress' the percent value as float between 0 and 1. */</i><br />
<i> CGContextFillRect(context, CGRectMake(0, 0, width * progress, height));</i><br />
<i><br />
</i><br />
<i>/* Now we can remove the graphic context from the stack, retrieve the freshly created UIImage and of course, release the Core Graphics image context we created at first. */</i><br />
<i> UIGraphicsPopContext();</i><br />
<i> UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();</i><br />
<i> UIGraphicsEndImageContext();</i><br />
<i><br />
</i><br />
<i>/* Set the new background. */</i><br />
<i> [myProgressButton setBackgroundImage:outputImage forState:UIControlStateNormal];</i><br />
<div>
<br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2244493337924663922.post-13673106620314531752011-05-25T13:45:00.000+02:002012-04-03T21:29:16.544+02:00Unit Testing an application with CoreData and RestKit.EDIT: Even though this article was written for RestKit 0.9 with the Object Mapper 1.0, it works with RestKit 0.9 and the Object Mapper 2.0.<br />
<br />
I recently had troubles with unit testing an iOS application which rely in <a href="http://restkit.org/">RestKit</a> and <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html">CoreData</a>.<br />
Since I didn't find a clear solution on the web, I share in this article how I solved this issue. It is, in fact, simpler that It may seem.<br />
Note that for my unit tests, I use the SenTestKit framework provided by Apple with XCode4.<br />
<a name='more'></a><br />
<div>
<h2>
<b>Setting up unit tests for CoreData</b></h2>
My application uses CoreData as a local cache. ResKit makes it easier to use CoreData to cache Rest responses therefore I use its RKManagedObject which is a subclass of NSManagedObject.<br />
<br />
However, when It came to initialize CoreData support through RestKit in my tests, I ran into two issues.<br />
<br />
The first looks like this:<br />
<div>
<br />
<i>'2011-05-22 13:47:00.431 otest[30023:903] CFPreferences: user home directory at file://localhost/Users/remy/Library/Application%20Support/iPhone%20Simulator/User/ is unavailable. User domains will be volatile.<br />
Test Suite '/Users/remy/Library/Developer/Xcode/DerivedData/myapp-ios-gisnhxgfwfnvxlgscffpdhamroxy/Build/Products/Debug-iphonesimulator/myapp-tests.octest(Tests)' started at 2011-05-22 11:47:03 +0000<br />
Test Suite 'BaseTestCase' started at 2011-05-22 11:47:03 +0000<br />
Test Suite 'BaseTestCase' finished at 2011-05-22 11:47:03 +0000.<br />
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds<br />
Test Suite 'SessionTest' started at 2011-05-22 11:47:03 +0000<br />
Test Case '-[SessionTest testLoginFailed]' started.<br />
2011-05-22 13:47:03.881 otest[30023:903] *** Assertion failure in -[RKManagedObjectStore createPersistentStoreCoordinator], /Users/remy/Project/myapp/vendor/RestKit/Code/CoreData/RKManagedObjectStore.m:176</i><br />
<br />
After some googling, I discovered that the issue was simply that when unit tests are initialized, the simulator path (/Users/remy/Library/Application%20Support/iPhone%20Simulator/User in this case) is not always already created.<br />
And the same goes for the iPhone Simulator/User/Documents directory which is where the CoreData sqlite database is created.<br />
Therefore a simple patch was to add the following piece of code in the -setUp method of my BaseTestCase class.<br />
<br />
<i>NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);<br />
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;<br />
if (basePath != nil && [[NSFileManager defaultManager] fileExistsAtPath:basePath] == NO)<br />
[[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil];</i><br />
<i><br />
</i><br />
Since RestKit with ObjectMapper 2.0, the Library/Caches directory is also needed<br />
<br />
<i>// Create the Library/Caches directory if the simulator doesn't have one (or the persistent store will fail to be created.)</i><br />
<i>paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);</i><br />
<i>basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;</i><br />
<i>if (basePath != nil && [[NSFileManager defaultManager] fileExistsAtPath:basePath] == NO)</i><br />
<i> [[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil];</i><br />
<div>
<br /></div>
I look for the Document directory and if it doesn't exists, I create it along with any intermediate directories in the path (in the case where the User directory does not exists).<br />
<br />
The second issue I ran into was with the model file.<br />
Normally, <a href="http://developer.apple.com/library/ios/#documentation/cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectModel_Class/Reference/Reference.html">NSManagedObjectModel::mergedModelFromBundles</a> is called by RestKit during the initialization of a new RKObjectManager. However, it looks like doing it in the unit tests does not work properly.<br />
To solve this issue, I loaded my own NSManagedObjectModel and passed it to the initialization method of RestKit.<br />
The piece of code looks like this:<br />
<br />
<i>// Force the loading of a specific object model since the OCUnit bundle is not able to do it using -mergedModelFromBundles:.<br />
NSString *modelPath = [[NSBundle bundleForClass:[MyApplication class]] pathForResource:@"DataModel" ofType:@"mom"];<br />
NSURL *modelURL = [NSURL fileURLWithPath:modelPath isDirectory:NO];<br />
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] autorelease];<br />
<br />
// Initialize the object manager.<br />
[RKObjectManager sharedManager].objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"mystore.sqlite" usingSeedDatabaseName:nil managedObjectModel: managedObjectModel];</i><br />
<br />
The important detail here is to specify a class of the Application (and not of the test bundle) in the -bundleForClass: method. It is also necessary to add the .xcdatamodel file to the source files of the unit test bundle so it will be compiled and made available in the test bundle.<br />
<br /></div>
<div>
<h2>
<b>Mocking RestKit</b></h2>
Once Core Data was up and running, I wanted to be able to mock the remote API on which my application relies. I looked around and found <a href="http://www.mulle-kybernetik.com/software/OCMock">OCMock</a> but after some tests, I concluded that it was not the right solution to simply mock the REST API I was using in my applicaton. I didn't want to modify my application code and I felt that with ObjectiveC, I should not have to use dependency injection techniques which are often used in Java to use mock objects instead of the actual network aware implementation.<br />
After some reading about <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html">the runtime and specific languages features of ObjC</a>, I realized that it was actually incredibly simple to mock anything you want using implementation exchange or more simply, categories.<br />
<br />
In spite of it, RestKit is a well designed object oriented framework and all the network communications are done using two classes: RKRequest and RKResponse.<br />
To solve my issue, I wrote a category to RKRequest which provides a reimplementation of the -fireAsynchronousRequest method (since I use only asynchronous request, but there is also a -fireSynchronousRequest for those who need it).<br />
The piece of code looks like this:<br />
<br />
<i>- (void)fireASynchronousRequest<br />
{<br />
// From the original implementation.<br />
<br />
[self prepareURLRequest];<br />
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];<br />
NSLog(@"Sending %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);<br />
[body release]; <br />
<br />
_isLoading = YES; <br />
if ([self.delegate respondsToSelector:@selector(requestDidStartLoad:)])<br />
[self.delegate requestDidStartLoad:self]; <br />
<br />
RKResponse* response = [[[RKResponse alloc] initWithRequest:self] autorelease];<br />
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil];<br />
<br />
// Now execute the mocking code.<br />
NSString *bundlePath = nil;<br />
NSInteger statusCode = 200;<br />
<br />
id requestJsonObject = nil;<br />
if (self.params != nil)</i><i> {<br />
<br />
</i><br />
<i><span class="Apple-style-span" style="font-style: normal;"><i> NSString *jsonString = [[[NSString alloc] initWithData:[self.params HTTPBody] encoding:NSUTF8StringEncoding] autorelease];</i></span></i><br />
<i><br />
</i><br />
<i> // If you use an old version of restkit with Object mapper 1.0:</i><br />
<i> requestJsonObject = [[[[RKJSONParser alloc] init] autorelease] objectFromString:jsonString];<br />
<br />
</i><br />
<i> // If you use the latest version of RestKit with Object Mapper 2.0:</i><br />
<i> id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeJSON];</i><br />
<i> NSAssert1(parser, @"Cannot perform object load without a parser for MIME Type '%@'", RKMIMETypeJSON);</i><br />
<i> NSError **error = nil;</i><br />
<i> requestJsonObject = [parser objectFromString:jsonString error:error];</i><br />
}<br />
<i> <br />
// Switch to determine which to to use<br />
…<br />
<br />
// Prepare the results.<br />
NSData *responseData = nil;<br />
if (bundlePath == nil)<br />
responseData = [NSData data];<br />
else<br />
{<br />
// Load the mock file.<br />
NSString *responseString = [NSString stringWithContentsOfFile:bundlePath encoding:NSUTF8StringEncoding error:nil];<br />
responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];<br />
}</i><br />
<br />
<i><br />
// Send the response. This is a superclass to be able to return a custom statusCode.<br />
MyHTTPURLResponse *urlResponse = [[[MyHTTPURLResponse alloc] initWithURL:_URL MIMEType:@"application/json" expectedContentLength:[responseData length] textEncodingName:nil] autorelease]; <br />
[urlResponse setStatusCode:statusCode];<br />
<br />
// Delegates in the order RestKit is expecting it.<br />
[response connection:nil didReceiveResponse:urlResponse];<br />
[response connection:nil didReceiveData:responseData];<br />
if ([response isError] == YES)<br />
[response connection:nil didFailWithError:[NSError errorWithDomain:@"test domain" code:statusCode userInfo:nil]];<br />
else<br />
[response connectionDidFinishLoading:nil];<br />
}</i><br />
<br />
That's all. Now you have no excuse to not unit test your application extensively!</div>
</div>
<div>
<br /></div>Unknownnoreply@blogger.com4