Distribuer votre appli XULRunner - 4 - Mac OSX
Par joliclic le jeudi, mai 26 2011, 17:00 - mozilla - Lien permanent
This post exists also in english
Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.
4 - Mac OSX
- 4.1 Icônes pour Mac OSX
- 4.2 Créer un lanceur
- 4.3 Quelques spécifités Mac
- 4.4 Créer un "Application Bundle"
- 4.5 Empaqueter un tar.gz et un dmg
4.1 Icônes pour Mac OSX
Nous avons besoin d'une icône icns Sur Mac les fenêtres n'ont pas d'icône, mais, plus tard, nous en utiliserons une dans le Dock. Et elle sera utilisée pour le bundle que nous créerons.
Nous pouvons générer ce fichier .icns
directement depuis
Linux. La restriction est que nous ne pouvons pas inclure des images avec
pluieurs profondeur de couleur, mais des dimensions multiples est possible.
Nous avons besoin du programme png2icns
compris dans le
paquet icnsutils.
Sur Debian/Ubuntu:
apt_get install icnsutils
Nous obtenoons notre fichier icns à partir de plusieurs png avec :
png2icns icon.icns icon128.png icon48.png icon32.png icon16.png
Vous trouverez un script bash avec cette ligne de commande dans l'archive
d'exemple relative à ce chapitre 4
(dans samples_chapter_4/data/icons/
).
4.2 Créer un lanceur
Comme pour Linux, nous utiliserons un script shell pour notre lanceur. Mais nous avons plusieurs problèmes à résoudre.
le premier n'est pas trop difficile. Le programme readlink
disponible sur Mac OSX n'est pas la version GNU, et nous ne pouvons pas
utiliser l'option -f
. Nous résouderons nous même cette fonctionnalité.
Un problème plus sérieux, est que nous ne pouvons pas déterminer où
Firefox est installé. Donc, ici, nous imposerons une limitation,
Firefox doit être installer à son emplacement par défaut,
c'est à dire /Applications/
.
Note : si vous une suggestions pour déterminer où est installer Firefox, merci de me le faire savoir ;) .
Voici ce script, myapp-mac.sh
, bien que ce ne soit
pas exactement celui que nous utiliserons plus tard :
#!/bin/sh
set -e
# see http://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script
# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && \
pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")
# resolve symlinks
while [ -h $SELF_PATH ]; do
DIR=$(dirname -- "$SELF_PATH")
SYM=$(readlink $SELF_PATH)
SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
CUR_DIR=$(dirname "$SELF_PATH")
if [ -x /Applications/Firefox.app/Contents/MacOS/firefox-bin ]; then
/Applications/Firefox.app/Contents/MacOS/firefox-bin -app "$CUR_DIR/application.ini" $@
elif [ -x /Library/Frameworks/XUL.framework/xulrunner-bin ]; then
/Library/Frameworks/XUL.framework/xulrunner-bin "$CUR_DIR/application.ini" $@
else
echo "Error: unable to find Firefox or XULRunner!"
fi
Si nous essayons ce lanceur, nous pouvons voir 2 autres problèmes,
l'icône affichée dans le dock est celui de Firefox, et le menu principal,
quand nous fermons toutes les fenêtres de notre appli, est celui de Firefox.
il y a des solutions à ces problèmes, comme nous le verrons dans les prochaines
parties.
Notez que si vous voulez vraiment utiliser un tel script, sans un bundle,
vous pouvez vouloir l'utiliser avec l'extension .command
plutôt que .sh
, car alors le fichier peut être double-cliqué
dans le Finder de Mac, ce qui ouvrira un terminal, puis l'appli.
4.3 Quelques spécifités Mac
Une particularité sur Mac, est le Menu principal contrôler par le système d'exploitation, et correspondant à l'application courante qui a le focus. Et quand toutes les fenêtres d'une même application sont fermées, ce menu reste présent tant que l'on ne quitte pas l'application;
Ceci est bien pris en charge dans une application XULRunner, mais nous devons ajouter un peu de code pour celà.
Quelques docuementation sur MDN:
Si notre appli utilises un élément menubar
principal, XULRunner/Firefox
l'utilisera (en fait le premier menubar) pour créer ce menu spécial. Si vous n'en
avez pas, vous devriez en créer un, masquer par défaut pour les autres plateformes,
il permettra la construction de ce menu.
les entrées dans le menu "pomme" sont construits d'après des éléments avec
des id
réservés. Vous devriez créer au moins quelques entrées,
pour permettre de quitter l'appli par exemple.
Voici la liste des id disponibles correspondants à ces entrées (sources) :
id de l'élément | item du menu correspondant |
---|---|
aboutName |
À propos de cette application |
menu_preferences |
Préférences... |
menu_mac_services |
Services |
menu_mac_hide_app |
Masquer l'appli |
menu_mac_hide_others |
Masquer les autres |
menu_mac_show_all |
Tout afficher |
menu_FileQuitItem |
Quitter |
et voici un exemple d'un menu xul minimal pour cet usage :
<commandset id="main-commands">
<command id="cmd:quit" oncommand="myappQuitApplication();"/>
</commandset>
<keyset id="ui-keys">
<key id="key:quitApp" key="Q" modifiers="accel" command="cmd:quit"/>
<key id="key:hideApp" key="H" modifiers="accel"/>
<key id="key:hideOthersApp" key="H" modifiers="accel,alt"/>
</keyset>
<menubar id="main-menubar" hidden="true">
<menu id="mac-menu">
<menupopup>
<menuitem id="menu_mac_hide_app" label="Hide My App" key="key:hideApp"/>
<menuitem id="menu_mac_hide_others" label="Hide Others" key="key:hideOthersApp"/>
<menuitem id="menu_mac_show_all" label="Show All"/>
<menuitem id="menu_FileQuitItem" label="Quit" key="key:quitApp" command="cmd:quit"/>
</menupopup>
</menu>
</menubar>
Bien sur, comme pour les autres parties de l'appli, les chaînes utilisées dans les labels et clés devraient être localisées. Mais ce n'est pas le propos de ce tutoriel.
La fonction myappQuitApplication
a été ajoutée dans le fichier
main.js
de notre appli :
function myappQuitApplication() {
const Cc = Components.classes;
const Ci = Components.interfaces;
let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);
return true;
}
Enfin, le dernier problème : quand toutes les fenêtres de notre
appli sont fermées, en fait l'appli ne quitte pas, et le menu principal
demeure. Plus, tel quel, c'est le menu de Firefox que nous voyons.
En fait, il y a une fenêtre speciale et cachée que XULRunner utilises pour ce menu.
Donc nous devons créer une telle fenêtre, et définir une préférence pour
la spécifier.
Voilà la préférence ajoutée dans defaults/preferences/pref.js
:
pref("browser.hiddenWindowChromeURL", "chrome://myapp/content/hiddenWindow.xul");
Et le contenu de hiddenWindow.xul
, qui contient uniquement notre menubar :
<window id="hiddenWindow"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript">
<![CDATA[
function myappQuitApplication() {
const Cc = Components.classes;
const Ci = Components.interfaces;
let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);
return true;
}
]]>
</script>
<commandset id="main-commands">
<command id="cmd:quit" oncommand="myappQuitApplication();"/>
</commandset>
<keyset id="ui-keys">
<key id="key:quitApp" key="Q" modifiers="accel" command="cmd:quit"/>
<key id="key:hideApp" key="H" modifiers="accel"/>
<key id="key:hideOthersApp" key="H" modifiers="accel,alt"/>
</keyset>
<menubar id="main-menubar" hidden="true">
<menu id="mac-menu">
<menupopup>
<menuitem id="menu_mac_hide_app" label="Hide My App" key="key:hideApp"/>
<menuitem id="menu_mac_hide_others" label="Hide Others" key="key:hideOthersApp"/>
<menuitem id="menu_mac_show_all" label="Show All"/>
<menuitem id="menu_FileQuitItem" label="Quit" key="key:quitApp" command="cmd:quit"/>
</menupopup>
</menu>
</menubar>
</window>
4.4 Créer un "Application Bundle"
Sur Mac OSX, les applications sont empaquetées dans un format spécial
nommé Application Bundle. C'est en fait un dossier, nommé
avec l'extension .app
, et avec une structure particulière.
Quelques documentations utiles :
- Inside Application Bundles
- Runtime Configuration Guidelines: Introduction
- Custom app bundles for Mac OS X
Voici une proposition d'un dossier .app
pour notre appli :
|- MyApp.app/
|- Contents/
|- MacOS/
|- chrome/
|- defaults/
|- application.ini
|- chrome.manifest
|- foxstub
|- myapp-mac.sh
|- Resources/
|- myapp.icns
|- Info.plist
|- PkgInfo
le dossier MacOS
contient en fait tous les fichiers
et dossiers de notre appli XULRunner.
le dossier Resources
contient uniquement notre
icône au format icns.
Le fichier PkgInfo
contient uniquement la chaîne
APPL????
. Je ne suis pas sûr que ce fichier soit réellement nécessaire,
il semble important pour la compatibilité avec Mac OS 9.
La valeur spécifie que ce bundle est une application, et comme nous n'avons
pas d'identifiant de 4 caractères valide, nous utilisons 4 points d'interrogation
(????
).
Le fichier Info.plist
décrit notre appli :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>myapp-mac.sh</string>
<key>CFBundleGetInfoString</key>
<string>MyApp 1.0</string>
<key>CFBundleIconFile</key>
<string>myapp</string>
<key>CFBundleIdentifier</key>
<string>net.yourcompany.myapp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MyApp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0.0.0</string>
<key>NSAppleScriptEnabled</key>
<true/>
</dict>
</plist>
Quelques commentaires sur ces propriétés :
CFBundleExecutable
pointe sur notre lanceur,
le script shell nommé myapp-mac.sh
.
la valeur de CFBundleIconFile
est
myapp
parce que notre icône dans le dossier Resources est nommée
myapp.icns
. Maintenant, l'utilisateur final
visualise notre bundle avec notre icône.
CFBundleIdentifier
est formaté tel que
domaine inversé point nom de l'application
. Ce doit être un
identifiant unique pour notre appli.
CFBundlePackageType
spécifie que c'est un
"application bundle" (APPL
).
La valeur de CFBundleSignature
est
????
parce que nous n'avons pas de signature. C'est supposé
être un identifiant unique de 4 caractères, et supposé être obtenue
après un enregistrement auprès d'Apple. Tel que je le comprend, c'est
exiger essentiellement pour Mac OS 9. Ne vous inquiétez pas, je n'ai pas
vu de problème avec cette valeur ;) .
Maintenant voyons une belle astuce. Tel quel, l'utilisateur
final voit notre appli avec notre icône, mais quand il la lance, l'icône
dans le dock est celle de Firefox.
Dans l'arborescence du dossier de notre bundle, vous pouvez voir un fichier
nommé foxstub
, ce fichier est en fait un
lien symbolique vers l'exécutable de Firefox.
Ce lien est obtenu simplement, dans le dossier MacOS, avec :
ln -s /Applications/Firefox.app/Contents/MacOS/firefox-bin foxstub
Maintenant quand l'utilisateur lance notre appli, c'est bien notre icône qui est affichée dans le dock :) .
En fait, notre icône apparait dans le dock, puis disparait, et réapparait de nouveau, parce que notre script est lancé, puis l'exécutable lié. mais ce n'est pas un gros problème.
Voici le script modifié de notre lanceur myapp-mac.sh
, qui
utilise dorénavant le lien symbolique vers Firefox :
#!/bin/sh
set -e
# see http://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script
# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && \
pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")
# resolve symlinks
while [ -h $SELF_PATH ]; do
DIR=$(dirname -- "$SELF_PATH")
SYM=$(readlink $SELF_PATH)
SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
CUR_DIR=$(dirname "$SELF_PATH")
if [ -x "$CUR_DIR/foxstub" ]; then
"$CUR_DIR/foxstub" -app "$CUR_DIR/application.ini" $@
else
echo "Error: unable to find Firefox or XULRunner!"
fi
Nous allons générer notre "application bundle" à la'ide d'un script bash.
Il est vraiment simple, nous avons juste à copier le contenu de notre appli
dans le dossier MacOS. Voici le contenu de build_mac.sh
:
#!/bin/bash
# exit the script on errors
set -e
TMP_DIR=./tmp
# get the absolute path of our TMP_DIR folder
TMP_DIR=$(readlink -f -- "$TMP_DIR")
# re-create the TMP_DIR folder
rm -rfv "$TMP_DIR"
mkdir -v "$TMP_DIR"
# create the .app folder
mkdir -v "$TMP_DIR/MyApp.app"
# copy our bundle skeleton
# (our launcher myapp-mac.sh and our symbolic link foxstub are included)
cp -rv data/bundle_skelet/. "$TMP_DIR/MyApp.app/"
# copy our app
cp -rv myapp/* "$TMP_DIR/MyApp.app/Contents/MacOS/"
# apply the correct permissions
chmod -R 755 "$TMP_DIR/MyApp.app"
# and copy the result in our main src folder
rm -frv MyApp.app
cp -Rv "$TMP_DIR/MyApp.app" ./
Ce script sera continuer par la suite. Mais pour le moment, en résultat,
nous avons créer "l'Application Bundle" MyApp.app
dans notre dossier source principal.
4.5 Empaqueter un tar.gz et un dmg
Pour distribuer notre bundle, nous devons créer une archive. Je propose 2 solutions, chacune avec ses avantages et inconvénients.
Créer un tar.gz
La première et la plus simple, est de créer un tar.gz. Ce format est bien pris en charge par Mac OSX. Le seul problème est l'utilisateur final risque de ne pas trouver celà très convivial. Voici ce qu'il a à faire :
- télécharger le fichier myapp.tar.gz.
- l'ouvrir. En fait le comportement par défaut est de décompresser l'archive dans le même dossier.
- aller dans le dossier décompressé
- déplacer par glisser/déposer le bundle où il le souhaite, par exemple dans /Applications/
Le problème est la phase 2, certains utilisateurs ne comprennent pas que l'archive est décompressée, et où.
pour créer ce tar.gz, nous ajoutons les lignes suivantes dans notre
script build_mac.sh
:
# create a sub-directory for the tar.gz creation
mkdir "$TMP_DIR/myapp-1.0"
# copy our bundle
# (It would be possible to add other files, the license for example)
cp -rv "$TMP_DIR/MyApp.app" "$TMP_DIR/myapp-1.0/"
rm -fv myapp-mac-1.0.tar.gz
cd "$TMP_DIR"
tar -zcvf "../myapp-mac-1.0.tar.gz" myapp-1.0
cd -
Créer un dmg
la seconde solution est de créer une
archive dmg.
En fait c'est un format d'image disque.
C'est une solution habituelle sur cette plateforme, et utilisée par Firefox par exemple.
Nous pouvons créer un dmg depuis Linux, mais avec une limitation :
nous ne pouvons pas générer de dmg compressé. Enfin en fait il y a une
méthode expérimentale de le faire, que je vais vous proposé ensuite, mais elle est encore
expérimentale.
L'article le plus utile que j'ai trouvé sur ce sujet est
ce billet
de l'auteur de DMDirc. Nous allons suivre les mêmes méthodes.
La méthode la plus simple sur linux est d'utiliser mkisofs
,
ou genisoimage
.
genisoimage
est un fork du premier, utilisé par certaines distributions,
et comme un lien symbolique nommé mkisofs
est également installé par ces
distributions, j'utiliserai la commande mkisofs
dans la suite du script.
Pour l'installer sur Debian/Ubuntu :
apt-get install genisoimage
Nous ajoutons dans notre script build_mac.sh
:
# create the dmg
rm -fv myapp-1.0.dmg
mkisofs -V 'MyApp' -no-pad -r -apple -o "myapp-1.0.dmg" "$TMP_DIR/myapp-1.0"
Avec cette ligne, nous créons le fichier myapp-1.0.dmg
, qui contient
tous les fichiers et dossiers inclus dans le dossier $TMP_DIR/myapp-1.0
,
avec un nom de volume 'MyApp'
(le titre de la fenêtre quand le dmg
est monté sur Mac). Et tous les fichiers et dossiers dans le dmg ont les droits 755.
the 755 rights.
Compresser ce dmg
La seule solution trouvée pour réaliser cette tâche sur Linux, mentionné
dans ce
billet,
est d'utiliser le programme dmg
du projet
libdmg-hfsplus.
L'auteur dit clairement :
THE CODE HEREIN SHOULD BE CONSIDERED HIGHLY EXPERIMENTAL
traduction approximative :
CE CODE DOIT ÊTRE CONSIDÉRER COMME HAUTEMENT EXPÉRIMENTAL
Noter que le dernier commit du projet que j'ai essayé ne compilait pas
(quelqu'un a rapporté
le bug).
Et l'auteur de DMDirc rapporte un autre bug d'une version précédente.
Mais essayer sa
And the author of DMDirc report another bug in a previous version. But I have
tried its version légèrement modifiée, avec succès !
Donc vous devriez l'essayer.
Voici les lignes ajoutées à notre script :
# try to compress our dmg, if the the command <dmg> is available
# see http://github.com/planetbeing/libdmg-hfsplus
# and http://shanemcc.co.uk/libdmg/
if [ -x "./tools/dmg" ]; then
# rename temporarily our dmg
mv myapp-1.0.dmg myapp-1.0.dmg.pre
# compress
"./tools/dmg" dmg myapp-1.0.dmg.pre myapp-1.0.dmg
rm -fv myapp-1.0.dmg.pre
fi
Noter que je n'inclus pas le programme dmg
dans l'archive jointe,
vous devrez le télécharger vous même depuis les liens précédents, et le
placer dans le dossier tools
.
Créer un dmg depuis Mac OSX
pour information, pour créer un dmg directement depuis Mac OSX, il existe le programme hdiutil. Pour créer un dmg compressé et s'ouvrant automatiquement, d'après un dossier nommé "myFolder", quelque chose du genre devrait marcher :
#!/bin/bash
hdiutil create -volname "myapp-1.0" -fs HFS+ -srcfolder "myFolder" -format UDRW myapp-temp.dmg
hdiutil convert myapp-temp.dmg -format UDZO -imagekey zlib-level=9 -o myapp.dmg
rm -fv myapp-temp.dmg
Personnaliser le dmg
il est possible de personnaliser notre dmg quand il est monté, c'est à dire la fenêtre affichée, par exemple : dimensions de l'icône, image d'arrière plan, dimensions de la fenêtre...
L'idée est de créer un dmg en lecture/écriture sur un mac, de le personnaliser
manuellement, puis de faire une copie du fichier
.DS_STORE
et de toutes les autres données. Ensuite nous utiliserons ces données lors
de la création de notre dmg à l'aide de notre script.
Cette partie ne peut être faite que manuellement et directement depuis un Mac.
Créer une image disque en lecture/écriture
Sur un Mac, ouvrez "Utilitaires de disque" dans le dossier "Utilitaires".
Cliquer sur "Nouvelle image".
Choisissez le même nom que le futur nom de volume de notre dmg
(MyApp
).
N'utilisez pas un format journalisé, pour être capable de choisir une
"petite" taille pour ce dmg. La taille importe peu, elle doit juste être
suffisante pour copier notre appli et les autres données.
Comme format
d'image, choisissez image disque en lecture et écriture
Puis cliquer sur "créer".
Ajouter nos données sur l'image disque
Maintenant montez ce dmg en cliquant dessus. Et ouvrez le.
Copiez notre appli dans la fenêtre ouverte.
Nous pouvons copier le lien symbolique vers /Applications
également,
si il existe. Sinon nous le créerons dans un terminal plus tard.
Ouvrez un terminal, depuis les Utilitaires.
Allez dans l'image disque monté :
cd /Volumes/MyApp
puis créez un dossier nommé .background
:
mkdir .background
comme ce nom commence par un point (.
), ce dossier est caché,
comme sur Linux.
copiez notre image d'arrière plan dans ce dossier :
cp pathToOurImage/background.png /Volumes/MyApp/.background/
Et, si besoin, créez le lien symbolique vers /Applications :
ln -s /Applications /Volumes/MyApp/Applications
Personnaliser l'image disque
Maintenant donnez le focus à la fenêtre du disque monté, et ouvrez
"Afficher les options de présentation" depuis le menu "Présentation"
Sélectionner Image
pour l'airrière plan, puis cliquer sur le bouton.
Nous devons sélectionner le fichier background.png dans le disque monté,
mais comme ce fichier est dans un dossier caché, nous ne pouvons pas le voir.
Pas d'inquiétude, taper Apple+Shift+G
:
puis taper /Volumes/MyApp/.background/
, puis entrée.
sélectionnez maintenant notre png.
Choissisez la taille d'icône, par exemple 128, arrangez les par aucun
,
puis déplacez les où vous le souhaitez, et adapter la taille de fenêtre
à votre arrière-plan.
Maintenant fermer cette fenêtre, et éjecter le disque. Puis monter le de nouveau, et ouvrez le.
Copier la personnalisation créée
Dans un terminal, copiez le fichier .DS_STORE
créé à la racine
du disque monté :
cp /Volumes/MyApp/.DS_STORE pathToSave/myDS_STORE
Maintenant nous avons enfin tous les fichiers nécessaires pour notre script,
nous avons juste à copier le fichier .DS_STORE et le dossier .background avec
le fichier background.png . Le dmg que nous créerons aura la même personnalisation.
Copions ces données dans nos sources :
|- samples_chapter_4/
|- data/
|- bundle_skelet/
|- dmg_extra_data/
|- .background/
|- background.png
|- Applications
|- .DS_STORE
Et nous ajoutons les lignes suivantes à notre script build_mac.sh
,
avant de créer le dmg :
# copy eventual extra data, by example a symbolic link to /Applications
if [ $(ls -A "data/dmg_extra_data" | wc -c) -ne 0 ]; then
cp -Rv data/dmg_extra_data/. "$TMP_DIR/myapp-1.0/"
fi
Notez que cette personnalisation est dépendente du nom de volume utilisé,
en particulier pour l'image d'arrière plan, parce que le fichier .DS_STORE
utilise des chemins absolus vers le disque monté, et le nom de volume en fait partie.
Donc si vous changer le nom de volume, vous devez recréer manuellement cette
personnalisation...
Lancer notre script de build
Pour lancer notre script (sur Linux), et créer nos dmg et tar.gz, dans un terminal :
cd samples_chapter_4
sh ./build_mac.sh
Et, en résultat, nous avons finalement le dossier MyApp.app
,
et les fichiers myapp-1.0.dmg
et myapp-1.0.tar.gz
dans notre dossier de source principal.
Vous pouvez télécharger tous les exemples de ce chapitre 4 (Mac OSX) dans l'archive samples_chapter_4.tar.gz .
L'application myapp, de developer.mozilla.org, est dans le Domaine Public.
L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.
Toutes les autres données ajoutées, et les fichiers en exemple, de ce chapitre 4, sont dans le Domain Public également.
Commentaires
Helⅼo this is somewhɑt of off topic but I wаs wanting to know іf bⅼogs use WYSIWΥG editors or if you have tο manually code with HTML.
I'm starting a blog soon but have no coding know-how so I
wanted tо gеt advice frօm ѕomeone wіth experience.
Any help would be enormoսsly appreciɑted!
I could not refrain from commenting. Exceptionally well written!
I read this piece of writing fully concerning the difference of newest and earlier technologies, it's awesome
article.
Good day! I simply wish to offer you a big thumbs up for your great information you've got right here on this post.
I am returning to your blog for more soon.
Heya just wanted to give you a quick heads up and let you know a
few of the pictures aren't loading correctly. I'm not sure why but I think its a linking issue.
I've tried it in two different browsers and both show the same outcome.
Nice post. I was checking continuously this blog and I am impressed!
Very useful information specifically the closing phase :) I maintain such info
a lot. I used to be seeking this certain info for a long time.
Thanks and good luck.
Pretty! This was a really wonderful article. Thank you for
providing these details.
Right away I am ready to do my breakfast, once having my
breakfast coming over again to read more news.
http://w.cidesa.com.ve/index.php/Wh... shirt j'adior https://genesisblock.one/index.php/... j.
shirts ladies http://zweiradwiki.realaxl.de/index... shirt zipper down back
http://americaswomenmagazine.xyz/bl... f t shirt http://nosys.ca/index.php/User:Yvet... shirt #1 pattern https://ffxiv-knights-ivalice.org/i... $1 shirts
free shipping
https://x4wiki.grayghostindustries.... shirts s oliver http://andytripp.org/index.php?titl... shirt zipper https://www.clars.dk/index.php?titl... i-shirt amazon
https://www.clars.dk/index.php?titl... shirt vector http://wiki.hnjhj.com/index.php?tit... shirt embroidery
machine https://beisbol-report.com/wiki/Sav... shirt heat press
https://genesisblock.one/index.php/... shirt #1 pattern https://www.algorithmictrading.wiki... u neck shirt http://wiki.ndf.taklia.com/index.ph... size 8 shirt in us
https://ffxiv-knights-ivalice.org/i... i-shirt amazon http://www.wiki-peps.fr/mediawiki/i... initial d shirt http://waldorfwiki.de/index.php?tit... shirt 17 34/35
https://wiki.flo.cash/index.php/How... shirt
4 letter word https://wiki.avora15.org/index.php/... shirt and tie combinations http://www.ffxiv-wiki.com/index.php... uniqlo u shirt
https://www.hotrodders.com/tw/index... shirt garters https://wiki.uni-due.de/wls/index.p... rafter c shirts https://ecosystem.fi/wiki/Houston_H... shirt 60
http://encyclopedia.php.xdomain.jp/... i shirt cotton https://www.zeldaclassic.com/wiki/i... shirt n tie https://8to80travel.org/index.php/W... $1 shirts free shipping
https://beisbol-report.com/wiki/Usu... rafter c shirts https://wiki.avora15.org/index.php/... pauly
d shirts http://wikibase.plantdata.io/wiki/H... shirt
gun
https://www.zeldaclassic.com/wiki/i... e shirts online https://beisbol-report.com/wiki/Whi... shirt jacs http://waldorfwiki.de/index.php?tit... shirt
vest
http://howtolearn.today/wiki/User:D... 0 irish shirt https://minecraftathome.com/minecra... l
shirt death note http://www.roovet.com/articles/Hous... shirt over dress
https://www.mgtow.wiki/index.php/Us... shirt embroidery https://wiki506.buildtools.com/inde... shirt long sleeve https://x4wiki.grayghostindustries.... t shirt press
https://www.mgtow.wiki/index.php/Us... jimmy z shirt https://physioexrx.com/index.php/Ho... shirt engraving
http://demo.sytian-productions.com/... shirt bathing suit
http://www.simracinglinks.com/index... shirt
space coupon http://andytripp.org/index.php?titl... short yellow dress https://www.readysetassist.org/wiki... shirt 16 1/2
http://www.wiki-peps.fr/mediawiki/i... shirt k design https://physioexrx.com/index.php/Bl... yakuza 0 shirt https://ptcrotator.tk/index.php?a=s... l shirt size
means
http://www.arctic-cool.de/index.php... kangen water machine
sd501 http://wiki.hnjhj.com/index.php?tit... kangen water machine price list
https://beisbol-report.com/wiki/Kan... best kangen water machine
https://wiki.flo.cash/index.php/Use... what is kangen water https://www.clars.dk/index.php?titl... kangen water machine japan https://www.wiki.clientigent.com/in... kangen water
machine price list
https://ffxiv-knights-ivalice.org/i... kangen water
machine japan https://www.clars.dk/index.php?titl... kangen water
machine k8 https://aarth-codex.com/index.php/U... kangen water machine japan
https://wiki506.buildtools.com/inde... best
kangen water machine https://beisbol-report.com/wiki/Bes... kangen water
machine japan http://www.ffxiv-wiki.com/index.php... Kangen water
machine sd501
http://www.arctic-cool.de/index.php... kangen water machine reviews
http://wiki.hnjhj.com/index.php?tit... kangen water
machines for sale https://wiki506.buildtools.com/inde... kangen water machine
sd501
https://physioexrx.com/index.php/Us... kangen water machines for sale https://wiki506.buildtools.com/inde... kangen water machine k8 https://wiki.darkcoin.eu/index.php?... best kangen water machine
https://physioexrx.com/index.php/Wh... what is kangen water http://bookmarkstar.com/story.php?t... best kangen water machine https://physioexrx.com/index.php/Be... best kangen water machine
http://darmowelinki.website.pl/book... best
kangen water machine https://asta.uni-saarland.de/wiki/i... kangen water machines for sale https://www.clars.dk/index.php?titl... kangen water machine k8
https://victims.wiki/index.php/Kang... what is
kangen water https://pt7.info/index.php?title=Ka... kangen water machine k8
https://victims.wiki/index.php/Kang... what is kangen water
https://www.zeldaclassic.com/wiki/i... kangen water machine japan https://aarth-codex.com/index.php/K... kangen water machine reviews https://pt7.info/index.php?title=Us... kangen water machine k8
https://wiki506.buildtools.com/inde... what is kangen water http://www.roovet.com/articles/What... kangen water machine k8 http://top.marriageable.ru/index.ph... kangen water machine k8
https://rockfishlax.com/library/ind... kangen water machine reviews
https://my-lgbt.wiki/index.php?titl... kangen water machines for sale https://www.clars.dk/index.php?titl... kangen water machine reviews
https://1bankir.ru/user/RickyMorin7... kangen water machine
k8 http://peptiki.org/User:AudreaDewit... best kangen water machine https://physioexrx.com/index.php/Ka... kangen water machine k8
https://www.wiki.clientigent.com/in... kangen water machine sd501 https://ffxiv-knights-ivalice.org/i... Kangen water machine reviews https://wiki506.buildtools.com/inde... kangen water machine k8
http://www.colleges.ipt.pw/News/kan... kangen water machine reviews https://www.zeldaclassic.com/wiki/i... what
is kangen water https://wiki.darkcoin.eu/index.php?... kangen water machines for sale
https://pt7.info/index.php?title=Us... kangen water machine price list http://www.schattentraum.net/Wiki/i... what is kangen water https://www.zeldaclassic.com/wiki/i... kangen water machine
japan
https://wiki.flo.cash/index.php/Sca... Scaleblaster water conditioner http://apejd.ch/wiki/index.php?titl... scaleblaster costco
https://cvcamp.org/index.php/Scaleb... scaleblaster water conditioner
https://asta.uni-saarland.de/wiki/i... scaleblaster
sb-150 https://pt7.info/index.php?title=Sc... scaleblaster reviews https://www.readysetassist.org/wiki... scaleblaster
https://aarth-codex.com/index.php/S... scaleblaster sb-75 https://osderby.com/wiki/Scaleblast... scaleblaster costco https://multi.wiki/index.php/Scaleb... scaleblaster reviews 2020
https://wiki506.buildtools.com/inde... scaleblaster sb-75 https://www.clars.dk/index.php?titl... scaleblaster reviews http://wiki.ndf.taklia.com/index.ph... scaleblaster sb-30
http://www.politics.ipt.pw/News/sca... scaleblaster sb-150 https://wiki.pbbg.com/wiki/Scalebla... scaleblaster costco https://my-lgbt.wiki/index.php?titl... scaleblaster costco
https://pt7.info/index.php?title=Sc... scaleblaster reviews 2020 http://www.lucamauri.net/wikilab/in... scaleblaster sb-175 https://wiki.psxdigital.com/index.p... scaleblaster reviews 2020
https://wikicorp.org/index.php?titl... scaleblaster sb-150 https://wiki506.buildtools.com/inde... scaleblaster water conditioner http://www.arctic-cool.de/index.php... scaleblaster reviews
http://www.ffxiv-wiki.com/index.php... scaleblaster sb-175 http://shorl.com/pomyfrafrifuma scaleblaster water conditioner http://www.distinction.ipt.pw/user/... scaleblaster reviews
http://wiki.ndf.taklia.com/index.ph... scaleblaster
sb-75 http://www.randmwiki.com/index.php?... scaleblaster sb-175 http://www.arctic-cool.de/index.php... scaleblaster sb-75
https://wiki506.buildtools.com/inde... scaleblaster sb-175
http://link.bookmarkstar.com/story.... scaleblaster reviews http://peptiki.org/User:ZacBorchgre... scaleblaster sb-75
http://www.slicedblu.com/wiki/index... scaleblaster reviews
https://physioexrx.com/index.php/Sc... scaleblaster reviews
http://www.factories.sbm.pw/user/da... scaleblaster sb-30
http://wiki.ndf.taklia.com/index.ph... scaleblaster https://victims.wiki/index.php/Scal... scaleblaster sb-150 https://asta.uni-saarland.de/wiki/i... scaleblaster sb-150
http://vps579.greenhost.nl/wiki/Sca... scaleblaster reviews 2020 https://wiki506.buildtools.com/inde... scaleblaster costco https://www.wiki.lavoxpopuli.com/in... scaleblaster costco
http://mediawiki.hslsoft.com/index.... scaleblaster https://elunivercity.net/wiki-start... scaleblaster sb-30 https://wikicorp.org/index.php?titl... scaleblaster costco
http://ameinema.synology.me/mediawi... scaleblaster reviews 2020 http://www.arctic-cool.de/index.php... scaleblaster sb-175 https://victims.wiki/index.php/Does... scaleblaster reviews
2020
http://www.ffxiv-wiki.com/index.php... scaleblaster reviews http://www.politics.ipt.pw/News/sca... scaleblaster costco https://wiki.psxdigital.com/index.p... scaleblaster sb-150
https://wiki506.buildtools.com/inde... kangen water machine sd501 http://wiki.hnjhj.com/index.php?tit... what is kangen water http://www.arctic-cool.de/index.php... what is kangen water
https://my-lgbt.wiki/index.php?titl... kangen water machine k8 https://wiki.darkcoin.eu/index.php?... kangen water machine japan https://www.clars.dk/index.php?titl... kangen water machine k8
https://my-lgbt.wiki/index.php?titl... kangen water
machine sd501 https://www.mgtow.wiki/index.php/Us... what
is kangen water http://top.marriageable.ru/index.ph... kangen water machines for sale
https://my-lgbt.wiki/index.php?titl... kangen water machine price list
https://physioexrx.com/index.php/Ka... what is kangen water https://www.zeldaclassic.com/wiki/i... kangen water machine k8
https://bunny.wiki/wiki/User:Marcus... what is kangen water https://pt7.info/index.php?title=Us... kangen water machine
reviews https://www.mgtow.wiki/index.php/Us... best kangen water machine
https://wiki506.buildtools.com/inde... kangen water machine
sd501 https://ultrapedia.org/wiki/index.p... best kangen water machine http://nosys.ca/index.php/Kangen_Wa... best kangen water machine
https://wiki506.buildtools.com/inde... what is kangen water https://www.clars.dk/index.php?titl... kangen water machines for sale https://www.mgtow.wiki/index.php/Us... kangen water machine k8
http://www.scheme.ipt.pw/out/kangen... what is kangen water https://victims.wiki/index.php/Best... kangen water machines for sale http://www.ffxiv-wiki.com/index.php... kangen water machine k8
http://wiki.hnjhj.com/index.php?tit... kangen water machine price list http://www.ffxiv-wiki.com/index.php... best kangen water machine https://wiki.darkcoin.eu/index.php?... kangen water machines for sale
https://wiki506.buildtools.com/inde... kangen water machine k8
https://porno365.su/user/ArmandoO99... best kangen water machine
https://aarth-codex.com/index.php/K... kangen water machines for sale
http://www.ffxiv-wiki.com/index.php... kangen water machines for sale https://wiki.darkcoin.eu/index.php?... kangen water machine k8 https://www.clars.dk/index.php?titl... best kangen water machine
https://physioexrx.com/index.php/Us... what is kangen water https://wiki.flo.cash/index.php/Wha... kangen water machine japan https://wiki506.buildtools.com/inde... best kangen water machine
https://www.mgtow.wiki/index.php/Be... kangen water machine sd501
https://wiki.darkcoin.eu/index.php?... kangen water machine japan http://wiki.hnjhj.com/index.php?tit... kangen water machine japan
http://darmowelinki.website.pl/book... kangen water machine sd501 http://www.financial-services.ipt.p... kangen water machine k8 http://www.ffxiv-wiki.com/index.php... kangen water machine reviews
https://ffxiv-knights-ivalice.org/i... kangen water machine k8
https://www.clars.dk/index.php?titl... kangen water machine japan http://www.schattentraum.net/Wiki/i... kangen water machine price list
https://wiki.darkcoin.eu/index.php?... what is kangen water https://www.clars.dk/index.php?titl... kangen water machine price list https://physioexrx.com/index.php/Ka... kangen water machines for
sale
https://elunivercity.net/wiki-start... atmospheric water generator reviews https://wiki506.buildtools.com/inde... nube water from
air generator http://wiki.sandship.rockbitegames.... commercial atmospheric
water generator
https://www.clars.dk/index.php?titl... nube
water from air generator https://www.krvresources.org/index.... atmospheric water
generator project https://sipcaster.com/ccawiki/index... commercial atmospheric water generator
https://asta.uni-saarland.de/wiki/i... atmospheric water generator reviews https://x4wiki.grayghostindustries.... commercial
atmospheric water generator https://wikicorp.org/index.php?titl... portable
atmospheric water generator
https://medarots.projectrisingbeetl... commercial
atmospheric water generator http://inglott.network/index.php/At... portable atmospheric water generator http://wiki.trumpchannel.org/index.... passive atmospheric water generator
https://ecosystem.fi/wiki/Atmospher... portable
atmospheric water generator https://ecosystem.fi/wiki/Atmospher... portable
atmospheric water generator http://gt-wiki.8u.cz/index.php?titl... atmospheric water generator project
http://wiki.hnjhj.com/index.php?tit... commercial atmospheric water generator https://wiki.ohiolinux.org/index.ph... portable atmospheric water generator https://genesisblock.one/index.php/... Atmospheric
water generator reviews
https://physioexrx.com/index.php/Us... atmospheric water generator project https://thethirdage.net/wiki/index.... atmospheric water generator reviews http://bu1106ucl.bimserver2.com/ucl... atmospheric water generator project
http://www.ffxiv-wiki.com/index.php... nube water from air generator https://vnashemnazvaniinetslovcraft... passive atmospheric
water generator http://gt-wiki.8u.cz/index.php?titl... passive atmospheric water generator
https://wiki.ohiolinux.org/index.ph... atmospheric water generator
project https://ecosystem.fi/wiki/User:Patr... atmospheric water generator project http://wiki.ndf.taklia.com/index.ph... commercial atmospheric water generator
https://www.readysetassist.org/wiki... nube water from air generator
https://thethirdage.net/wiki/index.... atmospheric water generator reviews https://wiki506.buildtools.com/inde... portable atmospheric water generator
https://bunny.wiki/wiki/Atmospheric... portable atmospheric water generator http://mediawiki.hslsoft.com/index.... atmospheric water generator project https://thethirdage.net/wiki/index.... atmospheric water generator reviews
https://genesisblock.one/index.php/... commercial atmospheric water generator https://wiki.dulovic.tech/index.php... atmospheric water generator project https://minecraftathome.com/minecra... commercial atmospheric
water generator
http://wiki.feedle.net/index.php?ti... portable atmospheric water generator http://bu1106ucl.bimserver2.com/ucl... passive atmospheric
water generator https://wikicorp.org/index.php?titl... portable atmospheric water
generator
http://ca.bookmarkstar.com/user.php... nube water from air generator http://wiki.sandship.rockbitegames.... atmospheric water generator project https://www.readysetassist.org/wiki... portable atmospheric water generator
https://envelopedia.com/index.php?t... portable atmospheric water generator https://thethirdage.net/wiki/index.... atmospheric water generator
project https://bunny.wiki/wiki/User:Kennit... commercial atmospheric water generator
http://inglott.network/index.php/Us... portable atmospheric water generator http://vps579.greenhost.nl/wiki/Geb... passive atmospheric water generator http://mediawiki.hslsoft.com/index.... commercial atmospheric water generator
https://www.kennethknee.com/mediawi... atmospheric water generator project
https://pt7.info/index.php?title=At... atmospheric water
generator reviews https://aarth-codex.com/index.php/U... portable atmospheric water generator
https://asta.uni-saarland.de/wiki/i... commercial
atmospheric water generator https://asta.uni-saarland.de/wiki/i... portable atmospheric water generator https://www.mgtow.wiki/index.php/At... nube water from air generator
https://ultrapedia.org/wiki/index.p... nube water from air generator https://wolvesbaneuo.com/Wiki/index... commercial atmospheric water generator http://andytripp.org/index.php?titl... atmospheric
water generator reviews
https://elunivercity.net/wiki-start... nube water
from air generator https://www.mgtow.wiki/index.php/Us... portable atmospheric water generator https://emulation.wiki/index.php?ti... nube water from air generator
http://wiki-intel.org/index.php?tit... nube
water from air generator https://emulation.wiki/index.php?ti... atmospheric water generator project
https://asta.uni-saarland.de/wiki/i... passive atmospheric water
generator
https://beisbol-report.com/wiki/Usu... portable atmospheric water
generator https://elunivercity.net/wiki-start... portable atmospheric water generator http://kcm.kr/jump.php?sid=43441&am... commercial atmospheric water generator
https://victims.wiki/index.php/Atmo... commercial atmospheric water
generator https://konzertkalender-osnabrueck.... atmospheric water generator project https://zerocarbon.email/wiki/index... atmospheric water generator
reviews
https://konzertkalender-osnabrueck.... atmospheric water generator reviews https://wolvesbaneuo.com/Wiki/index... commercial atmospheric water generator http://www.idealogy.ipt.pw/user/cli... nube
water from air generator
http://www.slicedblu.com/wiki/index... portable
atmospheric water generator http://www.php.ipt.pw/out/public-pr... atmospheric water generator project https://www.clars.dk/index.php?titl... atmospheric water generator
project
http://www.slicedblu.com/wiki/index... atmospheric water generator reviews https://wiki.psxdigital.com/index.p... commercial atmospheric water generator http://vps579.greenhost.nl/wiki/Atm... atmospheric water generator project
http://wiki.feedle.net/index.php?ti... atmospheric water generator project http://www.ffxiv-wiki.com/index.php... atmospheric water generator reviews http://ameinema.synology.me/mediawi... nube water from air generator
https://wiki.psxdigital.com/index.p... commercial atmospheric water generator https://ultrapedia.org/wiki/index.p... atmospheric water generator
project http://wiki.sandship.rockbitegames.... nube water from air generator
http://wiki.genki.dk/wiki/Atmospher... passive
atmospheric water generator http://nosys.ca/index.php/Atmospher... portable atmospheric water
generator http://waldorfwiki.de/index.php?tit... atmospheric water generator reviews
http://www.venture.ipt.pw/user/chet... nube water from air generator https://wiki.jdranastasia.com/media... nube water from air
generator https://wiki.psxdigital.com/index.p... portable atmospheric water generator
https://ffxiv-knights-ivalice.org/i... portable atmospheric water generator https://eddiefarzad.com/index.php?t... portable
atmospheric water generator https://polaritylibrary.com/index.p... commercial atmospheric water generator
https://ffxiv-knights-ivalice.org/i... portable atmospheric water generator https://ffxiv-knights-ivalice.org/i... atmospheric water generator reviews http://www.mental-health.sbm.pw/out... commercial atmospheric water generator
Your method of telling the whole thing in this article is in fact good, all can without difficulty understand it, Thanks a
lot.우리카지노
My Ьrother suggesteԁ I miɡht like this bl᧐g. Hе was totɑlly right.
Thiѕ post truly mаde my dаy. You can not imagine simply how mucһ time
Ӏ haԀ spent for this info! Thanks!
Hi there to all, how is everything, I think every one is getting more from this web page, and your
views are good in favor of new viewers.