diff --git a/src/fr/devinsy/xidyn/pages/Page.java b/src/fr/devinsy/xidyn/pages/Page.java
new file mode 100644
index 0000000..655a343
--- /dev/null
+++ b/src/fr/devinsy/xidyn/pages/Page.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (C) 2016 Christian Pierre MOMON
+ *
+ * This file is part of Xidyn.
+ *
+ * Xidyn is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Xidyn is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Xidyn. If not, see
+ */
+package fr.devinsy.xidyn.pages;
+
+import fr.devinsy.xidyn.data.TagDataManager;
+import fr.devinsy.xidyn.presenters.Presenter;
+
+/**
+ *
+ */
+public class Page extends TagDataManager
+{
+ private Presenter presenter;
+ private StringBuffer lastDynamize;
+
+ /**
+ *
+ */
+ public Page(final Presenter presenter)
+ {
+ super();
+
+ if (presenter == null)
+ {
+ throw new IllegalArgumentException("Null parameter.");
+ }
+ else
+ {
+ this.presenter = presenter;
+ this.lastDynamize = null;
+ }
+ }
+
+ /**
+ *
+ * @return
+ * @throws Exception
+ */
+ public StringBuffer dynamize() throws Exception
+ {
+ StringBuffer result;
+
+ this.lastDynamize = this.presenter.dynamize(this);
+
+ result = this.lastDynamize;
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public boolean isComplete()
+ {
+ boolean result;
+
+ if (this.lastDynamize == null)
+ {
+ result = false;
+ }
+ else
+ {
+ result = true;
+ }
+
+ //
+ return result;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public StringBuffer lastVersion() throws Exception
+ {
+ StringBuffer result;
+
+ if ((this.lastDynamize == null) || (this.presenter.isOutdated()))
+ {
+ dynamize();
+ }
+
+ result = this.lastDynamize;
+
+ //
+ return result;
+ }
+}
+
+// ////////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/src/fr/devinsy/xidyn/pages/PageFactory.java b/src/fr/devinsy/xidyn/pages/PageFactory.java
new file mode 100644
index 0000000..8376893
--- /dev/null
+++ b/src/fr/devinsy/xidyn/pages/PageFactory.java
@@ -0,0 +1,246 @@
+/**
+ * Copyright (C) 2016 Christian Pierre MOMON
+ *
+ * This file is part of Xidyn.
+ *
+ * Xidyn is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Xidyn is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Xidyn. If not, see
+ */
+package fr.devinsy.xidyn.pages;
+
+import java.io.File;
+import java.net.URL;
+
+import org.w3c.dom.Document;
+
+import fr.devinsy.util.strings.StringListUtils;
+import fr.devinsy.xidyn.presenters.PresenterFactory;
+import fr.devinsy.xidyn.utils.cache.Cache;
+
+/**
+ *
+ * @author Christian Pierre MOMON (christian.momon@devinsy.fr)
+ */
+public class PageFactory
+{
+ /**
+ * http://thecodersbreakfast.net/index.php?post/2008/02/25/26-de-la-bonne-
+ * implementation-du-singleton-en-java
+ *
+ */
+ private static class SingletonHolder
+ {
+ private final static PageFactory INSTANCE = new PageFactory();
+ }
+
+ private Cache cache;
+
+ /**
+ *
+ */
+ private PageFactory()
+ {
+ this.cache = new Cache();
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final Document source)
+ {
+ Page result;
+
+ result = new Page(PresenterFactory.instance().get(source));
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ * @throws Exception
+ */
+ public Page get(final Document source, final String... keys)
+ {
+ Page result;
+
+ String key = StringListUtils.toStringSeparatedBy(keys, "-").toString();
+
+ result = this.cache.get(key);
+ if (result == null)
+ {
+ result = get(source);
+ this.cache.put(key, result);
+ }
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final File source)
+ {
+ Page result;
+
+ result = new Page(PresenterFactory.instance().get(source));
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final File source, final String... keys)
+ {
+ Page result;
+
+ String key = StringListUtils.toStringSeparatedBy(keys, "-").toString();
+
+ result = this.cache.get(key);
+ if (result == null)
+ {
+ result = get(source);
+ this.cache.put(key, result);
+ }
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final String source)
+ {
+ Page result;
+
+ result = new Page(PresenterFactory.instance().get(source));
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final String source, final String... keys)
+ {
+ Page result;
+
+ String key = StringListUtils.toStringSeparatedBy(keys, "-").toString();
+
+ result = this.cache.get(key);
+ if (result == null)
+ {
+ result = get(source);
+ this.cache.put(key, result);
+ }
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final URL source)
+ {
+ Page result;
+
+ result = new Page(PresenterFactory.instance().get(source));
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @param source
+ * @param parameters
+ * @return
+ */
+ public Page get(final URL source, final String... keys)
+ {
+ Page result;
+
+ String key = StringListUtils.toStringSeparatedBy(keys, "-").toString();
+
+ result = this.cache.get(key);
+ if (result == null)
+ {
+ result = get(source);
+ this.cache.put(key, result);
+ }
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ */
+ public void clear()
+ {
+ this.cache.clear();
+ PresenterFactory.instance().clear();
+ }
+
+ /**
+ *
+ * @return
+ */
+ public int size()
+ {
+ int result;
+
+ result = this.cache.size();
+
+ //
+ return result;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public static PageFactory instance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+}
+
+// ////////////////////////////////////////////////////////////////////////
\ No newline at end of file