_Config.cs

Description du code

_Config.cs est un fichier du projet BiblioBrol.
Ce fichier est situé dans /var/www/bin/sniplets/bibliobrol/src/.

Projet BiblioBrol :

Gestion de media en CSharp.

Pour plus d'infos, vous pouvez consulter la brève analyse.

Code source ou contenu du fichier

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using be.gaudry.bibliobrol.model;
  5. using System.Configuration;
  6. using System.IO;
  7. using System.Windows.Forms;
  8. using be.gaudry.observer;
  9. using be.gaudry.model.config;
  10. using be.gaudry.bibliobrol.model.enums;
  11. using be.gaudry.model.enums;
  12. using be.gaudry.model.exceptions;
  13.  
  14. namespace be.gaudry.bibliobrol
  15. {
  16. public class Config : Observable
  17. {
  18. #region declarations
  19. /// <summary>
  20. /// Used to get the brol identifier of reference Bibliobrol.
  21. /// This brol is used to store default roles for the persons.
  22. /// </summary>
  23. public const int BibliobrolId = 1;//838;
  24. public const string eidDllPath = "beidlib.dll";
  25. public const string Kernel32DLL = "kernel32.dll";
  26. /// <summary>
  27. /// Class used to read the configuration file
  28. /// </summary>
  29. private Settings brolSettings;
  30. private Person owner;
  31. /// <summary>
  32. /// Used only to store for a short time owner.Id instead of creating a new Person
  33. /// </summary>
  34. private int ownerId;
  35. private String
  36. refDataDirPath, dataDirPath, imgBrolDir, imgPersDir, imgAppDir,
  37. useDB, accessSourceDB,
  38. awsSubscription, proxyAddress;
  39. private ACCESS_VERSION accessVersion;
  40. private Version dbVersion;
  41. private bool pCriticalError, pOpsResult, dispConsoleForm, cCriticalError, cOpsResult, cLowError, cBasicOps, cAdvancedOps, cDebug, firstUse;
  42. private PERSON_DISPLAY personDisplay;
  43. #endregion
  44.  
  45. #region singleton
  46.  
  47.  
  48. static readonly Config instance = new Config();
  49.  
  50. // Explicit static constructor to tell C# compiler
  51. // not to mark type as beforefieldinit
  52. static Config()
  53. {
  54. }
  55.  
  56. private Config()
  57. {
  58. refDataDirPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +
  59. Path.DirectorySeparatorChar +
  60. "bibliobrol";
  61. dataDirPath = Properties.Settings.Default.dataDir;
  62. brolSettings = new Settings(
  63. String.Format("{0}{1}settings.xml", getDataPath(), Path.DirectorySeparatorChar)
  64. );
  65. awsSubscription = brolSettings.GetSetting("login/aws", "0525E2PQ81DD7ZTWTK82");
  66. ownerId = brolSettings.GetSetting("general/ownerId", 0);
  67. //owner = BiblioBrol.Model.DAO.DAOFactory.Instance.getConfigDao().loadOwner();
  68. imgAppDir = "images/application";
  69. imgBrolDir = "images/ouvrages";
  70. imgPersDir = "images/personnes";
  71.  
  72. useDB = brolSettings.GetSetting("persistance/useDB", "Access");
  73. accessSourceDB = brolSettings.GetSetting("persistance/Access/filename", "data.bdb");
  74. try
  75. {
  76. accessVersion = (ACCESS_VERSION)brolSettings.GetSetting("persistance/Access/version", (int)ACCESS_VERSION.Access03);
  77. }
  78. catch (ArgumentException) { accessVersion = ACCESS_VERSION.Access03; }
  79.  
  80. dispConsoleForm = "true".Equals(brolSettings.GetSetting("console/visible", "false"));
  81. pCriticalError = "true".Equals(brolSettings.GetSetting("popup/criticalError", "true"));
  82. pOpsResult = "true".Equals(brolSettings.GetSetting("popup/opsResult", "true"));
  83. cCriticalError = "true".Equals(brolSettings.GetSetting("console/criticalError", "false"));
  84. cOpsResult = "true".Equals(brolSettings.GetSetting("console/opsResult", "false"));
  85. cLowError = "true".Equals(brolSettings.GetSetting("console/lowError", "false"));
  86. cBasicOps = "true".Equals(brolSettings.GetSetting("console/basicOps", "false"));
  87. cAdvancedOps = "true".Equals(brolSettings.GetSetting("console/advancedOps", "false"));
  88. cDebug = "true".Equals(brolSettings.GetSetting("console/debug", "false"));
  89. firstUse = "true".Equals(brolSettings.GetSetting("firstUse", "true"));
  90. try
  91. {
  92. personDisplay = (PERSON_DISPLAY)brolSettings.GetSetting("display/person", (int)PERSON_DISPLAY.pseudo);
  93. }
  94. catch (ArgumentException) { personDisplay = PERSON_DISPLAY.pseudo; }
  95. proxyAddress = brolSettings.GetSetting("net/proxy", "");
  96. }
  97.  
  98. public static Config Instance
  99. {
  100. get
  101. {
  102. return instance;
  103. }
  104. }
  105. #endregion
  106.  
  107. #region getters and setters
  108.  
  109. /// <summary>
  110. /// Version of the persistant layer.
  111. /// Used to detect if a schema modification is needed
  112. /// </summary>
  113. public static Version DBVersion
  114. {
  115. get
  116. {
  117. if (Instance.dbVersion == null)
  118. {
  119. try
  120. {
  121. string[] versionArray = model.dao.DAOFactory.Instance.getConfigDao().loadConfig("persistanceVersion").Split(new char[] { '.' });
  122.  
  123. int major, minor, build, revision;
  124. int.TryParse(versionArray[0], out major);
  125. int.TryParse(versionArray[1], out minor);
  126. int.TryParse(versionArray[2], out build);
  127. int.TryParse(versionArray[3], out revision);
  128. System.Console.WriteLine("test : " + major + "," + minor + "," + build + "," + revision);
  129.  
  130. Instance.dbVersion = new Version(major, minor, build, revision);
  131. }
  132. catch
  133. {
  134. Instance.dbVersion = new Version(0, 0, 0, 0);
  135. }
  136. }
  137. return Instance.dbVersion;
  138. }
  139. }
  140.  
  141. /// <summary>
  142. /// Subscription on Amazon webservice
  143. /// </summary>
  144. public static String AwsSubscription
  145. {
  146. get { return Instance.awsSubscription; }
  147. set { Instance.awsSubscription = value; }
  148. }
  149.  
  150. /// <summary>
  151. /// Address of the client proxy to access the web
  152. /// </summary>
  153. public static string ProxyAddress
  154. {
  155. get { return Instance.proxyAddress; }
  156. set
  157. {
  158. Instance.proxyAddress = value;
  159. //Instance.brolSettings.PutSetting("net/proxy", value);
  160. }
  161. }
  162. /// <summary>
  163. /// Owner of this application
  164. /// </summary>
  165. public static Person Owner
  166. {
  167. get
  168. {
  169. if (Instance.ownerId == 0)
  170. Instance.notify(new Notification(Notification.VERBOSE.criticalError,"Erreur critique",new Exception("Aucun propriétaire n'est défini pour l'application. Veuillez en définir un."),Instance));
  171. if (Instance.owner == null || Instance.owner.Equals(new Person()))
  172. {
  173. Instance.owner = be.gaudry.bibliobrol.model.dao.DAOFactory.Instance.getPersonDao().loadPerson(Instance.ownerId, false);
  174. }
  175. return Instance.owner;
  176. }
  177. set
  178. {
  179. Instance.owner = value;
  180. }
  181. }
  182. /// <summary>
  183. /// Directory path to store all brol data
  184. /// </summary>
  185. public static String DataDirPath
  186. {
  187. get
  188. {
  189. return Instance.getDataPath();
  190. }
  191. set
  192. {
  193. /*if (Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).Equals(value))
  194.   {
  195.   Instance.dataDirPath = "";
  196.   }
  197.   else*/
  198. Instance.dataDirPath = value;
  199. }
  200. }
  201.  
  202. private string getDataPath()
  203. {
  204. return (String.Empty.Equals(dataDirPath)) ? refDataDirPath : dataDirPath;
  205. }
  206. /// <summary>
  207. /// Directory path of export files
  208. /// </summary>
  209. public static String ExportDir
  210. {
  211. get
  212. {
  213. StringBuilder s = new StringBuilder(DataDirPath);
  214. s.Append(Path.DirectorySeparatorChar);
  215. s.Append("export");
  216. s.Append(Path.DirectorySeparatorChar);
  217. return s.ToString();
  218. }
  219. }
  220. /// <summary>
  221. /// Directory path of brol's images
  222. /// </summary>
  223. public static String ImgBrolDir
  224. {
  225. get { return Instance.imgBrolDir; }
  226. set { Instance.imgBrolDir = value; }
  227. }
  228. /// <summary>
  229. /// Directory relative path of brol's images
  230. /// </summary>
  231. public static String RelImgBrolDir
  232. {
  233. get
  234. {
  235. StringBuilder s = new StringBuilder(DataDirPath);
  236. s.Append(Path.DirectorySeparatorChar);
  237. s.Append(Instance.imgBrolDir);
  238. s.Append(Path.DirectorySeparatorChar);
  239. return s.ToString();
  240. }
  241. }
  242. /// <summary>
  243. /// Directory path of person's images
  244. /// </summary>
  245. public static String ImgPersDir
  246. {
  247. get { return Instance.imgPersDir; }
  248. set { Instance.imgPersDir = value; }
  249. }
  250.  
  251. /// <summary>
  252. /// Directory relative path of person's images
  253. /// </summary>
  254. public static String RelImgPersDir
  255. {
  256. get
  257. {
  258. StringBuilder s = new StringBuilder(DataDirPath);
  259. s.Append(Path.DirectorySeparatorChar);
  260. s.Append(Instance.imgPersDir);
  261. s.Append(Path.DirectorySeparatorChar);
  262. return s.ToString();
  263. }
  264. }
  265. /// <summary>
  266. /// Directory path of application's images
  267. /// </summary>
  268. public static String ImgAppDir
  269. {
  270. get { return Instance.imgAppDir; }
  271. set { Instance.imgAppDir = value; }
  272. }
  273. /// <summary>
  274. /// Directory relative path of application's images
  275. /// </summary>
  276. public static String RelImgAppDir
  277. {
  278. get
  279. {
  280. StringBuilder s = new StringBuilder(DataDirPath);
  281. s.Append(Path.DirectorySeparatorChar);
  282. s.Append(Instance.imgAppDir);
  283. s.Append(Path.DirectorySeparatorChar);
  284. return s.ToString();
  285. }
  286. }
  287. public static String UseDB
  288. {
  289. get
  290. {
  291. return Instance.useDB;
  292. }
  293. }
  294. public static String AccessSourceDB
  295. {
  296. get
  297. {
  298. if (Instance.accessSourceDB.Contains(":"))
  299. { return Instance.accessSourceDB; }
  300.  
  301. StringBuilder s = new StringBuilder(Config.DataDirPath);
  302. s.Append(Path.DirectorySeparatorChar);
  303. s.Append(Instance.accessSourceDB);
  304. return s.ToString();
  305. }
  306. set
  307. {
  308. StringBuilder s;
  309. if (String.Empty.Equals(value))
  310. {
  311. s = new StringBuilder("data.bdb");
  312. }
  313. else
  314. {
  315. s = new StringBuilder(value);
  316. s.Replace(Config.DataDirPath + Path.DirectorySeparatorChar, "");
  317. }
  318. Instance.accessSourceDB = s.ToString();
  319. Instance.brolSettings.PutSetting("persistance/Access/filename", Instance.accessSourceDB);
  320. }
  321. }
  322. public static ACCESS_VERSION AccessVersion
  323. {
  324. get
  325. {
  326. return Instance.accessVersion;
  327. }
  328. set
  329. {
  330. Instance.brolSettings.PutSetting("persistance/Access/version", (int)Instance.accessVersion);
  331. }
  332. }
  333. public static PERSON_DISPLAY PersonDisplay
  334. {
  335. get { return Instance.personDisplay; }
  336. set { Instance.personDisplay = value; }
  337. }
  338. /// <summary>
  339. /// Shows or hides the <code>be.gaudry.bibliobrol.view.ConsoleForm</code>
  340. /// </summary>
  341. public static bool ShowConsoleForm
  342. {
  343. get { return Instance.dispConsoleForm; }
  344. set
  345. {
  346. Instance.dispConsoleForm = value;
  347. Instance.notify(new Notification(Notification.VERBOSE.internalNotification, "display console", value.ToString(), Instance));
  348. }
  349. }
  350. public static bool PopupCriticalError
  351. {
  352. get { return Instance.pCriticalError; }
  353. set { Instance.pCriticalError = value; }
  354. }
  355. public static bool PopupOpsResult
  356. {
  357. get { return Instance.pOpsResult; }
  358. set { Instance.pOpsResult = value; }
  359. }
  360. public static bool ConsoleCriticalError
  361. {
  362. get { return Instance.cCriticalError; }
  363. set { Instance.cCriticalError = value; }
  364. }
  365. public static bool ConsoleOpsResult
  366. {
  367. get { return Instance.cOpsResult; }
  368. set { Instance.cOpsResult = value; }
  369. }
  370. public static bool ConsoleLowError
  371. {
  372. get { return Instance.cLowError; }
  373. set { Instance.cLowError = value; }
  374. }
  375. public static bool ConsoleBasicOps
  376. {
  377. get { return Instance.cBasicOps; }
  378. set { Instance.cBasicOps = value; }
  379. }
  380. public static bool ConsoleAdvancedOps
  381. {
  382. get { return Instance.cAdvancedOps; }
  383. set { Instance.cAdvancedOps = value; }
  384. }
  385. public static bool ConsoleDebug
  386. {
  387. get { return Instance.cDebug; }
  388. set { Instance.cDebug = value; }
  389. }
  390. public static bool FirstUse
  391. {
  392. get { return Instance.firstUse; }
  393. set { Instance.firstUse = value; }
  394. }
  395.  
  396. #endregion
  397.  
  398. #region static methods
  399.  
  400. #region specific save
  401. /// <summary>
  402. /// Set the Config.DataDirPath value and save it on the config file
  403. /// in the same directory than the executable file
  404. /// </summary>
  405. /// <param name="path">(String) Path of the data directory</param>
  406. public static void saveDataDir(String path)
  407. {
  408. Config.DataDirPath = path;
  409. if (Instance.refDataDirPath.Equals(Config.DataDirPath))
  410. //saveAppSetting("dataPath", "");
  411. Properties.Settings.Default.dataDir = "";
  412. else
  413. //saveAppSetting("dataPath", Instance.dataDirPath);
  414. Properties.Settings.Default.dataDir = Instance.dataDirPath;
  415. Properties.Settings.Default.Save();
  416. }
  417. /// <summary>
  418. /// Set the Config.Owner value, and save it
  419. /// </summary>
  420. /// <param name="owner"></param>
  421. public static void saveOwner(Person owner)
  422. {
  423. Config.Owner = owner;
  424. Instance.brolSettings.PutSetting("general/ownerId", owner.Id);
  425. }
  426.  
  427. public static void savePersonDisplay(PERSON_DISPLAY personDisplay)
  428. {
  429. Config.PersonDisplay = personDisplay;
  430. Instance.brolSettings.PutSetting("display/person", (int)personDisplay);
  431. }
  432. public static void savePersonDisplay(int personDisplay)
  433. {
  434. try
  435. {
  436. savePersonDisplay((PERSON_DISPLAY)personDisplay);
  437. }
  438. catch (ArgumentException)
  439. {
  440. savePersonDisplay(PERSON_DISPLAY.pseudo);
  441. }
  442. }
  443. /// <summary>
  444. /// Set the Config.DataDirPath value and save it on the config file
  445. /// in the same directory than the executable file
  446. /// </summary>
  447. public static void saveAwsSubscription(String amazonSubscription)
  448. {
  449. Config.AwsSubscription = amazonSubscription;
  450. Instance.brolSettings.PutSetting("login/aws", amazonSubscription);
  451. }
  452. #endregion
  453.  
  454. #region multi save
  455. public static void save()
  456. {
  457. StringBuilder str = new StringBuilder("Sauvegarde des options effectuée");
  458. //BiblioBrol.Model.DAO.DAOFactory.Instance.getConfigDao().saveOwner(owner);
  459. Instance.brolSettings.PutSetting("general/ownerId", Config.Owner.Id);
  460. str.AppendLine("\n\nPropriétaire :");
  461. str.Append(Config.Owner.ToString());
  462. //str.Append(" [");
  463. //str.Append(Config.Owner.Id.ToString());
  464. //str.Append("]");
  465. saveDirsPath(str);
  466. saveConsolePrefs(str);
  467. Instance.notify(new Notification(Notification.VERBOSE.basicOperation, str.ToString(), Instance));
  468. }
  469.  
  470. public static void saveConsolePrefs(StringBuilder str)
  471. {
  472. str.AppendLine("\n\nPréférences notifications : ");
  473. Instance.brolSettings.PutSetting("console/visible", Instance.dispConsoleForm);
  474. str.Append("\nAfficher la console : ");
  475. str.Append(Instance.dispConsoleForm.ToString());
  476.  
  477. Instance.brolSettings.PutSetting("popup/criticalError", Instance.pCriticalError);
  478. str.Append("\nErreur critique (popup) : ");
  479. str.Append(Instance.pCriticalError.ToString());
  480.  
  481. Instance.brolSettings.PutSetting("console/criticalError", Instance.cCriticalError);
  482. str.Append("\nErreur critique (console) : ");
  483. str.Append(Instance.cCriticalError.ToString());
  484.  
  485. Instance.brolSettings.PutSetting("popup/opsResult", Instance.pOpsResult);
  486. str.Append("\nRésultat d'opération (popup) : ");
  487. str.Append(Instance.pOpsResult.ToString());
  488.  
  489. Instance.brolSettings.PutSetting("console/opsResult", Instance.cOpsResult);
  490. str.Append("\nRésultat d'opération (console) : ");
  491. str.Append(Instance.cOpsResult.ToString());
  492.  
  493. Instance.brolSettings.PutSetting("console/basicOps", Instance.cBasicOps);
  494. str.Append("\nOpération de base : ");
  495. str.Append(Instance.cBasicOps.ToString());
  496.  
  497. Instance.brolSettings.PutSetting("console/advancedOps", Instance.cAdvancedOps);
  498. str.Append("\nOpération avancée : ");
  499. str.Append(Instance.cAdvancedOps.ToString());
  500.  
  501. Instance.brolSettings.PutSetting("console/lowError", Instance.cLowError);
  502. str.Append("\nErreur non bloquante : ");
  503. str.Append(Instance.cLowError.ToString());
  504.  
  505. Instance.brolSettings.PutSetting("console/debug", Instance.cDebug);
  506. str.Append("\nDebug (requêtes) : ");
  507. str.Append(Instance.cDebug.ToString());
  508. }
  509.  
  510. private static void saveDirsPath(StringBuilder str)
  511. {
  512. str.AppendLine("\n\nRépertoire : ");
  513. String key = "dataPath";
  514. String value = "";
  515. if (!Instance.refDataDirPath.Equals(Config.DataDirPath))
  516. value = Instance.dataDirPath;
  517. if(saveAppSetting(key, value))
  518. str.AppendLine((value == "") ? Config.DataDirPath : value);
  519. else
  520. str.AppendLine("Valeur non sauvée");
  521. }
  522. #endregion
  523.  
  524. #region save application settings (in the exe directory)
  525. /// <summary>
  526. /// Be carefull : the value may be lost after an application update
  527. /// Save a setting from memory to config file
  528. /// We don't need to provide the value (value is read from the setting into memory)
  529. /// </summary>
  530. /// <param name="key"></param>
  531. /// <returns></returns>
  532. public static bool saveAppSetting(String key)
  533. {
  534. try
  535. {
  536. String value = ConfigurationManager.AppSettings[key];
  537. return Config.saveAppSetting(key, value);
  538. }
  539. catch (NullReferenceException nre)
  540. {
  541. Instance.notify(new Notification(Notification.VERBOSE.error, "Sauvegarde de la configuration", "soit le fichier de configuration n'est pas présent (il doit se trouver dans le même répertoire que l'application), soit il est incomplet ou endommagé.", nre, Instance));
  542. }
  543. catch (Exception e)
  544. {
  545. Instance.notify(new Notification(Notification.VERBOSE.error, "Sauvegarde de la configuration", e, Instance));
  546. }
  547. return false;
  548. }
  549. /// <summary>
  550. /// Be carefull : the value may be lost after an application update
  551. /// </summary>
  552. /// <param name="key"></param>
  553. /// <param name="value"></param>
  554. /// <returns></returns>
  555. public static bool saveAppSetting(String key, String value)
  556. {
  557. String exePath = System.IO.Path.Combine(Environment.CurrentDirectory, "BiblioBrol.exe");
  558. Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
  559. try
  560. {
  561. config.AppSettings.Settings[key].Value = value;
  562. ConfigurationManager.AppSettings[key] = value;
  563. }
  564. catch (NullReferenceException nre)
  565. {
  566. Instance.notify(new Notification(Notification.VERBOSE.criticalError, "Sauvegarde d'une valeur de configuration", "Soit le fichier de configuration n'est pas présent (il doit se trouver dans le même répertoire que l'application), soit il est incomplet ou endommagé.", nre, Instance));
  567. }
  568. catch (Exception e)
  569. {
  570. Instance.notify(new Notification(Notification.VERBOSE.error, "Sauvegarde d'une valeur de configuration", e, Instance));
  571. }
  572. try
  573. {
  574. config.Save(ConfigurationSaveMode.Modified);
  575. Instance.notify(new Notification(Notification.VERBOSE.modified, key, Instance));
  576. Instance.notify(new Notification(Notification.VERBOSE.advancedOperation, "Configuration " + key + " sauvée avec la valeur " + value, Instance));
  577. }
  578. catch (ConfigurationException cEEx)
  579. {
  580. Instance.notify(new Notification(Notification.VERBOSE.error, "Sauvegarde d'une valeur de configuration", cEEx, Instance));
  581. return false;
  582. }
  583. return true;
  584. }
  585. #endregion
  586.  
  587. #endregion
  588.  
  589. }
  590. }

Structure et Fichiers du projet

Afficher/masquer...


Répertoires contenus dans /var/www/bin/sniplets/bibliobrol/src/config/ 
IcôneNomTailleModification
Pas de sous-répertoires.
IcôneNomTailleModification
| _ Répertoire parent0 octets1734871073 22/12/2024 13:37:53
Fichiers contenus dans /var/www/bin/sniplets/bibliobrol/src/config/ 
IcôneNomTailleModificationAction
IcôneNomTailleModificationAction
Afficher le fichier .cs|.cs_Config.cs22.75 Ko31/10/2018 18:32:23-refusé-
Afficher le fichier .cs|.csConfig.cs16.76 Ko31/10/2018 18:32:23-refusé-

Utilisation de l'explorateur de code

  • Navigation :
    • Un clic sur une icône de répertoire ouvre ce répertoire pour en afficher les fichiers.
    • Lorsque le répertoire en cours ne contient pas de sous-répertoires il est possible de remonter vers le répertoire parent.
    • La structure de répertoires en treetable (tableau en forme d'arborescence) n'est plus possibledans cette version.
    • Un clic sur une icône de fichier ouvre ce fichier pour en afficher le code avec la coloration syntaxique adaptée en fonction du langage principal utilisé dans le fichier.
  • Affichage :
    • Il est possible de trier les répertoires ou les fichiers selon certains critères (nom, taille, date).
  • Actions :
    • Les actions possible sur les fichiers dépendent de vos droits d'utilisateur sur le site. Veuillez activer le mode utilisateur pour activer les actions.

Nederlandse vertaling

U hebt gevraagd om deze site in het Nederlands te bezoeken. Voor nu wordt alleen de interface vertaald, maar nog niet alle inhoud.

Als je me wilt helpen met vertalingen, is je bijdrage welkom. Het enige dat u hoeft te doen, is u op de site registreren en mij een bericht sturen waarin u wordt gevraagd om u toe te voegen aan de groep vertalers, zodat u de gewenste pagina's kunt vertalen. Een link onderaan elke vertaalde pagina geeft aan dat u de vertaler bent en heeft een link naar uw profiel.

Bij voorbaat dank.

Document heeft de 16/10/2009 gemaakt, de laatste keer de 26/10/2018 gewijzigd
Bron van het afgedrukte document:https://www.gaudry.be/nl/cs-bibliobrol-source-rf-config/_Config.cs.html

De infobrol is een persoonlijke site waarvan de inhoud uitsluitend mijn verantwoordelijkheid is. De tekst is beschikbaar onder CreativeCommons-licentie (BY-NC-SA). Meer info op de gebruiksvoorwaarden en de auteur.